Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 : #include <ObjexxFCL/string.functions.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/Autosizing/Base.hh>
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/CurveManager.hh>
60 : #include <EnergyPlus/Data/EnergyPlusData.hh>
61 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
62 : #include <EnergyPlus/DataEnvironment.hh>
63 : #include <EnergyPlus/DataGlobalConstants.hh>
64 : #include <EnergyPlus/DataHVACGlobals.hh>
65 : #include <EnergyPlus/DataIPShortCuts.hh>
66 : #include <EnergyPlus/DataLoopNode.hh>
67 : #include <EnergyPlus/DataSizing.hh>
68 : #include <EnergyPlus/EMSManager.hh>
69 : #include <EnergyPlus/FaultsManager.hh>
70 : #include <EnergyPlus/FluidProperties.hh>
71 : #include <EnergyPlus/General.hh>
72 : #include <EnergyPlus/GeneralRoutines.hh>
73 : #include <EnergyPlus/GlobalNames.hh>
74 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
75 : #include <EnergyPlus/NodeInputManager.hh>
76 : #include <EnergyPlus/OutAirNodeManager.hh>
77 : #include <EnergyPlus/OutputProcessor.hh>
78 : #include <EnergyPlus/OutputReportPredefined.hh>
79 : #include <EnergyPlus/Plant/DataPlant.hh>
80 : #include <EnergyPlus/Plant/PlantLocation.hh>
81 : #include <EnergyPlus/PlantChillers.hh>
82 : #include <EnergyPlus/PlantUtilities.hh>
83 : #include <EnergyPlus/Psychrometrics.hh>
84 : #include <EnergyPlus/ScheduleManager.hh>
85 : #include <EnergyPlus/UtilityRoutines.hh>
86 :
87 : namespace EnergyPlus {
88 :
89 : namespace PlantChillers {
90 :
91 : // MODULE INFORMATION:
92 : // AUTHOR Dan Fisher / Brandon Anderson
93 : // DATE WRITTEN September 2000
94 : // MODIFIED Richard Liesen Nov-Dec 2001; Jan 2002
95 : // Chandan Sharma, FSEC, February 2010, Added basin heater
96 : // RE-ENGINEERED Edwin: Merged Four Chiller Modules Into One
97 :
98 : // PURPOSE OF THIS MODULE:
99 : // This module simulates the performance of the Electric vapor
100 : // compression Chillers, Gas Turbine Chillers, Engine Drivent chillers, and
101 : // Constant COP chillers
102 :
103 : // METHODOLOGY EMPLOYED:
104 : // Called by plantloopequipment, model accepts inputs, and calculates a
105 : // thermal response using new plant routines such as SetComponentFlowRate
106 :
107 : // REFERENCES:
108 : // 1. BLAST Users Manual
109 :
110 : // Parameters for use in Chillers
111 : Real64 constexpr KJtoJ(1000.0); // convert Kjoules to joules
112 :
113 0 : void BaseChillerSpecs::getDesignCapacities(
114 : [[maybe_unused]] EnergyPlusData &state, const PlantLocation &calledFromLocation, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
115 : {
116 0 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) {
117 0 : MinLoad = this->NomCap * this->MinPartLoadRat;
118 0 : MaxLoad = this->NomCap * this->MaxPartLoadRat;
119 0 : OptLoad = this->NomCap * this->OptPartLoadRat;
120 : } else {
121 0 : MinLoad = 0.0;
122 0 : MaxLoad = 0.0;
123 0 : OptLoad = 0.0;
124 : }
125 0 : }
126 :
127 0 : void BaseChillerSpecs::getSizingFactor(Real64 &sizFac)
128 : {
129 0 : sizFac = this->SizFac;
130 0 : }
131 :
132 0 : void BaseChillerSpecs::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
133 : {
134 0 : this->initialize(state, false, 0.0);
135 0 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) {
136 0 : this->size(state);
137 : }
138 0 : }
139 :
140 0 : void BaseChillerSpecs::getDesignTemperatures(Real64 &tempDesCondIn, Real64 &tempDesEvapOut)
141 : {
142 0 : tempDesEvapOut = this->TempDesEvapOut;
143 0 : tempDesCondIn = this->TempDesCondIn;
144 0 : }
145 :
146 0 : ElectricChillerSpecs *ElectricChillerSpecs::factory(EnergyPlusData &state, std::string const &chillerName)
147 : {
148 0 : if (state.dataPlantChillers->GetElectricInput) {
149 0 : ElectricChillerSpecs::getInput(state);
150 0 : state.dataPlantChillers->GetElectricInput = false;
151 : }
152 0 : for (auto &thisChiller : state.dataPlantChillers->ElectricChiller) {
153 0 : if (Util::makeUPPER(thisChiller.Name) == chillerName) {
154 0 : return &thisChiller;
155 : }
156 : }
157 0 : ShowFatalError(state, format("Could not locate electric chiller with name: {}", chillerName));
158 0 : return nullptr;
159 : }
160 :
161 2 : void ElectricChillerSpecs::getInput(EnergyPlusData &state)
162 : {
163 : // SUBROUTINE INFORMATION:
164 : // AUTHOR: Dan Fisher / Brandon Anderson
165 : // DATE WRITTEN: September 2000
166 :
167 : // PURPOSE OF THIS SUBROUTINE:
168 : // This routine will get the input
169 : // required by the Electric Chiller model.
170 :
171 : static constexpr std::string_view RoutineName("GetElectricChillerInput: "); // include trailing blank space
172 : static constexpr std::string_view routineName = "GetElectricChillerInput";
173 :
174 : int NumAlphas; // Number of elements in the alpha array
175 : int NumNums; // Number of elements in the numeric array
176 : int IOStat; // IO Status when calling get input subroutine
177 2 : bool ErrorsFound(false);
178 :
179 2 : state.dataIPShortCut->cCurrentModuleObject = "Chiller:Electric";
180 4 : state.dataPlantChillers->NumElectricChillers =
181 2 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
182 :
183 2 : if (state.dataPlantChillers->NumElectricChillers <= 0) {
184 0 : ShowSevereError(state, format("No {} Equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
185 0 : ErrorsFound = true;
186 : }
187 :
188 : // See if load distribution manager has already gotten the input
189 2 : if (allocated(state.dataPlantChillers->ElectricChiller)) return;
190 :
191 : // ALLOCATE ARRAYS
192 2 : state.dataPlantChillers->ElectricChiller.allocate(state.dataPlantChillers->NumElectricChillers);
193 :
194 : // LOAD ARRAYS WITH Electric CURVE FIT CHILLER DATA
195 4 : for (int ChillerNum = 1; ChillerNum <= state.dataPlantChillers->NumElectricChillers; ++ChillerNum) {
196 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
197 2 : state.dataIPShortCut->cCurrentModuleObject,
198 : ChillerNum,
199 2 : state.dataIPShortCut->cAlphaArgs,
200 : NumAlphas,
201 2 : state.dataIPShortCut->rNumericArgs,
202 : NumNums,
203 : IOStat,
204 2 : state.dataIPShortCut->lNumericFieldBlanks,
205 2 : state.dataIPShortCut->lAlphaFieldBlanks,
206 2 : state.dataIPShortCut->cAlphaFieldNames,
207 2 : state.dataIPShortCut->cNumericFieldNames);
208 :
209 2 : ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
210 :
211 2 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
212 :
213 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
214 2 : GlobalNames::VerifyUniqueChillerName(state,
215 2 : state.dataIPShortCut->cCurrentModuleObject,
216 2 : state.dataIPShortCut->cAlphaArgs(1),
217 : ErrorsFound,
218 4 : state.dataIPShortCut->cCurrentModuleObject + " Name");
219 :
220 2 : auto &thisChiller = state.dataPlantChillers->ElectricChiller(ChillerNum);
221 2 : thisChiller.Name = state.dataIPShortCut->cAlphaArgs(1);
222 2 : thisChiller.ChillerType = DataPlant::PlantEquipmentType::Chiller_Electric;
223 :
224 2 : thisChiller.CondenserType = static_cast<DataPlant::CondenserType>(
225 2 : getEnumValue(DataPlant::CondenserTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(2))));
226 2 : switch (thisChiller.CondenserType) {
227 2 : case DataPlant::CondenserType::AirCooled:
228 : case DataPlant::CondenserType::WaterCooled:
229 : case DataPlant::CondenserType::EvapCooled:
230 2 : break;
231 0 : default: {
232 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
233 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
234 0 : ErrorsFound = true;
235 : }
236 : }
237 :
238 2 : thisChiller.NomCap = state.dataIPShortCut->rNumericArgs(1);
239 2 : if (thisChiller.NomCap == DataSizing::AutoSize) {
240 0 : thisChiller.NomCapWasAutoSized = true;
241 : }
242 2 : if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
243 0 : ShowSevereError(state,
244 0 : format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
245 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
246 0 : ErrorsFound = true;
247 : }
248 2 : thisChiller.COP = state.dataIPShortCut->rNumericArgs(2);
249 2 : if (state.dataIPShortCut->rNumericArgs(2) == 0.0) {
250 0 : ShowSevereError(state,
251 0 : format("Invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
252 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
253 0 : ErrorsFound = true;
254 : }
255 2 : thisChiller.EvapInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
256 2 : state.dataIPShortCut->cAlphaArgs(3),
257 : ErrorsFound,
258 : DataLoopNode::ConnectionObjectType::ChillerElectric,
259 2 : state.dataIPShortCut->cAlphaArgs(1),
260 : DataLoopNode::NodeFluidType::Water,
261 : DataLoopNode::ConnectionType::Inlet,
262 : NodeInputManager::CompFluidStream::Primary,
263 : DataLoopNode::ObjectIsNotParent);
264 4 : thisChiller.EvapOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
265 2 : state.dataIPShortCut->cAlphaArgs(4),
266 : ErrorsFound,
267 : DataLoopNode::ConnectionObjectType::ChillerElectric,
268 2 : state.dataIPShortCut->cAlphaArgs(1),
269 : DataLoopNode::NodeFluidType::Water,
270 : DataLoopNode::ConnectionType::Outlet,
271 : NodeInputManager::CompFluidStream::Primary,
272 : DataLoopNode::ObjectIsNotParent);
273 4 : BranchNodeConnections::TestCompSet(state,
274 2 : state.dataIPShortCut->cCurrentModuleObject,
275 2 : state.dataIPShortCut->cAlphaArgs(1),
276 2 : state.dataIPShortCut->cAlphaArgs(3),
277 2 : state.dataIPShortCut->cAlphaArgs(4),
278 : "Chilled Water Nodes");
279 :
280 2 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
281 2 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
282 : // Connection not required for air or evap cooled condenser
283 : // If the condenser inlet is blank for air cooled and evap cooled condensers then supply a generic name
284 : // since it is not used elsewhere for connection
285 : // for transition purposes, add this node if not there.
286 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
287 0 : if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 21) { // protect against long name leading to > 100 chars
288 0 : state.dataIPShortCut->cAlphaArgs(5) = state.dataIPShortCut->cAlphaArgs(1) + " CONDENSER INLET NODE";
289 : } else {
290 0 : state.dataIPShortCut->cAlphaArgs(5) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 79) + " CONDENSER INLET NODE";
291 : }
292 : }
293 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
294 0 : if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 22) { // protect against long name leading to > 100 chars
295 0 : state.dataIPShortCut->cAlphaArgs(6) = state.dataIPShortCut->cAlphaArgs(1) + " CONDENSER OUTLET NODE";
296 : } else {
297 0 : state.dataIPShortCut->cAlphaArgs(6) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 78) + " CONDENSER OUTLET NODE";
298 : }
299 : }
300 :
301 0 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
302 0 : state.dataIPShortCut->cAlphaArgs(5),
303 : ErrorsFound,
304 : DataLoopNode::ConnectionObjectType::ChillerElectric,
305 0 : state.dataIPShortCut->cAlphaArgs(1),
306 : DataLoopNode::NodeFluidType::Air,
307 : DataLoopNode::ConnectionType::OutsideAirReference,
308 : NodeInputManager::CompFluidStream::Secondary,
309 : DataLoopNode::ObjectIsNotParent);
310 : bool Okay;
311 0 : OutAirNodeManager::CheckAndAddAirNodeNumber(state, thisChiller.CondInletNodeNum, Okay);
312 0 : if (!Okay) {
313 0 : ShowWarningError(
314 : state,
315 0 : format("{}, Adding OutdoorAir:Node={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(5)));
316 : }
317 :
318 0 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
319 0 : state.dataIPShortCut->cAlphaArgs(6),
320 : ErrorsFound,
321 : DataLoopNode::ConnectionObjectType::ChillerElectric,
322 0 : state.dataIPShortCut->cAlphaArgs(1),
323 : DataLoopNode::NodeFluidType::Air,
324 : DataLoopNode::ConnectionType::Outlet,
325 : NodeInputManager::CompFluidStream::Secondary,
326 : DataLoopNode::ObjectIsNotParent);
327 2 : } else if (thisChiller.CondenserType == DataPlant::CondenserType::WaterCooled) {
328 2 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
329 2 : state.dataIPShortCut->cAlphaArgs(5),
330 : ErrorsFound,
331 : DataLoopNode::ConnectionObjectType::ChillerElectric,
332 2 : state.dataIPShortCut->cAlphaArgs(1),
333 : DataLoopNode::NodeFluidType::Water,
334 : DataLoopNode::ConnectionType::Inlet,
335 : NodeInputManager::CompFluidStream::Secondary,
336 : DataLoopNode::ObjectIsNotParent);
337 4 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
338 2 : state.dataIPShortCut->cAlphaArgs(6),
339 : ErrorsFound,
340 : DataLoopNode::ConnectionObjectType::ChillerElectric,
341 2 : state.dataIPShortCut->cAlphaArgs(1),
342 : DataLoopNode::NodeFluidType::Water,
343 : DataLoopNode::ConnectionType::Outlet,
344 : NodeInputManager::CompFluidStream::Secondary,
345 : DataLoopNode::ObjectIsNotParent);
346 4 : BranchNodeConnections::TestCompSet(state,
347 2 : state.dataIPShortCut->cCurrentModuleObject,
348 2 : state.dataIPShortCut->cAlphaArgs(1),
349 2 : state.dataIPShortCut->cAlphaArgs(5),
350 2 : state.dataIPShortCut->cAlphaArgs(6),
351 : "Condenser Water Nodes");
352 : // Condenser Inlet node name is necessary for Water Cooled
353 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
354 0 : ShowSevereError(state, format("Invalid, {}is blank ", state.dataIPShortCut->cAlphaFieldNames(5)));
355 0 : ShowContinueError(state,
356 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
357 0 : ErrorsFound = true;
358 2 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
359 0 : ShowSevereError(state, format("Invalid, {}is blank ", state.dataIPShortCut->cAlphaFieldNames(6)));
360 0 : ShowContinueError(state,
361 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
362 0 : ErrorsFound = true;
363 : }
364 : } else {
365 0 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
366 0 : state.dataIPShortCut->cAlphaArgs(5),
367 : ErrorsFound,
368 : DataLoopNode::ConnectionObjectType::ChillerElectric,
369 0 : state.dataIPShortCut->cAlphaArgs(1),
370 : DataLoopNode::NodeFluidType::Blank,
371 : DataLoopNode::ConnectionType::Inlet,
372 : NodeInputManager::CompFluidStream::Secondary,
373 : DataLoopNode::ObjectIsNotParent);
374 0 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
375 0 : state.dataIPShortCut->cAlphaArgs(6),
376 : ErrorsFound,
377 : DataLoopNode::ConnectionObjectType::ChillerElectric,
378 0 : state.dataIPShortCut->cAlphaArgs(1),
379 : DataLoopNode::NodeFluidType::Blank,
380 : DataLoopNode::ConnectionType::Outlet,
381 : NodeInputManager::CompFluidStream::Secondary,
382 : DataLoopNode::ObjectIsNotParent);
383 0 : BranchNodeConnections::TestCompSet(state,
384 0 : state.dataIPShortCut->cCurrentModuleObject,
385 0 : state.dataIPShortCut->cAlphaArgs(1),
386 0 : state.dataIPShortCut->cAlphaArgs(5),
387 0 : state.dataIPShortCut->cAlphaArgs(6),
388 : "Condenser (unknown?) Nodes");
389 : // Condenser Inlet node name is necessary
390 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
391 0 : ShowSevereError(state, format("Invalid, {}is blank ", state.dataIPShortCut->cAlphaFieldNames(5)));
392 0 : ShowContinueError(state,
393 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
394 0 : ErrorsFound = true;
395 0 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
396 0 : ShowSevereError(state, format("Invalid, {}is blank ", state.dataIPShortCut->cAlphaFieldNames(6)));
397 0 : ShowContinueError(state,
398 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
399 0 : ErrorsFound = true;
400 : }
401 : }
402 :
403 2 : thisChiller.MinPartLoadRat = state.dataIPShortCut->rNumericArgs(3);
404 2 : thisChiller.MaxPartLoadRat = state.dataIPShortCut->rNumericArgs(4);
405 2 : thisChiller.OptPartLoadRat = state.dataIPShortCut->rNumericArgs(5);
406 2 : thisChiller.TempDesCondIn = state.dataIPShortCut->rNumericArgs(6);
407 2 : thisChiller.TempRiseCoef = state.dataIPShortCut->rNumericArgs(7);
408 2 : thisChiller.TempDesEvapOut = state.dataIPShortCut->rNumericArgs(8);
409 2 : thisChiller.EvapVolFlowRate = state.dataIPShortCut->rNumericArgs(9);
410 2 : if (thisChiller.EvapVolFlowRate == DataSizing::AutoSize) {
411 0 : thisChiller.EvapVolFlowRateWasAutoSized = true;
412 : }
413 2 : thisChiller.CondVolFlowRate = state.dataIPShortCut->rNumericArgs(10);
414 2 : if (thisChiller.CondVolFlowRate == DataSizing::AutoSize) {
415 0 : if (thisChiller.CondenserType == DataPlant::CondenserType::WaterCooled) {
416 0 : thisChiller.CondVolFlowRateWasAutoSized = true;
417 : }
418 : }
419 2 : thisChiller.CapRatCoef(1) = state.dataIPShortCut->rNumericArgs(11);
420 2 : thisChiller.CapRatCoef(2) = state.dataIPShortCut->rNumericArgs(12);
421 2 : thisChiller.CapRatCoef(3) = state.dataIPShortCut->rNumericArgs(13);
422 2 : if ((state.dataIPShortCut->rNumericArgs(11) + state.dataIPShortCut->rNumericArgs(12) + state.dataIPShortCut->rNumericArgs(13)) == 0.0) {
423 0 : ShowSevereError(state,
424 0 : format("{}: Sum of Capacity Ratio Coef = 0.0, chiller={}",
425 0 : state.dataIPShortCut->cCurrentModuleObject,
426 0 : state.dataIPShortCut->cAlphaArgs(1)));
427 0 : ErrorsFound = true;
428 : }
429 2 : thisChiller.PowerRatCoef(1) = state.dataIPShortCut->rNumericArgs(14);
430 2 : thisChiller.PowerRatCoef(2) = state.dataIPShortCut->rNumericArgs(15);
431 2 : thisChiller.PowerRatCoef(3) = state.dataIPShortCut->rNumericArgs(16);
432 2 : thisChiller.FullLoadCoef(1) = state.dataIPShortCut->rNumericArgs(17);
433 2 : thisChiller.FullLoadCoef(2) = state.dataIPShortCut->rNumericArgs(18);
434 2 : thisChiller.FullLoadCoef(3) = state.dataIPShortCut->rNumericArgs(19);
435 2 : thisChiller.TempLowLimitEvapOut = state.dataIPShortCut->rNumericArgs(20);
436 2 : thisChiller.SizFac = state.dataIPShortCut->rNumericArgs(22);
437 2 : if (thisChiller.SizFac <= 0.0) thisChiller.SizFac = 1.0;
438 :
439 2 : thisChiller.FlowMode = static_cast<DataPlant::FlowMode>(getEnumValue(DataPlant::FlowModeNamesUC, state.dataIPShortCut->cAlphaArgs(7)));
440 2 : if (thisChiller.FlowMode == DataPlant::FlowMode::Invalid) {
441 0 : ShowSevereError(state,
442 0 : format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
443 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
444 0 : ShowContinueError(state, "Available choices are ConstantFlow, NotModulated, or LeavingSetpointModulated");
445 0 : ShowContinueError(state, "Flow mode NotModulated is assumed and the simulation continues.");
446 0 : thisChiller.FlowMode = DataPlant::FlowMode::NotModulated;
447 : }
448 :
449 : // These are the Heat Recovery Inputs
450 2 : thisChiller.DesignHeatRecVolFlowRate = state.dataIPShortCut->rNumericArgs(21);
451 2 : if (thisChiller.DesignHeatRecVolFlowRate == DataSizing::AutoSize) {
452 0 : thisChiller.DesignHeatRecVolFlowRateWasAutoSized = true;
453 : }
454 :
455 2 : if ((thisChiller.DesignHeatRecVolFlowRate > 0.0) || (thisChiller.DesignHeatRecVolFlowRate == DataSizing::AutoSize)) {
456 0 : thisChiller.HeatRecActive = true;
457 0 : thisChiller.HeatRecInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
458 0 : state.dataIPShortCut->cAlphaArgs(8),
459 : ErrorsFound,
460 : DataLoopNode::ConnectionObjectType::ChillerElectric,
461 0 : state.dataIPShortCut->cAlphaArgs(1),
462 : DataLoopNode::NodeFluidType::Water,
463 : DataLoopNode::ConnectionType::Inlet,
464 : NodeInputManager::CompFluidStream::Tertiary,
465 : DataLoopNode::ObjectIsNotParent);
466 0 : if (thisChiller.HeatRecInletNodeNum == 0) {
467 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
468 0 : ShowContinueError(state,
469 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
470 0 : ErrorsFound = true;
471 : }
472 0 : thisChiller.HeatRecOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
473 0 : state.dataIPShortCut->cAlphaArgs(9),
474 : ErrorsFound,
475 : DataLoopNode::ConnectionObjectType::ChillerElectric,
476 0 : state.dataIPShortCut->cAlphaArgs(1),
477 : DataLoopNode::NodeFluidType::Water,
478 : DataLoopNode::ConnectionType::Outlet,
479 : NodeInputManager::CompFluidStream::Tertiary,
480 : DataLoopNode::ObjectIsNotParent);
481 0 : if (thisChiller.HeatRecOutletNodeNum == 0) {
482 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
483 0 : ShowContinueError(state,
484 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
485 0 : ErrorsFound = true;
486 : }
487 :
488 0 : BranchNodeConnections::TestCompSet(state,
489 0 : state.dataIPShortCut->cCurrentModuleObject,
490 0 : state.dataIPShortCut->cAlphaArgs(1),
491 0 : state.dataIPShortCut->cAlphaArgs(8),
492 0 : state.dataIPShortCut->cAlphaArgs(9),
493 : "Heat Recovery Nodes");
494 0 : if (thisChiller.DesignHeatRecVolFlowRate > 0.0) {
495 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, thisChiller.HeatRecInletNodeNum, thisChiller.DesignHeatRecVolFlowRate);
496 : }
497 : // Condenser flow rate must be specified for heat reclaim
498 0 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
499 0 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
500 0 : if (thisChiller.CondVolFlowRate <= 0.0) {
501 0 : ShowSevereError(
502 0 : state, format("Invalid {}={:.6R}", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->rNumericArgs(10)));
503 0 : ShowContinueError(state, "Condenser fluid flow rate must be specified for Heat Reclaim applications.");
504 0 : ShowContinueError(
505 0 : state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
506 0 : ErrorsFound = true;
507 : }
508 : }
509 :
510 0 : if (NumNums > 24) {
511 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(25)) {
512 0 : thisChiller.HeatRecCapacityFraction = state.dataIPShortCut->rNumericArgs(25);
513 : } else {
514 0 : thisChiller.HeatRecCapacityFraction = 1.0;
515 : }
516 : } else {
517 0 : thisChiller.HeatRecCapacityFraction = 1.0;
518 : }
519 :
520 0 : if (NumAlphas <= 10 || state.dataIPShortCut->lAlphaFieldBlanks(11)) {
521 0 : } else if ((thisChiller.heatRecInletLimitSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(11))) == nullptr) {
522 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11));
523 0 : ErrorsFound = true;
524 : }
525 :
526 0 : if (NumAlphas > 11) {
527 0 : if (!state.dataIPShortCut->lAlphaFieldBlanks(12)) {
528 0 : thisChiller.HeatRecSetPointNodeNum = NodeInputManager::GetOnlySingleNode(state,
529 0 : state.dataIPShortCut->cAlphaArgs(12),
530 : ErrorsFound,
531 : DataLoopNode::ConnectionObjectType::ChillerElectric,
532 0 : state.dataIPShortCut->cAlphaArgs(1),
533 : DataLoopNode::NodeFluidType::Water,
534 : DataLoopNode::ConnectionType::Sensor,
535 : NodeInputManager::CompFluidStream::Primary,
536 : DataLoopNode::ObjectIsNotParent);
537 : } else {
538 0 : thisChiller.HeatRecSetPointNodeNum = 0;
539 : }
540 : } else {
541 0 : thisChiller.HeatRecSetPointNodeNum = 0;
542 : }
543 :
544 : } else {
545 2 : thisChiller.HeatRecActive = false;
546 2 : thisChiller.DesignHeatRecMassFlowRate = 0.0;
547 2 : thisChiller.HeatRecInletNodeNum = 0;
548 2 : thisChiller.HeatRecOutletNodeNum = 0;
549 : // if heat recovery is not used, don't care about condenser flow rate for air/evap-cooled equip.
550 2 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
551 2 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
552 0 : thisChiller.CondVolFlowRate = 0.0011; // set to avoid errors in calc routine
553 : }
554 2 : if ((!state.dataIPShortCut->lAlphaFieldBlanks(8)) || (!state.dataIPShortCut->lAlphaFieldBlanks(9))) {
555 0 : ShowWarningError(state,
556 0 : format("Since Design Heat Flow Rate = 0.0, Heat Recovery inactive for {}={}",
557 0 : state.dataIPShortCut->cCurrentModuleObject,
558 0 : state.dataIPShortCut->cAlphaArgs(1)));
559 0 : ShowContinueError(state, "However, Node names were specified for Heat Recovery inlet or outlet nodes");
560 : }
561 : }
562 : // Basin heater power as a function of temperature must be greater than or equal to 0
563 2 : thisChiller.BasinHeaterPowerFTempDiff = state.dataIPShortCut->rNumericArgs(23);
564 2 : if (state.dataIPShortCut->rNumericArgs(23) < 0.0) {
565 0 : ShowSevereError(state,
566 0 : format("{}, \"{}\" TRIM(state.dataIPShortCut->cNumericFieldNames(23)) must be >= 0",
567 0 : state.dataIPShortCut->cCurrentModuleObject,
568 0 : thisChiller.Name));
569 0 : ErrorsFound = true;
570 : }
571 :
572 2 : thisChiller.BasinHeaterSetPointTemp = state.dataIPShortCut->rNumericArgs(24);
573 :
574 2 : if (thisChiller.BasinHeaterPowerFTempDiff > 0.0) {
575 0 : if (NumNums < 24) {
576 0 : thisChiller.BasinHeaterSetPointTemp = 2.0;
577 : }
578 0 : if (thisChiller.BasinHeaterSetPointTemp < 2.0) {
579 0 : ShowWarningError(state,
580 0 : format("{}:\"{}\", {} is less than 2 deg C. Freezing could occur.",
581 0 : state.dataIPShortCut->cCurrentModuleObject,
582 0 : thisChiller.Name,
583 0 : state.dataIPShortCut->cNumericFieldNames(24)));
584 : }
585 : }
586 :
587 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(10)) {
588 0 : } else if ((thisChiller.basinHeaterSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(10))) == nullptr) {
589 0 : ShowWarningItemNotFound(state,
590 : eoh,
591 0 : state.dataIPShortCut->cAlphaFieldNames(10),
592 0 : state.dataIPShortCut->cAlphaArgs(10),
593 : "Basin heater operation will not be modeled and the simulation continues");
594 : }
595 :
596 2 : if (NumAlphas > 12) {
597 1 : thisChiller.EndUseSubcategory = state.dataIPShortCut->cAlphaArgs(13);
598 : } else {
599 1 : thisChiller.EndUseSubcategory = "General";
600 : }
601 2 : if (!state.dataIPShortCut->lAlphaFieldBlanks(14)) {
602 1 : thisChiller.thermosiphonTempCurveIndex = Curve::GetCurveIndex(state, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(14)));
603 1 : if (thisChiller.thermosiphonTempCurveIndex == 0) {
604 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, state.dataIPShortCut->cCurrentModuleObject, thisChiller.Name));
605 0 : ShowContinueError(state,
606 0 : format("Invalid {} = {}", state.dataIPShortCut->cAlphaFieldNames(14), state.dataIPShortCut->cAlphaArgs(14)));
607 0 : ErrorsFound = true;
608 : }
609 : }
610 2 : thisChiller.thermosiphonMinTempDiff = state.dataIPShortCut->rNumericArgs(26);
611 : }
612 :
613 2 : if (ErrorsFound) {
614 0 : ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
615 : }
616 : }
617 :
618 2 : void ElectricChillerSpecs::setupOutputVariables(EnergyPlusData &state)
619 : {
620 4 : SetupOutputVariable(state,
621 : "Chiller Electricity Rate",
622 : Constant::Units::W,
623 2 : this->Power,
624 : OutputProcessor::TimeStepType::System,
625 : OutputProcessor::StoreType::Average,
626 2 : this->Name);
627 4 : SetupOutputVariable(state,
628 : "Chiller Electricity Energy",
629 : Constant::Units::J,
630 2 : this->Energy,
631 : OutputProcessor::TimeStepType::System,
632 : OutputProcessor::StoreType::Sum,
633 2 : this->Name,
634 : Constant::eResource::Electricity,
635 : OutputProcessor::Group::Plant,
636 : OutputProcessor::EndUseCat::Cooling,
637 : this->EndUseSubcategory);
638 :
639 4 : SetupOutputVariable(state,
640 : "Chiller Evaporator Cooling Rate",
641 : Constant::Units::W,
642 2 : this->QEvaporator,
643 : OutputProcessor::TimeStepType::System,
644 : OutputProcessor::StoreType::Average,
645 2 : this->Name);
646 4 : SetupOutputVariable(state,
647 : "Chiller Evaporator Cooling Energy",
648 : Constant::Units::J,
649 2 : this->EvaporatorEnergy,
650 : OutputProcessor::TimeStepType::System,
651 : OutputProcessor::StoreType::Sum,
652 2 : this->Name,
653 : Constant::eResource::EnergyTransfer,
654 : OutputProcessor::Group::Plant,
655 : OutputProcessor::EndUseCat::Chillers);
656 4 : SetupOutputVariable(state,
657 : "Chiller Evaporator Inlet Temperature",
658 : Constant::Units::C,
659 2 : this->EvapInletTemp,
660 : OutputProcessor::TimeStepType::System,
661 : OutputProcessor::StoreType::Average,
662 2 : this->Name);
663 4 : SetupOutputVariable(state,
664 : "Chiller Evaporator Outlet Temperature",
665 : Constant::Units::C,
666 2 : this->EvapOutletTemp,
667 : OutputProcessor::TimeStepType::System,
668 : OutputProcessor::StoreType::Average,
669 2 : this->Name);
670 4 : SetupOutputVariable(state,
671 : "Chiller Evaporator Mass Flow Rate",
672 : Constant::Units::kg_s,
673 2 : this->EvapMassFlowRate,
674 : OutputProcessor::TimeStepType::System,
675 : OutputProcessor::StoreType::Average,
676 2 : this->Name);
677 4 : SetupOutputVariable(state,
678 : "Chiller Condenser Heat Transfer Rate",
679 : Constant::Units::W,
680 2 : this->QCondenser,
681 : OutputProcessor::TimeStepType::System,
682 : OutputProcessor::StoreType::Average,
683 2 : this->Name);
684 4 : SetupOutputVariable(state,
685 : "Chiller Condenser Heat Transfer Energy",
686 : Constant::Units::J,
687 2 : this->CondenserEnergy,
688 : OutputProcessor::TimeStepType::System,
689 : OutputProcessor::StoreType::Sum,
690 2 : this->Name,
691 : Constant::eResource::EnergyTransfer,
692 : OutputProcessor::Group::Plant,
693 : OutputProcessor::EndUseCat::HeatRejection);
694 4 : SetupOutputVariable(state,
695 : "Chiller COP",
696 : Constant::Units::W_W,
697 2 : this->ActualCOP,
698 : OutputProcessor::TimeStepType::System,
699 : OutputProcessor::StoreType::Average,
700 2 : this->Name);
701 4 : SetupOutputVariable(state,
702 : "Chiller Condenser Inlet Temperature",
703 : Constant::Units::C,
704 2 : this->CondInletTemp,
705 : OutputProcessor::TimeStepType::System,
706 : OutputProcessor::StoreType::Average,
707 2 : this->Name);
708 2 : SetupOutputVariable(state,
709 : "Thermosiphon Status",
710 : Constant::Units::None,
711 2 : this->thermosiphonStatus,
712 : OutputProcessor::TimeStepType::System,
713 : OutputProcessor::StoreType::Average,
714 2 : this->Name);
715 :
716 : // Condenser mass flow and outlet temp are valid for water cooled
717 2 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
718 4 : SetupOutputVariable(state,
719 : "Chiller Condenser Outlet Temperature",
720 : Constant::Units::C,
721 2 : this->CondOutletTemp,
722 : OutputProcessor::TimeStepType::System,
723 : OutputProcessor::StoreType::Average,
724 2 : this->Name);
725 4 : SetupOutputVariable(state,
726 : "Chiller Condenser Mass Flow Rate",
727 : Constant::Units::kg_s,
728 2 : this->CondMassFlowRate,
729 : OutputProcessor::TimeStepType::System,
730 : OutputProcessor::StoreType::Average,
731 2 : this->Name);
732 0 : } else if (this->CondenserType == DataPlant::CondenserType::AirCooled) {
733 0 : } else if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
734 0 : if (this->BasinHeaterPowerFTempDiff > 0.0) {
735 0 : SetupOutputVariable(state,
736 : "Chiller Basin Heater Electricity Rate",
737 : Constant::Units::W,
738 0 : this->BasinHeaterPower,
739 : OutputProcessor::TimeStepType::System,
740 : OutputProcessor::StoreType::Average,
741 0 : this->Name);
742 0 : SetupOutputVariable(state,
743 : "Chiller Basin Heater Electricity Energy",
744 : Constant::Units::J,
745 0 : this->BasinHeaterConsumption,
746 : OutputProcessor::TimeStepType::System,
747 : OutputProcessor::StoreType::Sum,
748 0 : this->Name,
749 : Constant::eResource::Electricity,
750 : OutputProcessor::Group::Plant,
751 : OutputProcessor::EndUseCat::Chillers);
752 : }
753 : }
754 :
755 : // If heat recovery is active then setup report variables
756 2 : if (this->HeatRecActive) {
757 0 : SetupOutputVariable(state,
758 : "Chiller Total Recovered Heat Rate",
759 : Constant::Units::W,
760 0 : this->QHeatRecovery,
761 : OutputProcessor::TimeStepType::System,
762 : OutputProcessor::StoreType::Average,
763 0 : this->Name);
764 0 : SetupOutputVariable(state,
765 : "Chiller Total Recovered Heat Energy",
766 : Constant::Units::J,
767 0 : this->EnergyHeatRecovery,
768 : OutputProcessor::TimeStepType::System,
769 : OutputProcessor::StoreType::Sum,
770 0 : this->Name,
771 : Constant::eResource::EnergyTransfer,
772 : OutputProcessor::Group::Plant,
773 : OutputProcessor::EndUseCat::HeatRecovery);
774 0 : SetupOutputVariable(state,
775 : "Chiller Heat Recovery Inlet Temperature",
776 : Constant::Units::C,
777 0 : this->HeatRecInletTemp,
778 : OutputProcessor::TimeStepType::System,
779 : OutputProcessor::StoreType::Average,
780 0 : this->Name);
781 0 : SetupOutputVariable(state,
782 : "Chiller Heat Recovery Outlet Temperature",
783 : Constant::Units::C,
784 0 : this->HeatRecOutletTemp,
785 : OutputProcessor::TimeStepType::System,
786 : OutputProcessor::StoreType::Average,
787 0 : this->Name);
788 0 : SetupOutputVariable(state,
789 : "Chiller Heat Recovery Mass Flow Rate",
790 : Constant::Units::kg_s,
791 0 : this->HeatRecMdot,
792 : OutputProcessor::TimeStepType::System,
793 : OutputProcessor::StoreType::Average,
794 0 : this->Name);
795 0 : SetupOutputVariable(state,
796 : "Chiller Effective Heat Rejection Temperature",
797 : Constant::Units::C,
798 0 : this->ChillerCondAvgTemp,
799 : OutputProcessor::TimeStepType::System,
800 : OutputProcessor::StoreType::Average,
801 0 : this->Name);
802 : }
803 2 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
804 0 : SetupEMSInternalVariable(state, "Chiller Nominal Capacity", this->Name, "[W]", this->NomCap);
805 : }
806 2 : }
807 :
808 1 : void ElectricChillerSpecs::simulate(
809 : EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, bool RunFlag)
810 : {
811 1 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) { // chilled water loop
812 1 : this->initialize(state, RunFlag, CurLoad);
813 1 : this->calculate(state, CurLoad, RunFlag, this->CWPlantLoc.comp->FlowCtrl);
814 1 : this->update(state, CurLoad, RunFlag);
815 0 : } else if (calledFromLocation.loopNum == this->CDPlantLoc.loopNum) { // condenser loop
816 0 : PlantUtilities::UpdateChillerComponentCondenserSide(state,
817 : this->CDPlantLoc.loopNum,
818 : this->CDPlantLoc.loopSideNum,
819 : this->ChillerType,
820 : this->CondInletNodeNum,
821 : this->CondOutletNodeNum,
822 : this->QCondenser,
823 : this->CondInletTemp,
824 : this->CondOutletTemp,
825 : this->CondMassFlowRate,
826 : FirstHVACIteration);
827 0 : } else if (calledFromLocation.loopNum == this->HRPlantLoc.loopNum) { // heat recovery loop
828 0 : PlantUtilities::UpdateComponentHeatRecoverySide(state,
829 : this->HRPlantLoc.loopNum,
830 : this->HRPlantLoc.loopSideNum,
831 : this->ChillerType,
832 : this->HeatRecInletNodeNum,
833 : this->HeatRecOutletNodeNum,
834 : this->QHeatRecovery,
835 : this->HeatRecInletTemp,
836 : this->HeatRecOutletTemp,
837 : this->HeatRecMdot,
838 : FirstHVACIteration);
839 : }
840 1 : }
841 :
842 10 : void ElectricChillerSpecs::initialize(EnergyPlusData &state, bool const RunFlag, Real64 const MyLoad)
843 : {
844 :
845 : // SUBROUTINE INFORMATION:
846 : // AUTHOR Fred Buhl
847 : // DATE WRITTEN April 2002
848 : // MODIFIED na
849 : // RE-ENGINEERED na
850 :
851 : // PURPOSE OF THIS SUBROUTINE:
852 : // This subroutine is for initializations of the Electric Chiller components
853 :
854 : // METHODOLOGY EMPLOYED:
855 : // Uses the status flags to trigger initializations.
856 :
857 : // SUBROUTINE PARAMETER DEFINITIONS:
858 : static constexpr std::string_view const RoutineName("InitElectricChiller");
859 :
860 10 : this->oneTimeInit(state);
861 :
862 10 : if (this->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
863 :
864 2 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
865 :
866 2 : this->EvapMassFlowRateMax = rho * this->EvapVolFlowRate;
867 2 : PlantUtilities::InitComponentNodes(state, 0.0, this->EvapMassFlowRateMax, this->EvapInletNodeNum, this->EvapOutletNodeNum);
868 :
869 : // init maximum available condenser flow rate
870 2 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
871 :
872 2 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = this->TempDesCondIn; // old behavior, still want?
873 :
874 2 : rho = this->CDPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
875 :
876 2 : this->CondMassFlowRateMax = rho * this->CondVolFlowRate;
877 :
878 2 : PlantUtilities::InitComponentNodes(state, 0.0, this->CondMassFlowRateMax, this->CondInletNodeNum, this->CondOutletNodeNum);
879 : } else { // air or evap-air
880 :
881 0 : rho = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, this->TempDesCondIn, 0.0, RoutineName);
882 0 : this->CondMassFlowRateMax = rho * this->CondVolFlowRate;
883 :
884 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate = this->CondMassFlowRateMax;
885 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
886 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMaxAvail =
887 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
888 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
889 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
890 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMinAvail = 0.0;
891 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMin = 0.0;
892 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMinAvail = 0.0;
893 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMin = 0.0;
894 : }
895 :
896 2 : if (this->HeatRecActive) {
897 0 : rho = this->HRPlantLoc.loop->glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
898 0 : this->DesignHeatRecMassFlowRate = rho * this->DesignHeatRecVolFlowRate;
899 :
900 0 : PlantUtilities::InitComponentNodes(
901 : state, 0.0, this->DesignHeatRecMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
902 0 : this->HeatRecMaxCapacityLimit = this->HeatRecCapacityFraction * (this->NomCap + this->NomCap / this->COP);
903 :
904 0 : if (this->HeatRecSetPointNodeNum > 0) {
905 0 : Real64 THeatRecSetPoint(0.0);
906 0 : if (this->HRPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
907 0 : THeatRecSetPoint = state.dataLoopNodes->Node(this->HeatRecSetPointNodeNum).TempSetPoint;
908 0 : } else if (this->HRPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
909 0 : THeatRecSetPoint = state.dataLoopNodes->Node(this->HeatRecSetPointNodeNum).TempSetPointHi;
910 : }
911 0 : if (THeatRecSetPoint == DataLoopNode::SensedNodeFlagValue) {
912 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
913 0 : if (!this->HRSPErrDone) {
914 0 : ShowWarningError(state, format("Missing heat recovery temperature setpoint for chiller named {}", this->Name));
915 0 : ShowContinueError(state,
916 : " A temperature setpoint is needed at the heat recovery leaving temperature setpoint node "
917 : "specified, use a SetpointManager");
918 0 : ShowContinueError(state,
919 : " The overall loop setpoint will be assumed for heat recovery. The simulation continues ...");
920 0 : this->HeatRecSetPointNodeNum = this->HRPlantLoc.loop->TempSetPointNodeNum;
921 0 : this->HRSPErrDone = true;
922 : }
923 : } else {
924 : // need call to EMS to check node
925 0 : bool FatalError = false; // but not really fatal yet, but should be.
926 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->EvapOutletNodeNum, HVAC::CtrlVarType::Temp, FatalError);
927 0 : state.dataLoopNodes->NodeSetpointCheck(this->EvapOutletNodeNum).needsSetpointChecking = false;
928 0 : if (FatalError) {
929 0 : if (!this->HRSPErrDone) {
930 0 : ShowWarningError(state, format("Missing heat recovery temperature setpoint for chiller named {}", this->Name));
931 0 : ShowContinueError(state,
932 : " A temperature setpoint is needed at the heat recovery leaving temperature setpoint node "
933 : "specified, use a SetpointManager to establish a setpoint");
934 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at this node ");
935 0 : ShowContinueError(state,
936 : " The overall loop setpoint will be assumed for heat recovery. The simulation continues ...");
937 0 : this->HeatRecSetPointNodeNum = this->HRPlantLoc.loop->TempSetPointNodeNum;
938 0 : this->HRSPErrDone = true;
939 : }
940 : }
941 : } // IF (.NOT. AnyEnergyManagementSystemInModel) THEN
942 : } // IF(THeatRecSetpoint == DataLoopNode::SensedNodeFlagValue)THEN
943 : } // IF(ElectricChiller(ChillNum)%HeatRecSetpointNodeNum > 0)THEN
944 : } // IF (ElectricChiller(ChillNum)%HeatRecActive) THEN
945 :
946 2 : this->MyEnvrnFlag = false;
947 : }
948 10 : if (!state.dataGlobal->BeginEnvrnFlag) {
949 2 : this->MyEnvrnFlag = true;
950 : }
951 :
952 10 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) && (this->ModulatedFlowSetToLoop)) {
953 : // fix for clumsy old input that worked because loop setpoint was spread.
954 : // could be removed with transition, testing , model change, period of being obsolete.
955 10 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
956 7 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
957 7 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
958 3 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
959 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
960 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
961 : }
962 : }
963 :
964 10 : Real64 mdot = 0.0;
965 10 : Real64 mdotCond = 0.0;
966 10 : if ((MyLoad < 0.0) && RunFlag) {
967 : // request full then take what can get
968 10 : mdot = this->EvapMassFlowRateMax;
969 10 : mdotCond = this->CondMassFlowRateMax;
970 : }
971 10 : PlantUtilities::SetComponentFlowRate(state, mdot, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
972 10 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
973 10 : PlantUtilities::SetComponentFlowRate(state, mdotCond, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
974 : }
975 :
976 : // Initialize heat recovery flow rates at node
977 10 : if (this->HeatRecActive) {
978 :
979 0 : Real64 thisMdot = 0.0;
980 0 : if (RunFlag) {
981 0 : thisMdot = this->DesignHeatRecMassFlowRate;
982 : }
983 :
984 0 : PlantUtilities::SetComponentFlowRate(state, thisMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
985 : }
986 :
987 10 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
988 0 : this->BasinHeaterPower = 0.0;
989 : }
990 10 : }
991 :
992 4 : void ElectricChillerSpecs::size(EnergyPlusData &state)
993 : {
994 :
995 : // SUBROUTINE INFORMATION:
996 : // AUTHOR Fred Buhl
997 : // DATE WRITTEN April 2002
998 : // MODIFIED November 2013 Daeho Kang, add component sizing table entries
999 : // RE-ENGINEERED B. Griffith, April 2011, allow repeated sizing calls, finish when ready to do so
1000 :
1001 : // PURPOSE OF THIS SUBROUTINE:
1002 : // This subroutine is for sizing Electric Chiller Components for which capacities and flow rates
1003 : // have not been specified in the input.
1004 :
1005 : // METHODOLOGY EMPLOYED:
1006 : // Obtains evaporator flow rate from the plant sizing array. Calculates nominal capacity from
1007 : // the evaporator flow rate and the chilled water loop design delta T. The condenser flow rate
1008 : // is calculated from the nominal capacity, the COP, and the condenser loop design delta T.
1009 :
1010 : // SUBROUTINE PARAMETER DEFINITIONS:
1011 : static constexpr std::string_view RoutineName("SizeElectricChiller");
1012 :
1013 4 : int PltSizCondNum(0); // Plant Sizing index for condenser loop
1014 4 : bool ErrorsFound(false); // If errors detected in input
1015 :
1016 4 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1017 4 : PltSizCondNum = this->CDPlantLoc.loop->PlantSizNum;
1018 : }
1019 :
1020 4 : int PltSizNum = this->CWPlantLoc.loop->PlantSizNum;
1021 :
1022 4 : Real64 tmpNomCap = this->NomCap;
1023 4 : if (PltSizNum > 0) {
1024 4 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1025 4 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
1026 4 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
1027 4 : tmpNomCap =
1028 4 : Cp * rho * state.dataSize->PlantSizData(PltSizNum).DeltaT * state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
1029 : } else {
1030 0 : if (this->NomCapWasAutoSized) tmpNomCap = 0.0;
1031 : }
1032 4 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1033 4 : if (this->NomCapWasAutoSized) {
1034 2 : this->NomCap = tmpNomCap;
1035 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1036 2 : BaseSizer::reportSizerOutput(state, "Chiller:Electric", this->Name, "Design Size Nominal Capacity [W]", tmpNomCap);
1037 : }
1038 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1039 2 : BaseSizer::reportSizerOutput(state, "Chiller:Electric", this->Name, "Initial Design Size Nominal Capacity [W]", tmpNomCap);
1040 : }
1041 : } else {
1042 2 : if (this->NomCap > 0.0 && tmpNomCap > 0.0) {
1043 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1044 2 : BaseSizer::reportSizerOutput(state,
1045 : "Chiller:Electric",
1046 : this->Name,
1047 : "Design Size Nominal Capacity [W]",
1048 : tmpNomCap,
1049 : "User-Specified Nominal Capacity [W]",
1050 2 : this->NomCap);
1051 2 : if (state.dataGlobal->DisplayExtraWarnings) {
1052 0 : if ((std::abs(tmpNomCap - this->NomCap) / this->NomCap) > state.dataSize->AutoVsHardSizingThreshold) {
1053 0 : ShowMessage(state, format("SizeChillerElectric: Potential issue with equipment sizing for {}", this->Name));
1054 0 : ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", this->NomCap));
1055 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", tmpNomCap));
1056 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1057 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1058 : }
1059 : }
1060 : }
1061 2 : tmpNomCap = this->NomCap;
1062 : }
1063 : }
1064 : }
1065 : } else {
1066 0 : if (this->NomCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1067 0 : ShowSevereError(state, "Autosizing of Electric Chiller nominal capacity requires a loop Sizing:Plant object");
1068 0 : ShowContinueError(state, format("Occurs in Electric Chiller object={}", this->Name));
1069 0 : ErrorsFound = true;
1070 : }
1071 0 : if (!this->NomCapWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->NomCap > 0.0)) {
1072 0 : BaseSizer::reportSizerOutput(state, "Chiller:Electric", this->Name, "User-Specified Nominal Capacity [W]", this->NomCap);
1073 : }
1074 : }
1075 :
1076 4 : Real64 tmpEvapVolFlowRate = this->EvapVolFlowRate;
1077 4 : if (PltSizNum > 0) {
1078 4 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1079 4 : tmpEvapVolFlowRate = state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
1080 : } else {
1081 0 : if (this->EvapVolFlowRateWasAutoSized) tmpEvapVolFlowRate = 0.0;
1082 : }
1083 4 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1084 4 : if (this->EvapVolFlowRateWasAutoSized) {
1085 2 : this->EvapVolFlowRate = tmpEvapVolFlowRate;
1086 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1087 2 : BaseSizer::reportSizerOutput(
1088 : state, "Chiller:Electric", this->Name, "Design Size Design Chilled Water Flow Rate [m3/s]", tmpEvapVolFlowRate);
1089 : }
1090 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1091 2 : BaseSizer::reportSizerOutput(
1092 : state, "Chiller:Electric", this->Name, "Initial Design Size Design Chilled Water Flow Rate [m3/s]", tmpEvapVolFlowRate);
1093 : }
1094 : } else {
1095 2 : if (this->EvapVolFlowRate > 0.0 && tmpEvapVolFlowRate > 0.0) {
1096 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1097 2 : BaseSizer::reportSizerOutput(state,
1098 : "Chiller:Electric",
1099 : this->Name,
1100 : "Design Size Design Chilled Water Flow Rate [m3/s]",
1101 : tmpEvapVolFlowRate,
1102 : "User-Specified Design Chilled Water Flow Rate [m3/s]",
1103 2 : this->EvapVolFlowRate);
1104 2 : if (state.dataGlobal->DisplayExtraWarnings) {
1105 0 : if ((std::abs(tmpEvapVolFlowRate - this->EvapVolFlowRate) / this->EvapVolFlowRate) >
1106 0 : state.dataSize->AutoVsHardSizingThreshold) {
1107 0 : ShowMessage(state, format("SizeChillerElectric: Potential issue with equipment sizing for {}", this->Name));
1108 0 : ShowContinueError(
1109 0 : state, format("User-Specified Design Chilled Water Flow Rate of {:.5R} [m3/s]", this->EvapVolFlowRate));
1110 0 : ShowContinueError(
1111 : state,
1112 0 : format("differs from Design Size Design Chilled Water Flow Rate of {:.5R} [m3/s]", tmpEvapVolFlowRate));
1113 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1114 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1115 : }
1116 : }
1117 : }
1118 2 : tmpEvapVolFlowRate = this->EvapVolFlowRate;
1119 : }
1120 : }
1121 : }
1122 : } else {
1123 0 : if (this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1124 0 : ShowSevereError(state, "Autosizing of Electric Chiller evap flow rate requires a loop Sizing:Plant object");
1125 0 : ShowContinueError(state, format("Occurs in Electric Chiller object={}", this->Name));
1126 0 : ErrorsFound = true;
1127 : }
1128 0 : if (!this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->EvapVolFlowRate > 0.0)) {
1129 0 : BaseSizer::reportSizerOutput(
1130 : state, "Chiller:Electric", this->Name, "User-Specified Design Chilled Water Flow Rate [m3/s]", this->EvapVolFlowRate);
1131 : }
1132 : }
1133 :
1134 4 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->EvapInletNodeNum, tmpEvapVolFlowRate);
1135 :
1136 4 : Real64 tmpCondVolFlowRate = this->CondVolFlowRate;
1137 4 : if (PltSizCondNum > 0 && PltSizNum > 0) {
1138 4 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow && tmpNomCap > 0.0) {
1139 4 : Real64 rho = this->CDPlantLoc.loop->glycol->getDensity(state, this->TempDesCondIn, RoutineName);
1140 4 : Real64 Cp = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, this->TempDesCondIn, RoutineName);
1141 4 : tmpCondVolFlowRate = tmpNomCap * (1.0 + 1.0 / this->COP) / (state.dataSize->PlantSizData(PltSizCondNum).DeltaT * Cp * rho);
1142 : } else {
1143 0 : if (this->CondVolFlowRateWasAutoSized) tmpCondVolFlowRate = 0.0;
1144 : }
1145 4 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1146 4 : if (this->CondVolFlowRateWasAutoSized) {
1147 2 : this->CondVolFlowRate = tmpCondVolFlowRate;
1148 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1149 2 : BaseSizer::reportSizerOutput(
1150 : state, "Chiller:Electric", this->Name, "Design Size Design Condenser Water Flow Rate [m3/s]", tmpCondVolFlowRate);
1151 : }
1152 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1153 2 : BaseSizer::reportSizerOutput(
1154 : state, "Chiller:Electric", this->Name, "Initial Design Size Design Condenser Water Flow Rate [m3/s]", tmpCondVolFlowRate);
1155 : }
1156 : } else {
1157 2 : if (this->CondVolFlowRate > 0.0 && tmpCondVolFlowRate > 0.0) {
1158 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1159 2 : BaseSizer::reportSizerOutput(state,
1160 : "Chiller:Electric",
1161 : this->Name,
1162 : "Design Size Design Condenser Water Flow Rate [m3/s]",
1163 : tmpCondVolFlowRate,
1164 : "User-Specified Design Condenser Water Flow Rate [m3/s]",
1165 2 : this->CondVolFlowRate);
1166 2 : if (state.dataGlobal->DisplayExtraWarnings) {
1167 0 : if ((std::abs(tmpCondVolFlowRate - this->CondVolFlowRate) / this->CondVolFlowRate) >
1168 0 : state.dataSize->AutoVsHardSizingThreshold) {
1169 0 : ShowMessage(state, format("SizeChillerElectric: Potential issue with equipment sizing for {}", this->Name));
1170 0 : ShowContinueError(
1171 0 : state, format("User-Specified Design Condenser Water Flow Rate of {:.5R} [m3/s]", this->CondVolFlowRate));
1172 0 : ShowContinueError(
1173 : state,
1174 0 : format("differs from Design Size Design Condenser Water Flow Rate of {:.5R} [m3/s]", tmpCondVolFlowRate));
1175 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1176 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1177 : }
1178 : }
1179 : }
1180 2 : tmpCondVolFlowRate = this->CondVolFlowRate;
1181 : }
1182 : }
1183 : }
1184 4 : } else {
1185 0 : if (this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1186 0 : ShowSevereError(state, "Autosizing of Electric Chiller condenser flow rate requires a condenser");
1187 0 : ShowContinueError(state, "loop Sizing:Plant object");
1188 0 : ShowContinueError(state, format("Occurs in Electric Chiller object={}", this->Name));
1189 0 : ErrorsFound = true;
1190 : }
1191 0 : if (!this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->CondVolFlowRate > 0.0)) {
1192 0 : BaseSizer::reportSizerOutput(
1193 : state, "Chiller:Electric", this->Name, "User-Specified Design Condenser Water Flow Rate [m3/s]", this->CondVolFlowRate);
1194 : }
1195 : }
1196 :
1197 : // save the design condenser water volumetric flow rate for use by the condenser water loop sizing algorithms
1198 4 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1199 4 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->CondInletNodeNum, tmpCondVolFlowRate);
1200 : }
1201 4 : if (ErrorsFound) {
1202 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
1203 : }
1204 :
1205 4 : if (this->HeatRecActive) {
1206 0 : Real64 tmpHeatRecVolFlowRate = this->CondVolFlowRate * this->HeatRecCapacityFraction;
1207 0 : if (!this->DesignHeatRecVolFlowRateWasAutoSized) tmpHeatRecVolFlowRate = this->DesignHeatRecVolFlowRate;
1208 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1209 0 : if (this->DesignHeatRecVolFlowRateWasAutoSized) {
1210 0 : this->DesignHeatRecVolFlowRate = tmpHeatRecVolFlowRate;
1211 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1212 0 : BaseSizer::reportSizerOutput(
1213 : state, "Chiller:Electric", this->Name, "Design Size Design Heat Recovery Fluid Flow Rate [m3/s]", tmpHeatRecVolFlowRate);
1214 : }
1215 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1216 0 : BaseSizer::reportSizerOutput(state,
1217 : "Chiller:Electric",
1218 : this->Name,
1219 : "Initial Design Size Design Heat Recovery Fluid Flow Rate [m3/s]",
1220 : tmpHeatRecVolFlowRate);
1221 : }
1222 : } else {
1223 0 : if (this->DesignHeatRecVolFlowRate > 0.0 && tmpHeatRecVolFlowRate > 0.0) {
1224 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1225 0 : BaseSizer::reportSizerOutput(state,
1226 : "Chiller:Electric",
1227 : this->Name,
1228 : "Design Size Design Heat Recovery Fluid Flow Rate [m3/s]",
1229 : tmpHeatRecVolFlowRate,
1230 : "User-Specified Design Heat Recovery Fluid Flow Rate [m3/s]",
1231 0 : this->DesignHeatRecVolFlowRate);
1232 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1233 0 : if ((std::abs(tmpHeatRecVolFlowRate - this->DesignHeatRecVolFlowRate) / this->DesignHeatRecVolFlowRate) >
1234 0 : state.dataSize->AutoVsHardSizingThreshold) {
1235 0 : ShowMessage(state, format("SizeChillerElectric: Potential issue with equipment sizing for {}", this->Name));
1236 0 : ShowContinueError(state,
1237 0 : format("User-Specified Design Heat Recovery Fluid Flow Rate of {:.5R} [m3/s]",
1238 0 : this->DesignHeatRecVolFlowRate));
1239 0 : ShowContinueError(state,
1240 0 : format("differs from Design Size Design Heat Recovery Fluid Flow Rate of {:.5R} [m3/s]",
1241 : tmpHeatRecVolFlowRate));
1242 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1243 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1244 : }
1245 : }
1246 : }
1247 0 : tmpHeatRecVolFlowRate = this->DesignHeatRecVolFlowRate;
1248 : }
1249 : }
1250 : }
1251 : // save the reference heat recovery fluid volumetric flow rate
1252 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->HeatRecInletNodeNum, tmpHeatRecVolFlowRate);
1253 : }
1254 :
1255 4 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1256 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "Chiller:Electric");
1257 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomEff, this->Name, this->COP);
1258 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->NomCap);
1259 :
1260 : // std 229 new Chillers table
1261 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerType, this->Name, "Chiller:Electric");
1262 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefCap, this->Name, this->NomCap);
1263 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEff, this->Name, this->COP); // Eff == COP?
1264 8 : OutputReportPredefined::PreDefTableEntry(
1265 4 : state, state.dataOutRptPredefined->pdchChillerRatedCap, this->Name, this->NomCap); // did not find rated cap
1266 8 : OutputReportPredefined::PreDefTableEntry(
1267 4 : state, state.dataOutRptPredefined->pdchChillerRatedEff, this->Name, this->COP); // did not find rated eff or cop ; also Eff == COP?
1268 8 : OutputReportPredefined::PreDefTableEntry(
1269 4 : state, state.dataOutRptPredefined->pdchChillerIPLVinSI, this->Name, "N/A"); // IPLVSI_rpt_std229);
1270 8 : OutputReportPredefined::PreDefTableEntry(
1271 4 : state, state.dataOutRptPredefined->pdchChillerIPLVinIP, this->Name, "N/A"); // IPLVIP_rpt_std229);
1272 8 : OutputReportPredefined::PreDefTableEntry(state,
1273 4 : state.dataOutRptPredefined->pdchChillerPlantloopName,
1274 : this->Name,
1275 8 : (this->CWPlantLoc.loop != nullptr) ? this->CWPlantLoc.loop->Name : "N/A");
1276 8 : OutputReportPredefined::PreDefTableEntry(state,
1277 4 : state.dataOutRptPredefined->pdchChillerPlantloopBranchName,
1278 : this->Name,
1279 8 : (this->CWPlantLoc.branch != nullptr) ? this->CWPlantLoc.branch->Name : "N/A");
1280 8 : OutputReportPredefined::PreDefTableEntry(state,
1281 4 : state.dataOutRptPredefined->pdchChillerCondLoopName,
1282 : this->Name,
1283 8 : (this->CDPlantLoc.loop != nullptr) ? this->CDPlantLoc.loop->Name : "N/A");
1284 8 : OutputReportPredefined::PreDefTableEntry(state,
1285 4 : state.dataOutRptPredefined->pdchChillerCondLoopBranchName,
1286 : this->Name,
1287 8 : (this->CDPlantLoc.branch != nullptr) ? this->CDPlantLoc.branch->Name : "N/A");
1288 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerMinPLR, this->Name, this->MinPartLoadRat);
1289 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerFuelType, this->Name, "Electricity");
1290 8 : OutputReportPredefined::PreDefTableEntry(
1291 4 : state, state.dataOutRptPredefined->pdchChillerRatedEntCondTemp, this->Name, this->TempDesCondIn); // Rated==Ref?
1292 8 : OutputReportPredefined::PreDefTableEntry(
1293 4 : state, state.dataOutRptPredefined->pdchChillerRatedLevEvapTemp, this->Name, this->TempDesEvapOut); // Rated==Ref?
1294 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEntCondTemp, this->Name, this->TempDesCondIn);
1295 4 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefLevEvapTemp, this->Name, this->TempDesEvapOut);
1296 :
1297 8 : OutputReportPredefined::PreDefTableEntry(state,
1298 4 : state.dataOutRptPredefined->pdchChillerDesSizeRefCHWFlowRate,
1299 : this->Name,
1300 : this->EvapMassFlowRateMax); // flowrate Max==DesignSizeRef flowrate?
1301 8 : OutputReportPredefined::PreDefTableEntry(state,
1302 4 : state.dataOutRptPredefined->pdchChillerDesSizeRefCondFluidFlowRate,
1303 : this->Name,
1304 : this->CondMassFlowRateMax); // Cond flowrate Max==DesignSizeRef Cond flowrate?
1305 8 : OutputReportPredefined::PreDefTableEntry(state,
1306 4 : state.dataOutRptPredefined->pdchChillerHeatRecPlantloopName,
1307 : this->Name,
1308 12 : (this->HRPlantLoc.loop != nullptr) ? this->HRPlantLoc.loop->Name : "N/A");
1309 8 : OutputReportPredefined::PreDefTableEntry(state,
1310 4 : state.dataOutRptPredefined->pdchChillerHeatRecPlantloopBranchName,
1311 : this->Name,
1312 12 : (this->HRPlantLoc.branch != nullptr) ? this->HRPlantLoc.branch->Name : "N/A");
1313 8 : OutputReportPredefined::PreDefTableEntry(
1314 4 : state, state.dataOutRptPredefined->pdchChillerRecRelCapFrac, this->Name, this->HeatRecCapacityFraction);
1315 : }
1316 4 : }
1317 :
1318 4 : void ElectricChillerSpecs::calculate(EnergyPlusData &state,
1319 : Real64 &MyLoad,
1320 : bool const RunFlag,
1321 : DataBranchAirLoopPlant::ControlType const EquipFlowCtrl)
1322 : {
1323 : // SUBROUTINE INFORMATION:
1324 : // AUTHOR Dan Fisher / Brandon Anderson
1325 : // DATE WRITTEN Sept. 2000
1326 : // MODIFIED Feb. 2010, Chandan Sharma, FSEC. Added basin heater
1327 : // Jun. 2016, Rongpeng Zhang, LBNL. Applied the chiller supply water temperature sensor fault model
1328 : // Nov. 2016, Rongpeng Zhang, LBNL. Added Fouling Chiller fault
1329 : // RE-ENGINEERED na
1330 :
1331 : // PURPOSE OF THIS SUBROUTINE:
1332 : // simulate a vapor compression chiller using the Electric model
1333 :
1334 : // METHODOLOGY EMPLOYED:
1335 : // curve fit of performance data:
1336 :
1337 : // REFERENCES:
1338 : // 1. BLAST Users Manual
1339 : // 2. CHILLER User Manual
1340 :
1341 : static constexpr std::string_view RoutineName("CalcElectricChillerModel");
1342 4 : this->EvapMassFlowRate = 0.0;
1343 4 : this->CondMassFlowRate = 0.0;
1344 4 : this->Power = 0.0;
1345 4 : this->Energy = 0.0;
1346 4 : this->QCondenser = 0.0;
1347 4 : this->QEvaporator = 0.0;
1348 4 : this->CondenserEnergy = 0.0;
1349 4 : this->EvaporatorEnergy = 0.0;
1350 4 : this->QHeatRecovered = 0.0;
1351 4 : this->ActualCOP = 0.0;
1352 4 : this->thermosiphonStatus = 0;
1353 :
1354 : // calculate end time of current time step
1355 4 : Real64 CurrentEndTime = state.dataGlobal->CurrentTime + state.dataHVACGlobal->SysTimeElapsed;
1356 :
1357 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
1358 : // Wait for next time step to print warnings. If simulation iterates, print out
1359 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
1360 : // If a warning occurs and the simulation down shifts, the warning is not valid.
1361 4 : if (CurrentEndTime > this->CurrentEndTimeLast && state.dataHVACGlobal->TimeStepSys >= this->TimeStepSysLast) {
1362 0 : if (this->PrintMessage) {
1363 0 : ++this->MsgErrorCount;
1364 : // Show single warning and pass additional info to ShowRecurringWarningErrorAtEnd
1365 0 : if (this->MsgErrorCount < 2) {
1366 0 : ShowWarningError(state, format("{}.", this->MsgBuffer1));
1367 0 : ShowContinueError(state, this->MsgBuffer2);
1368 : } else {
1369 0 : ShowRecurringWarningErrorAtEnd(
1370 0 : state, this->MsgBuffer1 + " error continues.", this->ErrCount1, this->MsgDataLast, this->MsgDataLast, _, "[C]", "[C]");
1371 : }
1372 : }
1373 : }
1374 :
1375 : // save last system time step and last end time of current time step (used to determine if warning is valid)
1376 4 : this->TimeStepSysLast = state.dataHVACGlobal->TimeStepSys;
1377 4 : this->CurrentEndTimeLast = CurrentEndTime;
1378 :
1379 : // If no loop demand or chiller OFF, return
1380 : // If Chiller load is 0 or chiller is not running then leave the subroutine.
1381 4 : if (MyLoad >= 0.0 || !RunFlag) {
1382 : // call for zero flow before leaving
1383 0 : if (EquipFlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive ||
1384 0 : this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Locked) {
1385 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
1386 : } else {
1387 0 : this->EvapMassFlowRate = 0.0;
1388 0 : PlantUtilities::SetComponentFlowRate(
1389 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1390 : }
1391 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1392 0 : if (DataPlant::CompData::getPlantComponent(state, this->CDPlantLoc).FlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive) {
1393 0 : this->CondMassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
1394 : } else {
1395 0 : this->CondMassFlowRate = 0.0;
1396 0 : PlantUtilities::SetComponentFlowRate(
1397 0 : state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
1398 : }
1399 : }
1400 :
1401 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
1402 0 : CalcBasinHeaterPower(
1403 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
1404 : }
1405 0 : this->PrintMessage = false;
1406 0 : return;
1407 : }
1408 :
1409 : // If not air or evap cooled then set to the condenser node that is attached to a cooling tower
1410 :
1411 : // Set mass flow rates
1412 4 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1413 4 : this->CondMassFlowRate = this->CondMassFlowRateMax;
1414 4 : PlantUtilities::SetComponentFlowRate(state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
1415 4 : PlantUtilities::PullCompInterconnectTrigger(
1416 4 : state, this->CWPlantLoc, this->CondMassFlowIndex, this->CDPlantLoc, DataPlant::CriteriaType::MassFlowRate, this->CondMassFlowRate);
1417 4 : if (this->CondMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance) {
1418 0 : MyLoad = 0.0;
1419 0 : this->EvapMassFlowRate = 0.0;
1420 0 : PlantUtilities::SetComponentFlowRate(
1421 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1422 0 : return;
1423 : }
1424 : }
1425 :
1426 : // LOAD LOCAL VARIABLES FROM DATA STRUCTURE (for code readability)
1427 4 : Real64 PartLoadRat = this->MinPartLoadRat;
1428 4 : Real64 ChillerNomCap = this->NomCap;
1429 4 : Real64 TempEvapOut = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
1430 :
1431 : // If there is a fault of chiller fouling
1432 4 : if (this->FaultyChillerFoulingFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1433 0 : (!state.dataGlobal->KickOffSimulation)) {
1434 0 : int FaultIndex = this->FaultyChillerFoulingIndex;
1435 0 : Real64 NomCap_ff = ChillerNomCap;
1436 0 : Real64 RatedCOP_ff = this->COP;
1437 :
1438 : // calculate the Faulty Chiller Fouling Factor using fault information
1439 0 : this->FaultyChillerFoulingFactor = state.dataFaultsMgr->FaultsChillerFouling(FaultIndex).CalFoulingFactor(state);
1440 :
1441 : // update the Chiller nominal capacity and COP at faulty cases
1442 0 : ChillerNomCap = NomCap_ff * this->FaultyChillerFoulingFactor;
1443 0 : this->COP = RatedCOP_ff * this->FaultyChillerFoulingFactor;
1444 : }
1445 :
1446 : // initialize outlet air humidity ratio of air or evap cooled chillers
1447 4 : this->CondOutletHumRat = state.dataLoopNodes->Node(this->CondInletNodeNum).HumRat;
1448 :
1449 4 : if (this->CondenserType == DataPlant::CondenserType::AirCooled) { // Condenser inlet temp = outdoor temp
1450 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirDryBulb;
1451 : // Warn user if entering condenser temperature falls below 0C
1452 0 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 0.0 && !state.dataGlobal->WarmupFlag) {
1453 0 : this->PrintMessage = true;
1454 : this->MsgBuffer1 =
1455 0 : format("CalcElectricChillerModel - Chiller:Electric \"{}\" - Air Cooled Condenser Inlet Temperature below 0C", this->Name);
1456 0 : this->MsgBuffer2 = format("... Outdoor Dry-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
1457 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
1458 0 : state.dataEnvrn->EnvironmentName,
1459 0 : state.dataEnvrn->CurMnDy,
1460 0 : General::CreateSysTimeIntervalString(state));
1461 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1462 : } else {
1463 0 : this->PrintMessage = false;
1464 : }
1465 4 : } else if (this->CondenserType == DataPlant::CondenserType::EvapCooled) { // Condenser inlet temp = (outdoor wet bulb)
1466 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirWetBulb;
1467 : // line above assumes evaporation pushes condenser inlet air humidity ratio to saturation
1468 0 : this->CondOutletHumRat = Psychrometrics::PsyWFnTdbTwbPb(state,
1469 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
1470 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
1471 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Press);
1472 : // Warn user if evap condenser wet bulb temperature falls below 10C
1473 0 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 10.0 && !state.dataGlobal->WarmupFlag) {
1474 0 : this->PrintMessage = true;
1475 : this->MsgBuffer1 =
1476 0 : format("CalcElectricChillerModel - Chiller:Electric \"{}\" - Evap Cooled Condenser Inlet Temperature below 10C", this->Name);
1477 0 : this->MsgBuffer2 = format("... Outdoor Wet-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
1478 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
1479 0 : state.dataEnvrn->EnvironmentName,
1480 0 : state.dataEnvrn->CurMnDy,
1481 0 : General::CreateSysTimeIntervalString(state));
1482 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1483 : } else {
1484 0 : this->PrintMessage = false;
1485 : }
1486 : } // End of the Air Cooled/Evap Cooled Logic block
1487 :
1488 4 : Real64 condInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1489 4 : this->CondInletTemp = condInletTemp; // needed if thermosiphon model is used
1490 :
1491 : // correct inlet temperature if using heat recovery
1492 4 : if (this->HeatRecActive) {
1493 0 : if ((this->QHeatRecovery + this->QCondenser) > 0.0) {
1494 0 : this->AvgCondSinkTemp = (this->QHeatRecovery * this->HeatRecInletTemp + this->QCondenser * this->CondInletTemp) /
1495 0 : (this->QHeatRecovery + this->QCondenser);
1496 : } else {
1497 0 : this->AvgCondSinkTemp = condInletTemp;
1498 : }
1499 : } else {
1500 4 : this->AvgCondSinkTemp = condInletTemp;
1501 : }
1502 :
1503 : // If there is a fault of Chiller SWT Sensor
1504 4 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1505 0 : (!state.dataGlobal->KickOffSimulation)) {
1506 0 : int FaultIndex = this->FaultyChillerSWTIndex;
1507 0 : Real64 EvapOutletTemp_ff = TempEvapOut;
1508 :
1509 : // calculate the sensor offset using fault information
1510 0 : this->FaultyChillerSWTOffset = state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex).CalFaultOffsetAct(state);
1511 : // update the TempEvapOut
1512 0 : TempEvapOut = max(this->TempLowLimitEvapOut,
1513 0 : min(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, EvapOutletTemp_ff - this->FaultyChillerSWTOffset));
1514 0 : this->FaultyChillerSWTOffset = EvapOutletTemp_ff - TempEvapOut;
1515 : }
1516 :
1517 : // Calculate chiller performance from this set of performance equations.
1518 4 : Real64 DeltaTemp = (this->AvgCondSinkTemp - this->TempDesCondIn) / this->TempRiseCoef - (TempEvapOut - this->TempDesEvapOut);
1519 :
1520 : // model should have bounds on DeltaTemp and check them (also needs engineering ref content)
1521 4 : Real64 AvailNomCapRat = this->CapRatCoef(1) + this->CapRatCoef(2) * DeltaTemp + this->CapRatCoef(3) * pow_2(DeltaTemp);
1522 :
1523 4 : Real64 AvailChillerCap = ChillerNomCap * AvailNomCapRat;
1524 :
1525 4 : Real64 FullLoadPowerRat = this->PowerRatCoef(1) + this->PowerRatCoef(2) * AvailNomCapRat + this->PowerRatCoef(3) * pow_2(AvailNomCapRat);
1526 :
1527 : // Calculate the PLR. When there is Min PLR and the load is less than Min PLR then the Frac Full load Power
1528 : // is calculated at Min PLR, while all other calculations are based on the actual PLR. So in that case once
1529 : // FracFullLoadPower is calculated the PLR should be recalculated
1530 4 : if (AvailChillerCap > 0.0) {
1531 4 : PartLoadRat = max(this->MinPartLoadRat, min(std::abs(MyLoad) / AvailChillerCap, this->MaxPartLoadRat));
1532 : }
1533 :
1534 4 : Real64 FracFullLoadPower = this->FullLoadCoef(1) + this->FullLoadCoef(2) * PartLoadRat + this->FullLoadCoef(3) * pow_2(PartLoadRat);
1535 :
1536 : // If the PLR is less than Min PLR calculate the actual PLR for calculations. The power will then adjust for
1537 : // the cycling.
1538 :
1539 : Real64 OperPartLoadRat; // Actual Operating PLR
1540 4 : if (AvailChillerCap > 0.0) {
1541 4 : if (std::abs(MyLoad) / AvailChillerCap < this->MinPartLoadRat) {
1542 1 : OperPartLoadRat = std::abs(MyLoad) / AvailChillerCap;
1543 : } else {
1544 3 : OperPartLoadRat = PartLoadRat;
1545 : }
1546 : } else {
1547 0 : OperPartLoadRat = 0.0;
1548 : }
1549 4 : this->partLoadRatio = OperPartLoadRat;
1550 :
1551 4 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, RoutineName);
1552 :
1553 : // If FlowLock is True, the new resolved mdot is used to update Power, QEvap, Qcond, and
1554 : // condenser side outlet temperature.
1555 4 : if (this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Unlocked) {
1556 4 : this->PossibleSubcooling =
1557 4 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType != DataPlant::OpScheme::CompSetPtBased;
1558 4 : this->QEvaporator = AvailChillerCap * OperPartLoadRat;
1559 : Real64 FRAC;
1560 4 : if (OperPartLoadRat < this->MinPartLoadRat) {
1561 1 : FRAC = min(1.0, (OperPartLoadRat / this->MinPartLoadRat));
1562 : } else {
1563 3 : FRAC = 1.0;
1564 : }
1565 4 : this->cyclingRatio = FRAC;
1566 :
1567 : // Either set the flow to the Constant value or calculate the flow for the variable volume
1568 4 : if ((this->FlowMode == DataPlant::FlowMode::Constant) || (this->FlowMode == DataPlant::FlowMode::NotModulated)) {
1569 :
1570 : // Start by assuming max (design) flow
1571 0 : this->EvapMassFlowRate = EvapMassFlowRateMax;
1572 : // Use SetComponentFlowRate to decide actual flow
1573 0 : PlantUtilities::SetComponentFlowRate(
1574 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1575 : // Evaluate delta temp based on actual flow rate
1576 0 : Real64 EvapDeltaTemp(0.0);
1577 0 : if (this->EvapMassFlowRate != 0.0) {
1578 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
1579 : } else {
1580 0 : EvapDeltaTemp = 0.0;
1581 : }
1582 : // Evaluate outlet temp based on delta
1583 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
1584 :
1585 4 : } else if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
1586 :
1587 : // Calculate the Delta Temp from the inlet temp to the chiller outlet setpoint
1588 4 : Real64 EvapDeltaTemp(0.0);
1589 4 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
1590 4 : EvapDeltaTemp =
1591 4 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
1592 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
1593 0 : EvapDeltaTemp =
1594 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
1595 : }
1596 :
1597 4 : if (EvapDeltaTemp != 0.0) {
1598 :
1599 : // Calculate desired flow to request based on load
1600 4 : this->EvapMassFlowRate = std::abs(this->QEvaporator / Cp / EvapDeltaTemp);
1601 : // Check to see if the Maximum is exceeded, if so set to maximum
1602 4 : if ((this->EvapMassFlowRate - EvapMassFlowRateMax) > DataBranchAirLoopPlant::MassFlowTolerance) this->PossibleSubcooling = true;
1603 4 : this->EvapMassFlowRate = min(EvapMassFlowRateMax, this->EvapMassFlowRate);
1604 : // Use SetComponentFlowRate to decide actual flow
1605 4 : PlantUtilities::SetComponentFlowRate(
1606 4 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1607 4 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
1608 4 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
1609 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
1610 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
1611 : }
1612 :
1613 : } else {
1614 :
1615 : // Try to request zero flow
1616 0 : this->EvapMassFlowRate = 0.0;
1617 : // Use SetComponentFlowRate to decide actual flow
1618 0 : PlantUtilities::SetComponentFlowRate(
1619 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1620 : // No deltaT since component is not running
1621 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1622 : }
1623 :
1624 : } // End of Constant Variable Flow If Block
1625 :
1626 4 : if (this->thermosiphonDisabled(state)) {
1627 3 : this->Power = FracFullLoadPower * FullLoadPowerRat * AvailChillerCap / this->COP * FRAC;
1628 : }
1629 :
1630 : // If there is a fault of Chiller SWT Sensor
1631 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1632 4 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
1633 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
1634 0 : int FaultIndex = this->FaultyChillerSWTIndex;
1635 0 : bool VarFlowFlag = (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated);
1636 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
1637 0 : .CalFaultChillerSWT(VarFlowFlag,
1638 : this->FaultyChillerSWTOffset,
1639 : Cp,
1640 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
1641 0 : this->EvapOutletTemp,
1642 0 : this->EvapMassFlowRate,
1643 0 : this->QEvaporator);
1644 : }
1645 :
1646 : } else { // If FlowLock is True
1647 :
1648 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
1649 0 : PlantUtilities::SetComponentFlowRate(state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1650 :
1651 : // Some other component set the flow to 0. No reason to continue with calculations.
1652 0 : if (this->EvapMassFlowRate == 0.0) {
1653 0 : MyLoad = 0.0;
1654 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
1655 0 : CalcBasinHeaterPower(
1656 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
1657 : }
1658 0 : this->PrintMessage = false;
1659 0 : return;
1660 : }
1661 : // Flow resolver might have given less flow or control scheme have provided more load, which may
1662 : // result in subcooling.
1663 0 : if (this->PossibleSubcooling) {
1664 0 : this->QEvaporator = std::abs(MyLoad);
1665 0 : Real64 EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
1666 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
1667 : } else { // No subcooling in this case.No recalculation required.Still need to check chiller low temp limit
1668 :
1669 0 : Real64 TempEvapOutSetPoint(0.0); // C - evaporator outlet temperature setpoint
1670 0 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
1671 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
1672 0 : (DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) ||
1673 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint != DataLoopNode::SensedNodeFlagValue)) {
1674 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
1675 : } else {
1676 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
1677 : }
1678 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
1679 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
1680 0 : (DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) ||
1681 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi != DataLoopNode::SensedNodeFlagValue)) {
1682 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
1683 : } else {
1684 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
1685 : }
1686 : }
1687 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - TempEvapOutSetPoint;
1688 0 : this->QEvaporator = std::abs(this->EvapMassFlowRate * Cp * EvapDeltaTemp);
1689 0 : this->EvapOutletTemp = TempEvapOutSetPoint;
1690 : }
1691 : // Check that the Evap outlet temp honors both plant loop temp low limit and also the chiller low limit
1692 0 : if (this->EvapOutletTemp < this->TempLowLimitEvapOut) {
1693 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->TempLowLimitEvapOut) > DataPlant::DeltaTempTol) {
1694 0 : this->EvapOutletTemp = this->TempLowLimitEvapOut;
1695 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
1696 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
1697 : } else {
1698 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1699 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
1700 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
1701 : }
1702 : }
1703 0 : if (this->EvapOutletTemp < state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) {
1704 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) >
1705 : DataPlant::DeltaTempTol) {
1706 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin;
1707 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
1708 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
1709 : } else {
1710 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1711 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
1712 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
1713 : }
1714 : }
1715 :
1716 : // If load exceeds the distributed load set to the distributed load
1717 0 : if (this->QEvaporator > std::abs(MyLoad)) {
1718 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
1719 0 : this->QEvaporator = std::abs(MyLoad);
1720 0 : Real64 EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
1721 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
1722 : } else {
1723 0 : this->QEvaporator = 0.0;
1724 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1725 : }
1726 : }
1727 :
1728 : // If there is a fault of Chiller SWT Sensor
1729 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1730 0 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
1731 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
1732 0 : int FaultIndex = this->FaultyChillerSWTIndex;
1733 0 : bool VarFlowFlag = false;
1734 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
1735 0 : .CalFaultChillerSWT(VarFlowFlag,
1736 : this->FaultyChillerSWTOffset,
1737 : Cp,
1738 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
1739 0 : this->EvapOutletTemp,
1740 0 : this->EvapMassFlowRate,
1741 0 : this->QEvaporator);
1742 : }
1743 :
1744 : // Checks QEvaporator on the basis of the machine limits.
1745 0 : if (this->QEvaporator > (AvailChillerCap * this->MaxPartLoadRat)) {
1746 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
1747 0 : this->QEvaporator = AvailChillerCap * OperPartLoadRat;
1748 0 : Real64 EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
1749 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
1750 : } else {
1751 0 : this->QEvaporator = 0.0;
1752 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1753 : }
1754 : }
1755 :
1756 : Real64 FRAC;
1757 0 : if (OperPartLoadRat < this->MinPartLoadRat) {
1758 0 : FRAC = min(1.0, (OperPartLoadRat / this->MinPartLoadRat));
1759 : } else {
1760 0 : FRAC = 1.0;
1761 : }
1762 0 : this->cyclingRatio = FRAC;
1763 :
1764 : // Chiller is false loading below PLR = minimum unloading ratio, find PLR used for energy calculation
1765 0 : if (this->thermosiphonDisabled(state)) {
1766 0 : this->Power = FracFullLoadPower * FullLoadPowerRat * AvailChillerCap / this->COP * FRAC;
1767 : }
1768 :
1769 0 : if (this->EvapMassFlowRate == 0.0) {
1770 0 : this->QEvaporator = 0.0;
1771 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1772 0 : this->Power = 0.0;
1773 0 : this->PrintMessage = false;
1774 : }
1775 0 : if (this->QEvaporator == 0.0 && this->CondenserType == DataPlant::CondenserType::EvapCooled) {
1776 0 : CalcBasinHeaterPower(
1777 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
1778 : }
1779 : } // This is the end of the FlowLock Block
1780 :
1781 : // QCondenser is calculated the same for each type, but the power consumption should be different
1782 : // depending on the performance coefficients used for the chiller model.
1783 4 : this->QCondenser = this->Power + this->QEvaporator;
1784 :
1785 4 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1786 4 : if (this->CondMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
1787 : // If Heat Recovery specified for this vapor compression chiller, then Qcondenser will be adjusted by this subroutine
1788 4 : if (this->HeatRecActive) this->calcHeatRecovery(state, this->QCondenser, this->CondMassFlowRate, condInletTemp, this->QHeatRecovered);
1789 4 : Real64 CpCond = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, condInletTemp, RoutineName);
1790 4 : this->CondOutletTemp = this->QCondenser / this->CondMassFlowRate / CpCond + condInletTemp;
1791 : } else {
1792 0 : ShowSevereError(state, format("CalcElectricChillerModel: Condenser flow = 0, for ElectricChiller={}", this->Name));
1793 0 : ShowContinueErrorTimeStamp(state, "");
1794 : }
1795 : } else { // Air Cooled or Evap Cooled
1796 :
1797 0 : if (this->QCondenser > 0.0) {
1798 0 : this->CondMassFlowRate = this->CondMassFlowRateMax * OperPartLoadRat;
1799 : } else {
1800 0 : this->CondMassFlowRate = 0.0;
1801 : }
1802 :
1803 : // If Heat Recovery specified for this vapor compression chiller, then Qcondenser will be adjusted by this subroutine
1804 0 : if (this->HeatRecActive) this->calcHeatRecovery(state, this->QCondenser, this->CondMassFlowRate, condInletTemp, this->QHeatRecovered);
1805 0 : if (this->CondMassFlowRate > 0.0) {
1806 0 : Real64 CpCond = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(this->CondInletNodeNum).HumRat);
1807 0 : this->CondOutletTemp = condInletTemp + this->QCondenser / this->CondMassFlowRate / CpCond;
1808 : } else {
1809 0 : this->CondOutletTemp = condInletTemp;
1810 : }
1811 : }
1812 :
1813 : // Calculate Energy
1814 4 : this->CondenserEnergy = this->QCondenser * state.dataHVACGlobal->TimeStepSysSec;
1815 4 : this->Energy = this->Power * state.dataHVACGlobal->TimeStepSysSec;
1816 4 : this->EvaporatorEnergy = this->QEvaporator * state.dataHVACGlobal->TimeStepSysSec;
1817 :
1818 : // check for problems (deal with observed negative energy results)
1819 4 : if (this->Energy < 0.0) { // there is a serious problem
1820 :
1821 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1822 : // first check for run away condenser loop temps (only reason yet to be observed for this?)
1823 0 : if (condInletTemp > 70.0) {
1824 0 : ShowSevereError(
1825 0 : state, format("CalcElectricChillerModel: Condenser loop inlet temperatures over 70.0 C for ElectricChiller={}", this->Name));
1826 0 : ShowContinueErrorTimeStamp(state, "");
1827 0 : ShowContinueError(state, format("Condenser loop water temperatures are too high at{:.2R}", condInletTemp));
1828 0 : ShowContinueError(state, "Check input for condenser plant loop, especially cooling tower");
1829 0 : ShowContinueError(state, format("Evaporator inlet temperature: {:.2R}", state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp));
1830 :
1831 0 : ShowFatalError(state, "Program Terminates due to previous error condition");
1832 : }
1833 : }
1834 0 : if (!state.dataGlobal->WarmupFlag) {
1835 0 : if (AvailNomCapRat < 0.0) { // apparently the real reason energy goes negative
1836 0 : ShowSevereError(state, format("CalcElectricChillerModel: Capacity ratio below zero for ElectricChiller={}", this->Name));
1837 0 : ShowContinueErrorTimeStamp(state, "");
1838 0 : ShowContinueError(state, "Check input for Capacity Ratio Curve");
1839 0 : ShowContinueError(state, format("Condenser inlet temperature: {:.2R}", condInletTemp));
1840 0 : ShowContinueError(state, format("Evaporator inlet temperature: {:.2R}", state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp));
1841 0 : ShowFatalError(state, "Program Terminates due to previous error condition");
1842 : }
1843 : }
1844 : // If makes it here, set limits, chiller can't have negative energy/power
1845 : // proceeding silently for now but may want to throw error here
1846 0 : this->Power = 0.0;
1847 0 : this->Energy = 0.0;
1848 : }
1849 : }
1850 :
1851 0 : void ElectricChillerSpecs::calcHeatRecovery(EnergyPlusData &state,
1852 : Real64 &QCond, // current condenser load
1853 : Real64 const CondMassFlow, // current condenser Mass Flow
1854 : Real64 const condInletTemp, // current condenser Inlet Temp
1855 : Real64 &QHeatRec // amount of heat recovered
1856 : )
1857 : {
1858 : // SUBROUTINE INFORMATION:
1859 : // AUTHOR: Richard Liesen
1860 : // DATE WRITTEN: January 2004
1861 :
1862 : // PURPOSE OF THIS SUBROUTINE:
1863 : // Calculate the heat recovered from the chiller condenser
1864 :
1865 : static constexpr std::string_view RoutineName("ChillerHeatRecovery");
1866 :
1867 : // setup initial state
1868 0 : PlantUtilities::SafeCopyPlantNode(state, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
1869 0 : this->QHeatRecovery = 0.0;
1870 0 : this->EnergyHeatRecovery = 0.0;
1871 :
1872 : // Begin routine
1873 0 : this->HeatRecInletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
1874 0 : Real64 HeatRecMassFlowRate = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
1875 :
1876 0 : Real64 CpHeatRec = this->HRPlantLoc.loop->glycol->getSpecificHeat(state, this->HeatRecInletTemp, RoutineName);
1877 :
1878 : Real64 CpCond;
1879 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1880 0 : CpCond = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, condInletTemp, RoutineName);
1881 : } else {
1882 0 : CpCond = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(this->CondInletNodeNum).HumRat);
1883 : }
1884 :
1885 : // Before we modify the QCondenser, the total or original value is transferred to QTot
1886 0 : Real64 QTotal = QCond;
1887 :
1888 0 : if (this->HeatRecSetPointNodeNum == 0) { // use original algorithm that blends temps
1889 0 : Real64 TAvgIn = (HeatRecMassFlowRate * CpHeatRec * this->HeatRecInletTemp + CondMassFlow * CpCond * condInletTemp) /
1890 0 : (HeatRecMassFlowRate * CpHeatRec + CondMassFlow * CpCond);
1891 :
1892 0 : Real64 TAvgOut = QTotal / (HeatRecMassFlowRate * CpHeatRec + CondMassFlow * CpCond) + TAvgIn;
1893 :
1894 0 : QHeatRec = HeatRecMassFlowRate * CpHeatRec * (TAvgOut - this->HeatRecInletTemp);
1895 0 : QHeatRec = max(QHeatRec, 0.0); // ensure non negative
1896 : // check if heat flow too large for physical size of bundle
1897 0 : QHeatRec = min(QHeatRec, this->HeatRecMaxCapacityLimit);
1898 : } else { // use new algorithm to meet setpoint
1899 0 : Real64 THeatRecSetPoint(0.0);
1900 :
1901 0 : if (this->HRPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
1902 0 : THeatRecSetPoint = state.dataLoopNodes->Node(this->HeatRecSetPointNodeNum).TempSetPoint;
1903 0 : } else if (this->HRPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
1904 0 : THeatRecSetPoint = state.dataLoopNodes->Node(this->HeatRecSetPointNodeNum).TempSetPointHi;
1905 : }
1906 :
1907 0 : Real64 QHeatRecToSetPoint = HeatRecMassFlowRate * CpHeatRec * (THeatRecSetPoint - this->HeatRecInletTemp);
1908 0 : QHeatRecToSetPoint = max(QHeatRecToSetPoint, 0.0);
1909 0 : QHeatRec = min(QTotal, QHeatRecToSetPoint);
1910 : // check if heat flow too large for physical size of bundle
1911 0 : QHeatRec = min(QHeatRec, this->HeatRecMaxCapacityLimit);
1912 : }
1913 : // check if limit on inlet is present and exceeded.
1914 0 : if (this->heatRecInletLimitSched != nullptr) {
1915 0 : Real64 HeatRecHighInletLimit = this->heatRecInletLimitSched->getCurrentVal();
1916 0 : if (this->HeatRecInletTemp > HeatRecHighInletLimit) { // shut down heat recovery
1917 0 : QHeatRec = 0.0;
1918 : }
1919 : }
1920 :
1921 0 : QCond = QTotal - QHeatRec;
1922 :
1923 : // Calculate a new Heat Recovery Coil Outlet Temp
1924 0 : if (HeatRecMassFlowRate > 0.0) {
1925 0 : this->HeatRecOutletTemp = QHeatRec / (HeatRecMassFlowRate * CpHeatRec) + this->HeatRecInletTemp;
1926 : } else {
1927 0 : this->HeatRecOutletTemp = this->HeatRecInletTemp;
1928 : }
1929 :
1930 0 : this->QHeatRecovery = this->QHeatRecovered;
1931 0 : this->EnergyHeatRecovery = this->QHeatRecovered * state.dataHVACGlobal->TimeStepSysSec;
1932 0 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = this->HeatRecOutletTemp;
1933 0 : this->HeatRecMdot = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
1934 0 : this->ChillerCondAvgTemp = this->AvgCondSinkTemp;
1935 0 : }
1936 :
1937 1 : void ElectricChillerSpecs::update(EnergyPlusData &state, Real64 const MyLoad, bool const RunFlag)
1938 : {
1939 : // SUBROUTINE INFORMATION:
1940 : // AUTHOR: Dan Fisher / Brandon Anderson
1941 : // DATE WRITTEN: September 2000
1942 :
1943 1 : Real64 const ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
1944 :
1945 1 : if (MyLoad >= 0.0 || !RunFlag) { // Chiller not running so pass inlet states to outlet states
1946 : // set node temperatures
1947 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1948 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1949 0 : if (this->CondenserType != DataPlant::CondenserType::WaterCooled) {
1950 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).HumRat = state.dataLoopNodes->Node(this->CondInletNodeNum).HumRat;
1951 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Enthalpy = state.dataLoopNodes->Node(this->CondInletNodeNum).Enthalpy;
1952 : }
1953 :
1954 0 : this->EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1955 0 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1956 0 : this->CondOutletTemp = state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp;
1957 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
1958 :
1959 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
1960 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
1961 : }
1962 :
1963 0 : if (this->HeatRecActive) {
1964 :
1965 0 : PlantUtilities::SafeCopyPlantNode(state, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
1966 0 : this->HeatRecInletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
1967 0 : this->HeatRecOutletTemp = state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp;
1968 0 : this->HeatRecMdot = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
1969 :
1970 0 : this->ChillerCondAvgTemp = this->AvgCondSinkTemp;
1971 : }
1972 :
1973 : } else { // Chiller is running, so pass calculated values
1974 : // set node temperatures
1975 1 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = this->EvapOutletTemp;
1976 1 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = this->CondOutletTemp;
1977 1 : if (this->CondenserType != DataPlant::CondenserType::WaterCooled) {
1978 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).HumRat = this->CondOutletHumRat;
1979 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Enthalpy =
1980 0 : Psychrometrics::PsyHFnTdbW(this->CondOutletTemp, this->CondOutletHumRat);
1981 : }
1982 : // set node flow rates; for these load based models
1983 : // assume that the sufficient evaporator flow rate available
1984 1 : this->EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1985 1 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1986 1 : this->CondOutletTemp = state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp;
1987 1 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
1988 1 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
1989 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
1990 : }
1991 1 : if (this->Power != 0.0) {
1992 1 : this->ActualCOP = this->QEvaporator / this->Power;
1993 : } else {
1994 0 : this->ActualCOP = 0.0;
1995 : }
1996 : }
1997 1 : }
1998 10 : void ElectricChillerSpecs::oneTimeInit(EnergyPlusData &state)
1999 : {
2000 :
2001 10 : if (this->MyFlag) {
2002 : // Locate the chillers on the plant loops for later usage
2003 2 : bool errFlag = false;
2004 2 : this->setupOutputVariables(state);
2005 6 : PlantUtilities::ScanPlantLoopsForObject(
2006 4 : state, this->Name, this->ChillerType, this->CWPlantLoc, errFlag, this->TempLowLimitEvapOut, _, _, this->EvapInletNodeNum, _);
2007 2 : if (this->CondenserType != DataPlant::CondenserType::AirCooled && this->CondenserType != DataPlant::CondenserType::EvapCooled) {
2008 6 : PlantUtilities::ScanPlantLoopsForObject(
2009 4 : state, this->Name, this->ChillerType, this->CDPlantLoc, errFlag, _, _, _, this->CondInletNodeNum, _);
2010 2 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CWPlantLoc, this->CDPlantLoc, this->ChillerType, true);
2011 : }
2012 2 : if (this->HeatRecActive) {
2013 0 : PlantUtilities::ScanPlantLoopsForObject(
2014 0 : state, this->Name, this->ChillerType, this->HRPlantLoc, errFlag, _, _, _, this->HeatRecInletNodeNum, _);
2015 0 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CWPlantLoc, this->HRPlantLoc, this->ChillerType, true);
2016 : }
2017 :
2018 2 : if (this->CondenserType != DataPlant::CondenserType::AirCooled && this->CondenserType != DataPlant::CondenserType::EvapCooled &&
2019 2 : this->HeatRecActive) {
2020 0 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CDPlantLoc, this->HRPlantLoc, this->ChillerType, false);
2021 : }
2022 :
2023 2 : if (errFlag) {
2024 0 : ShowFatalError(state, "InitElectricChiller: Program terminated due to previous condition(s).");
2025 : }
2026 :
2027 2 : if (this->FlowMode == DataPlant::FlowMode::Constant) {
2028 : // reset flow priority
2029 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
2030 : }
2031 :
2032 2 : if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
2033 : // reset flow priority
2034 2 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
2035 :
2036 : // check if setpoint on outlet node
2037 4 : if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
2038 2 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == DataLoopNode::SensedNodeFlagValue)) {
2039 2 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
2040 2 : if (!this->ModulatedFlowErrDone) {
2041 4 : ShowWarningError(state,
2042 4 : format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
2043 4 : ShowContinueError(
2044 : state,
2045 : " A temperature setpoint is needed at the outlet node of a chiller in variable flow mode, use a SetpointManager");
2046 4 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
2047 2 : this->ModulatedFlowErrDone = true;
2048 : }
2049 : } else {
2050 : // need call to EMS to check node
2051 0 : bool FatalError = false; // but not really fatal yet, but should be.
2052 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->EvapOutletNodeNum, HVAC::CtrlVarType::Temp, FatalError);
2053 0 : state.dataLoopNodes->NodeSetpointCheck(this->EvapOutletNodeNum).needsSetpointChecking = false;
2054 0 : if (FatalError) {
2055 0 : if (!this->ModulatedFlowErrDone) {
2056 0 : ShowWarningError(
2057 0 : state, format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
2058 0 : ShowContinueError(
2059 : state, " A temperature setpoint is needed at the outlet node of a chiller evaporator in variable flow mode");
2060 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the chiller evaporator outlet node ");
2061 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the outlet node ");
2062 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
2063 0 : this->ModulatedFlowErrDone = true;
2064 : }
2065 : }
2066 : }
2067 2 : this->ModulatedFlowSetToLoop = true;
2068 2 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
2069 1 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
2070 1 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
2071 1 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
2072 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
2073 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
2074 : }
2075 : }
2076 : }
2077 2 : this->MyFlag = false;
2078 : }
2079 10 : }
2080 4 : bool ElectricChillerSpecs::thermosiphonDisabled(EnergyPlusData &state)
2081 : {
2082 4 : if (this->thermosiphonTempCurveIndex > 0) {
2083 4 : this->thermosiphonStatus = 0;
2084 4 : Real64 dT = this->EvapOutletTemp - this->CondInletTemp;
2085 4 : if (dT < this->thermosiphonMinTempDiff) {
2086 2 : return true;
2087 : }
2088 2 : Real64 thermosiphonCapFrac = Curve::CurveValue(state, this->thermosiphonTempCurveIndex, dT);
2089 2 : Real64 capFrac = this->partLoadRatio * this->cyclingRatio;
2090 2 : if (thermosiphonCapFrac >= capFrac) {
2091 1 : this->thermosiphonStatus = 1;
2092 1 : this->Power = 0.0;
2093 1 : return false;
2094 : }
2095 1 : return true;
2096 : } else {
2097 0 : return true;
2098 : }
2099 : }
2100 :
2101 0 : EngineDrivenChillerSpecs *EngineDrivenChillerSpecs::factory(EnergyPlusData &state, std::string const &chillerName)
2102 : {
2103 0 : if (state.dataPlantChillers->GetEngineDrivenInput) {
2104 0 : EngineDrivenChillerSpecs::getInput(state);
2105 0 : state.dataPlantChillers->GetEngineDrivenInput = false;
2106 : }
2107 0 : for (auto &thisChiller : state.dataPlantChillers->EngineDrivenChiller) {
2108 0 : if (Util::makeUPPER(thisChiller.Name) == chillerName) {
2109 0 : return &thisChiller;
2110 : }
2111 : }
2112 0 : ShowFatalError(state, format("Could not locate engine driven chiller with name: {}", chillerName));
2113 0 : return nullptr;
2114 : }
2115 :
2116 0 : void EngineDrivenChillerSpecs::simulate(
2117 : EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, bool RunFlag)
2118 : {
2119 0 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) { // chilled water loop
2120 0 : this->initialize(state, RunFlag, CurLoad);
2121 0 : this->calculate(state, CurLoad, RunFlag, this->CWPlantLoc.comp->FlowCtrl);
2122 0 : this->update(state, CurLoad, RunFlag);
2123 0 : } else if (calledFromLocation.loopNum == this->CDPlantLoc.loopNum) { // condenser loop
2124 0 : PlantUtilities::UpdateChillerComponentCondenserSide(state,
2125 : this->CDPlantLoc.loopNum,
2126 : this->CDPlantLoc.loopSideNum,
2127 : this->ChillerType,
2128 : this->CondInletNodeNum,
2129 : this->CondOutletNodeNum,
2130 : this->QCondenser,
2131 : this->CondInletTemp,
2132 : this->CondOutletTemp,
2133 : this->CondMassFlowRate,
2134 : FirstHVACIteration);
2135 0 : } else if (calledFromLocation.loopNum == this->HRPlantLoc.loopNum) { // heat recovery loop
2136 0 : PlantUtilities::UpdateComponentHeatRecoverySide(state,
2137 : this->HRPlantLoc.loopNum,
2138 : this->HRPlantLoc.loopSideNum,
2139 : this->ChillerType,
2140 : this->HeatRecInletNodeNum,
2141 : this->HeatRecOutletNodeNum,
2142 : this->QTotalHeatRecovered,
2143 : this->HeatRecInletTemp,
2144 : this->HeatRecOutletTemp,
2145 : this->HeatRecMdot,
2146 : FirstHVACIteration);
2147 : }
2148 0 : }
2149 :
2150 1 : void EngineDrivenChillerSpecs::getInput(EnergyPlusData &state)
2151 : {
2152 : // SUBROUTINE INFORMATION:
2153 : // AUTHOR: Dan Fisher / Brandon Anderson
2154 : // DATE WRITTEN: September 2000
2155 : // PURPOSE OF THIS SUBROUTINE:
2156 : // This routine will get the input
2157 : // required by the EngineDriven Chiller model.
2158 :
2159 : // Locals
2160 : // PARAMETERS
2161 : static constexpr std::string_view RoutineName("GetEngineDrivenChillerInput: "); // include trailing blank space
2162 : static constexpr std::string_view routineName = "GetEngineDrivenChillerInput";
2163 :
2164 : int NumAlphas; // Number of elements in the alpha array
2165 : int NumNums; // Number of elements in the numeric array
2166 : int IOStat; // IO Status when calling get input subroutine
2167 1 : bool ErrorsFound(false);
2168 :
2169 1 : state.dataIPShortCut->cCurrentModuleObject = "Chiller:EngineDriven";
2170 2 : state.dataPlantChillers->NumEngineDrivenChillers =
2171 1 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
2172 :
2173 1 : if (state.dataPlantChillers->NumEngineDrivenChillers <= 0) {
2174 0 : ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
2175 0 : ErrorsFound = true;
2176 : }
2177 : // See if load distribution manager has already gotten the input
2178 1 : if (allocated(state.dataPlantChillers->EngineDrivenChiller)) return;
2179 :
2180 : // ALLOCATE ARRAYS
2181 1 : state.dataPlantChillers->EngineDrivenChiller.allocate(state.dataPlantChillers->NumEngineDrivenChillers);
2182 :
2183 : // LOAD ARRAYS WITH EngineDriven CURVE FIT CHILLER DATA
2184 2 : for (int ChillerNum = 1; ChillerNum <= state.dataPlantChillers->NumEngineDrivenChillers; ++ChillerNum) {
2185 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2186 1 : state.dataIPShortCut->cCurrentModuleObject,
2187 : ChillerNum,
2188 1 : state.dataIPShortCut->cAlphaArgs,
2189 : NumAlphas,
2190 1 : state.dataIPShortCut->rNumericArgs,
2191 : NumNums,
2192 : IOStat,
2193 1 : state.dataIPShortCut->lNumericFieldBlanks,
2194 1 : state.dataIPShortCut->lAlphaFieldBlanks,
2195 1 : state.dataIPShortCut->cAlphaFieldNames,
2196 1 : state.dataIPShortCut->cNumericFieldNames);
2197 :
2198 1 : ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
2199 :
2200 1 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
2201 :
2202 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
2203 1 : GlobalNames::VerifyUniqueChillerName(state,
2204 1 : state.dataIPShortCut->cCurrentModuleObject,
2205 1 : state.dataIPShortCut->cAlphaArgs(1),
2206 : ErrorsFound,
2207 2 : state.dataIPShortCut->cCurrentModuleObject + " Name");
2208 :
2209 1 : auto &thisChiller = state.dataPlantChillers->EngineDrivenChiller(ChillerNum);
2210 1 : thisChiller.Name = state.dataIPShortCut->cAlphaArgs(1);
2211 1 : thisChiller.ChillerType = DataPlant::PlantEquipmentType::Chiller_EngineDriven;
2212 :
2213 1 : thisChiller.NomCap = state.dataIPShortCut->rNumericArgs(1);
2214 1 : if (thisChiller.NomCap == DataSizing::AutoSize) {
2215 0 : thisChiller.NomCapWasAutoSized = true;
2216 : }
2217 1 : if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
2218 0 : ShowSevereError(state,
2219 0 : format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
2220 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2221 0 : ErrorsFound = true;
2222 : }
2223 :
2224 1 : thisChiller.COP = state.dataIPShortCut->rNumericArgs(2);
2225 1 : if (state.dataIPShortCut->rNumericArgs(2) == 0.0) {
2226 0 : ShowSevereError(state,
2227 0 : format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
2228 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2229 0 : ErrorsFound = true;
2230 : }
2231 :
2232 1 : if (state.dataIPShortCut->cAlphaArgs(2) == "AIRCOOLED") {
2233 0 : thisChiller.CondenserType = DataPlant::CondenserType::AirCooled;
2234 1 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "WATERCOOLED") {
2235 1 : thisChiller.CondenserType = DataPlant::CondenserType::WaterCooled;
2236 0 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "EVAPORATIVELYCOOLED") {
2237 0 : thisChiller.CondenserType = DataPlant::CondenserType::EvapCooled;
2238 : } else {
2239 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
2240 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2241 0 : ErrorsFound = true;
2242 : }
2243 :
2244 1 : thisChiller.EvapInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2245 1 : state.dataIPShortCut->cAlphaArgs(3),
2246 : ErrorsFound,
2247 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2248 1 : state.dataIPShortCut->cAlphaArgs(1),
2249 : DataLoopNode::NodeFluidType::Water,
2250 : DataLoopNode::ConnectionType::Inlet,
2251 : NodeInputManager::CompFluidStream::Primary,
2252 : DataLoopNode::ObjectIsNotParent);
2253 2 : thisChiller.EvapOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2254 1 : state.dataIPShortCut->cAlphaArgs(4),
2255 : ErrorsFound,
2256 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2257 1 : state.dataIPShortCut->cAlphaArgs(1),
2258 : DataLoopNode::NodeFluidType::Water,
2259 : DataLoopNode::ConnectionType::Outlet,
2260 : NodeInputManager::CompFluidStream::Primary,
2261 : DataLoopNode::ObjectIsNotParent);
2262 2 : BranchNodeConnections::TestCompSet(state,
2263 1 : state.dataIPShortCut->cCurrentModuleObject,
2264 1 : state.dataIPShortCut->cAlphaArgs(1),
2265 1 : state.dataIPShortCut->cAlphaArgs(3),
2266 1 : state.dataIPShortCut->cAlphaArgs(4),
2267 : "Chilled Water Nodes");
2268 :
2269 1 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
2270 1 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
2271 : // Connection not required for air or evap cooled condenser
2272 : // If the condenser inlet is blank for air cooled and evap cooled condensers then supply a generic name
2273 : // since it is not used elsewhere for connection
2274 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
2275 0 : if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 21) { // protect against long name leading to > 100 chars
2276 0 : state.dataIPShortCut->cAlphaArgs(5) = state.dataIPShortCut->cAlphaArgs(1) + " CONDENSER INLET NODE";
2277 : } else {
2278 0 : state.dataIPShortCut->cAlphaArgs(5) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 79) + " CONDENSER INLET NODE";
2279 : }
2280 : }
2281 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
2282 0 : if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 22) { // protect against long name leading to > 100 chars
2283 0 : state.dataIPShortCut->cAlphaArgs(6) = state.dataIPShortCut->cAlphaArgs(1) + " CONDENSER OUTLET NODE";
2284 : } else {
2285 0 : state.dataIPShortCut->cAlphaArgs(6) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 78) + " CONDENSER OUTLET NODE";
2286 : }
2287 : }
2288 :
2289 0 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2290 0 : state.dataIPShortCut->cAlphaArgs(5),
2291 : ErrorsFound,
2292 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2293 0 : state.dataIPShortCut->cAlphaArgs(1),
2294 : DataLoopNode::NodeFluidType::Air,
2295 : DataLoopNode::ConnectionType::OutsideAirReference,
2296 : NodeInputManager::CompFluidStream::Secondary,
2297 : DataLoopNode::ObjectIsNotParent);
2298 : bool Okay;
2299 0 : OutAirNodeManager::CheckAndAddAirNodeNumber(state, thisChiller.CondInletNodeNum, Okay);
2300 0 : if (!Okay) {
2301 0 : ShowWarningError(state,
2302 0 : format("{}, Adding OutdoorAir:DataLoopNode::Node={}",
2303 0 : state.dataIPShortCut->cCurrentModuleObject,
2304 0 : state.dataIPShortCut->cAlphaArgs(5)));
2305 : }
2306 :
2307 0 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2308 0 : state.dataIPShortCut->cAlphaArgs(6),
2309 : ErrorsFound,
2310 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2311 0 : state.dataIPShortCut->cAlphaArgs(1),
2312 : DataLoopNode::NodeFluidType::Air,
2313 : DataLoopNode::ConnectionType::Outlet,
2314 : NodeInputManager::CompFluidStream::Secondary,
2315 : DataLoopNode::ObjectIsNotParent);
2316 1 : } else if (thisChiller.CondenserType == DataPlant::CondenserType::WaterCooled) {
2317 1 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2318 1 : state.dataIPShortCut->cAlphaArgs(5),
2319 : ErrorsFound,
2320 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2321 1 : state.dataIPShortCut->cAlphaArgs(1),
2322 : DataLoopNode::NodeFluidType::Water,
2323 : DataLoopNode::ConnectionType::Inlet,
2324 : NodeInputManager::CompFluidStream::Secondary,
2325 : DataLoopNode::ObjectIsNotParent);
2326 2 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2327 1 : state.dataIPShortCut->cAlphaArgs(6),
2328 : ErrorsFound,
2329 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2330 1 : state.dataIPShortCut->cAlphaArgs(1),
2331 : DataLoopNode::NodeFluidType::Water,
2332 : DataLoopNode::ConnectionType::Outlet,
2333 : NodeInputManager::CompFluidStream::Secondary,
2334 : DataLoopNode::ObjectIsNotParent);
2335 2 : BranchNodeConnections::TestCompSet(state,
2336 1 : state.dataIPShortCut->cCurrentModuleObject,
2337 1 : state.dataIPShortCut->cAlphaArgs(1),
2338 1 : state.dataIPShortCut->cAlphaArgs(5),
2339 1 : state.dataIPShortCut->cAlphaArgs(6),
2340 : "Condenser Water Nodes");
2341 : // Condenser Inlet node name is necessary for Water Cooled
2342 1 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
2343 0 : ShowSevereError(state, format("Invalid, {} is blank ", state.dataIPShortCut->cAlphaFieldNames(5)));
2344 0 : ShowContinueError(state,
2345 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2346 0 : ErrorsFound = true;
2347 1 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
2348 0 : ShowSevereError(state, format("Invalid, {} is blank ", state.dataIPShortCut->cAlphaFieldNames(6)));
2349 0 : ShowContinueError(state,
2350 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2351 0 : ErrorsFound = true;
2352 : }
2353 : } else {
2354 0 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2355 0 : state.dataIPShortCut->cAlphaArgs(5),
2356 : ErrorsFound,
2357 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2358 0 : state.dataIPShortCut->cAlphaArgs(1),
2359 : DataLoopNode::NodeFluidType::Blank,
2360 : DataLoopNode::ConnectionType::Inlet,
2361 : NodeInputManager::CompFluidStream::Secondary,
2362 : DataLoopNode::ObjectIsNotParent);
2363 0 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2364 0 : state.dataIPShortCut->cAlphaArgs(6),
2365 : ErrorsFound,
2366 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2367 0 : state.dataIPShortCut->cAlphaArgs(1),
2368 : DataLoopNode::NodeFluidType::Blank,
2369 : DataLoopNode::ConnectionType::Outlet,
2370 : NodeInputManager::CompFluidStream::Secondary,
2371 : DataLoopNode::ObjectIsNotParent);
2372 0 : BranchNodeConnections::TestCompSet(state,
2373 0 : state.dataIPShortCut->cCurrentModuleObject,
2374 0 : state.dataIPShortCut->cAlphaArgs(1),
2375 0 : state.dataIPShortCut->cAlphaArgs(5),
2376 0 : state.dataIPShortCut->cAlphaArgs(6),
2377 : "Condenser (unknown?) Nodes");
2378 : // Condenser Inlet node name is necessary for Water Cooled
2379 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
2380 0 : ShowSevereError(state, format("Invalid, {} is blank ", state.dataIPShortCut->cAlphaFieldNames(5)));
2381 0 : ShowContinueError(state,
2382 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2383 0 : ErrorsFound = true;
2384 0 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
2385 0 : ShowSevereError(state, format("Invalid, {} is blank ", state.dataIPShortCut->cAlphaFieldNames(6)));
2386 0 : ShowContinueError(state,
2387 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2388 0 : ErrorsFound = true;
2389 : }
2390 : }
2391 :
2392 1 : thisChiller.MinPartLoadRat = state.dataIPShortCut->rNumericArgs(3);
2393 1 : thisChiller.MaxPartLoadRat = state.dataIPShortCut->rNumericArgs(4);
2394 1 : thisChiller.OptPartLoadRat = state.dataIPShortCut->rNumericArgs(5);
2395 1 : thisChiller.TempDesCondIn = state.dataIPShortCut->rNumericArgs(6);
2396 1 : thisChiller.TempRiseCoef = state.dataIPShortCut->rNumericArgs(7);
2397 1 : thisChiller.TempDesEvapOut = state.dataIPShortCut->rNumericArgs(8);
2398 1 : thisChiller.EvapVolFlowRate = state.dataIPShortCut->rNumericArgs(9);
2399 1 : if (thisChiller.EvapVolFlowRate == DataSizing::AutoSize) {
2400 0 : thisChiller.EvapVolFlowRateWasAutoSized = true;
2401 : }
2402 1 : thisChiller.CondVolFlowRate = state.dataIPShortCut->rNumericArgs(10);
2403 1 : if (thisChiller.CondVolFlowRate == DataSizing::AutoSize) {
2404 0 : if (thisChiller.CondenserType == DataPlant::CondenserType::WaterCooled) {
2405 0 : thisChiller.CondVolFlowRateWasAutoSized = true;
2406 : }
2407 : }
2408 1 : thisChiller.CapRatCoef(1) = state.dataIPShortCut->rNumericArgs(11);
2409 1 : thisChiller.CapRatCoef(2) = state.dataIPShortCut->rNumericArgs(12);
2410 1 : thisChiller.CapRatCoef(3) = state.dataIPShortCut->rNumericArgs(13);
2411 1 : if ((state.dataIPShortCut->rNumericArgs(11) + state.dataIPShortCut->rNumericArgs(12) + state.dataIPShortCut->rNumericArgs(13)) == 0.0) {
2412 0 : ShowSevereError(state,
2413 0 : format("{}: Sum of Capacity Ratio Coef = 0.0, chiller={}",
2414 0 : state.dataIPShortCut->cCurrentModuleObject,
2415 0 : state.dataIPShortCut->cAlphaArgs(1)));
2416 0 : ErrorsFound = true;
2417 : }
2418 1 : thisChiller.PowerRatCoef(1) = state.dataIPShortCut->rNumericArgs(14);
2419 1 : thisChiller.PowerRatCoef(2) = state.dataIPShortCut->rNumericArgs(15);
2420 1 : thisChiller.PowerRatCoef(3) = state.dataIPShortCut->rNumericArgs(16);
2421 1 : thisChiller.FullLoadCoef(1) = state.dataIPShortCut->rNumericArgs(17);
2422 1 : thisChiller.FullLoadCoef(2) = state.dataIPShortCut->rNumericArgs(18);
2423 1 : thisChiller.FullLoadCoef(3) = state.dataIPShortCut->rNumericArgs(19);
2424 1 : thisChiller.TempLowLimitEvapOut = state.dataIPShortCut->rNumericArgs(20);
2425 :
2426 : // Load Special EngineDriven Chiller Curve Fit Inputs
2427 1 : thisChiller.ClngLoadtoFuelCurve = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(7)); // convert curve name to number
2428 1 : if (thisChiller.ClngLoadtoFuelCurve == 0) {
2429 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
2430 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2431 0 : ErrorsFound = true;
2432 : }
2433 :
2434 1 : thisChiller.RecJacHeattoFuelCurve = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(8)); // convert curve name to number
2435 1 : if (thisChiller.RecJacHeattoFuelCurve == 0) {
2436 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
2437 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2438 0 : ErrorsFound = true;
2439 : }
2440 :
2441 1 : thisChiller.RecLubeHeattoFuelCurve = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(9)); // convert curve name to number
2442 1 : if (thisChiller.RecLubeHeattoFuelCurve == 0) {
2443 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
2444 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2445 0 : ErrorsFound = true;
2446 : }
2447 :
2448 1 : thisChiller.TotExhausttoFuelCurve = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(10)); // convert curve name to number
2449 1 : if (thisChiller.TotExhausttoFuelCurve == 0) {
2450 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10)));
2451 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2452 0 : ErrorsFound = true;
2453 : }
2454 :
2455 1 : thisChiller.ExhaustTempCurve = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(11)); // convert curve name to number
2456 1 : if (thisChiller.ExhaustTempCurve == 0) {
2457 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11)));
2458 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2459 0 : ErrorsFound = true;
2460 : }
2461 :
2462 1 : thisChiller.UACoef(1) = state.dataIPShortCut->rNumericArgs(21);
2463 1 : thisChiller.UACoef(2) = state.dataIPShortCut->rNumericArgs(22);
2464 :
2465 1 : thisChiller.MaxExhaustperPowerOutput = state.dataIPShortCut->rNumericArgs(23);
2466 1 : thisChiller.DesignMinExitGasTemp = state.dataIPShortCut->rNumericArgs(24);
2467 :
2468 : // Validate fuel type input
2469 1 : thisChiller.FuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(12)));
2470 :
2471 1 : thisChiller.FuelHeatingValue = state.dataIPShortCut->rNumericArgs(25);
2472 :
2473 : // add support of autosize to this.
2474 :
2475 1 : thisChiller.DesignHeatRecVolFlowRate = state.dataIPShortCut->rNumericArgs(26);
2476 1 : if (thisChiller.DesignHeatRecVolFlowRate > 0.0 || thisChiller.DesignHeatRecVolFlowRate == DataSizing::AutoSize) {
2477 0 : thisChiller.HeatRecActive = true;
2478 0 : thisChiller.HeatRecInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2479 0 : state.dataIPShortCut->cAlphaArgs(13),
2480 : ErrorsFound,
2481 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2482 0 : state.dataIPShortCut->cAlphaArgs(1),
2483 : DataLoopNode::NodeFluidType::Water,
2484 : DataLoopNode::ConnectionType::Inlet,
2485 : NodeInputManager::CompFluidStream::Tertiary,
2486 : DataLoopNode::ObjectIsNotParent);
2487 0 : if (thisChiller.HeatRecInletNodeNum == 0) {
2488 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(13), state.dataIPShortCut->cAlphaArgs(13)));
2489 0 : ShowContinueError(state,
2490 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2491 0 : ErrorsFound = true;
2492 : }
2493 0 : thisChiller.HeatRecOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
2494 0 : state.dataIPShortCut->cAlphaArgs(14),
2495 : ErrorsFound,
2496 : DataLoopNode::ConnectionObjectType::ChillerEngineDriven,
2497 0 : state.dataIPShortCut->cAlphaArgs(1),
2498 : DataLoopNode::NodeFluidType::Water,
2499 : DataLoopNode::ConnectionType::Outlet,
2500 : NodeInputManager::CompFluidStream::Tertiary,
2501 : DataLoopNode::ObjectIsNotParent);
2502 0 : if (thisChiller.HeatRecOutletNodeNum == 0) {
2503 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(14), state.dataIPShortCut->cAlphaArgs(14)));
2504 0 : ShowContinueError(state,
2505 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2506 0 : ErrorsFound = true;
2507 : }
2508 0 : BranchNodeConnections::TestCompSet(state,
2509 0 : state.dataIPShortCut->cCurrentModuleObject,
2510 0 : state.dataIPShortCut->cAlphaArgs(1),
2511 0 : state.dataIPShortCut->cAlphaArgs(13),
2512 0 : state.dataIPShortCut->cAlphaArgs(14),
2513 : "Heat Recovery Nodes");
2514 0 : if (thisChiller.DesignHeatRecVolFlowRate == DataSizing::AutoSize) {
2515 0 : thisChiller.DesignHeatRecVolFlowRateWasAutoSized = true;
2516 : } else {
2517 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, thisChiller.HeatRecInletNodeNum, thisChiller.DesignHeatRecVolFlowRate);
2518 : }
2519 :
2520 : // Condenser flow rate must be specified for heat reclaim
2521 0 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
2522 0 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
2523 0 : if (thisChiller.CondVolFlowRate <= 0.0) {
2524 0 : ShowSevereError(
2525 0 : state, format("Invalid {}={:.6R}", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->rNumericArgs(10)));
2526 0 : ShowContinueError(state, "Condenser fluid flow rate must be specified for Heat Reclaim applications.");
2527 0 : ShowContinueError(
2528 0 : state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2529 0 : ErrorsFound = true;
2530 : }
2531 : }
2532 :
2533 : } else {
2534 :
2535 1 : thisChiller.HeatRecActive = false;
2536 1 : thisChiller.DesignHeatRecMassFlowRate = 0.0;
2537 1 : thisChiller.HeatRecInletNodeNum = 0;
2538 1 : thisChiller.HeatRecOutletNodeNum = 0;
2539 : // if heat recovery is not used, don't care about condenser flow rate for air/evap-cooled equip.
2540 1 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
2541 1 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
2542 0 : thisChiller.CondVolFlowRate = 0.0011; // set to avoid errors in calc routine
2543 : }
2544 1 : if ((!state.dataIPShortCut->lAlphaFieldBlanks(13)) || (!state.dataIPShortCut->lAlphaFieldBlanks(14))) {
2545 0 : ShowWarningError(state,
2546 0 : format("Since Design Heat Flow Rate = 0.0, Heat Recovery inactive for {}={}",
2547 0 : state.dataIPShortCut->cCurrentModuleObject,
2548 0 : state.dataIPShortCut->cAlphaArgs(1)));
2549 0 : ShowContinueError(state, "However, Node names were specified for Heat Recovery inlet or outlet nodes");
2550 : }
2551 : }
2552 :
2553 1 : thisChiller.FlowMode = static_cast<DataPlant::FlowMode>(getEnumValue(DataPlant::FlowModeNamesUC, state.dataIPShortCut->cAlphaArgs(15)));
2554 1 : if (thisChiller.FlowMode == DataPlant::FlowMode::Invalid) {
2555 0 : ShowSevereError(state,
2556 0 : format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
2557 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(15), state.dataIPShortCut->cAlphaArgs(15)));
2558 0 : ShowContinueError(state, "Available choices are ConstantFlow, NotModulated, or LeavingSetpointModulated");
2559 0 : ShowContinueError(state, "Flow mode NotModulated is assumed and the simulation continues.");
2560 0 : thisChiller.FlowMode = DataPlant::FlowMode::NotModulated;
2561 : }
2562 :
2563 1 : thisChiller.HeatRecMaxTemp = state.dataIPShortCut->rNumericArgs(27);
2564 1 : thisChiller.SizFac = state.dataIPShortCut->rNumericArgs(28);
2565 1 : if (thisChiller.SizFac <= 0.0) thisChiller.SizFac = 1.0;
2566 :
2567 : // Basin heater power as a function of temperature must be greater than or equal to 0
2568 1 : thisChiller.BasinHeaterPowerFTempDiff = state.dataIPShortCut->rNumericArgs(29);
2569 1 : if (state.dataIPShortCut->rNumericArgs(29) < 0.0) {
2570 0 : ShowSevereError(state,
2571 0 : format("{}, \"{}\" TRIM(state.dataIPShortCut->cNumericFieldNames(29)) must be >= 0",
2572 0 : state.dataIPShortCut->cCurrentModuleObject,
2573 0 : thisChiller.Name));
2574 0 : ErrorsFound = true;
2575 : }
2576 :
2577 1 : thisChiller.BasinHeaterSetPointTemp = state.dataIPShortCut->rNumericArgs(30);
2578 :
2579 1 : if (thisChiller.BasinHeaterPowerFTempDiff > 0.0) {
2580 0 : if (NumNums < 30) {
2581 0 : thisChiller.BasinHeaterSetPointTemp = 2.0;
2582 : }
2583 0 : if (thisChiller.BasinHeaterSetPointTemp < 2.0) {
2584 0 : ShowWarningError(state,
2585 0 : format("{}:\"{}\", {} is less than 2 deg C. Freezing could occur.",
2586 0 : state.dataIPShortCut->cCurrentModuleObject,
2587 0 : thisChiller.Name,
2588 0 : state.dataIPShortCut->cNumericFieldNames(30)));
2589 : }
2590 : }
2591 :
2592 1 : if (state.dataIPShortCut->lAlphaFieldBlanks(16)) {
2593 0 : } else if ((thisChiller.basinHeaterSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(16))) == nullptr) {
2594 0 : ShowWarningItemNotFound(state,
2595 : eoh,
2596 0 : state.dataIPShortCut->cAlphaFieldNames(16),
2597 0 : state.dataIPShortCut->cAlphaArgs(16),
2598 : "Basin heater operation will not be modeled and the simulation continues");
2599 : }
2600 :
2601 1 : if (NumNums > 30) {
2602 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(31)) {
2603 0 : thisChiller.HeatRecCapacityFraction = state.dataIPShortCut->rNumericArgs(31);
2604 : } else {
2605 0 : thisChiller.HeatRecCapacityFraction = 1.0;
2606 : }
2607 : } else {
2608 1 : thisChiller.HeatRecCapacityFraction = 1.0;
2609 : }
2610 : }
2611 :
2612 1 : if (ErrorsFound) {
2613 0 : ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
2614 : }
2615 : }
2616 :
2617 0 : void EngineDrivenChillerSpecs::setupOutputVariables(EnergyPlusData &state)
2618 : {
2619 0 : SetupOutputVariable(state,
2620 : "Chiller Drive Shaft Power",
2621 : Constant::Units::W,
2622 0 : this->Power,
2623 : OutputProcessor::TimeStepType::System,
2624 : OutputProcessor::StoreType::Average,
2625 0 : this->Name);
2626 0 : SetupOutputVariable(state,
2627 : "Chiller Drive Shaft Energy",
2628 : Constant::Units::J,
2629 0 : this->Energy,
2630 : OutputProcessor::TimeStepType::System,
2631 : OutputProcessor::StoreType::Sum,
2632 0 : this->Name);
2633 0 : SetupOutputVariable(state,
2634 : "Chiller Evaporator Cooling Rate",
2635 : Constant::Units::W,
2636 0 : this->QEvaporator,
2637 : OutputProcessor::TimeStepType::System,
2638 : OutputProcessor::StoreType::Average,
2639 0 : this->Name);
2640 0 : SetupOutputVariable(state,
2641 : "Chiller Evaporator Cooling Energy",
2642 : Constant::Units::J,
2643 0 : this->EvaporatorEnergy,
2644 : OutputProcessor::TimeStepType::System,
2645 : OutputProcessor::StoreType::Sum,
2646 0 : this->Name,
2647 : Constant::eResource::EnergyTransfer,
2648 : OutputProcessor::Group::Plant,
2649 : OutputProcessor::EndUseCat::Chillers);
2650 0 : SetupOutputVariable(state,
2651 : "Chiller Evaporator Inlet Temperature",
2652 : Constant::Units::C,
2653 0 : this->EvapInletTemp,
2654 : OutputProcessor::TimeStepType::System,
2655 : OutputProcessor::StoreType::Average,
2656 0 : this->Name);
2657 0 : SetupOutputVariable(state,
2658 : "Chiller Evaporator Outlet Temperature",
2659 : Constant::Units::C,
2660 0 : this->EvapOutletTemp,
2661 : OutputProcessor::TimeStepType::System,
2662 : OutputProcessor::StoreType::Average,
2663 0 : this->Name);
2664 0 : SetupOutputVariable(state,
2665 : "Chiller Evaporator Mass Flow Rate",
2666 : Constant::Units::kg_s,
2667 0 : this->EvapMassFlowRate,
2668 : OutputProcessor::TimeStepType::System,
2669 : OutputProcessor::StoreType::Average,
2670 0 : this->Name);
2671 0 : SetupOutputVariable(state,
2672 : "Chiller Condenser Heat Transfer Rate",
2673 : Constant::Units::W,
2674 0 : this->QCondenser,
2675 : OutputProcessor::TimeStepType::System,
2676 : OutputProcessor::StoreType::Average,
2677 0 : this->Name);
2678 0 : SetupOutputVariable(state,
2679 : "Chiller Condenser Heat Transfer Energy",
2680 : Constant::Units::J,
2681 0 : this->CondenserEnergy,
2682 : OutputProcessor::TimeStepType::System,
2683 : OutputProcessor::StoreType::Sum,
2684 0 : this->Name,
2685 : Constant::eResource::EnergyTransfer,
2686 : OutputProcessor::Group::Plant,
2687 : OutputProcessor::EndUseCat::HeatRejection);
2688 :
2689 0 : SetupOutputVariable(state,
2690 : "Chiller Condenser Inlet Temperature",
2691 : Constant::Units::C,
2692 0 : this->CondInletTemp,
2693 : OutputProcessor::TimeStepType::System,
2694 : OutputProcessor::StoreType::Average,
2695 0 : this->Name);
2696 :
2697 : // Condenser mass flow and outlet temp are valid for Water Cooled
2698 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
2699 0 : SetupOutputVariable(state,
2700 : "Chiller Condenser Outlet Temperature",
2701 : Constant::Units::C,
2702 0 : this->CondOutletTemp,
2703 : OutputProcessor::TimeStepType::System,
2704 : OutputProcessor::StoreType::Average,
2705 0 : this->Name);
2706 0 : SetupOutputVariable(state,
2707 : "Chiller Condenser Mass Flow Rate",
2708 : Constant::Units::kg_s,
2709 0 : this->CondMassFlowRate,
2710 : OutputProcessor::TimeStepType::System,
2711 : OutputProcessor::StoreType::Average,
2712 0 : this->Name);
2713 0 : } else if (this->CondenserType == DataPlant::CondenserType::AirCooled) {
2714 0 : } else if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
2715 0 : if (this->BasinHeaterPowerFTempDiff > 0.0) {
2716 0 : SetupOutputVariable(state,
2717 : "Chiller Basin Heater Electricity Rate",
2718 : Constant::Units::W,
2719 0 : this->BasinHeaterPower,
2720 : OutputProcessor::TimeStepType::System,
2721 : OutputProcessor::StoreType::Average,
2722 0 : this->Name);
2723 0 : SetupOutputVariable(state,
2724 : "Chiller Basin Heater Electricity Energy",
2725 : Constant::Units::J,
2726 0 : this->BasinHeaterConsumption,
2727 : OutputProcessor::TimeStepType::System,
2728 : OutputProcessor::StoreType::Sum,
2729 0 : this->Name,
2730 : Constant::eResource::Electricity,
2731 : OutputProcessor::Group::Plant,
2732 : OutputProcessor::EndUseCat::Chillers);
2733 : }
2734 : }
2735 :
2736 0 : std::string_view const sFuelType = Constant::eFuelNames[static_cast<int>(this->FuelType)];
2737 0 : SetupOutputVariable(state,
2738 0 : format("Chiller {} Rate", sFuelType),
2739 : Constant::Units::W,
2740 0 : this->FuelEnergyUseRate,
2741 : OutputProcessor::TimeStepType::System,
2742 : OutputProcessor::StoreType::Average,
2743 0 : this->Name);
2744 0 : SetupOutputVariable(state,
2745 0 : format("Chiller {} Energy", sFuelType),
2746 : Constant::Units::J,
2747 0 : this->FuelEnergy,
2748 : OutputProcessor::TimeStepType::System,
2749 : OutputProcessor::StoreType::Sum,
2750 0 : this->Name,
2751 0 : Constant::eFuel2eResource[(int)this->FuelType],
2752 : OutputProcessor::Group::Plant,
2753 : OutputProcessor::EndUseCat::Cooling);
2754 :
2755 0 : SetupOutputVariable(state,
2756 : "Chiller COP",
2757 : Constant::Units::W_W,
2758 0 : this->FuelCOP,
2759 : OutputProcessor::TimeStepType::System,
2760 : OutputProcessor::StoreType::Average,
2761 0 : this->Name);
2762 0 : SetupOutputVariable(state,
2763 0 : format("Chiller {} Mass Flow Rate", sFuelType),
2764 : Constant::Units::kg_s,
2765 0 : this->FuelMdot,
2766 : OutputProcessor::TimeStepType::System,
2767 : OutputProcessor::StoreType::Average,
2768 0 : this->Name);
2769 0 : SetupOutputVariable(state,
2770 : "Chiller Exhaust Temperature",
2771 : Constant::Units::C,
2772 0 : this->ExhaustStackTemp,
2773 : OutputProcessor::TimeStepType::System,
2774 : OutputProcessor::StoreType::Average,
2775 0 : this->Name);
2776 0 : SetupOutputVariable(state,
2777 : "Chiller Heat Recovery Mass Flow Rate",
2778 : Constant::Units::kg_s,
2779 0 : this->HeatRecMdot,
2780 : OutputProcessor::TimeStepType::System,
2781 : OutputProcessor::StoreType::Average,
2782 0 : this->Name);
2783 :
2784 0 : if (this->HeatRecActive) {
2785 : // need to only report if heat recovery active
2786 0 : SetupOutputVariable(state,
2787 : "Chiller Jacket Recovered Heat Rate",
2788 : Constant::Units::W,
2789 0 : this->QJacketRecovered,
2790 : OutputProcessor::TimeStepType::System,
2791 : OutputProcessor::StoreType::Average,
2792 0 : this->Name);
2793 0 : SetupOutputVariable(state,
2794 : "Chiller Jacket Recovered Heat Energy",
2795 : Constant::Units::J,
2796 0 : this->JacketEnergyRec,
2797 : OutputProcessor::TimeStepType::System,
2798 : OutputProcessor::StoreType::Sum,
2799 0 : this->Name,
2800 : Constant::eResource::EnergyTransfer,
2801 : OutputProcessor::Group::Plant,
2802 : OutputProcessor::EndUseCat::HeatRecovery);
2803 :
2804 0 : SetupOutputVariable(state,
2805 : "Chiller Lube Recovered Heat Rate",
2806 : Constant::Units::W,
2807 0 : this->QLubeOilRecovered,
2808 : OutputProcessor::TimeStepType::System,
2809 : OutputProcessor::StoreType::Average,
2810 0 : this->Name);
2811 0 : SetupOutputVariable(state,
2812 : "Chiller Lube Recovered Heat Energy",
2813 : Constant::Units::J,
2814 0 : this->LubeOilEnergyRec,
2815 : OutputProcessor::TimeStepType::System,
2816 : OutputProcessor::StoreType::Sum,
2817 0 : this->Name,
2818 : Constant::eResource::EnergyTransfer,
2819 : OutputProcessor::Group::Plant,
2820 : OutputProcessor::EndUseCat::HeatRecovery);
2821 :
2822 0 : SetupOutputVariable(state,
2823 : "Chiller Exhaust Recovered Heat Rate",
2824 : Constant::Units::W,
2825 0 : this->QExhaustRecovered,
2826 : OutputProcessor::TimeStepType::System,
2827 : OutputProcessor::StoreType::Average,
2828 0 : this->Name);
2829 0 : SetupOutputVariable(state,
2830 : "Chiller Exhaust Recovered Heat Energy",
2831 : Constant::Units::J,
2832 0 : this->ExhaustEnergyRec,
2833 : OutputProcessor::TimeStepType::System,
2834 : OutputProcessor::StoreType::Sum,
2835 0 : this->Name,
2836 : Constant::eResource::EnergyTransfer,
2837 : OutputProcessor::Group::Plant,
2838 : OutputProcessor::EndUseCat::HeatRecovery);
2839 :
2840 0 : SetupOutputVariable(state,
2841 : "Chiller Total Recovered Heat Rate",
2842 : Constant::Units::W,
2843 0 : this->QTotalHeatRecovered,
2844 : OutputProcessor::TimeStepType::System,
2845 : OutputProcessor::StoreType::Average,
2846 0 : this->Name);
2847 0 : SetupOutputVariable(state,
2848 : "Chiller Total Recovered Heat Energy",
2849 : Constant::Units::J,
2850 0 : this->TotalHeatEnergyRec,
2851 : OutputProcessor::TimeStepType::System,
2852 : OutputProcessor::StoreType::Sum,
2853 0 : this->Name);
2854 0 : SetupOutputVariable(state,
2855 : "Chiller Heat Recovery Inlet Temperature",
2856 : Constant::Units::C,
2857 0 : this->HeatRecInletTemp,
2858 : OutputProcessor::TimeStepType::System,
2859 : OutputProcessor::StoreType::Average,
2860 0 : this->Name);
2861 0 : SetupOutputVariable(state,
2862 : "Chiller Heat Recovery Outlet Temperature",
2863 : Constant::Units::C,
2864 0 : this->HeatRecOutletTemp,
2865 : OutputProcessor::TimeStepType::System,
2866 : OutputProcessor::StoreType::Average,
2867 0 : this->Name);
2868 : }
2869 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
2870 0 : SetupEMSInternalVariable(state, "Chiller Nominal Capacity", this->Name, "[W]", this->NomCap);
2871 : }
2872 0 : }
2873 :
2874 0 : void EngineDrivenChillerSpecs::initialize(EnergyPlusData &state, bool const RunFlag, Real64 const MyLoad)
2875 : {
2876 :
2877 : // SUBROUTINE INFORMATION:
2878 : // AUTHOR Fred Buhl
2879 : // DATE WRITTEN June 2002
2880 : // MODIFIED na
2881 : // RE-ENGINEERED na
2882 :
2883 : // PURPOSE OF THIS SUBROUTINE:
2884 : // This subroutine is for initializations of the Engine Driven Chiller components
2885 :
2886 : // METHODOLOGY EMPLOYED:
2887 : // Uses the status flags to trigger initializations.
2888 :
2889 : // SUBROUTINE PARAMETER DEFINITIONS:
2890 : static constexpr std::string_view RoutineName("InitEngineDrivenChiller");
2891 :
2892 0 : this->oneTimeInit(state);
2893 :
2894 : // Initialize critical Demand Side Variables
2895 0 : if (this->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
2896 :
2897 0 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
2898 :
2899 0 : this->EvapMassFlowRateMax = rho * this->EvapVolFlowRate;
2900 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->EvapMassFlowRateMax, this->EvapInletNodeNum, this->EvapOutletNodeNum);
2901 :
2902 : // init maximum available condenser flow rate
2903 :
2904 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
2905 :
2906 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = this->TempDesCondIn;
2907 :
2908 0 : rho = this->CDPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
2909 :
2910 0 : this->CondMassFlowRateMax = rho * this->CondVolFlowRate;
2911 :
2912 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->CondMassFlowRateMax, this->CondInletNodeNum, this->CondOutletNodeNum);
2913 : } else { // air or evap-air
2914 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate =
2915 0 : this->CondVolFlowRate *
2916 0 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, this->TempDesCondIn, 0.0, RoutineName);
2917 :
2918 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
2919 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMaxAvail =
2920 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
2921 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
2922 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
2923 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMinAvail = 0.0;
2924 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMin = 0.0;
2925 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMinAvail = 0.0;
2926 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMin = 0.0;
2927 : }
2928 :
2929 0 : if (this->HeatRecActive) {
2930 0 : rho = this->HRPlantLoc.loop->glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
2931 0 : this->DesignHeatRecMassFlowRate = rho * this->DesignHeatRecVolFlowRate;
2932 :
2933 0 : PlantUtilities::InitComponentNodes(
2934 : state, 0.0, this->DesignHeatRecMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
2935 : }
2936 :
2937 0 : this->MyEnvrnFlag = false;
2938 : }
2939 :
2940 0 : if (!state.dataGlobal->BeginEnvrnFlag) {
2941 0 : this->MyEnvrnFlag = true;
2942 : }
2943 :
2944 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) && (this->ModulatedFlowSetToLoop)) {
2945 : // fix for clumsy old input that worked because loop setpoint was spread.
2946 : // could be removed with transition, testing , model change, period of being obsolete.
2947 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
2948 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
2949 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
2950 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
2951 : }
2952 :
2953 : Real64 mdot;
2954 : Real64 mdotCond;
2955 0 : if ((std::abs(MyLoad) > 0.0) && RunFlag) {
2956 0 : mdot = this->EvapMassFlowRateMax;
2957 0 : mdotCond = this->CondMassFlowRateMax;
2958 : } else {
2959 0 : mdot = 0.0;
2960 0 : mdotCond = 0.0;
2961 : }
2962 :
2963 0 : PlantUtilities::SetComponentFlowRate(state, mdot, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
2964 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
2965 0 : PlantUtilities::SetComponentFlowRate(state, mdotCond, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
2966 : }
2967 :
2968 : // Initialize heat recovery flow rates at node
2969 0 : if (this->HeatRecActive) {
2970 :
2971 0 : if (RunFlag) {
2972 0 : mdot = this->DesignHeatRecMassFlowRate;
2973 : } else {
2974 0 : mdot = 0.0;
2975 : }
2976 :
2977 0 : PlantUtilities::SetComponentFlowRate(state, mdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
2978 : }
2979 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
2980 0 : this->BasinHeaterPower = 0.0;
2981 : }
2982 0 : }
2983 :
2984 1 : void EngineDrivenChillerSpecs::size(EnergyPlusData &state)
2985 : {
2986 :
2987 : // SUBROUTINE INFORMATION:
2988 : // AUTHOR Fred Buhl
2989 : // DATE WRITTEN June 2002
2990 : // MODIFIED November 2013 Daeho Kang, add component sizing table entries
2991 : // RE-ENGINEERED na
2992 :
2993 : // PURPOSE OF THIS SUBROUTINE:
2994 : // This subroutine is for sizing Engine Driven Chiller Components for which capacities and flow rates
2995 : // have not been specified in the input.
2996 :
2997 : // METHODOLOGY EMPLOYED:
2998 : // Obtains evaporator flow rate from the plant sizing array. Calculates nominal capacity from
2999 : // the evaporator flow rate and the chilled water loop design delta T. The condenser flow rate
3000 : // is calculated from the nominal capacity, the COP, and the condenser loop design delta T.
3001 :
3002 : // SUBROUTINE PARAMETER DEFINITIONS:
3003 : static constexpr std::string_view RoutineName("SizeEngineDrivenChiller");
3004 :
3005 1 : int PltSizCondNum = 0;
3006 1 : bool ErrorsFound = false;
3007 1 : Real64 tmpNomCap = this->NomCap;
3008 1 : Real64 tmpEvapVolFlowRate = this->EvapVolFlowRate;
3009 1 : Real64 tmpCondVolFlowRate = this->CondVolFlowRate;
3010 :
3011 1 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
3012 1 : PltSizCondNum = this->CDPlantLoc.loop->PlantSizNum;
3013 : }
3014 :
3015 1 : int PltSizNum = this->CWPlantLoc.loop->PlantSizNum;
3016 :
3017 1 : if (PltSizNum > 0) {
3018 1 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
3019 1 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
3020 1 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
3021 1 : tmpNomCap =
3022 1 : Cp * rho * state.dataSize->PlantSizData(PltSizNum).DeltaT * state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
3023 : } else {
3024 0 : if (this->NomCapWasAutoSized) tmpNomCap = 0.0;
3025 : }
3026 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3027 1 : if (this->NomCapWasAutoSized) {
3028 0 : this->NomCap = tmpNomCap;
3029 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3030 0 : BaseSizer::reportSizerOutput(state, "Chiller:EngineDriven", this->Name, "Design Size Nominal Capacity [W]", tmpNomCap);
3031 : }
3032 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3033 0 : BaseSizer::reportSizerOutput(
3034 : state, "Chiller:EngineDriven", this->Name, "Initial Design Size Nominal Capacity [W]", tmpNomCap);
3035 : }
3036 : } else {
3037 1 : if (this->NomCap > 0.0 && tmpNomCap > 0.0) {
3038 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3039 0 : BaseSizer::reportSizerOutput(state,
3040 : "Chiller:EngineDriven",
3041 : this->Name,
3042 : "Design Size Nominal Capacity [W]",
3043 : tmpNomCap,
3044 : "User-Specified Nominal Capacity [W]",
3045 0 : this->NomCap);
3046 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3047 0 : if ((std::abs(tmpNomCap - this->NomCap) / this->NomCap) > state.dataSize->AutoVsHardSizingThreshold) {
3048 0 : ShowMessage(state, format("SizeChillerEngineDriven: Potential issue with equipment sizing for {}", this->Name));
3049 0 : ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", this->NomCap));
3050 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", tmpNomCap));
3051 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3052 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3053 : }
3054 : }
3055 : }
3056 1 : tmpNomCap = this->NomCap;
3057 : }
3058 : }
3059 : }
3060 : } else {
3061 0 : if (this->NomCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3062 0 : ShowSevereError(state, "Autosizing of Engine Driven Chiller nominal capacity requires a loop Sizing:Plant object");
3063 0 : ShowContinueError(state, format("Occurs in Engine Driven Chiller object={}", this->Name));
3064 0 : ErrorsFound = true;
3065 : }
3066 0 : if (!this->NomCapWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->NomCap > 0.0)) {
3067 0 : BaseSizer::reportSizerOutput(state, "Chiller:EngineDriven", this->Name, "User-Specified Nominal Capacity [W]", this->NomCap);
3068 : }
3069 : }
3070 :
3071 1 : if (PltSizNum > 0) {
3072 1 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
3073 1 : tmpEvapVolFlowRate = state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
3074 : } else {
3075 0 : if (this->EvapVolFlowRateWasAutoSized) tmpEvapVolFlowRate = 0.0;
3076 : }
3077 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3078 1 : if (this->EvapVolFlowRateWasAutoSized) {
3079 0 : this->EvapVolFlowRate = tmpEvapVolFlowRate;
3080 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3081 0 : BaseSizer::reportSizerOutput(
3082 : state, "Chiller:EngineDriven", this->Name, "Design Chilled Water Flow Rate [m3/s]", tmpEvapVolFlowRate);
3083 : }
3084 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3085 0 : BaseSizer::reportSizerOutput(
3086 : state, "Chiller:EngineDriven", this->Name, "Initial Design Chilled Water Flow Rate [m3/s]", tmpEvapVolFlowRate);
3087 : }
3088 : } else {
3089 1 : if (this->EvapVolFlowRate > 0.0 && tmpEvapVolFlowRate > 0.0) {
3090 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3091 0 : BaseSizer::reportSizerOutput(state,
3092 : "Chiller:EngineDriven",
3093 : this->Name,
3094 : "Design Size Design Chilled Water Flow Rate [m3/s]",
3095 : tmpEvapVolFlowRate,
3096 : "User-Specified Design Chilled Water Flow Rate [m3/s]",
3097 0 : this->EvapVolFlowRate);
3098 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3099 0 : if ((std::abs(tmpEvapVolFlowRate - this->EvapVolFlowRate) / this->EvapVolFlowRate) >
3100 0 : state.dataSize->AutoVsHardSizingThreshold) {
3101 0 : ShowMessage(state, format("SizeChillerEngineDriven: Potential issue with equipment sizing for {}", this->Name));
3102 0 : ShowContinueError(
3103 0 : state, format("User-Specified Design Chilled Water Flow Rate of {:.5R} [m3/s]", this->EvapVolFlowRate));
3104 0 : ShowContinueError(
3105 : state,
3106 0 : format("differs from Design Size Design Chilled Water Flow Rate of {:.5R} [m3/s]", tmpEvapVolFlowRate));
3107 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3108 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3109 : }
3110 : }
3111 : }
3112 1 : tmpEvapVolFlowRate = this->EvapVolFlowRate;
3113 : }
3114 : }
3115 : }
3116 : } else {
3117 0 : if (this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3118 0 : ShowSevereError(state, "Autosizing of Engine Driven Chiller evap flow rate requires a loop Sizing:Plant object");
3119 0 : ShowContinueError(state, format("Occurs in Engine Driven Chiller object={}", this->Name));
3120 0 : ErrorsFound = true;
3121 : }
3122 0 : if (!this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->EvapVolFlowRate > 0.0)) {
3123 0 : BaseSizer::reportSizerOutput(
3124 : state, "Chiller:EngineDriven", this->Name, "User-Specified Design Chilled Water Flow Rate [m3/s]", this->EvapVolFlowRate);
3125 : }
3126 : }
3127 :
3128 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->EvapInletNodeNum, tmpEvapVolFlowRate);
3129 :
3130 1 : if (PltSizCondNum > 0 && PltSizNum > 0) {
3131 0 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow && tmpNomCap > 0.0) {
3132 0 : Real64 rho = this->CDPlantLoc.loop->glycol->getDensity(state, this->TempDesCondIn, RoutineName);
3133 :
3134 0 : Real64 Cp = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, this->TempDesCondIn, RoutineName);
3135 0 : tmpCondVolFlowRate = tmpNomCap * (1.0 + 1.0 / this->COP) / (state.dataSize->PlantSizData(PltSizCondNum).DeltaT * Cp * rho);
3136 : } else {
3137 0 : if (this->CondVolFlowRateWasAutoSized) tmpCondVolFlowRate = 0.0;
3138 : }
3139 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3140 0 : if (this->CondVolFlowRateWasAutoSized) {
3141 0 : this->CondVolFlowRate = tmpCondVolFlowRate;
3142 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3143 0 : BaseSizer::reportSizerOutput(
3144 : state, "Chiller:EngineDriven", this->Name, "Design Size Design Condenser Water Flow Rate [m3/s]", tmpCondVolFlowRate);
3145 : }
3146 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3147 0 : BaseSizer::reportSizerOutput(state,
3148 : "Chiller:EngineDriven",
3149 : this->Name,
3150 : "Initial Design Size Design Condenser Water Flow Rate [m3/s]",
3151 : tmpCondVolFlowRate);
3152 : }
3153 : } else {
3154 0 : if (this->CondVolFlowRate > 0.0 && tmpCondVolFlowRate > 0.0) {
3155 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3156 0 : BaseSizer::reportSizerOutput(state,
3157 : "Chiller:EngineDriven",
3158 : this->Name,
3159 : "Design Size Design Condenser Water Flow Rate [m3/s]",
3160 : tmpCondVolFlowRate,
3161 : "User-Specified Design Condenser Water Flow Rate [m3/s]",
3162 0 : this->CondVolFlowRate);
3163 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3164 0 : if ((std::abs(tmpCondVolFlowRate - this->CondVolFlowRate) / this->CondVolFlowRate) >
3165 0 : state.dataSize->AutoVsHardSizingThreshold) {
3166 0 : ShowMessage(state, format("SizeChillerEngineDriven: Potential issue with equipment sizing for {}", this->Name));
3167 0 : ShowContinueError(
3168 0 : state, format("User-Specified Design Condenser Water Flow Rate of {:.5R} [m3/s]", this->CondVolFlowRate));
3169 0 : ShowContinueError(
3170 : state,
3171 0 : format("differs from Design Size Design Condenser Water Flow Rate of {:.5R} [m3/s]", tmpCondVolFlowRate));
3172 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3173 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3174 : }
3175 : }
3176 : }
3177 0 : tmpCondVolFlowRate = this->CondVolFlowRate;
3178 : }
3179 : }
3180 : }
3181 0 : } else {
3182 1 : if (this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3183 0 : ShowSevereError(state, "Autosizing of EngineDriven Chiller condenser flow rate requires a condenser");
3184 0 : ShowContinueError(state, "loop Sizing:Plant object");
3185 0 : ShowContinueError(state, format("Occurs in EngineDriven Chiller object={}", this->Name));
3186 0 : ErrorsFound = true;
3187 : }
3188 1 : if (!this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->CondVolFlowRate > 0.0)) {
3189 0 : BaseSizer::reportSizerOutput(
3190 : state, "Chiller:EngineDriven", this->Name, "User-Specified Design Condenser Water Flow Rate [m3/s]", this->CondVolFlowRate);
3191 : }
3192 : }
3193 :
3194 : // save the design condenser water volumetric flow rate for use by the condenser water loop sizing algorithms
3195 1 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
3196 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->CondInletNodeNum, tmpCondVolFlowRate);
3197 : }
3198 :
3199 : // autosize support for heat recovery flow rate.
3200 1 : if (this->HeatRecActive) {
3201 1 : Real64 tmpHeatRecVolFlowRate = tmpCondVolFlowRate * this->HeatRecCapacityFraction;
3202 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3203 1 : if (this->DesignHeatRecVolFlowRateWasAutoSized) {
3204 1 : this->DesignHeatRecVolFlowRate = tmpHeatRecVolFlowRate;
3205 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3206 0 : BaseSizer::reportSizerOutput(state,
3207 : "Chiller:EngineDriven",
3208 : this->Name,
3209 : "Design Size Design Heat Recovery Fluid Flow Rate [m3/s]",
3210 : tmpHeatRecVolFlowRate);
3211 : }
3212 1 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3213 0 : BaseSizer::reportSizerOutput(state,
3214 : "Chiller:EngineDriven",
3215 : this->Name,
3216 : "Initial Design Size Design Heat Recovery Fluid Flow Rate [m3/s]",
3217 : tmpHeatRecVolFlowRate);
3218 : }
3219 : } else {
3220 0 : if (this->DesignHeatRecVolFlowRate > 0.0 && tmpHeatRecVolFlowRate > 0.0) {
3221 0 : Real64 DesignHeatRecVolFlowRateUser = this->DesignHeatRecVolFlowRate;
3222 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3223 0 : if (state.dataGlobal->DoPlantSizing) {
3224 0 : BaseSizer::reportSizerOutput(state,
3225 : "Chiller:EngineDriven",
3226 : this->Name,
3227 : "Design Size Design Heat Recovery Fluid Flow Rate [m3/s]",
3228 : tmpHeatRecVolFlowRate,
3229 : "User-Specified Design Heat Recovery Fluid Flow Rate [m3/s]",
3230 : DesignHeatRecVolFlowRateUser);
3231 : } else {
3232 0 : BaseSizer::reportSizerOutput(state,
3233 : "Chiller:EngineDriven",
3234 : this->Name,
3235 : "User-Specified Design Heat Recovery Fluid Flow Rate [m3/s]",
3236 : DesignHeatRecVolFlowRateUser);
3237 : }
3238 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3239 0 : if ((std::abs(tmpHeatRecVolFlowRate - DesignHeatRecVolFlowRateUser) / DesignHeatRecVolFlowRateUser) >
3240 0 : state.dataSize->AutoVsHardSizingThreshold) {
3241 0 : ShowMessage(state, format("SizeEngineDrivenChiller: Potential issue with equipment sizing for {}", this->Name));
3242 0 : ShowContinueError(
3243 : state,
3244 0 : format("User-Specified Design Heat Recovery Fluid Flow Rate of {:.5R} [m3/s]", DesignHeatRecVolFlowRateUser));
3245 0 : ShowContinueError(state,
3246 0 : format("differs from Design Size Design Heat Recovery Fluid Flow Rate of {:.5R} [m3/s]",
3247 : tmpHeatRecVolFlowRate));
3248 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3249 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3250 : }
3251 : }
3252 : }
3253 0 : tmpHeatRecVolFlowRate = DesignHeatRecVolFlowRateUser;
3254 : }
3255 : }
3256 : }
3257 1 : if (!this->DesignHeatRecVolFlowRateWasAutoSized) tmpHeatRecVolFlowRate = this->DesignHeatRecVolFlowRate;
3258 : // save the reference heat recovery fluid volumetric flow rate
3259 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->HeatRecInletNodeNum, tmpHeatRecVolFlowRate);
3260 : }
3261 :
3262 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3263 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "Chiller:EngineDriven");
3264 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomEff, this->Name, this->COP);
3265 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->NomCap);
3266 :
3267 : // std 229 new Chillers table
3268 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerType, this->Name, "Chiller:EngineDriven");
3269 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefCap, this->Name, this->NomCap);
3270 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEff, this->Name, this->COP); // Eff == COP?
3271 0 : OutputReportPredefined::PreDefTableEntry(
3272 0 : state, state.dataOutRptPredefined->pdchChillerRatedCap, this->Name, this->NomCap); // did not find rated cap
3273 0 : OutputReportPredefined::PreDefTableEntry(
3274 0 : state, state.dataOutRptPredefined->pdchChillerRatedEff, this->Name, this->COP); // did not find rated eff or cop ; also Eff == COP?
3275 0 : OutputReportPredefined::PreDefTableEntry(
3276 0 : state, state.dataOutRptPredefined->pdchChillerIPLVinSI, this->Name, "N/A"); // IPLVSI_rpt_std229);
3277 0 : OutputReportPredefined::PreDefTableEntry(
3278 0 : state, state.dataOutRptPredefined->pdchChillerIPLVinIP, this->Name, "N/A"); // IPLVIP_rpt_std229);
3279 0 : OutputReportPredefined::PreDefTableEntry(state,
3280 0 : state.dataOutRptPredefined->pdchChillerPlantloopName,
3281 : this->Name,
3282 0 : (this->CWPlantLoc.loop != nullptr) ? this->CWPlantLoc.loop->Name : "N/A");
3283 0 : OutputReportPredefined::PreDefTableEntry(state,
3284 0 : state.dataOutRptPredefined->pdchChillerPlantloopBranchName,
3285 : this->Name,
3286 0 : (this->CWPlantLoc.branch != nullptr) ? this->CWPlantLoc.branch->Name : "N/A");
3287 0 : OutputReportPredefined::PreDefTableEntry(state,
3288 0 : state.dataOutRptPredefined->pdchChillerCondLoopName,
3289 : this->Name,
3290 0 : (this->CDPlantLoc.loop != nullptr) ? this->CDPlantLoc.loop->Name : "N/A");
3291 0 : OutputReportPredefined::PreDefTableEntry(state,
3292 0 : state.dataOutRptPredefined->pdchChillerCondLoopBranchName,
3293 : this->Name,
3294 0 : (this->CDPlantLoc.branch != nullptr) ? this->CDPlantLoc.branch->Name : "N/A");
3295 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerMinPLR, this->Name, this->MinPartLoadRat);
3296 0 : OutputReportPredefined::PreDefTableEntry(
3297 0 : state, state.dataOutRptPredefined->pdchChillerFuelType, this->Name, Constant::eResourceNames[static_cast<int>(this->FuelType)]);
3298 0 : OutputReportPredefined::PreDefTableEntry(
3299 0 : state, state.dataOutRptPredefined->pdchChillerRatedEntCondTemp, this->Name, this->TempDesCondIn); // Rated==Ref?
3300 0 : OutputReportPredefined::PreDefTableEntry(
3301 0 : state, state.dataOutRptPredefined->pdchChillerRatedLevEvapTemp, this->Name, this->TempDesEvapOut); // Rated==Ref?
3302 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEntCondTemp, this->Name, this->TempDesCondIn);
3303 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefLevEvapTemp, this->Name, this->TempDesEvapOut);
3304 :
3305 0 : OutputReportPredefined::PreDefTableEntry(state,
3306 0 : state.dataOutRptPredefined->pdchChillerDesSizeRefCHWFlowRate,
3307 : this->Name,
3308 : this->EvapMassFlowRateMax); // flowrate Max==DesignSizeRef flowrate?
3309 0 : OutputReportPredefined::PreDefTableEntry(state,
3310 0 : state.dataOutRptPredefined->pdchChillerDesSizeRefCondFluidFlowRate,
3311 : this->Name,
3312 : this->CondMassFlowRateMax); // Cond flowrate Max==DesignSizeRef Cond flowrate?
3313 0 : OutputReportPredefined::PreDefTableEntry(state,
3314 0 : state.dataOutRptPredefined->pdchChillerHeatRecPlantloopName,
3315 : this->Name,
3316 0 : (this->HRPlantLoc.loop != nullptr) ? this->HRPlantLoc.loop->Name : "N/A");
3317 0 : OutputReportPredefined::PreDefTableEntry(state,
3318 0 : state.dataOutRptPredefined->pdchChillerHeatRecPlantloopBranchName,
3319 : this->Name,
3320 0 : (this->HRPlantLoc.branch != nullptr) ? this->HRPlantLoc.branch->Name : "N/A");
3321 0 : OutputReportPredefined::PreDefTableEntry(
3322 0 : state, state.dataOutRptPredefined->pdchChillerRecRelCapFrac, this->Name, this->HeatRecCapacityFraction);
3323 : }
3324 :
3325 1 : if (ErrorsFound) {
3326 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
3327 : }
3328 1 : }
3329 :
3330 0 : void EngineDrivenChillerSpecs::calculate(EnergyPlusData &state,
3331 : Real64 &MyLoad,
3332 : bool const RunFlag,
3333 : DataBranchAirLoopPlant::ControlType const EquipFlowCtrl)
3334 : {
3335 : // SUBROUTINE INFORMATION:
3336 : // AUTHOR Dan Fisher / Brandon Anderson
3337 : // DATE WRITTEN Sept. 2000
3338 : // MODIFIED Feb. 2010, Chandan Sharma, FSEC. Added basin heater
3339 : // Jun. 2016, Rongpeng Zhang, LBNL. Applied the chiller supply water temperature sensor fault model
3340 : // Nov. 2016, Rongpeng Zhang, LBNL. Added Fouling Chiller fault
3341 : // RE-ENGINEERED na
3342 :
3343 : // PURPOSE OF THIS SUBROUTINE:
3344 : // simulate a vapor compression chiller using the EngineDriven model
3345 :
3346 : // METHODOLOGY EMPLOYED:
3347 : // curve fit of performance data:
3348 :
3349 : // REFERENCES:
3350 : // 1. BLAST Users Manual
3351 : // 2. CHILLER User Manual
3352 :
3353 0 : Real64 constexpr ExhaustCP(1.047); // Exhaust Gas Specific Heat (J/kg-K)
3354 0 : Real64 constexpr ReferenceTemp(25.0); // Reference temperature by which lower heating
3355 : // value is reported. This should be subtracted
3356 : // off of when calculated exhaust energies.
3357 : static constexpr std::string_view RoutineName("CalcEngineDrivenChillerModel");
3358 :
3359 : // set module level inlet and outlet nodes
3360 0 : this->EvapMassFlowRate = 0.0;
3361 0 : this->CondMassFlowRate = 0.0;
3362 0 : this->Power = 0.0;
3363 0 : this->QCondenser = 0.0;
3364 0 : this->QEvaporator = 0.0;
3365 0 : this->Energy = 0.0;
3366 0 : this->CondenserEnergy = 0.0;
3367 0 : this->EvaporatorEnergy = 0.0;
3368 0 : this->HeatRecMdotActual = 0.0;
3369 0 : this->QTotalHeatRecovered = 0.0;
3370 0 : this->QJacketRecovered = 0.0;
3371 0 : this->QLubeOilRecovered = 0.0;
3372 0 : this->QExhaustRecovered = 0.0;
3373 0 : this->FuelEnergyUseRate = 0.0;
3374 0 : this->TotalHeatEnergyRec = 0.0;
3375 0 : this->JacketEnergyRec = 0.0;
3376 0 : this->LubeOilEnergyRec = 0.0;
3377 0 : this->ExhaustEnergyRec = 0.0;
3378 0 : this->FuelEnergy = 0.0;
3379 0 : this->FuelMdot = 0.0;
3380 0 : this->ExhaustStackTemp = 0.0;
3381 :
3382 0 : if (this->HeatRecActive) {
3383 0 : this->HeatRecInletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
3384 0 : this->HeatRecOutletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
3385 : }
3386 :
3387 : // calculate end time of current time step
3388 0 : Real64 CurrentEndTime = state.dataGlobal->CurrentTime + state.dataHVACGlobal->SysTimeElapsed;
3389 :
3390 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
3391 : // Wait for next time step to print warnings. If simulation iterates, print out
3392 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
3393 : // If a warning occurs and the simulation down shifts, the warning is not valid.
3394 0 : if (CurrentEndTime > this->CurrentEndTimeLast && state.dataHVACGlobal->TimeStepSys >= this->TimeStepSysLast) {
3395 0 : if (this->PrintMessage) {
3396 0 : ++this->MsgErrorCount;
3397 : // Show single warning and pass additional info to ShowRecurringWarningErrorAtEnd
3398 0 : if (this->MsgErrorCount < 2) {
3399 0 : ShowWarningError(state, format("{}.", this->MsgBuffer1));
3400 0 : ShowContinueError(state, this->MsgBuffer2);
3401 : } else {
3402 0 : ShowRecurringWarningErrorAtEnd(
3403 0 : state, this->MsgBuffer1 + " error continues.", this->ErrCount1, this->MsgDataLast, this->MsgDataLast, _, "[C]", "[C]");
3404 : }
3405 : }
3406 : }
3407 :
3408 : // save last system time step and last end time of current time step (used to determine if warning is valid)
3409 0 : this->TimeStepSysLast = state.dataHVACGlobal->TimeStepSys;
3410 0 : this->CurrentEndTimeLast = CurrentEndTime;
3411 :
3412 : // If Chiller load is 0 or chiller is not running then leave the subroutine.
3413 0 : if (MyLoad >= 0.0 || !RunFlag) {
3414 0 : if (EquipFlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive ||
3415 0 : this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Locked) {
3416 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
3417 : } else {
3418 0 : this->EvapMassFlowRate = 0.0;
3419 :
3420 0 : PlantUtilities::SetComponentFlowRate(
3421 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
3422 : }
3423 :
3424 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
3425 0 : if (DataPlant::CompData::getPlantComponent(state, this->CDPlantLoc).FlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive) {
3426 0 : this->CondMassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
3427 : } else {
3428 0 : this->CondMassFlowRate = 0.0;
3429 0 : PlantUtilities::SetComponentFlowRate(
3430 0 : state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
3431 : }
3432 : }
3433 :
3434 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
3435 0 : CalcBasinHeaterPower(
3436 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
3437 : }
3438 0 : this->PrintMessage = false;
3439 0 : return;
3440 : }
3441 :
3442 0 : if (this->CondenserType == DataPlant::CondenserType::AirCooled) { // Condenser inlet temp = outdoor temp
3443 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirDryBulb;
3444 : // Warn user if entering condenser temperature falls below 0C
3445 0 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 0.0 && !state.dataGlobal->WarmupFlag) {
3446 0 : this->PrintMessage = true;
3447 0 : this->MsgBuffer1 = format(
3448 0 : "CalcEngineDrivenChillerModel - Chiller:EngineDriven \"{}\" - Air Cooled Condenser Inlet Temperature below 0C", this->Name);
3449 0 : this->MsgBuffer2 = format("... Outdoor Dry-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
3450 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
3451 0 : state.dataEnvrn->EnvironmentName,
3452 0 : state.dataEnvrn->CurMnDy,
3453 0 : General::CreateSysTimeIntervalString(state));
3454 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
3455 : } else {
3456 0 : this->PrintMessage = false;
3457 : }
3458 0 : } else if (this->CondenserType == DataPlant::CondenserType::EvapCooled) { // Condenser inlet temp = (outdoor wet bulb)
3459 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirWetBulb;
3460 : // Warn user if evap condenser wet bulb temperature falls below 10C
3461 0 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 10.0 && !state.dataGlobal->WarmupFlag) {
3462 0 : this->PrintMessage = true;
3463 0 : this->MsgBuffer1 = format(
3464 0 : "CalcEngineDrivenChillerModel - Chiller:EngineDriven \"{}\" - Evap Cooled Condenser Inlet Temperature below 10C", this->Name);
3465 0 : this->MsgBuffer2 = format("... Outdoor Wet-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
3466 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
3467 0 : state.dataEnvrn->EnvironmentName,
3468 0 : state.dataEnvrn->CurMnDy,
3469 0 : General::CreateSysTimeIntervalString(state));
3470 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
3471 : } else {
3472 0 : this->PrintMessage = false;
3473 : }
3474 : } // End of the Air Cooled/Evap Cooled Logic block
3475 :
3476 : // If not air or evap cooled then set to the condenser node that is attached to a cooling tower
3477 0 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
3478 :
3479 : // Set mass flow rates
3480 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
3481 0 : this->CondMassFlowRate = this->CondMassFlowRateMax;
3482 0 : PlantUtilities::SetComponentFlowRate(state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
3483 0 : PlantUtilities::PullCompInterconnectTrigger(
3484 0 : state, this->CWPlantLoc, this->CondMassFlowIndex, this->CDPlantLoc, DataPlant::CriteriaType::MassFlowRate, this->CondMassFlowRate);
3485 0 : if (this->CondMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance) {
3486 0 : MyLoad = 0.0;
3487 0 : this->EvapMassFlowRate = 0.0;
3488 0 : PlantUtilities::SetComponentFlowRate(
3489 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
3490 0 : return;
3491 : }
3492 : }
3493 :
3494 : // LOAD LOCAL VARIABLES FROM DATA STRUCTURE (for code readability)
3495 0 : Real64 ChillerNomCap = this->NomCap;
3496 0 : Real64 COPLocal = this->COP;
3497 0 : Real64 TempCondIn = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
3498 0 : Real64 TempEvapOut = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
3499 :
3500 : // If there is a fault of chiller fouling
3501 0 : if (this->FaultyChillerFoulingFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
3502 0 : (!state.dataGlobal->KickOffSimulation)) {
3503 0 : int FaultIndex = this->FaultyChillerFoulingIndex;
3504 0 : Real64 NomCap_ff = ChillerNomCap;
3505 0 : Real64 COP_ff = COPLocal;
3506 :
3507 : // calculate the Faulty Chiller Fouling Factor using fault information
3508 0 : this->FaultyChillerFoulingFactor = state.dataFaultsMgr->FaultsChillerFouling(FaultIndex).CalFoulingFactor(state);
3509 :
3510 : // update the Chiller nominal capacity and COP at faulty cases
3511 0 : ChillerNomCap = NomCap_ff * this->FaultyChillerFoulingFactor;
3512 0 : COPLocal = COP_ff * this->FaultyChillerFoulingFactor;
3513 : }
3514 :
3515 : // If there is a fault of Chiller SWT Sensor
3516 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
3517 0 : (!state.dataGlobal->KickOffSimulation)) {
3518 0 : int FaultIndex = this->FaultyChillerSWTIndex;
3519 0 : Real64 EvapOutletTemp_ff = TempEvapOut;
3520 :
3521 : // calculate the sensor offset using fault information
3522 0 : this->FaultyChillerSWTOffset = state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex).CalFaultOffsetAct(state);
3523 : // update the TempEvapOut
3524 0 : TempEvapOut = max(this->TempLowLimitEvapOut,
3525 0 : min(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, EvapOutletTemp_ff - this->FaultyChillerSWTOffset));
3526 0 : this->FaultyChillerSWTOffset = EvapOutletTemp_ff - TempEvapOut;
3527 : }
3528 :
3529 : // Calculate chiller performance from this set of performance equations.
3530 0 : Real64 DeltaTemp = (TempCondIn - this->TempDesCondIn) / this->TempRiseCoef - (TempEvapOut - this->TempDesEvapOut);
3531 :
3532 : // available nominal capacity ratio
3533 0 : Real64 AvailNomCapRat = this->CapRatCoef(1) + this->CapRatCoef(2) * DeltaTemp + this->CapRatCoef(3) * pow_2(DeltaTemp);
3534 :
3535 0 : Real64 AvailChillerCap = ChillerNomCap * AvailNomCapRat;
3536 :
3537 : // full load power ratio
3538 0 : Real64 FullLoadPowerRat = this->PowerRatCoef(1) + this->PowerRatCoef(2) * AvailNomCapRat + this->PowerRatCoef(3) * pow_2(AvailNomCapRat);
3539 :
3540 0 : Real64 PartLoadRat(0.0); // part load ratio for efficiency
3541 0 : if (AvailChillerCap > 0.0) {
3542 0 : PartLoadRat = max(this->MinPartLoadRat, min(std::abs(MyLoad) / AvailChillerCap, this->MaxPartLoadRat));
3543 : }
3544 :
3545 0 : Real64 FracFullLoadPower = this->FullLoadCoef(1) + this->FullLoadCoef(2) * PartLoadRat + this->FullLoadCoef(3) * pow_2(PartLoadRat);
3546 :
3547 : Real64 OperPartLoadRat; // Actual operating PLR
3548 0 : if (AvailChillerCap > 0.0) {
3549 0 : if (std::abs(MyLoad) / AvailChillerCap < this->MinPartLoadRat) {
3550 0 : OperPartLoadRat = std::abs(MyLoad) / AvailChillerCap;
3551 : } else {
3552 0 : OperPartLoadRat = PartLoadRat;
3553 : }
3554 : } else {
3555 0 : OperPartLoadRat = 0.0;
3556 : }
3557 :
3558 0 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, RoutineName);
3559 :
3560 : // If FlowLock is True, the new resolved mdot is used to update Power, QEvap, Qcond, and
3561 : // condenser side outlet temperature.
3562 0 : if (this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Unlocked) {
3563 0 : this->PossibleSubcooling = false;
3564 0 : this->QEvaporator = AvailChillerCap * OperPartLoadRat;
3565 : Real64 FRAC;
3566 0 : if (OperPartLoadRat < this->MinPartLoadRat) {
3567 0 : FRAC = min(1.0, (OperPartLoadRat / this->MinPartLoadRat));
3568 : } else {
3569 0 : FRAC = 1.0;
3570 : }
3571 0 : this->Power = FracFullLoadPower * FullLoadPowerRat * AvailChillerCap / COPLocal * FRAC;
3572 :
3573 : // Either set the flow to the Constant value or calculate the flow for the variable volume
3574 0 : if ((this->FlowMode == DataPlant::FlowMode::Constant) || (this->FlowMode == DataPlant::FlowMode::NotModulated)) {
3575 : // Start by assuming max (design) flow
3576 0 : this->EvapMassFlowRate = this->EvapMassFlowRateMax;
3577 : // Use SetComponentFlowRate to decide actual flow
3578 0 : PlantUtilities::SetComponentFlowRate(
3579 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
3580 : // Evaluate delta temp based on actual flow rate
3581 0 : Real64 EvapDeltaTemp(0.0);
3582 0 : if (this->EvapMassFlowRate != 0.0) {
3583 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
3584 : } else {
3585 0 : EvapDeltaTemp = 0.0;
3586 : }
3587 : // Evaluate outlet temp based on delta
3588 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
3589 :
3590 0 : } else if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
3591 :
3592 : // Calculate the Delta Temp from the inlet temp to the chiller outlet setpoint
3593 0 : Real64 EvapDeltaTemp(0.0);
3594 0 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
3595 0 : EvapDeltaTemp =
3596 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
3597 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
3598 0 : EvapDeltaTemp =
3599 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
3600 : }
3601 :
3602 0 : if (EvapDeltaTemp != 0.0) {
3603 0 : this->EvapMassFlowRate = std::abs(this->QEvaporator / Cp / EvapDeltaTemp);
3604 0 : if ((this->EvapMassFlowRate - this->EvapMassFlowRateMax) > DataBranchAirLoopPlant::MassFlowTolerance)
3605 0 : this->PossibleSubcooling = true;
3606 : // Check to see if the Maximum is exceeded, if so set to maximum
3607 0 : this->EvapMassFlowRate = min(this->EvapMassFlowRateMax, this->EvapMassFlowRate);
3608 : // Use SetComponentFlowRate to decide actual flow
3609 0 : PlantUtilities::SetComponentFlowRate(
3610 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
3611 0 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
3612 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
3613 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
3614 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
3615 : }
3616 : } else {
3617 : // Try to request zero flow
3618 0 : this->EvapMassFlowRate = 0.0;
3619 : // Use SetComponentFlowRate to decide actual flow
3620 0 : PlantUtilities::SetComponentFlowRate(
3621 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
3622 : // No deltaT since component is not running
3623 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
3624 : }
3625 : } // End of Constant Variable Flow If Block
3626 :
3627 : // If there is a fault of Chiller SWT Sensor
3628 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
3629 0 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
3630 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
3631 0 : int FaultIndex = this->FaultyChillerSWTIndex;
3632 0 : bool VarFlowFlag = (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated);
3633 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
3634 0 : .CalFaultChillerSWT(VarFlowFlag,
3635 : this->FaultyChillerSWTOffset,
3636 : Cp,
3637 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
3638 0 : this->EvapOutletTemp,
3639 0 : this->EvapMassFlowRate,
3640 0 : this->QEvaporator);
3641 : // update corresponding variables at faulty case
3642 0 : PartLoadRat = (AvailChillerCap > 0.0) ? (this->QEvaporator / AvailChillerCap) : 0.0;
3643 0 : PartLoadRat = max(0.0, min(PartLoadRat, this->MaxPartLoadRat));
3644 : }
3645 :
3646 : } else { // If FlowLock is True
3647 :
3648 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
3649 0 : PlantUtilities::SetComponentFlowRate(state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
3650 : // Some other component set the flow to 0. No reason to continue with calculations.
3651 0 : if (this->EvapMassFlowRate == 0.0) {
3652 0 : MyLoad = 0.0;
3653 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
3654 0 : CalcBasinHeaterPower(
3655 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
3656 : }
3657 0 : this->PrintMessage = false;
3658 0 : return;
3659 : }
3660 :
3661 0 : if (this->PossibleSubcooling) {
3662 0 : this->QEvaporator = std::abs(MyLoad);
3663 0 : Real64 EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
3664 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
3665 0 : if (this->EvapOutletTemp < state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) {
3666 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin;
3667 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
3668 0 : this->QEvaporator = std::abs(this->EvapMassFlowRate * Cp * EvapDeltaTemp);
3669 : }
3670 : } else { // No subcooling in this case.No recalculation required.Still need to check chiller low temp limit
3671 :
3672 0 : Real64 TempEvapOutSetPoint(0.0); // C - evaporator outlet temperature setpoint
3673 :
3674 0 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
3675 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
3676 0 : this->CWPlantLoc.comp->CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased ||
3677 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint != DataLoopNode::SensedNodeFlagValue)) {
3678 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
3679 : } else {
3680 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
3681 : }
3682 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
3683 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
3684 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased ||
3685 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi != DataLoopNode::SensedNodeFlagValue)) {
3686 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
3687 : } else {
3688 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
3689 : }
3690 : }
3691 :
3692 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - TempEvapOutSetPoint;
3693 0 : this->QEvaporator = std::abs(this->EvapMassFlowRate * Cp * EvapDeltaTemp);
3694 0 : this->EvapOutletTemp = TempEvapOutSetPoint;
3695 : }
3696 : // Check that the Evap outlet temp honors both plant loop temp low limit and also the chiller low limit
3697 0 : if (this->EvapOutletTemp < this->TempLowLimitEvapOut) {
3698 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->TempLowLimitEvapOut) > DataPlant::DeltaTempTol) {
3699 0 : this->EvapOutletTemp = this->TempLowLimitEvapOut;
3700 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
3701 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
3702 : } else {
3703 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
3704 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
3705 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
3706 : }
3707 : }
3708 0 : if (this->EvapOutletTemp < state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) {
3709 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) >
3710 : DataPlant::DeltaTempTol) {
3711 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin;
3712 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
3713 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
3714 : } else {
3715 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
3716 0 : Real64 EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
3717 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
3718 : }
3719 : }
3720 : // If load exceeds the distributed load set to the distributed load
3721 0 : if (this->QEvaporator > std::abs(MyLoad)) {
3722 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
3723 0 : this->QEvaporator = std::abs(MyLoad);
3724 0 : Real64 EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
3725 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
3726 : } else {
3727 0 : this->QEvaporator = 0.0;
3728 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
3729 : }
3730 : }
3731 :
3732 : // If there is a fault of Chiller SWT Sensor
3733 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
3734 0 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
3735 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
3736 0 : int FaultIndex = this->FaultyChillerSWTIndex;
3737 0 : bool VarFlowFlag = false;
3738 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
3739 0 : .CalFaultChillerSWT(VarFlowFlag,
3740 : this->FaultyChillerSWTOffset,
3741 : Cp,
3742 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
3743 0 : this->EvapOutletTemp,
3744 0 : this->EvapMassFlowRate,
3745 0 : this->QEvaporator);
3746 : }
3747 :
3748 : // Checks QEvaporator on the basis of the machine limits.
3749 0 : if (this->QEvaporator > (AvailChillerCap * this->MaxPartLoadRat)) {
3750 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
3751 0 : this->QEvaporator = AvailChillerCap * OperPartLoadRat;
3752 0 : Real64 EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
3753 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
3754 : } else {
3755 0 : this->QEvaporator = 0.0;
3756 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
3757 : }
3758 : }
3759 :
3760 : Real64 FRAC;
3761 0 : if (OperPartLoadRat < this->MinPartLoadRat) {
3762 0 : FRAC = min(1.0, (OperPartLoadRat / this->MinPartLoadRat));
3763 : } else {
3764 0 : FRAC = 1.0;
3765 : }
3766 :
3767 : // Chiller is false loading below PLR = minimum unloading ratio, find PLR used for energy calculation
3768 0 : this->Power = FracFullLoadPower * FullLoadPowerRat * AvailChillerCap / COPLocal * FRAC;
3769 :
3770 0 : if (this->EvapMassFlowRate == 0.0) {
3771 0 : this->QEvaporator = 0.0;
3772 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
3773 0 : this->Power = 0.0;
3774 0 : this->PrintMessage = false;
3775 : }
3776 0 : if (this->QEvaporator == 0.0 && this->CondenserType == DataPlant::CondenserType::EvapCooled) {
3777 0 : CalcBasinHeaterPower(
3778 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
3779 : }
3780 : } // This is the end of the FlowLock Block
3781 :
3782 : // Now determine Cooling
3783 : // QCondenser is calculated the same for each type, but the power consumption should be different
3784 : // depending on the performance coefficients used for the chiller model.
3785 0 : this->QCondenser = this->Power + this->QEvaporator;
3786 :
3787 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
3788 :
3789 0 : if (this->CondMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
3790 0 : Real64 CpCond = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, this->CondInletTemp, RoutineName);
3791 0 : this->CondOutletTemp = this->QCondenser / this->CondMassFlowRate / CpCond + this->CondInletTemp;
3792 : } else {
3793 0 : ShowSevereError(state, format("CalcEngineDrivenChillerModel: Condenser flow = 0, for EngineDrivenChiller={}", this->Name));
3794 0 : ShowContinueErrorTimeStamp(state, "");
3795 : }
3796 :
3797 : } else { // Air Cooled or Evap Cooled
3798 :
3799 : // don't care about outlet temp for Air-Cooled or Evap Cooled
3800 0 : this->CondOutletTemp = this->CondInletTemp;
3801 : }
3802 :
3803 : // EngineDriven Portion of the Engine Driven Chiller:
3804 :
3805 : // DETERMINE FUEL CONSUMED AND AVAILABLE WASTE HEAT
3806 :
3807 : // Use Curve fit to determine Fuel Energy Input. For electric power generated in Watts, the fuel
3808 : // energy input is calculated in J/s. The PLBasedFuelInputCurve selects ratio of fuel flow (J/s)/cooling load (J/s).
3809 : Real64 EngineDrivenFuelEnergy;
3810 0 : if (PartLoadRat == 0) {
3811 0 : EngineDrivenFuelEnergy = 0.0;
3812 : } else {
3813 0 : PartLoadRat = max(this->MinPartLoadRat, PartLoadRat);
3814 : // (RELDC) Ratio of Shaft Power to Fuel Energy Input
3815 0 : Real64 ClngLoadFuelRat = Curve::CurveValue(state, this->ClngLoadtoFuelCurve, PartLoadRat);
3816 0 : EngineDrivenFuelEnergy = this->QEvaporator / ClngLoadFuelRat;
3817 : }
3818 : // Use Curve fit to determine energy recovered in the water jacket. This curve calculates the water jacket energy recovered (J/s) by
3819 : // multiplying the total fuel input (J/s) by the fraction of that power that could be recovered in the water jacket at that
3820 : // particular part load.
3821 :
3822 : // (RJACDC) Ratio of Recoverable Jacket Heat to Fuel Energy Input
3823 0 : Real64 RecJacHeattoFuelRat = Curve::CurveValue(state, this->RecJacHeattoFuelCurve, PartLoadRat);
3824 0 : this->QJacketRecovered = EngineDrivenFuelEnergy * RecJacHeattoFuelRat;
3825 :
3826 : // Use Curve fit to determine Heat Recovered Lubricant Energy. This curve calculates the lube energy recovered (J/s) by
3827 : // multiplying the total fuel input (J/s) by the fraction of that power that could be recovered in the lube oil at that
3828 : // particular part load.
3829 : // (RLUBDC) Ratio of Recoverable Lube Oil Heat to Fuel Energy Input
3830 0 : Real64 RecLubeHeattoFuelRat = Curve::CurveValue(state, this->RecLubeHeattoFuelCurve, PartLoadRat);
3831 0 : this->QLubeOilRecovered = EngineDrivenFuelEnergy * RecLubeHeattoFuelRat;
3832 :
3833 : // Use Curve fit to determine Heat Recovered from the exhaust. This curve calculates the energy recovered (J/s) by
3834 : // multiplying the total fuel input (J/s) by the fraction of that power that could be recovered in the exhaust at that
3835 : // particular part load.
3836 0 : Real64 TotExhausttoFuelRat = Curve::CurveValue(state, this->TotExhausttoFuelCurve, PartLoadRat);
3837 0 : Real64 TotalExhaustEnergy = EngineDrivenFuelEnergy * TotExhausttoFuelRat;
3838 :
3839 : // Use Curve fit to determine Exhaust Temperature in C. The temperature is simply a curve fit
3840 : // of the exhaust temperature in C to the part load ratio.
3841 0 : if (PartLoadRat != 0) {
3842 0 : Real64 exhaustTemp = Curve::CurveValue(state, this->ExhaustTempCurve, PartLoadRat);
3843 0 : Real64 ExhaustGasFlow = TotalExhaustEnergy / (ExhaustCP * (exhaustTemp - ReferenceTemp));
3844 :
3845 : // Use Curve fit to determine stack temp after heat recovery
3846 0 : Real64 UALocal = this->UACoef(1) * std::pow(ChillerNomCap, this->UACoef(2));
3847 0 : Real64 designMinExitGasTemp = this->DesignMinExitGasTemp;
3848 :
3849 0 : this->ExhaustStackTemp =
3850 0 : designMinExitGasTemp + (exhaustTemp - designMinExitGasTemp) /
3851 0 : std::exp(UALocal / (max(ExhaustGasFlow, this->MaxExhaustperPowerOutput * ChillerNomCap) * ExhaustCP));
3852 :
3853 0 : this->QExhaustRecovered = max(ExhaustGasFlow * ExhaustCP * (exhaustTemp - this->ExhaustStackTemp), 0.0);
3854 : } else {
3855 0 : this->QExhaustRecovered = 0.0;
3856 : }
3857 :
3858 0 : this->QTotalHeatRecovered = this->QExhaustRecovered + this->QLubeOilRecovered + this->QJacketRecovered;
3859 :
3860 : // Update Heat Recovery temperatures
3861 0 : if (this->HeatRecActive) {
3862 : Real64 HeatRecRatio;
3863 0 : this->calcHeatRecovery(state, this->QTotalHeatRecovered, HeatRecRatio);
3864 0 : this->QExhaustRecovered *= HeatRecRatio;
3865 0 : this->QLubeOilRecovered *= HeatRecRatio;
3866 0 : this->QJacketRecovered *= HeatRecRatio;
3867 : }
3868 :
3869 : // Calculate Energy
3870 0 : this->CondenserEnergy = this->QCondenser * state.dataHVACGlobal->TimeStepSysSec;
3871 0 : this->Energy = this->Power * state.dataHVACGlobal->TimeStepSysSec;
3872 0 : this->EvaporatorEnergy = this->QEvaporator * state.dataHVACGlobal->TimeStepSysSec;
3873 0 : this->FuelEnergyUseRate = EngineDrivenFuelEnergy;
3874 0 : this->FuelEnergy = this->FuelEnergyUseRate * state.dataHVACGlobal->TimeStepSysSec;
3875 0 : this->JacketEnergyRec = this->QJacketRecovered * state.dataHVACGlobal->TimeStepSysSec;
3876 0 : this->LubeOilEnergyRec = this->QLubeOilRecovered * state.dataHVACGlobal->TimeStepSysSec;
3877 0 : this->ExhaustEnergyRec = this->QExhaustRecovered * state.dataHVACGlobal->TimeStepSysSec;
3878 0 : this->QTotalHeatRecovered = this->QExhaustRecovered + this->QLubeOilRecovered + this->QJacketRecovered;
3879 0 : this->TotalHeatEnergyRec = this->ExhaustEnergyRec + this->LubeOilEnergyRec + this->JacketEnergyRec;
3880 0 : this->FuelEnergyUseRate = std::abs(this->FuelEnergyUseRate);
3881 0 : this->FuelEnergy = std::abs(this->FuelEnergy);
3882 0 : this->FuelMdot = std::abs(this->FuelEnergyUseRate) / (this->FuelHeatingValue * KJtoJ);
3883 :
3884 : // check for problems BG 9/12/06 (deal with observed negative energy results)
3885 0 : if (this->Energy < 0.0) { // there is a serious problem
3886 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
3887 : // first check for run away condenser loop temps (only reason yet to be observed for this?)
3888 0 : if (this->CondInletTemp > 70.0) {
3889 0 : ShowSevereError(
3890 : state,
3891 0 : format("CalcEngineDrivenChillerModel: Condenser loop inlet temperatures > 70.0 C for EngineDrivenChiller={}", this->Name));
3892 0 : ShowContinueErrorTimeStamp(state, "");
3893 0 : ShowContinueError(state, format("Condenser loop water temperatures are too high at{:.2R}", this->CondInletTemp));
3894 0 : ShowContinueError(state, "Check input for condenser plant loop, especially cooling tower");
3895 0 : ShowContinueError(state, format("Evaporator inlet temperature: {:.2R}", state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp));
3896 :
3897 0 : ShowFatalError(state, "Program Terminates due to previous error condition");
3898 : }
3899 : }
3900 0 : if (!state.dataGlobal->WarmupFlag) {
3901 0 : if (AvailNomCapRat < 0.0) { // apparently the real reason energy goes negative
3902 0 : ShowSevereError(state, format("CalcEngineDrivenChillerModel: Capacity ratio below zero for EngineDrivenChiller={}", this->Name));
3903 0 : ShowContinueErrorTimeStamp(state, "");
3904 0 : ShowContinueError(state, "Check input for Capacity Ratio Curve");
3905 0 : ShowContinueError(state, format("Condenser inlet temperature: {:.2R}", this->CondInletTemp));
3906 0 : ShowContinueError(state, format("Evaporator inlet temperature: {:.2R}", state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp));
3907 0 : ShowFatalError(state, "Program Terminates due to previous error condition");
3908 : }
3909 : }
3910 : // If makes it here, set limits, chiller can't have negative energy/power
3911 : // proceeding silently for now but may want to throw error here
3912 0 : this->Power = 0.0;
3913 0 : this->Energy = 0.0;
3914 : }
3915 : }
3916 :
3917 0 : void EngineDrivenChillerSpecs::calcHeatRecovery(EnergyPlusData &state, Real64 const EnergyRecovered, Real64 &HeatRecRatio)
3918 : {
3919 : // SUBROUTINE INFORMATION:
3920 : // AUTHOR: Brandon Anderson
3921 : // DATE WRITTEN: November 2000
3922 :
3923 : // PURPOSE OF THIS SUBROUTINE:
3924 : // To perform heat recovery calculations and node updates
3925 :
3926 : // METHODOLOGY EMPLOYED: This routine is required for the heat recovery loop.
3927 : // It works in conjunction with the Heat Recovery Manager, and the PlantWaterHeater.
3928 : // The chiller sets the flow on the loop first by the input design flowrate and then
3929 : // performs a check to verify that
3930 :
3931 : // SUBROUTINE PARAMETER DEFINITIONS:
3932 : static constexpr std::string_view RoutineName("ChillerHeatRecovery");
3933 :
3934 : // Need to set the HeatRecRatio to 1.0 if it is not modified
3935 0 : HeatRecRatio = 1.0;
3936 :
3937 : // This mdot is input specified mdot "Desired Flowrate", already set in init routine
3938 0 : this->HeatRecMdotActual = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
3939 :
3940 0 : this->HeatRecInletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
3941 0 : Real64 cp = this->HRPlantLoc.loop->glycol->getSpecificHeat(state, this->HeatRecInletTemp, RoutineName);
3942 :
3943 : // Don't divide by zero - Note This also results in no heat recovery when
3944 : // design Mdot for Heat Recovery - Specified on Chiller Input - is zero
3945 : // In order to see what minimum heat recovery flow rate is for the design temperature
3946 : // The design heat recovery flow rate can be set very small, but greater than zero.
3947 0 : if ((this->HeatRecMdotActual > 0) && (cp > 0)) {
3948 0 : this->HeatRecOutletTemp = (EnergyRecovered) / (this->HeatRecMdotActual * cp) + this->HeatRecInletTemp;
3949 : } else {
3950 0 : this->HeatRecOutletTemp = this->HeatRecInletTemp;
3951 : }
3952 :
3953 : // Now verify that the design flowrate was large enough to prevent phase change
3954 0 : if (this->HeatRecOutletTemp > this->HeatRecMaxTemp) {
3955 0 : Real64 MinHeatRecMdot(0.0);
3956 0 : if (this->HeatRecMaxTemp != this->HeatRecInletTemp) {
3957 0 : MinHeatRecMdot = (EnergyRecovered) / (cp * (this->HeatRecMaxTemp - this->HeatRecInletTemp));
3958 0 : if (MinHeatRecMdot < 0.0) MinHeatRecMdot = 0.0;
3959 : }
3960 :
3961 : // Recalculate Outlet Temperature, with adjusted flowrate
3962 0 : if ((MinHeatRecMdot > 0.0) && (cp > 0.0)) {
3963 0 : this->HeatRecOutletTemp = (EnergyRecovered) / (MinHeatRecMdot * cp) + this->HeatRecInletTemp;
3964 0 : HeatRecRatio = this->HeatRecMdotActual / MinHeatRecMdot;
3965 : } else {
3966 0 : this->HeatRecOutletTemp = this->HeatRecInletTemp;
3967 0 : HeatRecRatio = 0.0;
3968 : }
3969 : }
3970 0 : }
3971 :
3972 0 : void EngineDrivenChillerSpecs::update(EnergyPlusData &state, Real64 const MyLoad, bool const RunFlag)
3973 : {
3974 : // SUBROUTINE INFORMATION:
3975 : // AUTHOR: Dan Fisher / Brandon Anderson
3976 : // DATE WRITTEN: September 2000
3977 :
3978 0 : Real64 const ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
3979 :
3980 0 : if (MyLoad >= 0.0 || !RunFlag) { // Chiller not running
3981 : // set node temperatures
3982 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
3983 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
3984 :
3985 0 : this->Power = 0.0;
3986 0 : this->QEvaporator = 0.0;
3987 0 : this->QCondenser = 0.0;
3988 0 : this->Energy = 0.0;
3989 0 : this->EvaporatorEnergy = 0.0;
3990 0 : this->CondenserEnergy = 0.0;
3991 0 : this->EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
3992 0 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
3993 0 : this->CondOutletTemp = state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp;
3994 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
3995 0 : this->FuelCOP = 0.0;
3996 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
3997 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
3998 : }
3999 : } else { // Chiller is running
4000 : // set node temperatures
4001 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = this->EvapOutletTemp;
4002 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = this->CondOutletTemp;
4003 :
4004 0 : this->EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
4005 0 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
4006 0 : this->CondOutletTemp = state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp;
4007 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
4008 0 : if (this->FuelEnergyUseRate != 0.0) {
4009 0 : this->FuelCOP = this->QEvaporator / this->FuelEnergyUseRate;
4010 : } else {
4011 0 : this->FuelCOP = 0.0;
4012 : }
4013 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
4014 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
4015 : }
4016 : }
4017 :
4018 : // Update Heat Recovery Stuff whether running or not, variables should be set correctly
4019 0 : this->HeatRecMdot = this->HeatRecMdotActual;
4020 :
4021 : // Update the Heat Recovery outlet
4022 0 : if (this->HeatRecActive) {
4023 0 : PlantUtilities::SafeCopyPlantNode(state, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
4024 0 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = this->HeatRecOutletTemp;
4025 : }
4026 0 : }
4027 0 : void EngineDrivenChillerSpecs::oneTimeInit(EnergyPlusData &state)
4028 : {
4029 :
4030 0 : if (this->MyFlag) {
4031 : // Locate the chillers on the plant loops for later usage
4032 0 : bool errFlag = false;
4033 0 : this->setupOutputVariables(state);
4034 0 : PlantUtilities::ScanPlantLoopsForObject(
4035 0 : state, this->Name, this->ChillerType, this->CWPlantLoc, errFlag, this->TempLowLimitEvapOut, _, _, this->EvapInletNodeNum, _);
4036 0 : if (this->CondenserType != DataPlant::CondenserType::AirCooled && this->CondenserType != DataPlant::CondenserType::EvapCooled) {
4037 0 : PlantUtilities::ScanPlantLoopsForObject(
4038 0 : state, this->Name, this->ChillerType, this->CDPlantLoc, errFlag, _, _, _, this->CondInletNodeNum, _);
4039 0 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CWPlantLoc, this->CDPlantLoc, this->ChillerType, true);
4040 : }
4041 0 : if (this->HeatRecActive) {
4042 0 : PlantUtilities::ScanPlantLoopsForObject(
4043 0 : state, this->Name, this->ChillerType, this->HRPlantLoc, errFlag, _, _, _, this->HeatRecInletNodeNum, _);
4044 0 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CWPlantLoc, this->HRPlantLoc, this->ChillerType, true);
4045 : }
4046 :
4047 0 : if (this->CondenserType != DataPlant::CondenserType::AirCooled && this->CondenserType != DataPlant::CondenserType::EvapCooled &&
4048 0 : this->HeatRecActive) {
4049 0 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CDPlantLoc, this->HRPlantLoc, this->ChillerType, false);
4050 : }
4051 0 : if (errFlag) {
4052 0 : ShowFatalError(state, "InitEngineDrivenChiller: Program terminated due to previous condition(s).");
4053 : }
4054 :
4055 0 : if (this->FlowMode == DataPlant::FlowMode::Constant) {
4056 : // reset flow priority
4057 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
4058 : }
4059 :
4060 0 : if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
4061 : // reset flow priority
4062 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
4063 : // check if setpoint on outlet node
4064 0 : if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
4065 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == DataLoopNode::SensedNodeFlagValue)) {
4066 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
4067 0 : if (!this->ModulatedFlowErrDone) {
4068 0 : ShowWarningError(state,
4069 0 : format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
4070 0 : ShowContinueError(
4071 : state,
4072 : " A temperature setpoint is needed at the outlet node of a chiller in variable flow mode, use a SetpointManager");
4073 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
4074 0 : this->ModulatedFlowErrDone = true;
4075 : }
4076 : } else {
4077 : // need call to EMS to check node
4078 0 : bool FatalError = false; // but not really fatal yet, but should be.
4079 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->EvapOutletNodeNum, HVAC::CtrlVarType::Temp, FatalError);
4080 0 : state.dataLoopNodes->NodeSetpointCheck(this->EvapOutletNodeNum).needsSetpointChecking = false;
4081 0 : if (FatalError) {
4082 0 : if (!this->ModulatedFlowErrDone) {
4083 0 : ShowWarningError(
4084 0 : state, format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
4085 0 : ShowContinueError(
4086 : state, " A temperature setpoint is needed at the outlet node of a chiller evaporator in variable flow mode");
4087 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the chiller evaporator outlet node ");
4088 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the outlet node ");
4089 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
4090 0 : this->ModulatedFlowErrDone = true;
4091 : }
4092 : }
4093 : }
4094 0 : this->ModulatedFlowSetToLoop = true;
4095 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
4096 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
4097 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
4098 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
4099 : }
4100 : }
4101 :
4102 0 : this->MyFlag = false;
4103 : }
4104 0 : }
4105 :
4106 0 : GTChillerSpecs *GTChillerSpecs::factory(EnergyPlusData &state, std::string const &chillerName)
4107 : {
4108 0 : if (state.dataPlantChillers->GetGasTurbineInput) {
4109 0 : GTChillerSpecs::getInput(state);
4110 0 : state.dataPlantChillers->GetGasTurbineInput = false;
4111 : }
4112 0 : for (auto &thisChiller : state.dataPlantChillers->GTChiller) {
4113 0 : if (Util::makeUPPER(thisChiller.Name) == chillerName) {
4114 0 : return &thisChiller;
4115 : }
4116 : }
4117 0 : ShowFatalError(state, format("Could not locate gas turbine chiller with name: {}", chillerName));
4118 0 : return nullptr;
4119 : }
4120 :
4121 : void
4122 0 : GTChillerSpecs::simulate(EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, bool RunFlag)
4123 : {
4124 0 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) { // chilled water loop
4125 0 : this->initialize(state, RunFlag, CurLoad);
4126 0 : this->calculate(state, CurLoad, RunFlag, this->CWPlantLoc.comp->FlowCtrl);
4127 0 : this->update(state, CurLoad, RunFlag);
4128 0 : } else if (calledFromLocation.loopNum == this->CDPlantLoc.loopNum) { // condenser loop
4129 0 : PlantUtilities::UpdateChillerComponentCondenserSide(state,
4130 : this->CDPlantLoc.loopNum,
4131 : this->CDPlantLoc.loopSideNum,
4132 : this->ChillerType,
4133 : this->CondInletNodeNum,
4134 : this->CondOutletNodeNum,
4135 : this->QCondenser,
4136 : this->CondInletTemp,
4137 : this->CondOutletTemp,
4138 : this->CondMassFlowRate,
4139 : FirstHVACIteration);
4140 0 : } else if (calledFromLocation.loopNum == this->HRPlantLoc.loopNum) { // heat recovery loop
4141 0 : PlantUtilities::UpdateComponentHeatRecoverySide(state,
4142 : this->HRPlantLoc.loopNum,
4143 : this->HRPlantLoc.loopSideNum,
4144 : this->ChillerType,
4145 : this->HeatRecInletNodeNum,
4146 : this->HeatRecOutletNodeNum,
4147 : this->HeatRecLubeRate,
4148 : this->HeatRecInletTemp,
4149 : this->HeatRecOutletTemp,
4150 : this->HeatRecMdot,
4151 : FirstHVACIteration);
4152 : }
4153 0 : }
4154 :
4155 1 : void GTChillerSpecs::getInput(EnergyPlusData &state)
4156 : {
4157 : // SUBROUTINE INFORMATION:
4158 : // AUTHOR: Dan Fisher / Brandon Anderson
4159 : // DATE WRITTEN: September 2000
4160 :
4161 : // PURPOSE OF THIS SUBROUTINE:
4162 : // This routine will get the input
4163 : // required by the GT Chiller model.
4164 :
4165 : // METHODOLOGY EMPLOYED:
4166 : // EnergyPlus input processor
4167 :
4168 : static constexpr std::string_view RoutineName("GetGTChillerInput: "); // include trailing blank space
4169 : static constexpr std::string_view routineName = "GetGTChillerInput";
4170 :
4171 : int NumAlphas; // Number of elements in the alpha array
4172 : int NumNums; // Number of elements in the numeric array
4173 : int IOStat; // IO Status when calling get input subroutine
4174 1 : bool ErrorsFound(false);
4175 :
4176 1 : state.dataIPShortCut->cCurrentModuleObject = "Chiller:CombustionTurbine";
4177 2 : state.dataPlantChillers->NumGTChillers =
4178 1 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
4179 :
4180 1 : if (state.dataPlantChillers->NumGTChillers <= 0) {
4181 0 : ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
4182 0 : ErrorsFound = true;
4183 : }
4184 : // See if load distribution manager has already gotten the input
4185 1 : if (allocated(state.dataPlantChillers->GTChiller)) return;
4186 :
4187 : // ALLOCATE ARRAYS
4188 1 : state.dataPlantChillers->GTChiller.allocate(state.dataPlantChillers->NumGTChillers);
4189 :
4190 2 : for (int ChillerNum = 1; ChillerNum <= state.dataPlantChillers->NumGTChillers; ++ChillerNum) {
4191 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4192 1 : state.dataIPShortCut->cCurrentModuleObject,
4193 : ChillerNum,
4194 1 : state.dataIPShortCut->cAlphaArgs,
4195 : NumAlphas,
4196 1 : state.dataIPShortCut->rNumericArgs,
4197 : NumNums,
4198 : IOStat,
4199 1 : state.dataIPShortCut->lNumericFieldBlanks,
4200 1 : state.dataIPShortCut->lAlphaFieldBlanks,
4201 1 : state.dataIPShortCut->cAlphaFieldNames,
4202 1 : state.dataIPShortCut->cNumericFieldNames);
4203 :
4204 1 : ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
4205 :
4206 1 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
4207 :
4208 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
4209 1 : GlobalNames::VerifyUniqueChillerName(state,
4210 1 : state.dataIPShortCut->cCurrentModuleObject,
4211 1 : state.dataIPShortCut->cAlphaArgs(1),
4212 : ErrorsFound,
4213 2 : state.dataIPShortCut->cCurrentModuleObject + " Name");
4214 :
4215 1 : auto &thisChiller = state.dataPlantChillers->GTChiller(ChillerNum);
4216 1 : thisChiller.Name = state.dataIPShortCut->cAlphaArgs(1);
4217 1 : thisChiller.ChillerType = DataPlant::PlantEquipmentType::Chiller_CombTurbine;
4218 :
4219 1 : thisChiller.NomCap = state.dataIPShortCut->rNumericArgs(1);
4220 :
4221 1 : if (thisChiller.NomCap == DataSizing::AutoSize) {
4222 0 : thisChiller.NomCapWasAutoSized = true;
4223 : }
4224 1 : if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
4225 0 : ShowSevereError(state,
4226 0 : format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
4227 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4228 0 : ErrorsFound = true;
4229 : }
4230 :
4231 1 : thisChiller.COP = state.dataIPShortCut->rNumericArgs(2);
4232 1 : if (state.dataIPShortCut->rNumericArgs(2) == 0.0) {
4233 0 : ShowSevereError(state,
4234 0 : format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
4235 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4236 0 : ErrorsFound = true;
4237 : }
4238 :
4239 1 : if (state.dataIPShortCut->cAlphaArgs(2) == "AIRCOOLED") {
4240 0 : thisChiller.CondenserType = DataPlant::CondenserType::AirCooled;
4241 1 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "WATERCOOLED") {
4242 1 : thisChiller.CondenserType = DataPlant::CondenserType::WaterCooled;
4243 0 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "EVAPORATIVELYCOOLED") {
4244 0 : thisChiller.CondenserType = DataPlant::CondenserType::EvapCooled;
4245 : } else {
4246 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
4247 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4248 0 : ErrorsFound = true;
4249 : }
4250 :
4251 1 : thisChiller.EvapInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
4252 1 : state.dataIPShortCut->cAlphaArgs(3),
4253 : ErrorsFound,
4254 : DataLoopNode::ConnectionObjectType::ChillerCombustionTurbine,
4255 1 : state.dataIPShortCut->cAlphaArgs(1),
4256 : DataLoopNode::NodeFluidType::Water,
4257 : DataLoopNode::ConnectionType::Inlet,
4258 : NodeInputManager::CompFluidStream::Primary,
4259 : DataLoopNode::ObjectIsNotParent);
4260 2 : thisChiller.EvapOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
4261 1 : state.dataIPShortCut->cAlphaArgs(4),
4262 : ErrorsFound,
4263 : DataLoopNode::ConnectionObjectType::ChillerCombustionTurbine,
4264 1 : state.dataIPShortCut->cAlphaArgs(1),
4265 : DataLoopNode::NodeFluidType::Water,
4266 : DataLoopNode::ConnectionType::Outlet,
4267 : NodeInputManager::CompFluidStream::Primary,
4268 : DataLoopNode::ObjectIsNotParent);
4269 2 : BranchNodeConnections::TestCompSet(state,
4270 1 : state.dataIPShortCut->cCurrentModuleObject,
4271 1 : state.dataIPShortCut->cAlphaArgs(1),
4272 1 : state.dataIPShortCut->cAlphaArgs(3),
4273 1 : state.dataIPShortCut->cAlphaArgs(4),
4274 : "Chilled Water Nodes");
4275 :
4276 1 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
4277 1 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
4278 : // Connection not required for air or evap cooled condenser
4279 : // If the condenser inlet is blank for air cooled and evap cooled condensers then supply a generic name
4280 : // since it is not used elsewhere for connection
4281 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
4282 0 : if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 21) { // protect against long name leading to > 100 chars
4283 0 : state.dataIPShortCut->cAlphaArgs(5) = state.dataIPShortCut->cAlphaArgs(1) + " CONDENSER INLET NODE";
4284 : } else {
4285 0 : state.dataIPShortCut->cAlphaArgs(5) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 79) + " CONDENSER INLET NODE";
4286 : }
4287 : }
4288 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
4289 0 : if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 22) { // protect against long name leading to > 100 chars
4290 0 : state.dataIPShortCut->cAlphaArgs(6) = state.dataIPShortCut->cAlphaArgs(1) + " CONDENSER OUTLET NODE";
4291 : } else {
4292 0 : state.dataIPShortCut->cAlphaArgs(6) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 78) + " CONDENSER OUTLET NODE";
4293 : }
4294 : }
4295 :
4296 0 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
4297 0 : state.dataIPShortCut->cAlphaArgs(5),
4298 : ErrorsFound,
4299 : DataLoopNode::ConnectionObjectType::ChillerCombustionTurbine,
4300 0 : state.dataIPShortCut->cAlphaArgs(1),
4301 : DataLoopNode::NodeFluidType::Air,
4302 : DataLoopNode::ConnectionType::OutsideAirReference,
4303 : NodeInputManager::CompFluidStream::Secondary,
4304 : DataLoopNode::ObjectIsNotParent);
4305 : bool Okay;
4306 0 : OutAirNodeManager::CheckAndAddAirNodeNumber(state, thisChiller.CondInletNodeNum, Okay);
4307 0 : if (!Okay) {
4308 0 : ShowWarningError(
4309 : state,
4310 0 : format("{}, Adding OutdoorAir:Node={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(5)));
4311 : }
4312 :
4313 0 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
4314 0 : state.dataIPShortCut->cAlphaArgs(6),
4315 : ErrorsFound,
4316 : DataLoopNode::ConnectionObjectType::ChillerCombustionTurbine,
4317 0 : state.dataIPShortCut->cAlphaArgs(1),
4318 : DataLoopNode::NodeFluidType::Air,
4319 : DataLoopNode::ConnectionType::Outlet,
4320 : NodeInputManager::CompFluidStream::Secondary,
4321 : DataLoopNode::ObjectIsNotParent);
4322 0 : } else { // WaterCooled CondenserType
4323 1 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
4324 1 : state.dataIPShortCut->cAlphaArgs(5),
4325 : ErrorsFound,
4326 : DataLoopNode::ConnectionObjectType::ChillerCombustionTurbine,
4327 1 : state.dataIPShortCut->cAlphaArgs(1),
4328 : DataLoopNode::NodeFluidType::Blank,
4329 : DataLoopNode::ConnectionType::Inlet,
4330 : NodeInputManager::CompFluidStream::Secondary,
4331 : DataLoopNode::ObjectIsNotParent);
4332 2 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
4333 1 : state.dataIPShortCut->cAlphaArgs(6),
4334 : ErrorsFound,
4335 : DataLoopNode::ConnectionObjectType::ChillerCombustionTurbine,
4336 1 : state.dataIPShortCut->cAlphaArgs(1),
4337 : DataLoopNode::NodeFluidType::Blank,
4338 : DataLoopNode::ConnectionType::Outlet,
4339 : NodeInputManager::CompFluidStream::Secondary,
4340 : DataLoopNode::ObjectIsNotParent);
4341 2 : BranchNodeConnections::TestCompSet(state,
4342 1 : state.dataIPShortCut->cCurrentModuleObject,
4343 1 : state.dataIPShortCut->cAlphaArgs(1),
4344 1 : state.dataIPShortCut->cAlphaArgs(5),
4345 1 : state.dataIPShortCut->cAlphaArgs(6),
4346 : "Condenser (unknown?) Nodes");
4347 : // Condenser Inlet node name is necessary for Water Cooled
4348 1 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
4349 0 : ShowSevereError(state, format("Invalid, {} is blank ", state.dataIPShortCut->cAlphaFieldNames(5)));
4350 0 : ShowContinueError(state,
4351 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4352 0 : ErrorsFound = true;
4353 1 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
4354 0 : ShowSevereError(state, format("Invalid, {} is blank ", state.dataIPShortCut->cAlphaFieldNames(6)));
4355 0 : ShowContinueError(state,
4356 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4357 0 : ErrorsFound = true;
4358 : }
4359 : }
4360 :
4361 1 : thisChiller.MinPartLoadRat = state.dataIPShortCut->rNumericArgs(3);
4362 1 : thisChiller.MaxPartLoadRat = state.dataIPShortCut->rNumericArgs(4);
4363 1 : thisChiller.OptPartLoadRat = state.dataIPShortCut->rNumericArgs(5);
4364 1 : thisChiller.TempDesCondIn = state.dataIPShortCut->rNumericArgs(6);
4365 1 : thisChiller.TempRiseCoef = state.dataIPShortCut->rNumericArgs(7);
4366 1 : thisChiller.TempDesEvapOut = state.dataIPShortCut->rNumericArgs(8);
4367 1 : thisChiller.EvapVolFlowRate = state.dataIPShortCut->rNumericArgs(9);
4368 1 : if (thisChiller.EvapVolFlowRate == DataSizing::AutoSize) {
4369 0 : thisChiller.EvapVolFlowRateWasAutoSized = true;
4370 : }
4371 :
4372 1 : thisChiller.CondVolFlowRate = state.dataIPShortCut->rNumericArgs(10);
4373 1 : if (thisChiller.CondVolFlowRate == DataSizing::AutoSize) {
4374 0 : if (thisChiller.CondenserType == DataPlant::CondenserType::WaterCooled) {
4375 0 : thisChiller.CondVolFlowRateWasAutoSized = true;
4376 : }
4377 : }
4378 1 : thisChiller.CapRatCoef(1) = state.dataIPShortCut->rNumericArgs(11);
4379 1 : thisChiller.CapRatCoef(2) = state.dataIPShortCut->rNumericArgs(12);
4380 1 : thisChiller.CapRatCoef(3) = state.dataIPShortCut->rNumericArgs(13);
4381 1 : if ((state.dataIPShortCut->rNumericArgs(11) + state.dataIPShortCut->rNumericArgs(12) + state.dataIPShortCut->rNumericArgs(13)) == 0.0) {
4382 0 : ShowSevereError(state,
4383 0 : format("{}: Sum of Capacity Ratio Coef = 0.0, chiller={}",
4384 0 : state.dataIPShortCut->cCurrentModuleObject,
4385 0 : state.dataIPShortCut->cAlphaArgs(1)));
4386 0 : ErrorsFound = true;
4387 : }
4388 1 : thisChiller.PowerRatCoef(1) = state.dataIPShortCut->rNumericArgs(14);
4389 1 : thisChiller.PowerRatCoef(2) = state.dataIPShortCut->rNumericArgs(15);
4390 1 : thisChiller.PowerRatCoef(3) = state.dataIPShortCut->rNumericArgs(16);
4391 1 : thisChiller.FullLoadCoef(1) = state.dataIPShortCut->rNumericArgs(17);
4392 1 : thisChiller.FullLoadCoef(2) = state.dataIPShortCut->rNumericArgs(18);
4393 1 : thisChiller.FullLoadCoef(3) = state.dataIPShortCut->rNumericArgs(19);
4394 1 : thisChiller.TempLowLimitEvapOut = state.dataIPShortCut->rNumericArgs(20);
4395 :
4396 : // Load Special GT Chiller Input
4397 :
4398 1 : thisChiller.PLBasedFuelInputCoef(1) = state.dataIPShortCut->rNumericArgs(21);
4399 1 : thisChiller.PLBasedFuelInputCoef(2) = state.dataIPShortCut->rNumericArgs(22);
4400 1 : thisChiller.PLBasedFuelInputCoef(3) = state.dataIPShortCut->rNumericArgs(23);
4401 :
4402 1 : thisChiller.TempBasedFuelInputCoef(1) = state.dataIPShortCut->rNumericArgs(24);
4403 1 : thisChiller.TempBasedFuelInputCoef(2) = state.dataIPShortCut->rNumericArgs(25);
4404 1 : thisChiller.TempBasedFuelInputCoef(3) = state.dataIPShortCut->rNumericArgs(26);
4405 :
4406 1 : thisChiller.ExhaustFlowCoef(1) = state.dataIPShortCut->rNumericArgs(27);
4407 1 : thisChiller.ExhaustFlowCoef(2) = state.dataIPShortCut->rNumericArgs(28);
4408 1 : thisChiller.ExhaustFlowCoef(3) = state.dataIPShortCut->rNumericArgs(29);
4409 :
4410 1 : thisChiller.PLBasedExhaustTempCoef(1) = state.dataIPShortCut->rNumericArgs(30);
4411 1 : thisChiller.PLBasedExhaustTempCoef(2) = state.dataIPShortCut->rNumericArgs(31);
4412 1 : thisChiller.PLBasedExhaustTempCoef(3) = state.dataIPShortCut->rNumericArgs(32);
4413 :
4414 1 : thisChiller.TempBasedExhaustTempCoef(1) = state.dataIPShortCut->rNumericArgs(33);
4415 1 : thisChiller.TempBasedExhaustTempCoef(2) = state.dataIPShortCut->rNumericArgs(34);
4416 1 : thisChiller.TempBasedExhaustTempCoef(3) = state.dataIPShortCut->rNumericArgs(35);
4417 :
4418 1 : thisChiller.HeatRecLubeEnergyCoef(1) = state.dataIPShortCut->rNumericArgs(36);
4419 1 : thisChiller.HeatRecLubeEnergyCoef(2) = state.dataIPShortCut->rNumericArgs(37);
4420 1 : thisChiller.HeatRecLubeEnergyCoef(3) = state.dataIPShortCut->rNumericArgs(38);
4421 :
4422 1 : thisChiller.UAtoCapCoef(1) = state.dataIPShortCut->rNumericArgs(39);
4423 1 : thisChiller.UAtoCapCoef(2) = state.dataIPShortCut->rNumericArgs(40);
4424 :
4425 1 : thisChiller.GTEngineCapacity = state.dataIPShortCut->rNumericArgs(41);
4426 1 : if (thisChiller.GTEngineCapacity == DataSizing::AutoSize) {
4427 0 : thisChiller.GTEngineCapacityWasAutoSized = true;
4428 : }
4429 1 : thisChiller.MaxExhaustperGTPower = state.dataIPShortCut->rNumericArgs(42);
4430 1 : thisChiller.DesignSteamSatTemp = state.dataIPShortCut->rNumericArgs(43);
4431 1 : thisChiller.FuelHeatingValue = state.dataIPShortCut->rNumericArgs(44);
4432 :
4433 : // Get the Heat Recovery information
4434 : // handle autosize
4435 1 : thisChiller.DesignHeatRecVolFlowRate = state.dataIPShortCut->rNumericArgs(45);
4436 1 : if (thisChiller.DesignHeatRecVolFlowRate > 0.0 || thisChiller.DesignHeatRecVolFlowRate == DataSizing::AutoSize) {
4437 0 : thisChiller.HeatRecActive = true;
4438 0 : thisChiller.HeatRecInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
4439 0 : state.dataIPShortCut->cAlphaArgs(7),
4440 : ErrorsFound,
4441 : DataLoopNode::ConnectionObjectType::ChillerCombustionTurbine,
4442 0 : state.dataIPShortCut->cAlphaArgs(1),
4443 : DataLoopNode::NodeFluidType::Water,
4444 : DataLoopNode::ConnectionType::Inlet,
4445 : NodeInputManager::CompFluidStream::Tertiary,
4446 : DataLoopNode::ObjectIsNotParent);
4447 0 : if (thisChiller.HeatRecInletNodeNum == 0) {
4448 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
4449 0 : ShowContinueError(state,
4450 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4451 0 : ErrorsFound = true;
4452 : }
4453 0 : thisChiller.HeatRecOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
4454 0 : state.dataIPShortCut->cAlphaArgs(8),
4455 : ErrorsFound,
4456 : DataLoopNode::ConnectionObjectType::ChillerCombustionTurbine,
4457 0 : state.dataIPShortCut->cAlphaArgs(1),
4458 : DataLoopNode::NodeFluidType::Water,
4459 : DataLoopNode::ConnectionType::Outlet,
4460 : NodeInputManager::CompFluidStream::Tertiary,
4461 : DataLoopNode::ObjectIsNotParent);
4462 0 : if (thisChiller.HeatRecOutletNodeNum == 0) {
4463 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
4464 0 : ShowContinueError(state,
4465 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4466 0 : ErrorsFound = true;
4467 : }
4468 0 : BranchNodeConnections::TestCompSet(state,
4469 0 : state.dataIPShortCut->cCurrentModuleObject,
4470 0 : state.dataIPShortCut->cAlphaArgs(1),
4471 0 : state.dataIPShortCut->cAlphaArgs(7),
4472 0 : state.dataIPShortCut->cAlphaArgs(8),
4473 : "Heat Recovery Nodes");
4474 :
4475 0 : if (thisChiller.DesignHeatRecVolFlowRate == DataSizing::AutoSize) {
4476 0 : thisChiller.DesignHeatRecVolFlowRateWasAutoSized = true;
4477 : } else {
4478 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, thisChiller.HeatRecInletNodeNum, thisChiller.DesignHeatRecVolFlowRate);
4479 : }
4480 :
4481 : // Condenser flow rate must be specified for heat reclaim, but Why couldn't this be okay??
4482 0 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
4483 0 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
4484 0 : if (thisChiller.CondVolFlowRate <= 0.0) {
4485 0 : ShowSevereError(
4486 0 : state, format("Invalid {}={:.6R}", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->rNumericArgs(10)));
4487 0 : ShowContinueError(state, "Condenser fluid flow rate must be specified for Heat Reclaim applications.");
4488 0 : ShowContinueError(
4489 0 : state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4490 0 : ErrorsFound = true;
4491 : }
4492 : }
4493 :
4494 : } else {
4495 1 : thisChiller.HeatRecActive = false;
4496 1 : thisChiller.DesignHeatRecMassFlowRate = 0.0;
4497 1 : thisChiller.HeatRecInletNodeNum = 0;
4498 1 : thisChiller.HeatRecOutletNodeNum = 0;
4499 1 : if ((!state.dataIPShortCut->lAlphaFieldBlanks(7)) || (!state.dataIPShortCut->lAlphaFieldBlanks(8))) {
4500 0 : ShowWarningError(state,
4501 0 : format("Since Design Heat Flow Rate = 0.0, Heat Recovery inactive for {}={}",
4502 0 : state.dataIPShortCut->cCurrentModuleObject,
4503 0 : state.dataIPShortCut->cAlphaArgs(1)));
4504 0 : ShowContinueError(state, "However, Node names were specified for heat recovery inlet or outlet nodes");
4505 : }
4506 1 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
4507 1 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
4508 0 : thisChiller.CondVolFlowRate = 0.0011; // set to avoid errors in calc routine
4509 : }
4510 : }
4511 :
4512 1 : thisChiller.FlowMode = static_cast<DataPlant::FlowMode>(getEnumValue(DataPlant::FlowModeNamesUC, state.dataIPShortCut->cAlphaArgs(9)));
4513 1 : if (thisChiller.FlowMode == DataPlant::FlowMode::Invalid) {
4514 0 : ShowSevereError(state,
4515 0 : format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4516 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
4517 0 : ShowContinueError(state, "Available choices are ConstantFlow, NotModulated, or LeavingSetpointModulated");
4518 0 : ShowContinueError(state, "Flow mode NotModulated is assumed and the simulation continues.");
4519 0 : thisChiller.FlowMode = DataPlant::FlowMode::NotModulated;
4520 : }
4521 :
4522 : // Fuel Type Case Statement
4523 1 : thisChiller.FuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(10)));
4524 1 : if (thisChiller.FuelType == Constant::eFuel::Invalid) {
4525 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10)));
4526 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
4527 0 : ShowContinueError(
4528 : state, "Valid choices are Electricity, NaturalGas, Propane, Diesel, Gasoline, FuelOilNo1, FuelOilNo2,OtherFuel1 or OtherFuel2");
4529 0 : ErrorsFound = true;
4530 : }
4531 :
4532 1 : thisChiller.HeatRecMaxTemp = state.dataIPShortCut->rNumericArgs(46);
4533 1 : thisChiller.SizFac = state.dataIPShortCut->rNumericArgs(47);
4534 1 : if (thisChiller.SizFac <= 0.0) thisChiller.SizFac = 1.0;
4535 :
4536 : // Basin heater power as a function of temperature must be greater than or equal to 0
4537 1 : thisChiller.BasinHeaterPowerFTempDiff = state.dataIPShortCut->rNumericArgs(48);
4538 1 : if (state.dataIPShortCut->rNumericArgs(48) < 0.0) {
4539 0 : ShowSevereError(state,
4540 0 : format("{}=\"{}\"{} must be >= 0",
4541 0 : state.dataIPShortCut->cCurrentModuleObject,
4542 0 : thisChiller.Name,
4543 0 : state.dataIPShortCut->cNumericFieldNames(48)));
4544 0 : ErrorsFound = true;
4545 : }
4546 :
4547 1 : thisChiller.BasinHeaterSetPointTemp = state.dataIPShortCut->rNumericArgs(49);
4548 :
4549 1 : if (thisChiller.BasinHeaterPowerFTempDiff > 0.0) {
4550 0 : if (NumNums < 49) {
4551 0 : thisChiller.BasinHeaterSetPointTemp = 2.0;
4552 : }
4553 0 : if (thisChiller.BasinHeaterSetPointTemp < 2.0) {
4554 0 : ShowWarningError(state,
4555 0 : format("{}:\"{}\", {} is less than 2 deg C. Freezing could occur.",
4556 0 : state.dataIPShortCut->cCurrentModuleObject,
4557 0 : thisChiller.Name,
4558 0 : state.dataIPShortCut->cNumericFieldNames(49)));
4559 : }
4560 : }
4561 :
4562 1 : if (state.dataIPShortCut->lAlphaFieldBlanks(11)) {
4563 0 : } else if ((thisChiller.basinHeaterSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(11))) == nullptr) {
4564 0 : ShowWarningItemNotFound(state,
4565 : eoh,
4566 0 : state.dataIPShortCut->cAlphaFieldNames(11),
4567 0 : state.dataIPShortCut->cAlphaArgs(11),
4568 : "Basin heater operation will not be modeled and the simulation continues");
4569 : }
4570 :
4571 1 : if (NumNums > 49) {
4572 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(50)) {
4573 0 : thisChiller.HeatRecCapacityFraction = state.dataIPShortCut->rNumericArgs(50);
4574 : } else {
4575 0 : thisChiller.HeatRecCapacityFraction = 1.0;
4576 : }
4577 : } else {
4578 1 : thisChiller.HeatRecCapacityFraction = 1.0;
4579 : }
4580 :
4581 1 : if (NumNums > 50) {
4582 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(51)) {
4583 0 : thisChiller.engineCapacityScalar = state.dataIPShortCut->rNumericArgs(51);
4584 : } else {
4585 0 : thisChiller.engineCapacityScalar = 0.35;
4586 : }
4587 : } else {
4588 1 : thisChiller.engineCapacityScalar = 0.35;
4589 : }
4590 : }
4591 :
4592 1 : if (ErrorsFound) {
4593 0 : ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
4594 : }
4595 : }
4596 :
4597 0 : void GTChillerSpecs::setupOutputVariables(EnergyPlusData &state)
4598 : {
4599 0 : SetupOutputVariable(state,
4600 : "Chiller Drive Shaft Power",
4601 : Constant::Units::W,
4602 0 : this->Power,
4603 : OutputProcessor::TimeStepType::System,
4604 : OutputProcessor::StoreType::Average,
4605 0 : this->Name);
4606 0 : SetupOutputVariable(state,
4607 : "Chiller Drive Shaft Energy",
4608 : Constant::Units::J,
4609 0 : this->Energy,
4610 : OutputProcessor::TimeStepType::System,
4611 : OutputProcessor::StoreType::Sum,
4612 0 : this->Name);
4613 0 : SetupOutputVariable(state,
4614 : "Chiller Evaporator Cooling Rate",
4615 : Constant::Units::W,
4616 0 : this->QEvaporator,
4617 : OutputProcessor::TimeStepType::System,
4618 : OutputProcessor::StoreType::Average,
4619 0 : this->Name);
4620 0 : SetupOutputVariable(state,
4621 : "Chiller Evaporator Cooling Energy",
4622 : Constant::Units::J,
4623 0 : this->EvaporatorEnergy,
4624 : OutputProcessor::TimeStepType::System,
4625 : OutputProcessor::StoreType::Sum,
4626 0 : this->Name,
4627 : Constant::eResource::EnergyTransfer,
4628 : OutputProcessor::Group::Plant,
4629 : OutputProcessor::EndUseCat::Chillers);
4630 0 : SetupOutputVariable(state,
4631 : "Chiller Evaporator Inlet Temperature",
4632 : Constant::Units::C,
4633 0 : this->EvapInletTemp,
4634 : OutputProcessor::TimeStepType::System,
4635 : OutputProcessor::StoreType::Average,
4636 0 : this->Name);
4637 0 : SetupOutputVariable(state,
4638 : "Chiller Evaporator Outlet Temperature",
4639 : Constant::Units::C,
4640 0 : this->EvapOutletTemp,
4641 : OutputProcessor::TimeStepType::System,
4642 : OutputProcessor::StoreType::Average,
4643 0 : this->Name);
4644 0 : SetupOutputVariable(state,
4645 : "Chiller Evaporator Mass Flow Rate",
4646 : Constant::Units::kg_s,
4647 0 : this->EvapMassFlowRate,
4648 : OutputProcessor::TimeStepType::System,
4649 : OutputProcessor::StoreType::Average,
4650 0 : this->Name);
4651 0 : SetupOutputVariable(state,
4652 : "Chiller Condenser Heat Transfer Rate",
4653 : Constant::Units::W,
4654 0 : this->QCondenser,
4655 : OutputProcessor::TimeStepType::System,
4656 : OutputProcessor::StoreType::Average,
4657 0 : this->Name);
4658 0 : SetupOutputVariable(state,
4659 : "Chiller Condenser Heat Transfer Energy",
4660 : Constant::Units::J,
4661 0 : this->CondenserEnergy,
4662 : OutputProcessor::TimeStepType::System,
4663 : OutputProcessor::StoreType::Sum,
4664 0 : this->Name,
4665 : Constant::eResource::EnergyTransfer,
4666 : OutputProcessor::Group::Plant,
4667 : OutputProcessor::EndUseCat::HeatRejection);
4668 :
4669 0 : SetupOutputVariable(state,
4670 : "Chiller Condenser Inlet Temperature",
4671 : Constant::Units::C,
4672 0 : this->CondInletTemp,
4673 : OutputProcessor::TimeStepType::System,
4674 : OutputProcessor::StoreType::Average,
4675 0 : this->Name);
4676 :
4677 : // Condenser mass flow and outlet temp are valid for water cooled
4678 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
4679 0 : SetupOutputVariable(state,
4680 : "Chiller Condenser Outlet Temperature",
4681 : Constant::Units::C,
4682 0 : this->CondOutletTemp,
4683 : OutputProcessor::TimeStepType::System,
4684 : OutputProcessor::StoreType::Average,
4685 0 : this->Name);
4686 0 : SetupOutputVariable(state,
4687 : "Chiller Condenser Mass Flow Rate",
4688 : Constant::Units::kg_s,
4689 0 : this->CondMassFlowRate,
4690 : OutputProcessor::TimeStepType::System,
4691 : OutputProcessor::StoreType::Average,
4692 0 : this->Name);
4693 0 : } else if (this->CondenserType == DataPlant::CondenserType::AirCooled) {
4694 0 : } else if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
4695 0 : if (this->BasinHeaterPowerFTempDiff > 0.0) {
4696 0 : SetupOutputVariable(state,
4697 : "Chiller Basin Heater Electricity Rate",
4698 : Constant::Units::W,
4699 0 : this->BasinHeaterPower,
4700 : OutputProcessor::TimeStepType::System,
4701 : OutputProcessor::StoreType::Average,
4702 0 : this->Name);
4703 0 : SetupOutputVariable(state,
4704 : "Chiller Basin Heater Electricity Energy",
4705 : Constant::Units::J,
4706 0 : this->BasinHeaterConsumption,
4707 : OutputProcessor::TimeStepType::System,
4708 : OutputProcessor::StoreType::Sum,
4709 0 : this->Name,
4710 : Constant::eResource::Electricity,
4711 : OutputProcessor::Group::Plant,
4712 : OutputProcessor::EndUseCat::Chillers);
4713 : }
4714 : }
4715 :
4716 0 : SetupOutputVariable(state,
4717 : "Chiller Lube Recovered Heat Rate",
4718 : Constant::Units::W,
4719 0 : this->HeatRecLubeRate,
4720 : OutputProcessor::TimeStepType::System,
4721 : OutputProcessor::StoreType::Average,
4722 0 : this->Name);
4723 0 : SetupOutputVariable(state,
4724 : "Chiller Lube Recovered Heat Energy",
4725 : Constant::Units::J,
4726 0 : this->HeatRecLubeEnergy,
4727 : OutputProcessor::TimeStepType::System,
4728 : OutputProcessor::StoreType::Sum,
4729 0 : this->Name,
4730 : Constant::eResource::EnergyTransfer,
4731 : OutputProcessor::Group::Plant,
4732 : OutputProcessor::EndUseCat::HeatRecovery);
4733 :
4734 0 : std::string_view const sFuelType = Constant::eFuelNames[static_cast<int>(this->FuelType)];
4735 0 : SetupOutputVariable(state,
4736 0 : format("Chiller {} Rate", sFuelType),
4737 : Constant::Units::W,
4738 0 : this->FuelEnergyUsedRate,
4739 : OutputProcessor::TimeStepType::System,
4740 : OutputProcessor::StoreType::Average,
4741 0 : this->Name);
4742 :
4743 0 : SetupOutputVariable(state,
4744 0 : format("Chiller {} Energy", sFuelType),
4745 : Constant::Units::J,
4746 0 : this->FuelEnergyUsed,
4747 : OutputProcessor::TimeStepType::System,
4748 : OutputProcessor::StoreType::Sum,
4749 0 : this->Name,
4750 0 : Constant::eFuel2eResource[(int)this->FuelType],
4751 : OutputProcessor::Group::Plant,
4752 : OutputProcessor::EndUseCat::Cooling);
4753 :
4754 0 : SetupOutputVariable(state,
4755 0 : format("Chiller {} Mass Flow Rate", sFuelType),
4756 : Constant::Units::kg_s,
4757 0 : this->FuelMassUsedRate,
4758 : OutputProcessor::TimeStepType::System,
4759 : OutputProcessor::StoreType::Average,
4760 0 : this->Name);
4761 0 : SetupOutputVariable(state,
4762 0 : format("Chiller {} Mass", sFuelType),
4763 : Constant::Units::kg,
4764 0 : this->FuelMassUsed,
4765 : OutputProcessor::TimeStepType::System,
4766 : OutputProcessor::StoreType::Sum,
4767 0 : this->Name);
4768 0 : SetupOutputVariable(state,
4769 : "Chiller Exhaust Temperature",
4770 : Constant::Units::C,
4771 0 : this->ExhaustStackTemp,
4772 : OutputProcessor::TimeStepType::System,
4773 : OutputProcessor::StoreType::Average,
4774 0 : this->Name);
4775 0 : SetupOutputVariable(state,
4776 : "Chiller Heat Recovery Inlet Temperature",
4777 : Constant::Units::C,
4778 0 : this->HeatRecInletTemp,
4779 : OutputProcessor::TimeStepType::System,
4780 : OutputProcessor::StoreType::Average,
4781 0 : this->Name);
4782 0 : SetupOutputVariable(state,
4783 : "Chiller Heat Recovery Outlet Temperature",
4784 : Constant::Units::C,
4785 0 : this->HeatRecOutletTemp,
4786 : OutputProcessor::TimeStepType::System,
4787 : OutputProcessor::StoreType::Average,
4788 0 : this->Name);
4789 0 : SetupOutputVariable(state,
4790 : "Chiller Heat Recovery Mass Flow Rate",
4791 : Constant::Units::kg_s,
4792 0 : this->HeatRecMdot,
4793 : OutputProcessor::TimeStepType::System,
4794 : OutputProcessor::StoreType::Average,
4795 0 : this->Name);
4796 0 : SetupOutputVariable(state,
4797 : "Chiller COP",
4798 : Constant::Units::W_W,
4799 0 : this->FuelCOP,
4800 : OutputProcessor::TimeStepType::System,
4801 : OutputProcessor::StoreType::Average,
4802 0 : this->Name);
4803 :
4804 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4805 0 : SetupEMSInternalVariable(state, "Chiller Nominal Capacity", this->Name, "[W]", this->NomCap);
4806 : }
4807 0 : }
4808 :
4809 0 : void GTChillerSpecs::initialize(EnergyPlusData &state, bool const RunFlag, Real64 const MyLoad)
4810 : {
4811 :
4812 : // SUBROUTINE INFORMATION:
4813 : // AUTHOR Fred Buhl
4814 : // DATE WRITTEN November 2003
4815 : // MODIFIED na
4816 : // RE-ENGINEERED na
4817 :
4818 : // PURPOSE OF THIS SUBROUTINE:
4819 : // This subroutine is for initializations of the Gas Turbine Chiller components
4820 :
4821 : // METHODOLOGY EMPLOYED:
4822 : // Uses the status flags to trigger initializations.
4823 :
4824 : // SUBROUTINE PARAMETER DEFINITIONS:
4825 : static constexpr std::string_view RoutineName("InitGTChiller");
4826 :
4827 0 : this->oneTimeInit(state);
4828 :
4829 0 : if (this->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
4830 :
4831 0 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
4832 :
4833 0 : this->EvapMassFlowRateMax = rho * this->EvapVolFlowRate;
4834 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->EvapMassFlowRateMax, this->EvapInletNodeNum, this->EvapOutletNodeNum);
4835 :
4836 : // init maximum available condenser flow rate
4837 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
4838 :
4839 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = this->TempDesCondIn;
4840 :
4841 0 : rho = this->CDPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
4842 :
4843 0 : this->CondMassFlowRateMax = rho * this->CondVolFlowRate;
4844 :
4845 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->CondMassFlowRateMax, this->CondInletNodeNum, this->CondOutletNodeNum);
4846 : } else { // air or evap-air
4847 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate =
4848 0 : this->CondVolFlowRate *
4849 0 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, this->TempDesCondIn, 0.0, RoutineName);
4850 :
4851 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
4852 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMaxAvail =
4853 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
4854 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
4855 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
4856 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMinAvail = 0.0;
4857 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMin = 0.0;
4858 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMinAvail = 0.0;
4859 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMin = 0.0;
4860 : }
4861 :
4862 0 : if (this->HeatRecActive) {
4863 0 : rho = this->HRPlantLoc.loop->glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
4864 0 : this->DesignHeatRecMassFlowRate = rho * this->DesignHeatRecVolFlowRate;
4865 :
4866 0 : PlantUtilities::InitComponentNodes(
4867 : state, 0.0, this->DesignHeatRecMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
4868 : }
4869 :
4870 0 : this->MyEnvrnFlag = false;
4871 : }
4872 :
4873 0 : if (!state.dataGlobal->BeginEnvrnFlag) {
4874 0 : this->MyEnvrnFlag = true;
4875 : }
4876 :
4877 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) && (this->ModulatedFlowSetToLoop)) {
4878 : // fix for clumsy old input that worked because loop setpoint was spread.
4879 : // could be removed with transition, testing , model change, period of being obsolete.
4880 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
4881 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
4882 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
4883 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
4884 : }
4885 :
4886 : Real64 mdot;
4887 : Real64 mdotCond;
4888 0 : if ((std::abs(MyLoad) > 0.0) && RunFlag) {
4889 0 : mdot = this->EvapMassFlowRateMax;
4890 0 : mdotCond = this->CondMassFlowRateMax;
4891 : } else {
4892 0 : mdot = 0.0;
4893 0 : mdotCond = 0.0;
4894 : }
4895 :
4896 0 : PlantUtilities::SetComponentFlowRate(state, mdot, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
4897 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
4898 0 : PlantUtilities::SetComponentFlowRate(state, mdotCond, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
4899 : }
4900 :
4901 : // Initialize heat recovery flow rates at node
4902 0 : if (this->HeatRecActive) {
4903 :
4904 0 : if (RunFlag) {
4905 0 : mdot = this->DesignHeatRecMassFlowRate;
4906 : } else {
4907 0 : mdot = 0.0;
4908 : }
4909 :
4910 0 : PlantUtilities::SetComponentFlowRate(state, mdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
4911 : }
4912 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
4913 0 : this->BasinHeaterPower = 0.0;
4914 : }
4915 0 : }
4916 :
4917 1 : void GTChillerSpecs::size(EnergyPlusData &state)
4918 : {
4919 :
4920 : // SUBROUTINE INFORMATION:
4921 : // AUTHOR Fred Buhl
4922 : // DATE WRITTEN June 2002
4923 : // MODIFIED November 2013 Daeho Kang, add component sizing table entries
4924 : // RE-ENGINEERED na
4925 :
4926 : // PURPOSE OF THIS SUBROUTINE:
4927 : // This subroutine is for sizing Gas Turbine Chiller Components for which capacities and flow rates
4928 : // have not been specified in the input.
4929 :
4930 : // METHODOLOGY EMPLOYED:
4931 : // Obtains evaporator flow rate from the plant sizing array. Calculates nominal capacity from
4932 : // the evaporator flow rate and the chilled water loop design delta T. The condenser flow rate
4933 : // is calculated from the nominal capacity, the COP, and the condenser loop design delta T.
4934 :
4935 : // SUBROUTINE PARAMETER DEFINITIONS:
4936 : static constexpr std::string_view RoutineName("SizeGTChiller");
4937 :
4938 1 : bool ErrorsFound = false;
4939 1 : Real64 tmpNomCap = this->NomCap;
4940 1 : Real64 tmpEvapVolFlowRate = this->EvapVolFlowRate;
4941 1 : Real64 tmpCondVolFlowRate = this->CondVolFlowRate;
4942 :
4943 1 : int PltSizCondNum(0); // Plant Sizing index for condenser loop
4944 1 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
4945 1 : PltSizCondNum = this->CDPlantLoc.loop->PlantSizNum;
4946 : }
4947 :
4948 1 : int PltSizNum = this->CWPlantLoc.loop->PlantSizNum;
4949 :
4950 1 : if (PltSizNum > 0) {
4951 1 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
4952 1 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
4953 1 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
4954 1 : tmpNomCap =
4955 1 : Cp * rho * state.dataSize->PlantSizData(PltSizNum).DeltaT * state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
4956 : } else {
4957 0 : if (this->NomCapWasAutoSized) tmpNomCap = 0.0;
4958 : }
4959 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4960 1 : if (this->NomCapWasAutoSized) {
4961 0 : this->NomCap = tmpNomCap;
4962 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4963 0 : BaseSizer::reportSizerOutput(state, "Chiller:CombustionTurbine", this->Name, "Design Size Nominal Capacity [W]", tmpNomCap);
4964 : }
4965 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4966 0 : BaseSizer::reportSizerOutput(
4967 : state, "Chiller:CombustionTurbine", this->Name, "Initial Design Size Nominal Capacity [W]", tmpNomCap);
4968 : }
4969 : } else {
4970 1 : if (this->NomCap > 0.0 && tmpNomCap > 0.0) {
4971 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4972 0 : BaseSizer::reportSizerOutput(state,
4973 : "Chiller:CombustionTurbine",
4974 : this->Name,
4975 : "Design Size Nominal Capacity [W]",
4976 : tmpNomCap,
4977 : "User-Specified Nominal Capacity [W]",
4978 0 : this->NomCap);
4979 0 : if (state.dataGlobal->DisplayExtraWarnings) {
4980 0 : if ((std::abs(tmpNomCap - this->NomCap) / this->NomCap) > state.dataSize->AutoVsHardSizingThreshold) {
4981 0 : ShowMessage(state, format("SizeGTChiller: Potential issue with equipment sizing for {}", this->Name));
4982 0 : ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", this->NomCap));
4983 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", tmpNomCap));
4984 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
4985 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
4986 : }
4987 : }
4988 : }
4989 1 : tmpNomCap = this->NomCap;
4990 : }
4991 : }
4992 : }
4993 : } else {
4994 0 : if (this->NomCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4995 0 : ShowSevereError(state, "Autosizing of Gas Turbine Chiller nominal capacity requires a loop Sizing:Plant object");
4996 0 : ShowContinueError(state, format("Occurs in Gas Turbine Chiller object={}", this->Name));
4997 0 : ErrorsFound = true;
4998 : }
4999 0 : if (!this->NomCapWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->NomCap > 0.0)) {
5000 0 : BaseSizer::reportSizerOutput(
5001 : state, "Chiller:CombustionTurbine", this->Name, "User-Specified Design Size Nominal Capacity [W]", this->NomCap);
5002 : }
5003 : }
5004 :
5005 1 : if (PltSizNum > 0) {
5006 1 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
5007 1 : tmpEvapVolFlowRate = state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
5008 : } else {
5009 0 : if (this->EvapVolFlowRateWasAutoSized) tmpEvapVolFlowRate = 0.0;
5010 : }
5011 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
5012 1 : if (this->EvapVolFlowRateWasAutoSized) {
5013 0 : this->EvapVolFlowRate = tmpEvapVolFlowRate;
5014 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
5015 0 : BaseSizer::reportSizerOutput(
5016 : state, "Chiller:CombustionTurbine", this->Name, "Design size Design Chilled Water Flow Rate [m3/s]", tmpEvapVolFlowRate);
5017 : }
5018 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
5019 0 : BaseSizer::reportSizerOutput(state,
5020 : "Chiller:CombustionTurbine",
5021 : this->Name,
5022 : "Initial Design size Design Chilled Water Flow Rate [m3/s]",
5023 : tmpEvapVolFlowRate);
5024 : }
5025 : } else {
5026 1 : if (this->EvapVolFlowRate > 0.0 && tmpEvapVolFlowRate > 0.0) {
5027 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
5028 0 : BaseSizer::reportSizerOutput(state,
5029 : "Chiller:CombustionTurbine",
5030 : this->Name,
5031 : "Design size Design Chilled Water Flow Rate [m3/s]",
5032 : tmpEvapVolFlowRate,
5033 : "User-Specified Design Chilled Water Flow Rate [m3/s]",
5034 0 : this->EvapVolFlowRate);
5035 0 : if (state.dataGlobal->DisplayExtraWarnings) {
5036 0 : if ((std::abs(tmpEvapVolFlowRate - this->EvapVolFlowRate) / this->EvapVolFlowRate) >
5037 0 : state.dataSize->AutoVsHardSizingThreshold) {
5038 0 : ShowMessage(state, format("SizeGTChiller: Potential issue with equipment sizing for {}", this->Name));
5039 0 : ShowContinueError(
5040 0 : state, format("User-Specified Design Chilled Water Flow Rate of {:.5R} [m3/s]", this->EvapVolFlowRate));
5041 0 : ShowContinueError(
5042 : state,
5043 0 : format("differs from Design Size Design Chilled Water Flow Rate of {:.5R} [m3/s]", tmpEvapVolFlowRate));
5044 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
5045 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
5046 : }
5047 : }
5048 : }
5049 1 : tmpEvapVolFlowRate = this->EvapVolFlowRate;
5050 : }
5051 : }
5052 : }
5053 : } else {
5054 0 : if (this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
5055 0 : ShowSevereError(state, "Autosizing of Gas Turbine Chiller evap flow rate requires a loop Sizing:Plant object");
5056 0 : ShowContinueError(state, format("Occurs in Gas Turbine Chiller object={}", this->Name));
5057 0 : ErrorsFound = true;
5058 : }
5059 0 : if (!this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->EvapVolFlowRate > 0.0)) {
5060 0 : BaseSizer::reportSizerOutput(
5061 : state, "Chiller:CombustionTurbine", this->Name, "User-Specified Design Chilled Water Flow Rate [m3/s]", this->EvapVolFlowRate);
5062 : }
5063 : }
5064 :
5065 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->EvapInletNodeNum, tmpEvapVolFlowRate);
5066 :
5067 1 : if (PltSizCondNum > 0 && PltSizNum > 0) {
5068 0 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow && tmpNomCap > 0.0) {
5069 0 : Real64 rho = this->CDPlantLoc.loop->glycol->getDensity(state, this->TempDesCondIn, RoutineName);
5070 0 : Real64 Cp = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, this->TempDesCondIn, RoutineName);
5071 0 : tmpCondVolFlowRate = tmpNomCap * (1.0 + 1.0 / this->COP) / (state.dataSize->PlantSizData(PltSizCondNum).DeltaT * Cp * rho);
5072 : } else {
5073 0 : if (this->CondVolFlowRateWasAutoSized) tmpCondVolFlowRate = 0.0;
5074 : }
5075 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
5076 0 : if (this->CondVolFlowRateWasAutoSized) {
5077 0 : this->CondVolFlowRate = tmpCondVolFlowRate;
5078 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
5079 0 : BaseSizer::reportSizerOutput(state,
5080 : "Chiller:CombustionTurbine",
5081 : this->Name,
5082 : "Design Size Design Condenser Water Flow Rate [m3/s]",
5083 : tmpCondVolFlowRate);
5084 : }
5085 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
5086 0 : BaseSizer::reportSizerOutput(state,
5087 : "Chiller:CombustionTurbine",
5088 : this->Name,
5089 : "Initial Design Size Design Condenser Water Flow Rate [m3/s]",
5090 : tmpCondVolFlowRate);
5091 : }
5092 : } else {
5093 0 : if (this->CondVolFlowRate > 0.0 && tmpCondVolFlowRate > 0.0) {
5094 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
5095 0 : BaseSizer::reportSizerOutput(state,
5096 : "Chiller:CombustionTurbine",
5097 : this->Name,
5098 : "Design Size Design Condenser Water Flow Rate [m3/s]",
5099 : tmpCondVolFlowRate,
5100 : "User-Specified Design Condenser Water Flow Rate [m3/s]",
5101 0 : this->CondVolFlowRate);
5102 0 : if (state.dataGlobal->DisplayExtraWarnings) {
5103 0 : if ((std::abs(tmpCondVolFlowRate - this->CondVolFlowRate) / this->CondVolFlowRate) >
5104 0 : state.dataSize->AutoVsHardSizingThreshold) {
5105 0 : ShowMessage(state, format("SizeGTChiller: Potential issue with equipment sizing for {}", this->Name));
5106 0 : ShowContinueError(
5107 0 : state, format("User-Specified Design Condenser Water Flow Rate of {:.5R} [m3/s]", this->CondVolFlowRate));
5108 0 : ShowContinueError(
5109 : state,
5110 0 : format("differs from Design Size Design Condenser Water Flow Rate of {:.5R} [m3/s]", tmpCondVolFlowRate));
5111 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
5112 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
5113 : }
5114 : }
5115 : }
5116 0 : tmpCondVolFlowRate = this->CondVolFlowRate;
5117 : }
5118 : }
5119 : }
5120 0 : } else {
5121 1 : if (this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
5122 0 : ShowSevereError(state, "Autosizing of Gas Turbine Chiller condenser flow rate requires a condenser");
5123 0 : ShowContinueError(state, "loop Sizing:Plant object");
5124 0 : ShowContinueError(state, format("Occurs in Gas Turbine Chiller object={}", this->Name));
5125 0 : ErrorsFound = true;
5126 : }
5127 1 : if (!this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->CondVolFlowRate > 0.0)) {
5128 0 : BaseSizer::reportSizerOutput(
5129 : state, "Chiller:CombustionTurbine", this->Name, "User-Specified Design Condenser Water Flow Rate [m3/s]", this->CondVolFlowRate);
5130 : }
5131 : }
5132 : // save the design condenser water volumetric flow rate for use by the condenser water loop sizing algorithms
5133 1 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled)
5134 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->CondInletNodeNum, tmpCondVolFlowRate);
5135 :
5136 1 : Real64 GTEngineCapacityDes = this->NomCap / (this->engineCapacityScalar * this->COP);
5137 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
5138 1 : if (this->GTEngineCapacityWasAutoSized) {
5139 0 : this->GTEngineCapacity = GTEngineCapacityDes;
5140 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
5141 0 : BaseSizer::reportSizerOutput(
5142 : state, "Chiller:CombustionTurbine", this->Name, "Design Size Gas Turbine Engine Capacity [W]", GTEngineCapacityDes);
5143 : }
5144 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
5145 0 : BaseSizer::reportSizerOutput(
5146 : state, "Chiller:CombustionTurbine", this->Name, "Initial Design Size Gas Turbine Engine Capacity [W]", GTEngineCapacityDes);
5147 : }
5148 : } else {
5149 1 : if (this->GTEngineCapacity > 0.0 && GTEngineCapacityDes > 0.0) {
5150 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
5151 0 : BaseSizer::reportSizerOutput(state,
5152 : "Chiller:CombustionTurbine",
5153 : this->Name,
5154 : "Design Size Gas Turbine Engine Capacity [W]",
5155 : GTEngineCapacityDes,
5156 : "User-Specified Gas Turbine Engine Capacity [W]",
5157 0 : this->GTEngineCapacity);
5158 : }
5159 0 : if (state.dataGlobal->DisplayExtraWarnings) {
5160 0 : if ((std::abs(GTEngineCapacityDes - this->GTEngineCapacity) / this->GTEngineCapacity) >
5161 0 : state.dataSize->AutoVsHardSizingThreshold) {
5162 0 : ShowMessage(state, format("SizeGTChiller: Potential issue with equipment sizing for {}", this->Name));
5163 0 : ShowContinueError(state, format("User-Specified Gas Turbine Engine Capacity of {:.2R} [W]", this->GTEngineCapacity));
5164 0 : ShowContinueError(state,
5165 0 : format("differs from Design Size Gas Turbine Engine Capacity of {:.2R} [W]", GTEngineCapacityDes));
5166 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
5167 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
5168 : }
5169 : }
5170 : }
5171 : }
5172 : }
5173 :
5174 : // autosize support for heat recovery flow rate.
5175 1 : if (this->HeatRecActive) {
5176 1 : Real64 tmpHeatRecVolFlowRate = this->CondVolFlowRate * this->HeatRecCapacityFraction;
5177 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
5178 1 : if (this->DesignHeatRecVolFlowRateWasAutoSized) {
5179 1 : this->DesignHeatRecVolFlowRate = tmpHeatRecVolFlowRate;
5180 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
5181 0 : BaseSizer::reportSizerOutput(state,
5182 : "Chiller:CombustionTurbine",
5183 : this->Name,
5184 : "Design Size Design Heat Recovery Fluid Flow Rate [m3/s]",
5185 : tmpHeatRecVolFlowRate);
5186 : }
5187 1 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
5188 0 : BaseSizer::reportSizerOutput(state,
5189 : "Chiller:CombustionTurbine",
5190 : this->Name,
5191 : "Initial Design Size Design Heat Recovery Fluid Flow Rate [m3/s]",
5192 : tmpHeatRecVolFlowRate);
5193 : }
5194 : } else {
5195 0 : if (this->DesignHeatRecVolFlowRate > 0.0 && tmpHeatRecVolFlowRate > 0.0) {
5196 0 : Real64 DesignHeatRecVolFlowRateUser = this->DesignHeatRecVolFlowRate;
5197 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
5198 0 : if (state.dataGlobal->DoPlantSizing) {
5199 0 : BaseSizer::reportSizerOutput(state,
5200 : "Chiller:CombustionTurbine",
5201 : this->Name,
5202 : "Design Size Design Heat Recovery Fluid Flow Rate [m3/s]",
5203 : tmpHeatRecVolFlowRate,
5204 : "User-Specified Design Heat Recovery Fluid Flow Rate [m3/s]",
5205 : DesignHeatRecVolFlowRateUser);
5206 : } else {
5207 0 : BaseSizer::reportSizerOutput(state,
5208 : "Chiller:CombustionTurbine",
5209 : this->Name,
5210 : "User-Specified Design Heat Recovery Fluid Flow Rate [m3/s]",
5211 : DesignHeatRecVolFlowRateUser);
5212 : }
5213 0 : if (state.dataGlobal->DisplayExtraWarnings) {
5214 0 : if ((std::abs(tmpHeatRecVolFlowRate - DesignHeatRecVolFlowRateUser) / DesignHeatRecVolFlowRateUser) >
5215 0 : state.dataSize->AutoVsHardSizingThreshold) {
5216 0 : ShowMessage(state, format("SizeGasTurbineChiller: Potential issue with equipment sizing for {}", this->Name));
5217 0 : ShowContinueError(
5218 : state,
5219 0 : format("User-Specified Design Heat Recovery Fluid Flow Rate of {:.5R} [m3/s]", DesignHeatRecVolFlowRateUser));
5220 0 : ShowContinueError(state,
5221 0 : format("differs from Design Size Design Heat Recovery Fluid Flow Rate of {:.5R} [m3/s]",
5222 : tmpHeatRecVolFlowRate));
5223 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
5224 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
5225 : }
5226 : }
5227 : }
5228 0 : tmpHeatRecVolFlowRate = DesignHeatRecVolFlowRateUser;
5229 : }
5230 : }
5231 : }
5232 1 : if (!this->DesignHeatRecVolFlowRateWasAutoSized) tmpHeatRecVolFlowRate = this->DesignHeatRecVolFlowRate;
5233 : // save the reference heat recovery fluid volumetric flow rate
5234 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->HeatRecInletNodeNum, tmpHeatRecVolFlowRate);
5235 : }
5236 :
5237 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
5238 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "Chiller:CombustionTurbine");
5239 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomEff, this->Name, this->COP);
5240 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->NomCap);
5241 :
5242 : // std 229 new Chillers table
5243 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerType, this->Name, "Chiller:CombustionTurbine");
5244 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefCap, this->Name, this->NomCap);
5245 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEff, this->Name, this->COP); // Eff == COP?
5246 0 : OutputReportPredefined::PreDefTableEntry(
5247 0 : state, state.dataOutRptPredefined->pdchChillerRatedCap, this->Name, this->NomCap); // did not find rated cap
5248 0 : OutputReportPredefined::PreDefTableEntry(
5249 0 : state, state.dataOutRptPredefined->pdchChillerRatedEff, this->Name, this->COP); // did not find rated eff or cop ; also Eff == COP?
5250 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinSI, this->Name, "N/A");
5251 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinIP, this->Name, "N/A");
5252 0 : OutputReportPredefined::PreDefTableEntry(state,
5253 0 : state.dataOutRptPredefined->pdchChillerPlantloopName,
5254 : this->Name,
5255 0 : (this->CWPlantLoc.loop != nullptr) ? this->CWPlantLoc.loop->Name : "N/A");
5256 0 : OutputReportPredefined::PreDefTableEntry(state,
5257 0 : state.dataOutRptPredefined->pdchChillerPlantloopBranchName,
5258 : this->Name,
5259 0 : (this->CWPlantLoc.branch != nullptr) ? this->CWPlantLoc.branch->Name : "N/A");
5260 0 : OutputReportPredefined::PreDefTableEntry(state,
5261 0 : state.dataOutRptPredefined->pdchChillerCondLoopName,
5262 : this->Name,
5263 0 : (this->CDPlantLoc.loop != nullptr) ? this->CDPlantLoc.loop->Name : "N/A");
5264 0 : OutputReportPredefined::PreDefTableEntry(state,
5265 0 : state.dataOutRptPredefined->pdchChillerCondLoopBranchName,
5266 : this->Name,
5267 0 : (this->CDPlantLoc.branch != nullptr) ? this->CDPlantLoc.branch->Name : "N/A");
5268 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerMinPLR, this->Name, this->MinPartLoadRat);
5269 0 : OutputReportPredefined::PreDefTableEntry( // Shouldn't this be eFuelNames?
5270 : state,
5271 0 : state.dataOutRptPredefined->pdchChillerFuelType,
5272 : this->Name,
5273 0 : Constant::eResourceNames[static_cast<int>(this->FuelType)]);
5274 0 : OutputReportPredefined::PreDefTableEntry(
5275 0 : state, state.dataOutRptPredefined->pdchChillerRatedEntCondTemp, this->Name, this->TempDesCondIn); // Rated==Ref?
5276 0 : OutputReportPredefined::PreDefTableEntry(
5277 0 : state, state.dataOutRptPredefined->pdchChillerRatedLevEvapTemp, this->Name, this->TempDesEvapOut); // Rated==Ref?
5278 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEntCondTemp, this->Name, this->TempDesCondIn);
5279 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefLevEvapTemp, this->Name, this->TempDesEvapOut);
5280 :
5281 0 : OutputReportPredefined::PreDefTableEntry(state,
5282 0 : state.dataOutRptPredefined->pdchChillerDesSizeRefCHWFlowRate,
5283 : this->Name,
5284 : this->EvapMassFlowRateMax); // flowrate Max==DesignSizeRef flowrate?
5285 0 : OutputReportPredefined::PreDefTableEntry(state,
5286 0 : state.dataOutRptPredefined->pdchChillerDesSizeRefCondFluidFlowRate,
5287 : this->Name,
5288 : this->CondMassFlowRateMax); // Cond flowrate Max==DesignSizeRef Cond flowrate?
5289 0 : OutputReportPredefined::PreDefTableEntry(state,
5290 0 : state.dataOutRptPredefined->pdchChillerHeatRecPlantloopName,
5291 : this->Name,
5292 0 : (this->HRPlantLoc.loop != nullptr) ? this->HRPlantLoc.loop->Name : "N/A");
5293 0 : OutputReportPredefined::PreDefTableEntry(state,
5294 0 : state.dataOutRptPredefined->pdchChillerHeatRecPlantloopBranchName,
5295 : this->Name,
5296 0 : (this->HRPlantLoc.branch != nullptr) ? this->HRPlantLoc.branch->Name : "N/A");
5297 0 : OutputReportPredefined::PreDefTableEntry(
5298 0 : state, state.dataOutRptPredefined->pdchChillerRecRelCapFrac, this->Name, this->HeatRecCapacityFraction);
5299 : }
5300 :
5301 1 : if (ErrorsFound) {
5302 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
5303 : }
5304 1 : }
5305 :
5306 0 : void GTChillerSpecs::calculate(EnergyPlusData &state, Real64 &MyLoad, bool const RunFlag, DataBranchAirLoopPlant::ControlType const EquipFlowCtrl)
5307 : {
5308 : // SUBROUTINE INFORMATION:
5309 : // AUTHOR Dan Fisher / Brandon Anderson
5310 : // DATE WRITTEN Sept. 2000
5311 : // MODIFIED Feb. 2010, Chandan Sharma, FSEC. Added basin heater
5312 : // Jun. 2016, Rongpeng Zhang, LBNL. Applied the chiller supply water temperature sensor fault model
5313 : // Nov. 2016, Rongpeng Zhang, LBNL. Added Fouling Chiller fault
5314 : // RE-ENGINEERED na
5315 :
5316 : // PURPOSE OF THIS SUBROUTINE:
5317 : // simulate a vapor compression chiller using the GT model
5318 :
5319 : // METHODOLOGY EMPLOYED:
5320 : // curve fit of performance data:
5321 :
5322 : // REFERENCES:
5323 : // 1. BLAST Users Manual
5324 : // 2. CHILLER User Manual
5325 :
5326 0 : Real64 constexpr ExhaustCP(1.047); // Exhaust Gas Specific Heat
5327 : static constexpr std::string_view RoutineName("CalcGTChillerModel");
5328 : static constexpr std::string_view RoutineNameHeatRecovery("ChillerHeatRecovery");
5329 :
5330 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5331 0 : Real64 EvapDeltaTemp(0.0); // C - evaporator temperature difference, water side
5332 0 : Real64 PartLoadRat(0.0); // part load ratio for efficiency calculations
5333 0 : Real64 fuelEnergyIn(0.0); // (EFUEL) Amount of Fuel Energy Required to run gas turbine
5334 0 : Real64 HeatRecOutTemp(0.0); // Heat Recovery Fluid Outlet Temperature
5335 0 : Real64 heatRecMdot(0.0); // Heat Recovery Fluid Mass FlowRate
5336 :
5337 : // set module level inlet and outlet nodes
5338 0 : this->EvapMassFlowRate = 0.0;
5339 0 : this->CondMassFlowRate = 0.0;
5340 0 : this->Power = 0.0;
5341 0 : this->QCondenser = 0.0;
5342 0 : this->QEvaporator = 0.0;
5343 0 : this->Energy = 0.0;
5344 0 : this->CondenserEnergy = 0.0;
5345 0 : this->EvaporatorEnergy = 0.0;
5346 0 : this->HeatRecLubeRate = 0.0;
5347 0 : this->ExhaustStackTemp = 0.0;
5348 :
5349 : // calculate end time of current time step
5350 0 : Real64 CurrentEndTime = state.dataGlobal->CurrentTime + state.dataHVACGlobal->SysTimeElapsed;
5351 :
5352 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
5353 : // Wait for next time step to print warnings. If simulation iterates, print out
5354 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
5355 : // If a warning occurs and the simulation down shifts, the warning is not valid.
5356 0 : if (CurrentEndTime > this->CurrentEndTimeLast && state.dataHVACGlobal->TimeStepSys >= this->TimeStepSysLast) {
5357 0 : if (this->PrintMessage) {
5358 0 : ++this->MsgErrorCount;
5359 : // Show single warning and pass additional info to ShowRecurringWarningErrorAtEnd
5360 0 : if (this->MsgErrorCount < 2) {
5361 0 : ShowWarningError(state, format("{}.", this->MsgBuffer1));
5362 0 : ShowContinueError(state, this->MsgBuffer2);
5363 : } else {
5364 0 : ShowRecurringWarningErrorAtEnd(
5365 0 : state, this->MsgBuffer1 + " error continues.", this->ErrCount1, this->MsgDataLast, this->MsgDataLast, _, "[C]", "[C]");
5366 : }
5367 : }
5368 : }
5369 :
5370 : // save last system time step and last end time of current time step (used to determine if warning is valid)
5371 0 : this->TimeStepSysLast = state.dataHVACGlobal->TimeStepSys;
5372 0 : this->CurrentEndTimeLast = CurrentEndTime;
5373 :
5374 : // If Chiller load is 0 or chiller is not running then leave the subroutine.Before leaving
5375 : // if the component control is SERIESACTIVE we set the component flow to inlet flow so that
5376 : // flow resolver will not shut down the branch
5377 0 : if (MyLoad >= 0.0 || !RunFlag) {
5378 0 : if (EquipFlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive ||
5379 0 : this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Locked) {
5380 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
5381 : } else {
5382 0 : this->EvapMassFlowRate = 0.0;
5383 :
5384 0 : PlantUtilities::SetComponentFlowRate(
5385 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
5386 : }
5387 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
5388 0 : if (DataPlant::CompData::getPlantComponent(state, this->CDPlantLoc).FlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive) {
5389 0 : this->CondMassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
5390 : } else {
5391 0 : this->CondMassFlowRate = 0.0;
5392 0 : PlantUtilities::SetComponentFlowRate(
5393 0 : state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
5394 : }
5395 : }
5396 :
5397 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
5398 0 : CalcBasinHeaterPower(
5399 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
5400 : }
5401 0 : this->PrintMessage = false;
5402 0 : return;
5403 : }
5404 :
5405 0 : if (this->CondenserType == DataPlant::CondenserType::AirCooled) { // Condenser inlet temp = outdoor temp
5406 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirDryBulb;
5407 : // Warn user if entering condenser temperature falls below 0C
5408 0 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 0.0 && !state.dataGlobal->WarmupFlag) {
5409 0 : this->PrintMessage = true;
5410 : this->MsgBuffer1 =
5411 0 : "CalcGasTurbineChillerModel - Chiller:CombustionTurbine \"" + this->Name + "\" - Air Cooled Condenser Inlet Temperature below 0C";
5412 0 : this->MsgBuffer2 = format("... Outdoor Dry-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
5413 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
5414 0 : state.dataEnvrn->EnvironmentName,
5415 0 : state.dataEnvrn->CurMnDy,
5416 0 : General::CreateSysTimeIntervalString(state));
5417 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
5418 : } else {
5419 0 : this->PrintMessage = false;
5420 : }
5421 0 : } else if (this->CondenserType == DataPlant::CondenserType::EvapCooled) { // Condenser inlet temp = (outdoor wet bulb)
5422 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirWetBulb;
5423 : // Warn user if evap condenser wet bulb temperature falls below 10C
5424 0 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 10.0 && !state.dataGlobal->WarmupFlag) {
5425 0 : this->PrintMessage = true;
5426 0 : this->MsgBuffer1 = "CalcGasTurbineChillerModel - Chiller:CombustionTurbine \"" + this->Name +
5427 0 : "\" - Evap Cooled Condenser Inlet Temperature below 10C";
5428 0 : this->MsgBuffer2 = format("... Outdoor Wet-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
5429 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
5430 0 : state.dataEnvrn->EnvironmentName,
5431 0 : state.dataEnvrn->CurMnDy,
5432 0 : General::CreateSysTimeIntervalString(state));
5433 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
5434 : } else {
5435 0 : this->PrintMessage = false;
5436 : }
5437 : } // End of the Air Cooled/Evap Cooled Logic block
5438 :
5439 : // If not air or evap cooled then set to the condenser node that is attached to a cooling tower
5440 0 : Real64 condInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
5441 :
5442 : // Set mass flow rates
5443 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
5444 0 : this->CondMassFlowRate = this->CondMassFlowRateMax;
5445 0 : PlantUtilities::SetComponentFlowRate(state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
5446 0 : PlantUtilities::PullCompInterconnectTrigger(
5447 0 : state, this->CWPlantLoc, this->CondMassFlowIndex, this->CDPlantLoc, DataPlant::CriteriaType::MassFlowRate, this->CondMassFlowRate);
5448 :
5449 0 : if (this->CondMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance) {
5450 0 : MyLoad = 0.0;
5451 0 : this->EvapMassFlowRate = 0.0;
5452 0 : PlantUtilities::SetComponentFlowRate(
5453 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
5454 0 : return;
5455 : }
5456 : }
5457 :
5458 : // LOAD LOCAL VARIABLES FROM DATA STRUCTURE (for code readability)
5459 0 : Real64 ChillerNomCap = this->NomCap;
5460 0 : Real64 COP = this->COP;
5461 0 : Real64 TempCondIn = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
5462 0 : Real64 TempEvapOut = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
5463 :
5464 : // If there is a fault of chiller fouling
5465 0 : if (this->FaultyChillerFoulingFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
5466 0 : (!state.dataGlobal->KickOffSimulation)) {
5467 0 : int FaultIndex = this->FaultyChillerFoulingIndex;
5468 0 : Real64 NomCap_ff = ChillerNomCap;
5469 0 : Real64 COP_ff = COP;
5470 :
5471 : // calculate the Faulty Chiller Fouling Factor using fault information
5472 0 : this->FaultyChillerFoulingFactor = state.dataFaultsMgr->FaultsChillerFouling(FaultIndex).CalFoulingFactor(state);
5473 :
5474 : // update the Chiller nominal capacity and COP at faulty cases
5475 0 : ChillerNomCap = NomCap_ff * this->FaultyChillerFoulingFactor;
5476 0 : COP = COP_ff * this->FaultyChillerFoulingFactor;
5477 : }
5478 :
5479 : // If there is a fault of Chiller SWT Sensor
5480 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
5481 0 : (!state.dataGlobal->KickOffSimulation)) {
5482 0 : int FaultIndex = this->FaultyChillerSWTIndex;
5483 0 : Real64 EvapOutletTemp_ff = TempEvapOut;
5484 :
5485 : // calculate the sensor offset using fault information
5486 0 : this->FaultyChillerSWTOffset = state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex).CalFaultOffsetAct(state);
5487 : // update the TempEvapOut
5488 0 : TempEvapOut = max(this->TempLowLimitEvapOut,
5489 0 : min(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, EvapOutletTemp_ff - this->FaultyChillerSWTOffset));
5490 0 : this->FaultyChillerSWTOffset = EvapOutletTemp_ff - TempEvapOut;
5491 : }
5492 :
5493 : // Calculate chiller performance from this set of performance equations.
5494 0 : Real64 DeltaTemp = (TempCondIn - this->TempDesCondIn) / this->TempRiseCoef - (TempEvapOut - this->TempDesEvapOut);
5495 0 : Real64 AvailNomCapRat = this->CapRatCoef(1) + this->CapRatCoef(2) * DeltaTemp + this->CapRatCoef(3) * pow_2(DeltaTemp);
5496 0 : Real64 AvailChillerCap = ChillerNomCap * AvailNomCapRat;
5497 0 : Real64 FullLoadPowerRat = this->PowerRatCoef(1) + this->PowerRatCoef(2) * AvailNomCapRat + this->PowerRatCoef(3) * pow_2(AvailNomCapRat);
5498 :
5499 0 : if (AvailChillerCap > 0.0) {
5500 0 : PartLoadRat = max(this->MinPartLoadRat, min(std::abs(MyLoad) / AvailChillerCap, this->MaxPartLoadRat));
5501 : }
5502 :
5503 0 : Real64 FracFullLoadPower = this->FullLoadCoef(1) + this->FullLoadCoef(2) * PartLoadRat + this->FullLoadCoef(3) * pow_2(PartLoadRat);
5504 : Real64 OperPartLoadRat; // Actual Operating PLR
5505 0 : if (AvailChillerCap > 0.0) {
5506 0 : if (std::abs(MyLoad) / AvailChillerCap < this->MinPartLoadRat) {
5507 0 : OperPartLoadRat = std::abs(MyLoad) / AvailChillerCap;
5508 : } else {
5509 0 : OperPartLoadRat = PartLoadRat;
5510 : }
5511 : } else {
5512 0 : OperPartLoadRat = 0.0;
5513 : }
5514 :
5515 0 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, RoutineName);
5516 : // If FlowLock is True, the new resolved mdot is used to update Power, QEvap, Qcond, and
5517 : // condenser side outlet temperature.
5518 0 : if (this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Unlocked) {
5519 0 : this->PossibleSubcooling = false;
5520 0 : this->QEvaporator = AvailChillerCap * OperPartLoadRat;
5521 : Real64 FRAC;
5522 0 : if (OperPartLoadRat < this->MinPartLoadRat) {
5523 0 : FRAC = min(1.0, (OperPartLoadRat / this->MinPartLoadRat));
5524 : } else {
5525 0 : FRAC = 1.0;
5526 : }
5527 0 : this->Power = FracFullLoadPower * FullLoadPowerRat * AvailChillerCap / COP * FRAC;
5528 :
5529 : // Either set the flow to the Constant value or calculate the flow for the variable volume
5530 0 : if ((this->FlowMode == DataPlant::FlowMode::Constant) || (this->FlowMode == DataPlant::FlowMode::NotModulated)) {
5531 : // Start by assuming max (design) flow
5532 0 : this->EvapMassFlowRate = this->EvapMassFlowRateMax;
5533 : // Use SetComponentFlowRate to decide actual flow
5534 0 : PlantUtilities::SetComponentFlowRate(
5535 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
5536 : // Evaluate delta temp based on actual flow rate
5537 0 : if (this->EvapMassFlowRate != 0.0) {
5538 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
5539 : } else {
5540 0 : EvapDeltaTemp = 0.0;
5541 : }
5542 : // Evaluate outlet temp based on delta
5543 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
5544 0 : } else if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
5545 : // Calculate the Delta Temp from the inlet temp to the chiller outlet setpoint
5546 0 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
5547 0 : EvapDeltaTemp =
5548 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
5549 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
5550 0 : EvapDeltaTemp =
5551 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
5552 : }
5553 0 : if (EvapDeltaTemp != 0.0) {
5554 : // Calculate desired flow to request based on load
5555 0 : this->EvapMassFlowRate = std::abs(this->QEvaporator / Cp / EvapDeltaTemp);
5556 0 : if ((this->EvapMassFlowRate - this->EvapMassFlowRateMax) > DataBranchAirLoopPlant::MassFlowTolerance)
5557 0 : this->PossibleSubcooling = true;
5558 : // Check to see if the Maximum is exceeded, if so set to maximum
5559 0 : this->EvapMassFlowRate = min(this->EvapMassFlowRateMax, this->EvapMassFlowRate);
5560 : // Use SetComponentFlowRate to decide actual flow
5561 0 : PlantUtilities::SetComponentFlowRate(
5562 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
5563 0 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
5564 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
5565 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
5566 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
5567 : }
5568 : } else {
5569 : // Try to request zero flow
5570 0 : this->EvapMassFlowRate = 0.0;
5571 : // Use SetComponentFlowRate to decide actual flow
5572 0 : PlantUtilities::SetComponentFlowRate(
5573 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
5574 : // No deltaT since component is not running
5575 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
5576 : }
5577 : } // End of Constant Variable Flow If Block
5578 :
5579 : // If there is a fault of Chiller SWT Sensor
5580 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
5581 0 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
5582 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
5583 0 : int FaultIndex = this->FaultyChillerSWTIndex;
5584 0 : bool VarFlowFlag = (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated);
5585 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
5586 0 : .CalFaultChillerSWT(VarFlowFlag,
5587 : this->FaultyChillerSWTOffset,
5588 : Cp,
5589 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
5590 0 : this->EvapOutletTemp,
5591 0 : this->EvapMassFlowRate,
5592 0 : this->QEvaporator);
5593 : }
5594 :
5595 : } else { // If FlowLock is True
5596 :
5597 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
5598 0 : PlantUtilities::SetComponentFlowRate(state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
5599 : // Some other component set the flow to 0. No reason to continue with calculations.
5600 0 : if (this->EvapMassFlowRate == 0.0) {
5601 0 : MyLoad = 0.0;
5602 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
5603 0 : CalcBasinHeaterPower(
5604 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
5605 : }
5606 0 : this->PrintMessage = false;
5607 0 : return;
5608 : }
5609 :
5610 0 : if (this->PossibleSubcooling) {
5611 0 : this->QEvaporator = std::abs(MyLoad);
5612 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
5613 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
5614 : } else { // No subcooling in this case.No recalculation required.Still need to check chiller low temp limit
5615 0 : Real64 TempEvapOutSetPoint = 0.0; // C - evaporator outlet temperature setpoint
5616 0 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
5617 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
5618 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased ||
5619 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint != DataLoopNode::SensedNodeFlagValue)) {
5620 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
5621 : } else {
5622 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
5623 : }
5624 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
5625 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
5626 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased ||
5627 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi != DataLoopNode::SensedNodeFlagValue)) {
5628 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
5629 : } else {
5630 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
5631 : }
5632 : }
5633 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - TempEvapOutSetPoint;
5634 0 : this->QEvaporator = std::abs(this->EvapMassFlowRate * Cp * EvapDeltaTemp);
5635 0 : this->EvapOutletTemp = TempEvapOutSetPoint;
5636 : }
5637 : // Check that the Evap outlet temp honors both plant loop temp low limit and also the chiller low limit
5638 0 : if (this->EvapOutletTemp < this->TempLowLimitEvapOut) {
5639 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->TempLowLimitEvapOut) > DataPlant::DeltaTempTol) {
5640 0 : this->EvapOutletTemp = this->TempLowLimitEvapOut;
5641 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
5642 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
5643 : } else {
5644 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
5645 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
5646 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
5647 : }
5648 : }
5649 0 : if (this->EvapOutletTemp < state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) {
5650 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) >
5651 : DataPlant::DeltaTempTol) {
5652 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin;
5653 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
5654 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
5655 : } else {
5656 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
5657 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
5658 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
5659 : }
5660 : }
5661 : // If load exceeds the distributed load set to the distributed load
5662 0 : if (this->QEvaporator > std::abs(MyLoad)) {
5663 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
5664 0 : this->QEvaporator = std::abs(MyLoad);
5665 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
5666 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
5667 : } else {
5668 0 : this->QEvaporator = 0.0;
5669 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
5670 : }
5671 : }
5672 :
5673 : // If there is a fault of Chiller SWT Sensor
5674 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
5675 0 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
5676 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
5677 0 : int FaultIndex = this->FaultyChillerSWTIndex;
5678 0 : bool VarFlowFlag = false;
5679 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
5680 0 : .CalFaultChillerSWT(VarFlowFlag,
5681 : this->FaultyChillerSWTOffset,
5682 : Cp,
5683 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
5684 0 : this->EvapOutletTemp,
5685 0 : this->EvapMassFlowRate,
5686 0 : this->QEvaporator);
5687 : }
5688 :
5689 : // Checks QEvaporator on the basis of the machine limits.
5690 0 : if (this->QEvaporator > (AvailChillerCap * this->MaxPartLoadRat)) {
5691 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
5692 0 : this->QEvaporator = AvailChillerCap * PartLoadRat;
5693 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
5694 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
5695 : } else {
5696 0 : this->QEvaporator = 0.0;
5697 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
5698 : }
5699 : }
5700 :
5701 : Real64 FRAC;
5702 0 : if (OperPartLoadRat < this->MinPartLoadRat) {
5703 0 : FRAC = min(1.0, (OperPartLoadRat / this->MinPartLoadRat));
5704 : } else {
5705 0 : FRAC = 1.0;
5706 : }
5707 :
5708 : // Chiller is false loading below PLR = minimum unloading ratio, find PLR used for energy calculation
5709 0 : this->Power = FracFullLoadPower * FullLoadPowerRat * AvailChillerCap / COP * FRAC;
5710 :
5711 0 : if (this->EvapMassFlowRate == 0.0) {
5712 0 : this->QEvaporator = 0.0;
5713 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
5714 0 : this->Power = 0.0;
5715 0 : this->PrintMessage = false;
5716 : }
5717 0 : if (this->QEvaporator == 0.0 && this->CondenserType == DataPlant::CondenserType::EvapCooled) {
5718 0 : CalcBasinHeaterPower(
5719 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
5720 : }
5721 :
5722 : } // This is the end of the FlowLock Block
5723 :
5724 : // Now determine Cooling
5725 : // QCondenser is calculated the same for each type, but the power consumption should be different
5726 : // depending on the performance coefficients used for the chiller model.
5727 0 : this->QCondenser = this->Power + this->QEvaporator;
5728 :
5729 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
5730 :
5731 0 : if (this->CondMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
5732 0 : Real64 CpCond = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, condInletTemp, RoutineName);
5733 0 : this->CondOutletTemp = this->QCondenser / this->CondMassFlowRate / CpCond + condInletTemp;
5734 : } else {
5735 0 : ShowSevereError(state, format("CalcGasTurbineChillerModel: Condenser flow = 0, for GasTurbineChiller={}", this->Name));
5736 0 : ShowContinueErrorTimeStamp(state, "");
5737 : }
5738 :
5739 : } else { // Air Cooled or Evap Cooled
5740 :
5741 : // don't care about outlet temp for Air-Cooled or Evap Cooled and there is no CondMassFlowRate and would divide by zero
5742 0 : this->CondOutletTemp = condInletTemp;
5743 : }
5744 :
5745 : // Gas Turbine Driven Portion of the Chiller:
5746 :
5747 : Real64 RPLoad;
5748 0 : if (AvailChillerCap > 0) {
5749 0 : RPLoad = this->Power / AvailChillerCap;
5750 : } else {
5751 0 : RPLoad = 0.0;
5752 : }
5753 :
5754 0 : if (this->Power > 0) {
5755 0 : Real64 PLoad = ChillerNomCap * RPLoad;
5756 0 : Real64 RL = max(PLoad / ChillerNomCap, this->MinPartLoadRat);
5757 0 : Real64 RL2 = pow_2(RL);
5758 :
5759 : // ??? Not sure about this Ambient Actual Temp - also do we need to have design ambient as input?
5760 :
5761 : Real64 AmbientDeltaT; // (ATAIR) Difference between ambient actual and ambient design temperatures
5762 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
5763 0 : AmbientDeltaT = state.dataEnvrn->OutDryBulbTemp - 25.0;
5764 : } else { // air or evap cooled
5765 0 : AmbientDeltaT = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirDryBulb - 25.0;
5766 : }
5767 :
5768 0 : fuelEnergyIn = PLoad * (this->PLBasedFuelInputCoef(1) + this->PLBasedFuelInputCoef(2) * RL + this->PLBasedFuelInputCoef(3) * RL2) *
5769 0 : (this->TempBasedFuelInputCoef(1) + this->TempBasedFuelInputCoef(2) * AmbientDeltaT +
5770 0 : this->TempBasedFuelInputCoef(3) * pow_2(AmbientDeltaT));
5771 :
5772 : // (FEX) Exhaust Gas Flow Rate cubic meters per second
5773 0 : Real64 const exhaustFlow = this->GTEngineCapacity * (this->ExhaustFlowCoef(1) + this->ExhaustFlowCoef(2) * AmbientDeltaT +
5774 0 : this->ExhaustFlowCoef(3) * pow_2(AmbientDeltaT));
5775 :
5776 : // (TEX) Exhaust Gas Temperature in C
5777 : Real64 const exhaustTemp =
5778 0 : (this->PLBasedExhaustTempCoef(1) + this->PLBasedExhaustTempCoef(2) * RL + this->PLBasedExhaustTempCoef(3) * RL2) *
5779 0 : (this->TempBasedExhaustTempCoef(1) + this->TempBasedExhaustTempCoef(2) * AmbientDeltaT +
5780 0 : this->TempBasedExhaustTempCoef(3) * pow_2(AmbientDeltaT)) -
5781 0 : 273;
5782 :
5783 0 : if (PLoad != 0.0) {
5784 0 : Real64 UAtoCapRatLocal = this->UAtoCapCoef(1) * std::pow(this->GTEngineCapacity, this->UAtoCapCoef(2));
5785 0 : this->ExhaustStackTemp =
5786 0 : this->DesignSteamSatTemp +
5787 0 : (exhaustTemp - this->DesignSteamSatTemp) /
5788 0 : std::exp(UAtoCapRatLocal / (max(exhaustFlow, this->MaxExhaustperGTPower * this->GTEngineCapacity) * ExhaustCP));
5789 : }
5790 :
5791 0 : if (this->HeatRecActive) {
5792 0 : this->HeatRecLubeRate =
5793 0 : PLoad * (this->HeatRecLubeEnergyCoef(1) + this->HeatRecLubeEnergyCoef(2) * RL + this->HeatRecLubeEnergyCoef(3) * RL2);
5794 :
5795 : } else {
5796 0 : this->HeatRecLubeRate = 0.0;
5797 : }
5798 :
5799 : // Heat Recovery Loop - lube recovered heat
5800 : // If lube is not present, then the energy should be 0 at this point
5801 : // Thigh = Energy / (Mdot*Cp) + Tlow
5802 :
5803 0 : if (this->HeatRecActive) {
5804 : // This mdot is input specified mdot "Desired Flowrate", already set at node in init routine
5805 0 : heatRecMdot = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
5806 0 : this->HeatRecInletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
5807 0 : Real64 HeatRecCp = this->HRPlantLoc.loop->glycol->getSpecificHeat(state, this->HeatRecInletTemp, RoutineNameHeatRecovery);
5808 :
5809 : // Don't divide by zero
5810 0 : if ((heatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
5811 0 : HeatRecOutTemp = (this->HeatRecLubeRate) / (heatRecMdot * HeatRecCp) + this->HeatRecInletTemp;
5812 : } else {
5813 0 : HeatRecOutTemp = this->HeatRecInletTemp;
5814 : }
5815 :
5816 : // Set HeatRecRatio to 1.0 if not modified
5817 0 : Real64 HeatRecRatio = 1.0;
5818 :
5819 : // Now verify that the design flowrate was large enough to prevent phase change
5820 0 : if (HeatRecOutTemp > this->HeatRecMaxTemp) {
5821 0 : Real64 MinHeatRecMdot(0.0); // Mass Flow rate that keeps from exceeding max temp
5822 0 : if (this->HeatRecMaxTemp != this->HeatRecInletTemp) {
5823 0 : MinHeatRecMdot = (this->HeatRecLubeRate) / (HeatRecCp * (this->HeatRecMaxTemp - this->HeatRecInletTemp));
5824 0 : if (MinHeatRecMdot < 0.0) {
5825 0 : MinHeatRecMdot = 0.0;
5826 : }
5827 : }
5828 :
5829 : // Recalculate Outlet Temperature, with adjusted flowrate
5830 0 : if ((MinHeatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
5831 0 : HeatRecOutTemp = (this->HeatRecLubeRate) / (MinHeatRecMdot * HeatRecCp) + this->HeatRecInletTemp;
5832 0 : HeatRecRatio = heatRecMdot / MinHeatRecMdot;
5833 : } else {
5834 0 : HeatRecOutTemp = this->HeatRecInletTemp;
5835 0 : HeatRecRatio = 0.0;
5836 : }
5837 : }
5838 :
5839 0 : this->HeatRecLubeRate *= HeatRecRatio;
5840 : } else {
5841 0 : this->HeatRecInletTemp = 0.0;
5842 0 : heatRecMdot = 0.0;
5843 0 : HeatRecOutTemp = 0.0;
5844 : }
5845 : }
5846 :
5847 0 : this->HeatRecOutletTemp = HeatRecOutTemp;
5848 0 : this->HeatRecMdot = heatRecMdot;
5849 0 : this->HeatRecLubeEnergy = this->HeatRecLubeRate * (state.dataHVACGlobal->TimeStepSysSec);
5850 0 : this->FuelEnergyIn = std::abs(fuelEnergyIn);
5851 0 : this->FuelMassUsedRate = std::abs(fuelEnergyIn) / (this->FuelHeatingValue * KJtoJ);
5852 :
5853 : // Calculate Energy
5854 0 : this->CondenserEnergy = this->QCondenser * state.dataHVACGlobal->TimeStepSysSec;
5855 0 : this->Energy = this->Power * state.dataHVACGlobal->TimeStepSysSec;
5856 0 : this->EvaporatorEnergy = this->QEvaporator * state.dataHVACGlobal->TimeStepSysSec;
5857 :
5858 : // check for problems BG 9/12/06 (deal with observed negative energy results)
5859 0 : if (this->Energy < 0.0) { // there is a serious problem
5860 :
5861 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
5862 : // first check for run away condenser loop temps (only reason yet to be observed for this?)
5863 0 : if (condInletTemp > 70.0) {
5864 0 : ShowSevereError(state, format("CalcGTChillerModel: Condenser loop inlet temperatures over 70.0 C for GTChiller={}", this->Name));
5865 0 : ShowContinueErrorTimeStamp(state, "");
5866 0 : ShowContinueError(state, format("Condenser loop water temperatures are too high at{:.2R}", condInletTemp));
5867 0 : ShowContinueError(state, "Check input for condenser plant loop, especially cooling tower");
5868 0 : ShowContinueError(state, format("Evaporator inlet temperature: {:.2R}", state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp));
5869 :
5870 0 : ShowFatalError(state, "Program Terminates due to previous error condition");
5871 : }
5872 : }
5873 0 : if (!state.dataGlobal->WarmupFlag) {
5874 0 : if (AvailNomCapRat < 0.0) { // apparently the real reason energy goes negative
5875 0 : ShowSevereError(state, format("CalcGTChillerModel: Capacity ratio below zero for GTChiller={}", this->Name));
5876 0 : ShowContinueErrorTimeStamp(state, "");
5877 0 : ShowContinueError(state, "Check input for Capacity Ratio Curve");
5878 0 : ShowContinueError(state, format("Condenser inlet temperature: {:.2R}", condInletTemp));
5879 0 : ShowContinueError(state, format("Evaporator inlet temperature: {:.2R}", state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp));
5880 0 : ShowFatalError(state, "Program Terminates due to previous error condition");
5881 : }
5882 : }
5883 : // If makes it here, set limits, chiller can't have negative energy/power
5884 : // proceeding silently for now but may want to throw error here
5885 0 : this->Power = 0.0;
5886 0 : this->Energy = 0.0;
5887 : }
5888 : }
5889 :
5890 0 : void GTChillerSpecs::update(EnergyPlusData &state, Real64 const MyLoad, bool const RunFlag)
5891 : {
5892 : // SUBROUTINE INFORMATION:
5893 : // AUTHOR: Dan Fisher / Brandon Anderson
5894 : // DATE WRITTEN: September 2000
5895 :
5896 0 : Real64 const ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
5897 :
5898 0 : if (MyLoad >= 0.0 || !RunFlag) { // Chiller not running so pass inlet states to outlet states
5899 : // set node temperatures
5900 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
5901 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
5902 :
5903 0 : if (this->HeatRecActive) {
5904 0 : PlantUtilities::SafeCopyPlantNode(state, this->HeatRecOutletNodeNum, this->HeatRecInletNodeNum);
5905 0 : this->HeatRecInletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
5906 0 : this->HeatRecOutletTemp = state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp;
5907 : }
5908 :
5909 0 : this->Power = 0.0;
5910 0 : this->QEvaporator = 0.0;
5911 0 : this->QCondenser = 0.0;
5912 0 : this->Energy = 0.0;
5913 0 : this->EvaporatorEnergy = 0.0;
5914 0 : this->CondenserEnergy = 0.0;
5915 0 : this->EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
5916 0 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
5917 0 : this->CondOutletTemp = state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp;
5918 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
5919 0 : this->FuelEnergyUsedRate = 0.0;
5920 0 : this->FuelMassUsedRate = 0.0;
5921 0 : this->FuelEnergyUsed = 0.0;
5922 0 : this->FuelMassUsed = 0.0;
5923 :
5924 0 : this->HeatRecLubeEnergy = 0.0;
5925 0 : this->HeatRecLubeRate = 0.0;
5926 0 : this->ExhaustStackTemp = 0.0;
5927 0 : this->FuelCOP = 0.0;
5928 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
5929 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
5930 : }
5931 :
5932 : } else { // Chiller is running so report calculated values
5933 : // set node temperatures
5934 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = this->EvapOutletTemp;
5935 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = this->CondOutletTemp;
5936 :
5937 0 : if (this->HeatRecActive) {
5938 0 : PlantUtilities::SafeCopyPlantNode(state, this->HeatRecOutletNodeNum, this->HeatRecInletNodeNum);
5939 0 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = this->HeatRecOutletTemp;
5940 : }
5941 :
5942 0 : this->EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
5943 0 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
5944 0 : this->CondOutletTemp = state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp;
5945 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
5946 :
5947 0 : this->FuelEnergyUsedRate = this->FuelEnergyIn;
5948 0 : this->FuelEnergyUsed = this->FuelEnergyUsedRate * state.dataHVACGlobal->TimeStepSysSec;
5949 0 : this->FuelMassUsed = this->FuelMassUsedRate * state.dataHVACGlobal->TimeStepSysSec;
5950 0 : if (this->FuelEnergyUsedRate != 0.0) {
5951 0 : this->FuelCOP = this->QEvaporator / this->FuelEnergyUsedRate;
5952 : } else {
5953 0 : this->FuelCOP = 0.0;
5954 : }
5955 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
5956 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
5957 : }
5958 : }
5959 0 : }
5960 0 : void GTChillerSpecs::oneTimeInit(EnergyPlusData &state)
5961 : {
5962 : // Init more variables
5963 0 : if (this->MyFlag) {
5964 : // Locate the chillers on the plant loops for later usage
5965 0 : bool errFlag = false;
5966 0 : this->setupOutputVariables(state);
5967 0 : PlantUtilities::ScanPlantLoopsForObject(
5968 0 : state, this->Name, this->ChillerType, this->CWPlantLoc, errFlag, this->TempLowLimitEvapOut, _, _, this->EvapInletNodeNum, _);
5969 0 : if (this->CondenserType != DataPlant::CondenserType::AirCooled && this->CondenserType != DataPlant::CondenserType::EvapCooled) {
5970 0 : PlantUtilities::ScanPlantLoopsForObject(
5971 0 : state, this->Name, this->ChillerType, this->CDPlantLoc, errFlag, _, _, _, this->CondInletNodeNum, _);
5972 0 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CWPlantLoc, this->CDPlantLoc, this->ChillerType, true);
5973 : }
5974 0 : if (this->HeatRecActive) {
5975 0 : PlantUtilities::ScanPlantLoopsForObject(
5976 0 : state, this->Name, this->ChillerType, this->HRPlantLoc, errFlag, _, _, _, this->HeatRecInletNodeNum, _);
5977 0 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CWPlantLoc, this->HRPlantLoc, this->ChillerType, true);
5978 : }
5979 :
5980 0 : if (this->CondenserType != DataPlant::CondenserType::AirCooled && this->CondenserType != DataPlant::CondenserType::EvapCooled &&
5981 0 : this->HeatRecActive) {
5982 0 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CDPlantLoc, this->HRPlantLoc, this->ChillerType, false);
5983 : }
5984 0 : if (errFlag) {
5985 0 : ShowFatalError(state, "InitGTChiller: Program terminated due to previous condition(s).");
5986 : }
5987 :
5988 0 : if (this->FlowMode == DataPlant::FlowMode::Constant) {
5989 : // reset flow priority
5990 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
5991 : }
5992 :
5993 0 : if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
5994 : // reset flow priority
5995 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
5996 :
5997 : // check if setpoint on outlet node
5998 0 : if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
5999 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == DataLoopNode::SensedNodeFlagValue)) {
6000 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
6001 0 : if (!this->ModulatedFlowErrDone) {
6002 0 : ShowWarningError(state,
6003 0 : format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
6004 0 : ShowContinueError(
6005 : state,
6006 : " A temperature setpoint is needed at the outlet node of a chiller in variable flow mode, use a SetpointManager");
6007 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
6008 0 : this->ModulatedFlowErrDone = true;
6009 : }
6010 : } else {
6011 : // need call to EMS to check node
6012 0 : bool FatalError = false; // but not really fatal yet, but should be.
6013 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->EvapOutletNodeNum, HVAC::CtrlVarType::Temp, FatalError);
6014 0 : state.dataLoopNodes->NodeSetpointCheck(this->EvapOutletNodeNum).needsSetpointChecking = false;
6015 0 : if (FatalError) {
6016 0 : if (!this->ModulatedFlowErrDone) {
6017 0 : ShowWarningError(
6018 0 : state, format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
6019 0 : ShowContinueError(
6020 : state, " A temperature setpoint is needed at the outlet node of a chiller evaporator in variable flow mode");
6021 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the chiller evaporator outlet node ");
6022 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the outlet node ");
6023 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
6024 0 : this->ModulatedFlowErrDone = true;
6025 : }
6026 : }
6027 : }
6028 0 : this->ModulatedFlowSetToLoop = true;
6029 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
6030 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
6031 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
6032 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
6033 : }
6034 : }
6035 0 : this->MyFlag = false;
6036 : }
6037 0 : }
6038 :
6039 0 : ConstCOPChillerSpecs *ConstCOPChillerSpecs::factory(EnergyPlusData &state, std::string const &chillerName)
6040 : {
6041 : // GET INPUT
6042 0 : if (state.dataPlantChillers->GetConstCOPInput) {
6043 0 : ConstCOPChillerSpecs::getInput(state);
6044 0 : state.dataPlantChillers->GetConstCOPInput = false;
6045 : }
6046 0 : for (auto &thisChiller : state.dataPlantChillers->ConstCOPChiller) {
6047 0 : if (Util::makeUPPER(thisChiller.Name) == chillerName) {
6048 0 : return &thisChiller;
6049 : }
6050 : }
6051 0 : ShowFatalError(state, format("Could not locate constant COP chiller with name: {}", chillerName));
6052 0 : return nullptr;
6053 : }
6054 :
6055 0 : void ConstCOPChillerSpecs::simulate(
6056 : EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, bool RunFlag)
6057 : {
6058 0 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) {
6059 0 : this->initialize(state, RunFlag, CurLoad);
6060 0 : this->calculate(state, CurLoad, RunFlag, this->CWPlantLoc.comp->FlowCtrl);
6061 0 : this->update(state, CurLoad, RunFlag);
6062 0 : } else if (calledFromLocation.loopNum == this->CDPlantLoc.loopNum) {
6063 0 : PlantUtilities::UpdateChillerComponentCondenserSide(state,
6064 : this->CDPlantLoc.loopNum,
6065 : this->CDPlantLoc.loopSideNum,
6066 : this->ChillerType,
6067 : this->CondInletNodeNum,
6068 : this->CondOutletNodeNum,
6069 : this->QCondenser,
6070 : this->CondInletTemp,
6071 : this->CondOutletTemp,
6072 : this->CondMassFlowRate,
6073 : FirstHVACIteration);
6074 : }
6075 0 : }
6076 :
6077 2 : void ConstCOPChillerSpecs::getInput(EnergyPlusData &state)
6078 : {
6079 : // SUBROUTINE INFORMATION:
6080 : // AUTHOR: Dan Fisher
6081 : // DATE WRITTEN: April 1998
6082 :
6083 : // PURPOSE OF THIS SUBROUTINE:!This routine will get the input
6084 : // required by the PrimaryPlantLoopManager. As such
6085 : // it will interact with the Input Scanner to retrieve
6086 : // information from the input file, count the number of
6087 : // heating and cooling loops and begin to fill the
6088 : // arrays associated with the type PlantLoopProps.
6089 :
6090 : // SUBROUTINE PARAMETER DEFINITIONS:
6091 : static constexpr std::string_view RoutineName("GetConstCOPChillerInput: "); // include trailing blank space
6092 : static constexpr std::string_view routineName = "GetConstCOPChillerInput"; // include trailing blank space
6093 :
6094 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6095 : int NumAlphas; // Number of elements in the alpha array
6096 : int NumNums; // Number of elements in the numeric array
6097 : int IOStat; // IO Status when calling get input subroutine
6098 2 : bool ErrorsFound(false);
6099 :
6100 : // GET NUMBER OF ALL EQUIPMENT TYPES
6101 2 : state.dataIPShortCut->cCurrentModuleObject = "Chiller:ConstantCOP";
6102 4 : state.dataPlantChillers->NumConstCOPChillers =
6103 2 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
6104 :
6105 2 : if (state.dataPlantChillers->NumConstCOPChillers <= 0) {
6106 0 : ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
6107 0 : ErrorsFound = true;
6108 : }
6109 :
6110 : // See if load distribution manager has already gotten the input
6111 2 : if (allocated(state.dataPlantChillers->ConstCOPChiller)) return;
6112 :
6113 2 : state.dataPlantChillers->ConstCOPChiller.allocate(state.dataPlantChillers->NumConstCOPChillers);
6114 :
6115 : // LOAD ARRAYS WITH BLAST ConstCOP CHILLER DATA
6116 6 : for (int ChillerNum = 1; ChillerNum <= state.dataPlantChillers->NumConstCOPChillers; ++ChillerNum) {
6117 12 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6118 4 : state.dataIPShortCut->cCurrentModuleObject,
6119 : ChillerNum,
6120 4 : state.dataIPShortCut->cAlphaArgs,
6121 : NumAlphas,
6122 4 : state.dataIPShortCut->rNumericArgs,
6123 : NumNums,
6124 : IOStat,
6125 : _,
6126 4 : state.dataIPShortCut->lAlphaFieldBlanks,
6127 4 : state.dataIPShortCut->cAlphaFieldNames,
6128 4 : state.dataIPShortCut->cNumericFieldNames);
6129 :
6130 4 : ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
6131 4 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
6132 :
6133 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
6134 4 : GlobalNames::VerifyUniqueChillerName(state,
6135 4 : state.dataIPShortCut->cCurrentModuleObject,
6136 4 : state.dataIPShortCut->cAlphaArgs(1),
6137 : ErrorsFound,
6138 8 : state.dataIPShortCut->cCurrentModuleObject + " Name");
6139 :
6140 4 : auto &thisChiller = state.dataPlantChillers->ConstCOPChiller(ChillerNum);
6141 4 : thisChiller.Name = state.dataIPShortCut->cAlphaArgs(1);
6142 4 : thisChiller.ChillerType = DataPlant::PlantEquipmentType::Chiller_ConstCOP;
6143 4 : thisChiller.NomCap = state.dataIPShortCut->rNumericArgs(1);
6144 4 : if (thisChiller.NomCap == DataSizing::AutoSize) {
6145 4 : thisChiller.NomCapWasAutoSized = true;
6146 : }
6147 4 : if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
6148 0 : ShowSevereError(state,
6149 0 : format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
6150 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
6151 0 : ErrorsFound = true;
6152 : }
6153 4 : thisChiller.COP = state.dataIPShortCut->rNumericArgs(2);
6154 4 : if (state.dataIPShortCut->rNumericArgs(2) == 0.0) {
6155 0 : ShowSevereError(state,
6156 0 : format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
6157 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
6158 0 : ErrorsFound = true;
6159 : }
6160 :
6161 : // Set the Condenser Type from input
6162 4 : if (state.dataIPShortCut->cAlphaArgs(6) == "AIRCOOLED") {
6163 1 : thisChiller.CondenserType = DataPlant::CondenserType::AirCooled;
6164 3 : } else if (state.dataIPShortCut->cAlphaArgs(6) == "EVAPORATIVELYCOOLED") {
6165 1 : thisChiller.CondenserType = DataPlant::CondenserType::EvapCooled;
6166 2 : } else if (state.dataIPShortCut->cAlphaArgs(6) == "WATERCOOLED") {
6167 2 : thisChiller.CondenserType = DataPlant::CondenserType::WaterCooled;
6168 : } else {
6169 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
6170 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
6171 0 : ErrorsFound = true;
6172 : }
6173 :
6174 4 : thisChiller.EvapVolFlowRate = state.dataIPShortCut->rNumericArgs(3);
6175 4 : if (thisChiller.EvapVolFlowRate == DataSizing::AutoSize) {
6176 4 : thisChiller.EvapVolFlowRateWasAutoSized = true;
6177 : }
6178 4 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
6179 3 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) { // Condenser flow rate not used for these cond types
6180 2 : thisChiller.CondVolFlowRate = 0.0011;
6181 : } else {
6182 2 : thisChiller.CondVolFlowRate = state.dataIPShortCut->rNumericArgs(4);
6183 2 : if (thisChiller.CondVolFlowRate == DataSizing::AutoSize) {
6184 2 : if (thisChiller.CondenserType == DataPlant::CondenserType::WaterCooled) {
6185 2 : thisChiller.CondVolFlowRateWasAutoSized = true;
6186 : }
6187 : }
6188 : }
6189 4 : thisChiller.SizFac = state.dataIPShortCut->rNumericArgs(5);
6190 :
6191 4 : thisChiller.EvapInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
6192 4 : state.dataIPShortCut->cAlphaArgs(2),
6193 : ErrorsFound,
6194 : DataLoopNode::ConnectionObjectType::ChillerConstantCOP,
6195 4 : state.dataIPShortCut->cAlphaArgs(1),
6196 : DataLoopNode::NodeFluidType::Water,
6197 : DataLoopNode::ConnectionType::Inlet,
6198 : NodeInputManager::CompFluidStream::Primary,
6199 : DataLoopNode::ObjectIsNotParent);
6200 8 : thisChiller.EvapOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
6201 4 : state.dataIPShortCut->cAlphaArgs(3),
6202 : ErrorsFound,
6203 : DataLoopNode::ConnectionObjectType::ChillerConstantCOP,
6204 4 : state.dataIPShortCut->cAlphaArgs(1),
6205 : DataLoopNode::NodeFluidType::Water,
6206 : DataLoopNode::ConnectionType::Outlet,
6207 : NodeInputManager::CompFluidStream::Primary,
6208 : DataLoopNode::ObjectIsNotParent);
6209 8 : BranchNodeConnections::TestCompSet(state,
6210 4 : state.dataIPShortCut->cCurrentModuleObject,
6211 4 : state.dataIPShortCut->cAlphaArgs(1),
6212 4 : state.dataIPShortCut->cAlphaArgs(2),
6213 4 : state.dataIPShortCut->cAlphaArgs(3),
6214 : "Chilled Water Nodes");
6215 :
6216 4 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled ||
6217 3 : thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
6218 : // Connection not required for air or evap cooled condenser
6219 : // If the condenser inlet is blank for air cooled and evap cooled condensers then supply a generic name
6220 : // since it is not used elsewhere for connection
6221 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
6222 0 : if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 21) { // protect against long name leading to > 100 chars
6223 0 : state.dataIPShortCut->cAlphaArgs(4) = state.dataIPShortCut->cAlphaArgs(1) + " CONDENSER INLET NODE";
6224 : } else {
6225 0 : state.dataIPShortCut->cAlphaArgs(4) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 79) + " CONDENSER INLET NODE";
6226 : }
6227 : }
6228 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
6229 0 : if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 22) { // protect against long name leading to > 100 chars
6230 0 : state.dataIPShortCut->cAlphaArgs(5) = state.dataIPShortCut->cAlphaArgs(1) + " CONDENSER OUTLET NODE";
6231 : } else {
6232 0 : state.dataIPShortCut->cAlphaArgs(5) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 78) + " CONDENSER OUTLET NODE";
6233 : }
6234 : }
6235 :
6236 2 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
6237 2 : state.dataIPShortCut->cAlphaArgs(4),
6238 : ErrorsFound,
6239 : DataLoopNode::ConnectionObjectType::ChillerConstantCOP,
6240 2 : state.dataIPShortCut->cAlphaArgs(1),
6241 : DataLoopNode::NodeFluidType::Air,
6242 : DataLoopNode::ConnectionType::OutsideAirReference,
6243 : NodeInputManager::CompFluidStream::Secondary,
6244 : DataLoopNode::ObjectIsNotParent);
6245 : bool Okay;
6246 2 : OutAirNodeManager::CheckAndAddAirNodeNumber(state, thisChiller.CondInletNodeNum, Okay);
6247 2 : if (!Okay) {
6248 4 : ShowWarningError(state,
6249 6 : format("{}, Adding OutdoorAir:DataLoopNode::Node={}",
6250 2 : state.dataIPShortCut->cCurrentModuleObject,
6251 2 : state.dataIPShortCut->cAlphaArgs(4)));
6252 : }
6253 :
6254 2 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
6255 2 : state.dataIPShortCut->cAlphaArgs(5),
6256 : ErrorsFound,
6257 : DataLoopNode::ConnectionObjectType::ChillerConstantCOP,
6258 2 : state.dataIPShortCut->cAlphaArgs(1),
6259 : DataLoopNode::NodeFluidType::Air,
6260 : DataLoopNode::ConnectionType::Outlet,
6261 : NodeInputManager::CompFluidStream::Secondary,
6262 : DataLoopNode::ObjectIsNotParent);
6263 4 : } else if (thisChiller.CondenserType == DataPlant::CondenserType::WaterCooled) {
6264 2 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
6265 2 : state.dataIPShortCut->cAlphaArgs(4),
6266 : ErrorsFound,
6267 : DataLoopNode::ConnectionObjectType::ChillerConstantCOP,
6268 2 : state.dataIPShortCut->cAlphaArgs(1),
6269 : DataLoopNode::NodeFluidType::Water,
6270 : DataLoopNode::ConnectionType::Inlet,
6271 : NodeInputManager::CompFluidStream::Secondary,
6272 : DataLoopNode::ObjectIsNotParent);
6273 4 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
6274 2 : state.dataIPShortCut->cAlphaArgs(5),
6275 : ErrorsFound,
6276 : DataLoopNode::ConnectionObjectType::ChillerConstantCOP,
6277 2 : state.dataIPShortCut->cAlphaArgs(1),
6278 : DataLoopNode::NodeFluidType::Water,
6279 : DataLoopNode::ConnectionType::Outlet,
6280 : NodeInputManager ::CompFluidStream::Secondary,
6281 : DataLoopNode::ObjectIsNotParent);
6282 4 : BranchNodeConnections::TestCompSet(state,
6283 2 : state.dataIPShortCut->cCurrentModuleObject,
6284 2 : state.dataIPShortCut->cAlphaArgs(1),
6285 2 : state.dataIPShortCut->cAlphaArgs(4),
6286 2 : state.dataIPShortCut->cAlphaArgs(5),
6287 : "Condenser Water Nodes");
6288 : // Condenser Inlet node name is necessary for Water Cooled
6289 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
6290 0 : ShowSevereError(state, format("Invalid, {}is blank ", state.dataIPShortCut->cAlphaFieldNames(4)));
6291 0 : ShowContinueError(state,
6292 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
6293 0 : ErrorsFound = true;
6294 2 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
6295 0 : ShowSevereError(state, format("Invalid, {}is blank ", state.dataIPShortCut->cAlphaFieldNames(5)));
6296 0 : ShowContinueError(state,
6297 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
6298 0 : ErrorsFound = true;
6299 : }
6300 : } else {
6301 0 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
6302 0 : state.dataIPShortCut->cAlphaArgs(4),
6303 : ErrorsFound,
6304 : DataLoopNode::ConnectionObjectType::ChillerConstantCOP,
6305 0 : state.dataIPShortCut->cAlphaArgs(1),
6306 : DataLoopNode::NodeFluidType::Blank,
6307 : DataLoopNode::ConnectionType::Inlet,
6308 : NodeInputManager::CompFluidStream::Secondary,
6309 : DataLoopNode::ObjectIsNotParent);
6310 0 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
6311 0 : state.dataIPShortCut->cAlphaArgs(5),
6312 : ErrorsFound,
6313 : DataLoopNode::ConnectionObjectType::ChillerConstantCOP,
6314 0 : state.dataIPShortCut->cAlphaArgs(1),
6315 : DataLoopNode::NodeFluidType::Blank,
6316 : DataLoopNode::ConnectionType::Outlet,
6317 : NodeInputManager::CompFluidStream::Secondary,
6318 : DataLoopNode::ObjectIsNotParent);
6319 0 : BranchNodeConnections::TestCompSet(state,
6320 0 : state.dataIPShortCut->cCurrentModuleObject,
6321 0 : state.dataIPShortCut->cAlphaArgs(1),
6322 0 : state.dataIPShortCut->cAlphaArgs(4),
6323 0 : state.dataIPShortCut->cAlphaArgs(5),
6324 : "Condenser (unknown?) Nodes");
6325 : // Condenser Inlet node name is necessary for Water Cooled
6326 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
6327 0 : ShowSevereError(state, format("Invalid, {}is blank ", state.dataIPShortCut->cAlphaFieldNames(4)));
6328 0 : ShowContinueError(state,
6329 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
6330 0 : ErrorsFound = true;
6331 0 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
6332 0 : ShowSevereError(state, format("Invalid, {}is blank ", state.dataIPShortCut->cAlphaFieldNames(5)));
6333 0 : ShowContinueError(state,
6334 0 : format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
6335 0 : ErrorsFound = true;
6336 : }
6337 : }
6338 :
6339 4 : thisChiller.FlowMode = static_cast<DataPlant::FlowMode>(getEnumValue(DataPlant::FlowModeNamesUC, state.dataIPShortCut->cAlphaArgs(7)));
6340 4 : if (thisChiller.FlowMode == DataPlant::FlowMode::Invalid) {
6341 0 : ShowSevereError(state,
6342 0 : format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
6343 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
6344 0 : ShowContinueError(state, "Available choices are ConstantFlow, NotModulated, or LeavingSetpointModulated");
6345 0 : ShowContinueError(state, "Flow mode NotModulated is assumed and the simulation continues.");
6346 0 : thisChiller.FlowMode = DataPlant::FlowMode::NotModulated;
6347 : }
6348 :
6349 : // Basin heater power as a function of temperature must be greater than or equal to 0
6350 4 : thisChiller.BasinHeaterPowerFTempDiff = state.dataIPShortCut->rNumericArgs(6);
6351 4 : if (state.dataIPShortCut->rNumericArgs(6) < 0.0) {
6352 0 : ShowSevereError(state,
6353 0 : format("{}, \"{}\" TRIM(state.dataIPShortCut->cNumericFieldNames(6)) must be >= 0",
6354 0 : state.dataIPShortCut->cCurrentModuleObject,
6355 0 : thisChiller.Name));
6356 0 : ErrorsFound = true;
6357 : }
6358 :
6359 4 : thisChiller.BasinHeaterSetPointTemp = state.dataIPShortCut->rNumericArgs(7);
6360 :
6361 4 : if (thisChiller.BasinHeaterPowerFTempDiff > 0.0) {
6362 0 : if (NumNums < 7) {
6363 0 : thisChiller.BasinHeaterSetPointTemp = 2.0;
6364 : }
6365 0 : if (thisChiller.BasinHeaterSetPointTemp < 2.0) {
6366 0 : ShowWarningError(state,
6367 0 : format("{}:\"{}\", {} is less than 2 deg C. Freezing could occur.",
6368 0 : state.dataIPShortCut->cCurrentModuleObject,
6369 0 : thisChiller.Name,
6370 0 : state.dataIPShortCut->cNumericFieldNames(7)));
6371 : }
6372 : }
6373 :
6374 4 : if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
6375 0 : } else if ((thisChiller.basinHeaterSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(8))) == nullptr) {
6376 0 : ShowWarningItemNotFound(state,
6377 : eoh,
6378 0 : state.dataIPShortCut->cAlphaFieldNames(8),
6379 0 : state.dataIPShortCut->cAlphaArgs(8),
6380 : "Basin heater operation will not be modeled and the simulation continues");
6381 : }
6382 :
6383 4 : if (!state.dataIPShortCut->lAlphaFieldBlanks(9)) {
6384 1 : thisChiller.thermosiphonTempCurveIndex = Curve::GetCurveIndex(state, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(9)));
6385 1 : if (thisChiller.thermosiphonTempCurveIndex == 0) {
6386 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, state.dataIPShortCut->cCurrentModuleObject, thisChiller.Name));
6387 0 : ShowContinueError(state,
6388 0 : format("Invalid {} = {}", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
6389 0 : ErrorsFound = true;
6390 : }
6391 : }
6392 4 : thisChiller.thermosiphonMinTempDiff = state.dataIPShortCut->rNumericArgs(8);
6393 :
6394 : // set default design condenser in and evaporator out temperatures
6395 : // Values from AHRI Standard 550/590 (2023, IP Version)
6396 4 : thisChiller.TempDesEvapOut = 6.67; // Degree Celsius, or 44 Degree Fahrenheit
6397 4 : if (thisChiller.CondenserType == DataPlant::CondenserType::WaterCooled) {
6398 2 : thisChiller.TempDesCondIn = 29.44; // Degree Celsius, or 85 Degree Fahrenheit
6399 2 : } else if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled) {
6400 1 : thisChiller.TempDesCondIn = 35.0; // Degree Celsius, or 95 Degree Fahrenheit
6401 1 : } else if (thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
6402 1 : thisChiller.TempDesCondIn = 35.0; // Degree Celsius, or 95 Degree Fahrenheit
6403 : } else {
6404 0 : thisChiller.TempDesCondIn = 35.0; // Degree Celsius, or 95 Degree Fahrenheit
6405 : }
6406 : }
6407 :
6408 2 : if (ErrorsFound) {
6409 0 : ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
6410 : }
6411 : }
6412 :
6413 1 : void ConstCOPChillerSpecs::setupOutputVariables(EnergyPlusData &state)
6414 : {
6415 2 : SetupOutputVariable(state,
6416 : "Chiller Electricity Rate",
6417 : Constant::Units::W,
6418 1 : this->Power,
6419 : OutputProcessor::TimeStepType::System,
6420 : OutputProcessor::StoreType::Average,
6421 1 : this->Name);
6422 2 : SetupOutputVariable(state,
6423 : "Chiller Electricity Energy",
6424 : Constant::Units::J,
6425 1 : this->Energy,
6426 : OutputProcessor::TimeStepType::System,
6427 : OutputProcessor::StoreType::Sum,
6428 1 : this->Name,
6429 : Constant::eResource::Electricity,
6430 : OutputProcessor::Group::Plant,
6431 : OutputProcessor::EndUseCat::Cooling);
6432 2 : SetupOutputVariable(state,
6433 : "Chiller Evaporator Cooling Rate",
6434 : Constant::Units::W,
6435 1 : this->QEvaporator,
6436 : OutputProcessor::TimeStepType::System,
6437 : OutputProcessor::StoreType::Average,
6438 1 : this->Name);
6439 2 : SetupOutputVariable(state,
6440 : "Chiller Evaporator Cooling Energy",
6441 : Constant::Units::J,
6442 1 : this->EvaporatorEnergy,
6443 : OutputProcessor::TimeStepType::System,
6444 : OutputProcessor::StoreType::Sum,
6445 1 : this->Name,
6446 : Constant::eResource::EnergyTransfer,
6447 : OutputProcessor::Group::Plant,
6448 : OutputProcessor::EndUseCat::Chillers);
6449 2 : SetupOutputVariable(state,
6450 : "Chiller Evaporator Inlet Temperature",
6451 : Constant::Units::C,
6452 1 : this->EvapInletTemp,
6453 : OutputProcessor::TimeStepType::System,
6454 : OutputProcessor::StoreType::Average,
6455 1 : this->Name);
6456 2 : SetupOutputVariable(state,
6457 : "Chiller Evaporator Outlet Temperature",
6458 : Constant::Units::C,
6459 1 : this->EvapOutletTemp,
6460 : OutputProcessor::TimeStepType::System,
6461 : OutputProcessor::StoreType::Average,
6462 1 : this->Name);
6463 2 : SetupOutputVariable(state,
6464 : "Chiller Evaporator Mass Flow Rate",
6465 : Constant::Units::kg_s,
6466 1 : this->EvapMassFlowRate,
6467 : OutputProcessor::TimeStepType::System,
6468 : OutputProcessor::StoreType::Average,
6469 1 : this->Name);
6470 2 : SetupOutputVariable(state,
6471 : "Chiller COP",
6472 : Constant::Units::W_W,
6473 1 : this->ActualCOP,
6474 : OutputProcessor::TimeStepType::System,
6475 : OutputProcessor::StoreType::Average,
6476 1 : this->Name);
6477 2 : SetupOutputVariable(state,
6478 : "Chiller Condenser Heat Transfer Rate",
6479 : Constant::Units::W,
6480 1 : this->QCondenser,
6481 : OutputProcessor::TimeStepType::System,
6482 : OutputProcessor::StoreType::Average,
6483 1 : this->Name);
6484 2 : SetupOutputVariable(state,
6485 : "Chiller Condenser Heat Transfer Energy",
6486 : Constant::Units::J,
6487 1 : this->CondenserEnergy,
6488 : OutputProcessor::TimeStepType::System,
6489 : OutputProcessor::StoreType::Sum,
6490 1 : this->Name,
6491 : Constant::eResource::EnergyTransfer,
6492 : OutputProcessor::Group::Plant,
6493 : OutputProcessor::EndUseCat::HeatRejection);
6494 :
6495 2 : SetupOutputVariable(state,
6496 : "Chiller Condenser Inlet Temperature",
6497 : Constant::Units::C,
6498 1 : this->CondInletTemp,
6499 : OutputProcessor::TimeStepType::System,
6500 : OutputProcessor::StoreType::Average,
6501 1 : this->Name);
6502 :
6503 1 : SetupOutputVariable(state,
6504 : "Thermosiphon Status",
6505 : Constant::Units::None,
6506 1 : this->thermosiphonStatus,
6507 : OutputProcessor::TimeStepType::System,
6508 : OutputProcessor::StoreType::Average,
6509 1 : this->Name);
6510 :
6511 : // Condenser mass flow and outlet temp are valid for water cooled
6512 1 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
6513 2 : SetupOutputVariable(state,
6514 : "Chiller Condenser Outlet Temperature",
6515 : Constant::Units::C,
6516 1 : this->CondOutletTemp,
6517 : OutputProcessor::TimeStepType::System,
6518 : OutputProcessor::StoreType::Average,
6519 1 : this->Name);
6520 2 : SetupOutputVariable(state,
6521 : "Chiller Condenser Mass Flow Rate",
6522 : Constant::Units::kg_s,
6523 1 : this->CondMassFlowRate,
6524 : OutputProcessor::TimeStepType::System,
6525 : OutputProcessor::StoreType::Average,
6526 1 : this->Name);
6527 0 : } else if (this->CondenserType == DataPlant::CondenserType::AirCooled) {
6528 0 : } else if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
6529 0 : if (this->BasinHeaterPowerFTempDiff > 0.0) {
6530 0 : SetupOutputVariable(state,
6531 : "Chiller Basin Heater Electricity Rate",
6532 : Constant::Units::W,
6533 0 : this->BasinHeaterPower,
6534 : OutputProcessor::TimeStepType::System,
6535 : OutputProcessor::StoreType::Average,
6536 0 : this->Name);
6537 0 : SetupOutputVariable(state,
6538 : "Chiller Basin Heater Electricity Energy",
6539 : Constant::Units::J,
6540 0 : this->BasinHeaterConsumption,
6541 : OutputProcessor::TimeStepType::System,
6542 : OutputProcessor::StoreType::Sum,
6543 0 : this->Name,
6544 : Constant::eResource::Electricity,
6545 : OutputProcessor::Group::Plant,
6546 : OutputProcessor::EndUseCat::Chillers);
6547 : }
6548 : }
6549 1 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
6550 0 : SetupEMSInternalVariable(state, "Chiller Nominal Capacity", this->Name, "[W]", this->NomCap);
6551 : }
6552 1 : }
6553 :
6554 5 : void ConstCOPChillerSpecs::initialize(EnergyPlusData &state, bool const RunFlag, Real64 const MyLoad)
6555 : {
6556 :
6557 : // SUBROUTINE INFORMATION:
6558 : // AUTHOR Chandan Sharma
6559 : // DATE WRITTEN September 2010
6560 : // MODIFIED na
6561 : // RE-ENGINEERED na
6562 :
6563 : // PURPOSE OF THIS SUBROUTINE:
6564 : // This subroutine is for initializations of the Electric Chiller components
6565 :
6566 : // METHODOLOGY EMPLOYED:
6567 : // Uses the status flags to trigger initializations.
6568 :
6569 : // REFERENCES:
6570 : // Based on InitElectricChiller from Fred Buhl
6571 :
6572 : // SUBROUTINE PARAMETER DEFINITIONS:
6573 : static constexpr std::string_view RoutineName("InitConstCOPChiller");
6574 5 : constexpr Real64 TempDesCondIn(25.0); // Design condenser inlet temp. C
6575 :
6576 5 : this->oneTimeInit(state);
6577 :
6578 : // Initialize critical Demand Side Variables at the beginning of each environment
6579 5 : if (this->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
6580 :
6581 1 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
6582 1 : this->EvapMassFlowRateMax = this->EvapVolFlowRate * rho;
6583 1 : PlantUtilities::InitComponentNodes(state, 0.0, this->EvapMassFlowRateMax, this->EvapInletNodeNum, this->EvapOutletNodeNum);
6584 :
6585 : // init maximum available condenser flow rate
6586 1 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
6587 :
6588 1 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = TempDesCondIn;
6589 :
6590 1 : rho = this->CDPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
6591 :
6592 1 : this->CondMassFlowRateMax = rho * this->CondVolFlowRate;
6593 :
6594 1 : PlantUtilities::InitComponentNodes(state, 0.0, this->CondMassFlowRateMax, this->CondInletNodeNum, this->CondOutletNodeNum);
6595 : } else { // air or evap-air
6596 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate =
6597 0 : this->CondVolFlowRate * Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, TempDesCondIn, 0.0, RoutineName);
6598 :
6599 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
6600 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMaxAvail =
6601 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
6602 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
6603 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
6604 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMinAvail = 0.0;
6605 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMin = 0.0;
6606 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMinAvail = 0.0;
6607 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMin = 0.0;
6608 : }
6609 1 : this->MyEnvrnFlag = false;
6610 : }
6611 :
6612 5 : if (!state.dataGlobal->BeginEnvrnFlag) {
6613 1 : this->MyEnvrnFlag = true;
6614 : }
6615 5 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) && (this->ModulatedFlowSetToLoop)) {
6616 : // fix for clumsy old input that worked because loop setpoint was spread.
6617 : // could be removed with transition, testing , model change, period of being obsolete.
6618 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
6619 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
6620 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
6621 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
6622 : }
6623 :
6624 5 : Real64 mdot = 0.0;
6625 5 : Real64 mdotCond = 0.0;
6626 5 : this->thermosiphonStatus = 0;
6627 5 : this->partLoadRatio = 0.0;
6628 5 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
6629 5 : this->EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
6630 5 : if ((MyLoad < 0.0) && RunFlag) {
6631 5 : mdot = this->EvapMassFlowRateMax;
6632 5 : mdotCond = this->CondMassFlowRateMax;
6633 : }
6634 :
6635 5 : PlantUtilities::SetComponentFlowRate(state, mdot, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
6636 5 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
6637 5 : PlantUtilities::SetComponentFlowRate(state, mdotCond, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
6638 : }
6639 :
6640 5 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
6641 0 : this->BasinHeaterPower = 0.0;
6642 : }
6643 5 : }
6644 :
6645 1 : void ConstCOPChillerSpecs::size(EnergyPlusData &state)
6646 : {
6647 :
6648 : // SUBROUTINE INFORMATION:
6649 : // AUTHOR Fred Buhl
6650 : // DATE WRITTEN March 2008
6651 : // MODIFIED November 2013 Daeho Kang, add component sizing table entries
6652 : // RE-ENGINEERED na
6653 :
6654 : // PURPOSE OF THIS SUBROUTINE:
6655 : // This subroutine is for sizing Constant COP Chiller Components for which capacities and flow rates
6656 : // have not been specified in the input.
6657 :
6658 : // METHODOLOGY EMPLOYED:
6659 : // Obtains evaporator flow rate from the plant sizing array. Calculates nominal capacity from
6660 : // the evaporator flow rate and the chilled water loop design delta T. The condenser flow rate
6661 : // is calculated from the nominal capacity, the COP, and the condenser loop design delta T.
6662 :
6663 : // SUBROUTINE PARAMETER DEFINITIONS:
6664 : static constexpr std::string_view RoutineName("SizeConstCOPChiller");
6665 :
6666 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6667 1 : Real64 tmpNomCap = this->NomCap; // local nominal capacity cooling power
6668 1 : Real64 tmpEvapVolFlowRate = this->EvapVolFlowRate; // local evaporator design volume flow rate
6669 1 : Real64 tmpCondVolFlowRate = this->CondVolFlowRate; // local condenser design volume flow rate
6670 :
6671 1 : int PltSizCondNum = 0;
6672 1 : bool ErrorsFound = false;
6673 :
6674 1 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
6675 1 : PltSizCondNum = this->CDPlantLoc.loop->PlantSizNum;
6676 : }
6677 :
6678 1 : int PltSizNum = this->CWPlantLoc.loop->PlantSizNum;
6679 :
6680 1 : if (PltSizNum > 0) {
6681 1 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
6682 1 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
6683 1 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
6684 1 : tmpNomCap =
6685 1 : Cp * rho * state.dataSize->PlantSizData(PltSizNum).DeltaT * state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
6686 : } else {
6687 0 : if (this->NomCapWasAutoSized) tmpNomCap = 0.0;
6688 : }
6689 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
6690 1 : if (this->NomCapWasAutoSized) {
6691 1 : this->NomCap = tmpNomCap;
6692 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
6693 1 : BaseSizer::reportSizerOutput(state, "Chiller:ConstantCOP", this->Name, "Design Size Nominal Capacity [W]", tmpNomCap);
6694 : }
6695 1 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
6696 1 : BaseSizer::reportSizerOutput(state, "Chiller:ConstantCOP", this->Name, "Initial Design Size Nominal Capacity [W]", tmpNomCap);
6697 : }
6698 : } else { // Hard-size with sizing data
6699 0 : if (this->NomCap > 0.0 && tmpNomCap > 0.0) {
6700 : // Hardsized reference capacity for reporting
6701 0 : Real64 const NomCapUser = this->NomCap;
6702 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
6703 0 : BaseSizer::reportSizerOutput(state,
6704 : "Chiller:ConstantCOP",
6705 : this->Name,
6706 : "Design Size Nominal Capacity [W]",
6707 : tmpNomCap,
6708 : "User-Specified Nominal Capacity [W]",
6709 : NomCapUser);
6710 0 : if (state.dataGlobal->DisplayExtraWarnings) {
6711 0 : if ((std::abs(tmpNomCap - NomCapUser) / NomCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
6712 0 : ShowMessage(state, format("SizeChillerConstantCOP: Potential issue with equipment sizing for {}", this->Name));
6713 0 : ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NomCapUser));
6714 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", tmpNomCap));
6715 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
6716 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
6717 : }
6718 : }
6719 : }
6720 0 : tmpNomCap = NomCapUser;
6721 : }
6722 : }
6723 : }
6724 : } else {
6725 0 : if (this->NomCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
6726 0 : ShowSevereError(state, "Autosizing of Constant COP Chiller nominal capacity requires a loop Sizing:Plant object");
6727 0 : ShowContinueError(state, format("Occurs in Chiller:ConstantCOP object={}", this->Name));
6728 0 : ErrorsFound = true;
6729 : }
6730 0 : if (!this->NomCapWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->NomCap > 0.0)) {
6731 0 : BaseSizer::reportSizerOutput(state, "Chiller:ConstantCOP", this->Name, "User-Specified Nominal Capacity [W]", this->NomCap);
6732 : }
6733 : }
6734 :
6735 1 : if (PltSizNum > 0) {
6736 1 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
6737 1 : tmpEvapVolFlowRate = state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
6738 : } else {
6739 0 : if (this->EvapVolFlowRateWasAutoSized) tmpEvapVolFlowRate = 0.0;
6740 : }
6741 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
6742 1 : if (this->EvapVolFlowRateWasAutoSized) {
6743 1 : this->EvapVolFlowRate = tmpEvapVolFlowRate;
6744 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
6745 1 : BaseSizer::reportSizerOutput(
6746 : state, "Chiller:ConstantCOP", this->Name, "Design Size Design Chilled Water Flow Rate [m3/s]", tmpEvapVolFlowRate);
6747 : }
6748 1 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
6749 1 : BaseSizer::reportSizerOutput(state,
6750 : "Chiller:ConstantCOP",
6751 : this->Name,
6752 : "Initial Design Size Design Chilled Water Flow Rate [m3/s]",
6753 : tmpEvapVolFlowRate);
6754 : }
6755 : } else {
6756 0 : if (this->EvapVolFlowRate > 0.0 && tmpEvapVolFlowRate > 0.0) {
6757 : // Hardsized evaporator flow for reporting
6758 0 : Real64 const EvapVolFlowRateUser = this->EvapVolFlowRate;
6759 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
6760 0 : BaseSizer::reportSizerOutput(state,
6761 : "Chiller:ConstantCOP",
6762 : this->Name,
6763 : "Design Size Design Chilled Water Flow Rate [m3/s]",
6764 : tmpEvapVolFlowRate,
6765 : "User-Specified Design Chilled Water Flow Rate [m3/s]",
6766 : EvapVolFlowRateUser);
6767 0 : if (state.dataGlobal->DisplayExtraWarnings) {
6768 0 : if ((std::abs(tmpEvapVolFlowRate - EvapVolFlowRateUser) / EvapVolFlowRateUser) >
6769 0 : state.dataSize->AutoVsHardSizingThreshold) {
6770 0 : ShowMessage(state, format("SizeChillerConstantCOP: Potential issue with equipment sizing for {}", this->Name));
6771 0 : ShowContinueError(state,
6772 0 : format("User-Specified Design Chilled Water Flow Rate of {:.5R} [m3/s]", EvapVolFlowRateUser));
6773 0 : ShowContinueError(
6774 : state,
6775 0 : format("differs from Design Size Design Chilled Water Flow Rate of {:.5R} [m3/s]", tmpEvapVolFlowRate));
6776 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
6777 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
6778 : }
6779 : }
6780 : }
6781 0 : tmpEvapVolFlowRate = EvapVolFlowRateUser;
6782 : }
6783 : }
6784 : }
6785 : } else {
6786 0 : if (this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
6787 0 : ShowSevereError(state, "Autosizing of Constant COP Chiller evap flow rate requires a loop Sizing:Plant object");
6788 0 : ShowContinueError(state, format("Occurs in Chiller:ConstantCOP object={}", this->Name));
6789 0 : ErrorsFound = true;
6790 : }
6791 0 : if (!this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->EvapVolFlowRate > 0.0)) {
6792 0 : BaseSizer::reportSizerOutput(
6793 : state, "Chiller:ConstantCOP", this->Name, "User-Specified Design Chilled Water Flow Rate [m3/s]", this->EvapVolFlowRate);
6794 : }
6795 : }
6796 :
6797 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->EvapInletNodeNum, tmpEvapVolFlowRate);
6798 :
6799 1 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
6800 1 : if (PltSizCondNum > 0 && PltSizNum > 0) {
6801 1 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow && tmpNomCap > 0.0) {
6802 1 : Real64 rho = this->CDPlantLoc.loop->glycol->getDensity(state, 29.44, RoutineName);
6803 1 : Real64 Cp = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, 29.44, RoutineName);
6804 1 : tmpCondVolFlowRate = tmpNomCap * (1.0 + 1.0 / this->COP) / (state.dataSize->PlantSizData(PltSizCondNum).DeltaT * Cp * rho);
6805 : } else {
6806 0 : if (this->CondVolFlowRateWasAutoSized) tmpCondVolFlowRate = 0.0;
6807 : }
6808 1 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
6809 1 : if (this->CondVolFlowRateWasAutoSized) {
6810 1 : this->CondVolFlowRate = tmpCondVolFlowRate;
6811 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
6812 1 : BaseSizer::reportSizerOutput(
6813 : state, "Chiller:ConstantCOP", this->Name, "Design Size Design Condenser Water Flow Rate [m3/s]", tmpCondVolFlowRate);
6814 : }
6815 1 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
6816 1 : BaseSizer::reportSizerOutput(state,
6817 : "Chiller:ConstantCOP",
6818 : this->Name,
6819 : "Initial Design Size Design Condenser Water Flow Rate [m3/s]",
6820 : tmpCondVolFlowRate);
6821 : }
6822 : } else {
6823 0 : if (this->CondVolFlowRate > 0.0 && tmpCondVolFlowRate > 0.0) {
6824 0 : Real64 CondVolFlowRateUser = this->CondVolFlowRate;
6825 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
6826 0 : BaseSizer::reportSizerOutput(state,
6827 : "Chiller:ConstantCOP",
6828 : this->Name,
6829 : "Design Size Design Condenser Water Flow Rate [m3/s]",
6830 : tmpCondVolFlowRate,
6831 : "User-Specified Design Condenser Water Flow Rate [m3/s]",
6832 : CondVolFlowRateUser);
6833 0 : if (state.dataGlobal->DisplayExtraWarnings) {
6834 0 : if ((std::abs(tmpCondVolFlowRate - CondVolFlowRateUser) / CondVolFlowRateUser) >
6835 0 : state.dataSize->AutoVsHardSizingThreshold) {
6836 0 : ShowMessage(state,
6837 0 : format("SizeChillerConstantCOP: Potential issue with equipment sizing for {}", this->Name));
6838 0 : ShowContinueError(
6839 0 : state, format("User-Specified Design Condenser Water Flow Rate of {:.5R} [m3/s]", CondVolFlowRateUser));
6840 0 : ShowContinueError(
6841 : state,
6842 0 : format("differs from Design Size Design Condenser Water Flow Rate of {:.5R} [m3/s]", tmpCondVolFlowRate));
6843 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
6844 0 : ShowContinueError(state,
6845 : "Verify that the value entered is intended and is consistent with other components.");
6846 : }
6847 : }
6848 : }
6849 0 : tmpCondVolFlowRate = CondVolFlowRateUser;
6850 : }
6851 : }
6852 : }
6853 1 : } else {
6854 0 : if (this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
6855 0 : ShowSevereError(state, "Autosizing of Constant COP Chiller condenser flow rate requires a condenser");
6856 0 : ShowContinueError(state, "loop Sizing:Plant object");
6857 0 : ShowContinueError(state, format("Occurs in Chiller:ConstantCOP object={}", this->Name));
6858 0 : ErrorsFound = true;
6859 : }
6860 0 : if (!this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->CondVolFlowRate > 0.0)) {
6861 0 : BaseSizer::reportSizerOutput(
6862 : state, "Chiller:ConstantCOP", this->Name, "User-Specified Design Condenser Water Flow Rate [m3/s]", this->CondVolFlowRate);
6863 : }
6864 : }
6865 : }
6866 :
6867 : // save the design condenser water volumetric flow rate for use by the condenser water loop sizing algorithms
6868 1 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled)
6869 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->CondInletNodeNum, tmpCondVolFlowRate);
6870 :
6871 1 : if (ErrorsFound) {
6872 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
6873 : }
6874 :
6875 : // create predefined report
6876 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
6877 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "Chiller:ConstantCOP");
6878 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomEff, this->Name, this->COP);
6879 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->NomCap);
6880 :
6881 : // std 229 new Chillers table
6882 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerType, this->Name, "Chiller:ConstantCOP");
6883 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefCap, this->Name, this->NomCap);
6884 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEff, this->Name, this->COP); // Eff == COP?
6885 2 : OutputReportPredefined::PreDefTableEntry(
6886 1 : state, state.dataOutRptPredefined->pdchChillerRatedCap, this->Name, this->NomCap); // did not find rated cap
6887 2 : OutputReportPredefined::PreDefTableEntry(
6888 1 : state, state.dataOutRptPredefined->pdchChillerRatedEff, this->Name, this->COP); // did not find rated eff or cop ; also Eff == COP?
6889 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinSI, this->Name, "N/A"); // or just plain COP?
6890 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinIP, this->Name, "N/A"); // or just plain COP?
6891 2 : OutputReportPredefined::PreDefTableEntry(state,
6892 1 : state.dataOutRptPredefined->pdchChillerPlantloopName,
6893 : this->Name,
6894 2 : (this->CWPlantLoc.loop != nullptr) ? this->CWPlantLoc.loop->Name : "N/A");
6895 2 : OutputReportPredefined::PreDefTableEntry(state,
6896 1 : state.dataOutRptPredefined->pdchChillerPlantloopBranchName,
6897 : this->Name,
6898 2 : (this->CWPlantLoc.branch != nullptr) ? this->CWPlantLoc.branch->Name : "N/A");
6899 2 : OutputReportPredefined::PreDefTableEntry(state,
6900 1 : state.dataOutRptPredefined->pdchChillerCondLoopName,
6901 : this->Name,
6902 2 : (this->CDPlantLoc.loop != nullptr) ? this->CDPlantLoc.loop->Name : "N/A");
6903 2 : OutputReportPredefined::PreDefTableEntry(state,
6904 1 : state.dataOutRptPredefined->pdchChillerCondLoopBranchName,
6905 : this->Name,
6906 2 : (this->CDPlantLoc.branch != nullptr) ? this->CDPlantLoc.branch->Name : "N/A");
6907 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerMinPLR, this->Name, this->MinPartLoadRat);
6908 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerFuelType, this->Name, "Electricity");
6909 2 : OutputReportPredefined::PreDefTableEntry(
6910 1 : state, state.dataOutRptPredefined->pdchChillerRatedEntCondTemp, this->Name, this->TempDesCondIn); // Rated==Ref?
6911 2 : OutputReportPredefined::PreDefTableEntry(
6912 1 : state, state.dataOutRptPredefined->pdchChillerRatedLevEvapTemp, this->Name, this->TempDesEvapOut); // Rated==Ref?
6913 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEntCondTemp, this->Name, this->TempDesCondIn);
6914 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefLevEvapTemp, this->Name, this->TempDesEvapOut);
6915 :
6916 2 : OutputReportPredefined::PreDefTableEntry(state,
6917 1 : state.dataOutRptPredefined->pdchChillerDesSizeRefCHWFlowRate,
6918 : this->Name,
6919 : this->EvapMassFlowRateMax); // flowrate Max==DesignSizeRef flowrate?
6920 2 : OutputReportPredefined::PreDefTableEntry(state,
6921 1 : state.dataOutRptPredefined->pdchChillerDesSizeRefCondFluidFlowRate,
6922 : this->Name,
6923 : this->CondMassFlowRateMax); // Cond flowrate Max==DesignSizeRef Cond flowrate?
6924 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerHeatRecPlantloopName, this->Name, "N/A");
6925 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerHeatRecPlantloopBranchName, this->Name, "N/A");
6926 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRecRelCapFrac, this->Name, "N/A");
6927 : }
6928 1 : }
6929 :
6930 3 : void ConstCOPChillerSpecs::calculate(EnergyPlusData &state,
6931 : Real64 &MyLoad,
6932 : bool const RunFlag,
6933 : DataBranchAirLoopPlant::ControlType const EquipFlowCtrl)
6934 : {
6935 : // SUBROUTINE INFORMATION:
6936 : // AUTHOR Dan Fisher
6937 : // DATE WRITTEN Sept. 1998
6938 : // MODIFIED Nov.-Dec. 2001, Jan. 2002, Richard Liesen
6939 : // Feb. 2010, Chandan Sharma, FSEC. Added basin heater
6940 : // Jun. 2016, Rongpeng Zhang, LBNL. Applied the chiller supply water temperature sensor fault model
6941 : // Nov. 2016, Rongpeng Zhang, LBNL. Added Fouling Chiller fault
6942 :
6943 : static constexpr std::string_view RoutineName("CalcConstCOPChillerModel");
6944 :
6945 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6946 3 : Real64 TempEvapOutSetPoint(0.0); // C - evaporator outlet temperature setpoint
6947 3 : Real64 COP = this->COP; // coefficient of performance
6948 3 : Real64 ChillerNomCap = this->NomCap; // chiller nominal capacity
6949 3 : this->Power = 0.0;
6950 :
6951 : // If there is a fault of chiller fouling
6952 3 : if (this->FaultyChillerFoulingFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
6953 0 : (!state.dataGlobal->KickOffSimulation)) {
6954 0 : int FaultIndex = this->FaultyChillerFoulingIndex;
6955 0 : Real64 NomCap_ff = ChillerNomCap;
6956 0 : Real64 COP_ff = COP;
6957 :
6958 : // calculate the Faulty Chiller Fouling Factor using fault information
6959 0 : this->FaultyChillerFoulingFactor = state.dataFaultsMgr->FaultsChillerFouling(FaultIndex).CalFoulingFactor(state);
6960 :
6961 : // update the Chiller nominal capacity and COP at faulty cases
6962 0 : ChillerNomCap = NomCap_ff * this->FaultyChillerFoulingFactor;
6963 0 : COP = COP_ff * this->FaultyChillerFoulingFactor;
6964 : }
6965 :
6966 3 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
6967 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
6968 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased ||
6969 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint != DataLoopNode::SensedNodeFlagValue)) {
6970 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
6971 : } else {
6972 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
6973 : }
6974 3 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
6975 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
6976 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased ||
6977 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi != DataLoopNode::SensedNodeFlagValue)) {
6978 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
6979 : } else {
6980 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
6981 : }
6982 : }
6983 :
6984 : // If there is a fault of Chiller SWT Sensor
6985 3 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
6986 0 : (!state.dataGlobal->KickOffSimulation)) {
6987 0 : int FaultIndex = this->FaultyChillerSWTIndex;
6988 0 : Real64 EvapOutletTemp_ff = TempEvapOutSetPoint;
6989 :
6990 : // calculate the sensor offset using fault information
6991 0 : this->FaultyChillerSWTOffset = state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex).CalFaultOffsetAct(state);
6992 : // update the TempEvapOutSetPoint
6993 0 : TempEvapOutSetPoint = min(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, EvapOutletTemp_ff - this->FaultyChillerSWTOffset);
6994 0 : this->FaultyChillerSWTOffset = EvapOutletTemp_ff - TempEvapOutSetPoint;
6995 : }
6996 :
6997 3 : Real64 EvapDeltaTemp = std::abs(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - TempEvapOutSetPoint);
6998 :
6999 : // If no component demand, or chiller OFF, or Chiller type set to 'Passive' by free
7000 : // cooling heat exchanger, then set condenser side flow and heat transfer rates set to zero
7001 3 : if (MyLoad >= 0.0 || !RunFlag) {
7002 :
7003 : // If Chiller load is 0 or greater or chiller is not running then leave the subroutine.Before leaving
7004 : // if the component control is SERIESACTIVE we set the component flow to inlet flow so that
7005 : // flow resolver will not shut down the branch
7006 0 : if (EquipFlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive ||
7007 0 : this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Locked) {
7008 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
7009 : } else {
7010 0 : this->EvapMassFlowRate = 0.0;
7011 0 : PlantUtilities::SetComponentFlowRate(
7012 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
7013 : }
7014 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
7015 0 : if (DataPlant::CompData::getPlantComponent(state, this->CDPlantLoc).FlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive) {
7016 0 : this->CondMassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
7017 : } else {
7018 0 : this->CondMassFlowRate = 0.0;
7019 0 : PlantUtilities::SetComponentFlowRate(
7020 0 : state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
7021 : }
7022 : }
7023 :
7024 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
7025 0 : this->CondOutletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
7026 :
7027 0 : this->Power = 0.0;
7028 0 : this->QEvaporator = 0.0;
7029 0 : this->QCondenser = 0.0;
7030 0 : this->Energy = 0.0;
7031 0 : this->EvaporatorEnergy = 0.0;
7032 0 : this->CondenserEnergy = 0.0;
7033 :
7034 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
7035 0 : CalcBasinHeaterPower(
7036 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
7037 : }
7038 0 : this->PrintMessage = false;
7039 0 : return;
7040 : }
7041 3 : this->partLoadRatio = std::abs(MyLoad) / ChillerNomCap;
7042 :
7043 : // calculate end time of current time step
7044 3 : Real64 const CurrentEndTime = state.dataGlobal->CurrentTime + state.dataHVACGlobal->SysTimeElapsed;
7045 :
7046 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
7047 : // Wait for next time step to print warnings. If simulation iterates, print out
7048 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
7049 : // If a warning occurs and the simulation down shifts, the warning is not valid.
7050 3 : if (CurrentEndTime > this->CurrentEndTimeLast && state.dataHVACGlobal->TimeStepSys >= this->TimeStepSysLast) {
7051 0 : if (this->PrintMessage) {
7052 0 : ++this->MsgErrorCount;
7053 : // Show single warning and pass additional info to ShowRecurringWarningErrorAtEnd
7054 0 : if (this->MsgErrorCount < 2) {
7055 0 : ShowWarningError(state, format("{}.", this->MsgBuffer1));
7056 0 : ShowContinueError(state, this->MsgBuffer2);
7057 : } else {
7058 0 : ShowRecurringWarningErrorAtEnd(
7059 0 : state, this->MsgBuffer1 + " error continues.", this->ErrCount1, this->MsgDataLast, this->MsgDataLast, _, "[C]", "[C]");
7060 : }
7061 : }
7062 : }
7063 :
7064 : // save last system time step and last end time of current time step (used to determine if warning is valid)
7065 3 : this->TimeStepSysLast = state.dataHVACGlobal->TimeStepSys;
7066 3 : this->CurrentEndTimeLast = CurrentEndTime;
7067 :
7068 : // otherwise the chiller is running...
7069 :
7070 3 : if (this->CondenserType == DataPlant::CondenserType::AirCooled) { // Condenser inlet temp = outdoor temp
7071 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirDryBulb;
7072 : // Warn user if entering condenser temperature falls below 0C
7073 0 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 0.0 && !state.dataGlobal->WarmupFlag) {
7074 0 : this->PrintMessage = true;
7075 : this->MsgBuffer1 =
7076 0 : "CalcConstCOPChillerModel - Chiller:ConstantCOP \"" + this->Name + "\" - Air Cooled Condenser Inlet Temperature below 0C";
7077 0 : this->MsgBuffer2 = format("... Outdoor Dry-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
7078 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
7079 0 : state.dataEnvrn->EnvironmentName,
7080 0 : state.dataEnvrn->CurMnDy,
7081 0 : General::CreateSysTimeIntervalString(state));
7082 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
7083 : } else {
7084 0 : this->PrintMessage = false;
7085 : }
7086 3 : } else if (this->CondenserType == DataPlant::CondenserType::EvapCooled) { // Condenser inlet temp = (outdoor wet bulb)
7087 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirWetBulb;
7088 : // Warn user if evap condenser wet bulb temperature falls below 10C
7089 0 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 10.0 && !state.dataGlobal->WarmupFlag) {
7090 0 : this->PrintMessage = true;
7091 : this->MsgBuffer1 =
7092 0 : "CalcConstCOPChillerModel - Chiller:ConstantCOP \"" + this->Name + "\" - Evap Cooled Condenser Inlet Temperature below 10C";
7093 0 : this->MsgBuffer2 = format("... Outdoor Wet-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
7094 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
7095 0 : state.dataEnvrn->EnvironmentName,
7096 0 : state.dataEnvrn->CurMnDy,
7097 0 : General::CreateSysTimeIntervalString(state));
7098 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
7099 : } else {
7100 0 : this->PrintMessage = false;
7101 : }
7102 : } // End of the Air Cooled/Evap Cooled Logic block
7103 :
7104 : // Set condenser flow rate
7105 3 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
7106 3 : this->CondMassFlowRate = this->CondMassFlowRateMax;
7107 3 : PlantUtilities::SetComponentFlowRate(state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
7108 3 : PlantUtilities::PullCompInterconnectTrigger(
7109 3 : state, this->CWPlantLoc, this->CondMassFlowIndex, this->CDPlantLoc, DataPlant::CriteriaType::MassFlowRate, this->CondMassFlowRate);
7110 :
7111 3 : if (this->CondMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance) {
7112 0 : MyLoad = 0.0;
7113 0 : this->EvapMassFlowRate = 0.0;
7114 0 : PlantUtilities::SetComponentFlowRate(
7115 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
7116 0 : return;
7117 : }
7118 : }
7119 :
7120 : // If FlowLock is True, the new resolved mdot is used to update Power, QEvap, Qcond, and
7121 : // condenser side outlet temperature.
7122 :
7123 : // local for fluid specif heat, for evaporator
7124 3 : Real64 const Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, RoutineName);
7125 :
7126 3 : if (this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Unlocked) {
7127 3 : this->PossibleSubcooling = false;
7128 3 : this->QEvaporator = std::abs(MyLoad);
7129 :
7130 : // Either set the flow to the Constant value or calculate the flow for the variable volume
7131 3 : if ((this->FlowMode == DataPlant::FlowMode::Constant) || (this->FlowMode == DataPlant::FlowMode::NotModulated)) {
7132 :
7133 : // Start by assuming max (design) flow
7134 3 : this->EvapMassFlowRate = this->EvapMassFlowRateMax;
7135 : // Use SetComponentFlowRate to decide actual flow
7136 3 : PlantUtilities::SetComponentFlowRate(
7137 3 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
7138 : // Evaluate delta temp based on actual flow rate
7139 3 : if (this->EvapMassFlowRate != 0.0) {
7140 3 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
7141 : } else {
7142 0 : EvapDeltaTemp = 0.0;
7143 : }
7144 : // Evaluate outlet temp based on delta
7145 3 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
7146 :
7147 0 : } else if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
7148 :
7149 : // Calculate the Delta Temp from the inlet temp to the chiller outlet setpoint
7150 0 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
7151 0 : EvapDeltaTemp = std::abs(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp -
7152 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint);
7153 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
7154 0 : EvapDeltaTemp = std::abs(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp -
7155 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi);
7156 : }
7157 :
7158 0 : if (EvapDeltaTemp > DataPlant::DeltaTempTol) {
7159 0 : this->EvapMassFlowRate = std::abs(this->QEvaporator / Cp / EvapDeltaTemp);
7160 0 : if ((this->EvapMassFlowRate - this->EvapMassFlowRateMax) > DataBranchAirLoopPlant::MassFlowTolerance)
7161 0 : this->PossibleSubcooling = true;
7162 : // Check to see if the Maximum is exceeded, if so set to maximum
7163 0 : this->EvapMassFlowRate = min(this->EvapMassFlowRateMax, this->EvapMassFlowRate);
7164 : // Use SetComponentFlowRate to decide actual flow
7165 0 : PlantUtilities::SetComponentFlowRate(
7166 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
7167 0 : if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
7168 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
7169 0 : } else if (this->CWPlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
7170 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
7171 : }
7172 : } else {
7173 : // Try to request zero flow
7174 0 : this->EvapMassFlowRate = 0.0;
7175 : // Use SetComponentFlowRate to decide actual flow
7176 0 : PlantUtilities::SetComponentFlowRate(
7177 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
7178 : // No deltaT since component is not running
7179 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
7180 : }
7181 : } // End of Constant or Variable Flow If Block for FlowLock = 0 (or making a flow request)
7182 3 : if (this->thermosiphonDisabled(state)) {
7183 2 : this->Power = std::abs(MyLoad) / COP;
7184 : }
7185 :
7186 : // If there is a fault of Chiller SWT Sensor
7187 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
7188 3 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
7189 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
7190 0 : int FaultIndex = this->FaultyChillerSWTIndex;
7191 0 : bool VarFlowFlag = (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated);
7192 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
7193 0 : .CalFaultChillerSWT(VarFlowFlag,
7194 : this->FaultyChillerSWTOffset,
7195 : Cp,
7196 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
7197 0 : this->EvapOutletTemp,
7198 0 : this->EvapMassFlowRate,
7199 0 : this->QEvaporator);
7200 : }
7201 :
7202 : } else { // If FlowLock is True
7203 :
7204 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
7205 0 : PlantUtilities::SetComponentFlowRate(state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
7206 : // Some other component set the flow to 0. No reason to continue with calculations.
7207 0 : if (this->EvapMassFlowRate == 0.0) {
7208 0 : MyLoad = 0.0;
7209 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
7210 0 : CalcBasinHeaterPower(
7211 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
7212 : }
7213 0 : this->PrintMessage = false;
7214 0 : return;
7215 : }
7216 :
7217 : // Recalculate the Delta Temp
7218 0 : if (this->PossibleSubcooling) {
7219 0 : this->QEvaporator = std::abs(MyLoad);
7220 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
7221 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
7222 0 : if (this->EvapOutletTemp < state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) {
7223 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin;
7224 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
7225 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
7226 : }
7227 : } else {
7228 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - TempEvapOutSetPoint;
7229 : // Calculate the evaporator heat transfer at the specified flow which could have changed
7230 : // in the Flow Resolution step.
7231 0 : this->QEvaporator = std::abs(this->EvapMassFlowRate * Cp * EvapDeltaTemp);
7232 0 : this->EvapOutletTemp = TempEvapOutSetPoint;
7233 : }
7234 : // Check that the Evap outlet temp honors both plant loop temp low limit and also the chiller low limit
7235 0 : if (this->EvapOutletTemp < state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) {
7236 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) >
7237 : DataPlant::DeltaTempTol) {
7238 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin;
7239 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
7240 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
7241 : } else {
7242 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
7243 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
7244 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
7245 : }
7246 : }
7247 : // If load exceeds the distributed load set to the distributed load
7248 0 : if (this->QEvaporator > std::abs(MyLoad)) {
7249 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
7250 0 : this->QEvaporator = std::abs(MyLoad);
7251 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
7252 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
7253 : } else {
7254 0 : this->QEvaporator = 0.0;
7255 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
7256 : }
7257 : }
7258 :
7259 : // If there is a fault of Chiller SWT Sensor
7260 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
7261 0 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
7262 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
7263 0 : int FaultIndex = this->FaultyChillerSWTIndex;
7264 0 : bool VarFlowFlag = false;
7265 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
7266 0 : .CalFaultChillerSWT(VarFlowFlag,
7267 : this->FaultyChillerSWTOffset,
7268 : Cp,
7269 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
7270 0 : this->EvapOutletTemp,
7271 0 : this->EvapMassFlowRate,
7272 0 : this->QEvaporator);
7273 : }
7274 :
7275 : // Checks QEvaporator on the basis of the machine limits.
7276 0 : if (this->QEvaporator > ChillerNomCap) {
7277 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
7278 0 : this->QEvaporator = ChillerNomCap;
7279 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
7280 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
7281 : } else {
7282 0 : this->QEvaporator = 0.0;
7283 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
7284 : }
7285 : }
7286 0 : if (this->EvapMassFlowRate == 0.0) {
7287 0 : this->QEvaporator = 0.0;
7288 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
7289 0 : this->Power = 0.0;
7290 0 : this->PrintMessage = false;
7291 : } else {
7292 : // Calculate the Power consumption of the Const COP chiller which is a simplified calculation
7293 0 : if (this->thermosiphonDisabled(state)) {
7294 0 : this->Power = this->QEvaporator / COP;
7295 : }
7296 : }
7297 0 : if (this->QEvaporator == 0.0 && this->CondenserType == DataPlant::CondenserType::EvapCooled) {
7298 0 : CalcBasinHeaterPower(
7299 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
7300 : }
7301 :
7302 : } // This is the end of the FlowLock Block
7303 :
7304 : // QCondenser is calculated the same for each type, but the power consumption should be different
7305 : // depending on the performance coefficients used for the chiller model.
7306 3 : this->QCondenser = this->Power + this->QEvaporator;
7307 :
7308 : // If not air or evap cooled then set to the condenser node that is attached to a cooling tower
7309 3 : Real64 const CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
7310 :
7311 3 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
7312 : // local for fluid specif heat, for condenser
7313 3 : Real64 const CpCond = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, CondInletTemp, RoutineName);
7314 3 : if (this->CondMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
7315 3 : this->CondOutletTemp = this->QCondenser / this->CondMassFlowRate / CpCond + CondInletTemp;
7316 : } else {
7317 0 : ShowSevereError(state, format("CalcConstCOPChillerModel: Condenser flow = 0, for CONST COP Chiller={}", this->Name));
7318 0 : ShowContinueErrorTimeStamp(state, "");
7319 : }
7320 : } else { // Air Cooled or Evap Cooled
7321 : // Set condenser outlet temp to condenser inlet temp for Air Cooled or Evap Cooled
7322 : // since there is no CondMassFlowRate and would divide by zero
7323 0 : this->CondOutletTemp = CondInletTemp;
7324 : }
7325 :
7326 : // Calculate Energy
7327 3 : this->CondenserEnergy = this->QCondenser * state.dataHVACGlobal->TimeStepSysSec;
7328 3 : this->Energy = this->Power * state.dataHVACGlobal->TimeStepSysSec;
7329 3 : this->EvaporatorEnergy = this->QEvaporator * state.dataHVACGlobal->TimeStepSysSec;
7330 :
7331 : // check for problems BG 9/12/06 (deal with observed negative energy results)
7332 3 : if (this->Energy < 0.0) { // there is a serious problem
7333 :
7334 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
7335 : // first check for run away condenser loop temps (only reason yet to be observed for this?)
7336 0 : if (CondInletTemp > 70.0) {
7337 0 : ShowSevereError(
7338 0 : state, format("CalcConstCOPChillerModel: Condenser loop inlet temperatures over 70.0 C for ConstCOPChiller={}", this->Name));
7339 0 : ShowContinueErrorTimeStamp(state, "");
7340 0 : ShowContinueError(state, format("Condenser loop water temperatures are too high at{:.2R}", CondInletTemp));
7341 0 : ShowContinueError(state, "Check input for condenser plant loop, especially cooling tower");
7342 0 : ShowContinueError(state, format("Evaporator inlet temperature: {:.2R}", state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp));
7343 :
7344 0 : ShowFatalError(state, "Program Terminates due to previous error condition");
7345 : }
7346 : }
7347 : // If makes it here, set limits, chiller can't have negative energy/power
7348 : // proceeding silently for now but may want to throw error here
7349 0 : this->Power = 0.0;
7350 0 : this->Energy = 0.0;
7351 : }
7352 : }
7353 :
7354 0 : void ConstCOPChillerSpecs::update(EnergyPlusData &state, Real64 const MyLoad, bool const RunFlag)
7355 : {
7356 : // SUBROUTINE INFORMATION:
7357 : // AUTHOR: Dan Fisher
7358 : // DATE WRITTEN: October 1998
7359 :
7360 0 : Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
7361 :
7362 0 : if (MyLoad >= 0.0 || !RunFlag) { // Chiller not running so pass inlet states to outlet states
7363 0 : this->Power = 0.0;
7364 0 : this->QEvaporator = 0.0;
7365 0 : this->QCondenser = 0.0;
7366 0 : this->Energy = 0.0;
7367 0 : this->EvaporatorEnergy = 0.0;
7368 0 : this->CondenserEnergy = 0.0;
7369 0 : this->CondOutletTemp = this->CondInletTemp;
7370 0 : this->EvapOutletTemp = this->EvapInletTemp;
7371 0 : this->ActualCOP = 0.0;
7372 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
7373 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
7374 : }
7375 :
7376 : // set outlet node temperatures
7377 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = this->EvapInletTemp;
7378 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = this->CondInletTemp;
7379 :
7380 : } else {
7381 0 : if (this->Power != 0.0) {
7382 0 : this->ActualCOP = this->QEvaporator / this->Power;
7383 : } else {
7384 0 : this->ActualCOP = 0.0;
7385 : }
7386 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
7387 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
7388 : }
7389 :
7390 : // set outlet node temperatures
7391 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = this->EvapOutletTemp;
7392 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = this->CondOutletTemp;
7393 : }
7394 0 : }
7395 5 : void ConstCOPChillerSpecs::oneTimeInit(EnergyPlusData &state)
7396 : {
7397 : // Init more variables
7398 5 : if (this->MyFlag) {
7399 : // Locate the chillers on the plant loops for later usage
7400 1 : bool errFlag = false;
7401 1 : this->setupOutputVariables(state);
7402 3 : PlantUtilities::ScanPlantLoopsForObject(
7403 2 : state, this->Name, this->ChillerType, this->CWPlantLoc, errFlag, _, _, _, this->EvapInletNodeNum, _);
7404 1 : if (this->CondenserType != DataPlant::CondenserType::AirCooled && this->CondenserType != DataPlant::CondenserType::EvapCooled) {
7405 3 : PlantUtilities::ScanPlantLoopsForObject(
7406 2 : state, this->Name, this->ChillerType, this->CDPlantLoc, errFlag, _, _, _, this->CondInletNodeNum, _);
7407 1 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->CWPlantLoc, this->CDPlantLoc, this->ChillerType, true);
7408 : }
7409 :
7410 1 : if (errFlag) {
7411 0 : ShowFatalError(state, "CalcConstCOPChillerModel: Program terminated due to previous condition(s).");
7412 : }
7413 1 : if (this->FlowMode == DataPlant::FlowMode::Constant) {
7414 : // reset flow priority
7415 1 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
7416 : }
7417 :
7418 1 : if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
7419 : // reset flow priority
7420 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
7421 :
7422 : // check if setpoint on outlet node
7423 0 : if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
7424 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == DataLoopNode::SensedNodeFlagValue)) {
7425 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
7426 0 : if (!this->ModulatedFlowErrDone) {
7427 0 : ShowWarningError(state,
7428 0 : format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
7429 0 : ShowContinueError(
7430 : state,
7431 : " A temperature setpoint is needed at the outlet node of a chiller in variable flow mode, use a SetpointManager");
7432 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
7433 0 : this->ModulatedFlowErrDone = true;
7434 : }
7435 : } else {
7436 : // need call to EMS to check node
7437 0 : bool FatalError = false; // but not really fatal yet, but should be.
7438 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->EvapOutletNodeNum, HVAC::CtrlVarType::Temp, FatalError);
7439 0 : state.dataLoopNodes->NodeSetpointCheck(this->EvapOutletNodeNum).needsSetpointChecking = false;
7440 0 : if (FatalError) {
7441 0 : if (!this->ModulatedFlowErrDone) {
7442 0 : ShowWarningError(
7443 0 : state, format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
7444 0 : ShowContinueError(
7445 : state, " A temperature setpoint is needed at the outlet node of a chiller evaporator in variable flow mode");
7446 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the chiller evaporator outlet node ");
7447 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the outlet node ");
7448 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
7449 0 : this->ModulatedFlowErrDone = true;
7450 : }
7451 : }
7452 : }
7453 0 : this->ModulatedFlowSetToLoop = true;
7454 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
7455 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
7456 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
7457 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
7458 : }
7459 : }
7460 1 : this->MyFlag = false;
7461 : }
7462 5 : }
7463 :
7464 3 : bool ConstCOPChillerSpecs::thermosiphonDisabled(EnergyPlusData &state)
7465 : {
7466 3 : if (this->thermosiphonTempCurveIndex > 0) {
7467 3 : this->thermosiphonStatus = 0;
7468 3 : Real64 dT = this->EvapOutletTemp - this->CondInletTemp;
7469 3 : if (dT < this->thermosiphonMinTempDiff) {
7470 1 : return true;
7471 : }
7472 2 : Real64 thermosiphonCapFrac = Curve::CurveValue(state, this->thermosiphonTempCurveIndex, dT);
7473 2 : Real64 capFrac = this->partLoadRatio * this->cyclingRatio;
7474 2 : if (thermosiphonCapFrac >= capFrac) {
7475 1 : this->thermosiphonStatus = 1;
7476 1 : this->Power = 0.0;
7477 1 : return false;
7478 : }
7479 1 : return true;
7480 : } else {
7481 0 : return true;
7482 : }
7483 : }
7484 :
7485 : } // namespace PlantChillers
7486 :
7487 : } // namespace EnergyPlus
|