Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 : #include <cmath>
51 : #include <string>
52 :
53 : // ObjexxFCL Headers
54 : #include <ObjexxFCL/Fmath.hh>
55 : #include <ObjexxFCL/string.functions.hh>
56 :
57 : // EnergyPlus Headers
58 : #include <EnergyPlus/Autosizing/All_Simple_Sizing.hh>
59 : #include <EnergyPlus/BranchNodeConnections.hh>
60 : #include <EnergyPlus/ChillerElectricEIR.hh>
61 : #include <EnergyPlus/CurveManager.hh>
62 : #include <EnergyPlus/Data/EnergyPlusData.hh>
63 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
64 : #include <EnergyPlus/DataEnvironment.hh>
65 : #include <EnergyPlus/DataHVACGlobals.hh>
66 : #include <EnergyPlus/DataIPShortCuts.hh>
67 : #include <EnergyPlus/DataLoopNode.hh>
68 : #include <EnergyPlus/DataSizing.hh>
69 : #include <EnergyPlus/EMSManager.hh>
70 : #include <EnergyPlus/FaultsManager.hh>
71 : #include <EnergyPlus/FluidProperties.hh>
72 : #include <EnergyPlus/General.hh>
73 : #include <EnergyPlus/GeneralRoutines.hh>
74 : #include <EnergyPlus/GlobalNames.hh>
75 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
76 : #include <EnergyPlus/NodeInputManager.hh>
77 : #include <EnergyPlus/OutAirNodeManager.hh>
78 : #include <EnergyPlus/OutputProcessor.hh>
79 : #include <EnergyPlus/OutputReportPredefined.hh>
80 : #include <EnergyPlus/Plant/DataPlant.hh>
81 : #include <EnergyPlus/Plant/PlantLocation.hh>
82 : #include <EnergyPlus/PlantUtilities.hh>
83 : #include <EnergyPlus/Psychrometrics.hh>
84 : #include <EnergyPlus/ScheduleManager.hh>
85 : #include <EnergyPlus/StandardRatings.hh>
86 : #include <EnergyPlus/UtilityRoutines.hh>
87 :
88 : namespace EnergyPlus::ChillerElectricEIR {
89 :
90 : // NOTES:
91 : // The Electric EIR and Reformulated EIR chiller models are similar.
92 : // They only differ in the independent variable used to evaluate the performance curves.
93 :
94 : // MODULE INFORMATION:
95 : // AUTHOR Richard Raustad
96 : // DATE WRITTEN June 2004
97 : // MODIFIED Chandan Sharma, FSEC, February 2010, Added basin heater
98 : // Brent Griffith, NREL, Sept 2010, revised for plant changes
99 : // generalized fluid properties
100 :
101 : // PURPOSE OF THIS MODULE:
102 : // This module simulates the performance of the electric vapor
103 : // compression chiller used in DOE-2.
104 :
105 : // METHODOLOGY EMPLOYED:
106 : // Once the PlantLoopManager determines that the Electric EIR chiller
107 : // is available to meet a loop cooling demand, it calls SimElectricEIRChiller
108 : // which in turn calls the electric EIR model. The EIR chiller model is based on
109 : // polynomial fits of chiller performance data.
110 :
111 : // REFERENCES:
112 : // 1. DOE-2 Engineers Manual, Version 2.1A, November 1982, LBL-11353
113 :
114 1 : ElectricEIRChillerSpecs *ElectricEIRChillerSpecs::factory(EnergyPlusData &state, std::string const &objectName)
115 : {
116 : // Process the input data if it hasn't been done already
117 1 : if (state.dataChillerElectricEIR->getInputFlag) {
118 1 : GetElectricEIRChillerInput(state);
119 1 : state.dataChillerElectricEIR->getInputFlag = false;
120 : }
121 : // Now look for this particular object in the list
122 1 : auto thisObj = std::find_if(state.dataChillerElectricEIR->ElectricEIRChiller.begin(),
123 1 : state.dataChillerElectricEIR->ElectricEIRChiller.end(),
124 1 : [&objectName](const ElectricEIRChillerSpecs &myObj) { return myObj.Name == objectName; });
125 1 : if (thisObj != state.dataChillerElectricEIR->ElectricEIRChiller.end()) return thisObj;
126 : // If we didn't find it, fatal
127 : ShowFatalError(state, format("LocalElectEIRChillerFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
128 : // Shut up the compiler
129 : return nullptr; // LCOV_EXCL_LINE
130 : }
131 :
132 1430 : void ElectricEIRChillerSpecs::simulate(
133 : EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, bool RunFlag)
134 : {
135 : // SUBROUTINE INFORMATION:
136 : // AUTHOR Richard Raustad
137 : // DATE WRITTEN June 2004
138 :
139 : // PURPOSE OF THIS SUBROUTINE:
140 : // This is the electric EIR chiller model driver. It gets the input for the
141 : // model, initializes simulation variables, calls the appropriate model and sets
142 : // up reporting variables.
143 :
144 1430 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) {
145 1430 : this->initialize(state, RunFlag, CurLoad);
146 1430 : this->calculate(state, CurLoad, RunFlag);
147 1430 : this->update(state, CurLoad, RunFlag);
148 :
149 0 : } else if (calledFromLocation.loopNum == this->CDPlantLoc.loopNum) {
150 0 : PlantUtilities::UpdateChillerComponentCondenserSide(state,
151 0 : calledFromLocation.loopNum,
152 : this->CDPlantLoc.loopSideNum,
153 : DataPlant::PlantEquipmentType::Chiller_ElectricEIR,
154 : this->CondInletNodeNum,
155 : this->CondOutletNodeNum,
156 : this->QCondenser,
157 : this->CondInletTemp,
158 : this->CondOutletTemp,
159 : this->CondMassFlowRate,
160 : FirstHVACIteration);
161 :
162 0 : } else if (calledFromLocation.loopNum == this->HRPlantLoc.loopNum) {
163 0 : PlantUtilities::UpdateComponentHeatRecoverySide(state,
164 : this->HRPlantLoc.loopNum,
165 : this->HRPlantLoc.loopSideNum,
166 : DataPlant::PlantEquipmentType::Chiller_ElectricEIR,
167 : this->HeatRecInletNodeNum,
168 : this->HeatRecOutletNodeNum,
169 : this->QHeatRecovered,
170 : this->HeatRecInletTemp,
171 : this->HeatRecOutletTemp,
172 : this->HeatRecMassFlow,
173 : FirstHVACIteration);
174 : }
175 1430 : }
176 :
177 5 : void ElectricEIRChillerSpecs::getDesignCapacities(
178 : [[maybe_unused]] EnergyPlusData &state, const PlantLocation &calledFromLocation, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
179 : {
180 5 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) {
181 5 : MinLoad = this->RefCap * this->MinPartLoadRat;
182 5 : MaxLoad = this->RefCap * this->MaxPartLoadRat;
183 5 : OptLoad = this->RefCap * this->OptPartLoadRat;
184 : } else {
185 0 : MinLoad = 0.0;
186 0 : MaxLoad = 0.0;
187 0 : OptLoad = 0.0;
188 : }
189 5 : }
190 :
191 5 : void ElectricEIRChillerSpecs::getDesignTemperatures(Real64 &TempDesCondIn, Real64 &TempDesEvapOut)
192 : {
193 5 : TempDesCondIn = this->TempRefCondIn;
194 5 : TempDesEvapOut = this->TempRefEvapOut;
195 5 : }
196 :
197 1 : void ElectricEIRChillerSpecs::getSizingFactor(Real64 &sizFac)
198 : {
199 1 : sizFac = this->SizFac;
200 1 : }
201 :
202 5 : void ElectricEIRChillerSpecs::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
203 : {
204 5 : bool runFlag = true;
205 5 : Real64 myLoad = 0.0;
206 :
207 5 : this->initialize(state, runFlag, myLoad);
208 :
209 5 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) {
210 5 : this->size(state);
211 : }
212 5 : }
213 :
214 5 : void GetElectricEIRChillerInput(EnergyPlusData &state)
215 : {
216 : // SUBROUTINE INFORMATION:
217 : // AUTHOR: Richard Raustad, FSEC
218 : // DATE WRITTEN: June 2004
219 :
220 : // PURPOSE OF THIS SUBROUTINE:
221 : // This routine will get the input required by the Electric EIR Chiller model.
222 :
223 : static constexpr std::string_view RoutineName("GetElectricEIRChillerInput: "); // include trailing blank space
224 : static constexpr std::string_view routineName = "GetElectricEIRChillerInput"; // include trailing blank space
225 :
226 5 : bool ErrorsFound(false); // True when input errors are found
227 :
228 5 : auto &s_ipsc = state.dataIPShortCut;
229 :
230 5 : s_ipsc->cCurrentModuleObject = "Chiller:Electric:EIR";
231 5 : int NumElectricEIRChillers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
232 :
233 5 : if (NumElectricEIRChillers <= 0) {
234 0 : ShowSevereError(state, format("No {} equipment specified in input file", s_ipsc->cCurrentModuleObject));
235 0 : ErrorsFound = true;
236 : }
237 :
238 : // ALLOCATE ARRAYS
239 5 : state.dataChillerElectricEIR->ElectricEIRChiller.allocate(NumElectricEIRChillers);
240 :
241 : // Load arrays with electric EIR chiller data
242 10 : for (int EIRChillerNum = 1; EIRChillerNum <= NumElectricEIRChillers; ++EIRChillerNum) {
243 5 : int NumAlphas = 0; // Number of elements in the alpha array
244 5 : int NumNums = 0; // Number of elements in the numeric array
245 5 : int IOStat = 0; // IO Status when calling get input subroutine
246 10 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
247 5 : s_ipsc->cCurrentModuleObject,
248 : EIRChillerNum,
249 5 : s_ipsc->cAlphaArgs,
250 : NumAlphas,
251 5 : s_ipsc->rNumericArgs,
252 : NumNums,
253 : IOStat,
254 5 : s_ipsc->lNumericFieldBlanks,
255 5 : s_ipsc->lAlphaFieldBlanks,
256 5 : s_ipsc->cAlphaFieldNames,
257 5 : s_ipsc->cNumericFieldNames);
258 :
259 5 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
260 :
261 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
262 5 : GlobalNames::VerifyUniqueChillerName(
263 10 : state, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject + " Name");
264 :
265 5 : auto &thisChiller = state.dataChillerElectricEIR->ElectricEIRChiller(EIRChillerNum);
266 5 : thisChiller.Name = s_ipsc->cAlphaArgs(1);
267 :
268 : // Performance curves
269 5 : thisChiller.ChillerCapFTIndex = Curve::GetCurveIndex(state, s_ipsc->cAlphaArgs(2));
270 5 : if (thisChiller.ChillerCapFTIndex == 0) {
271 0 : ShowSevereError(state, format("{}{} \"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
272 0 : ShowContinueError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
273 0 : ErrorsFound = true;
274 : }
275 :
276 5 : thisChiller.ChillerEIRFTIndex = Curve::GetCurveIndex(state, s_ipsc->cAlphaArgs(3));
277 5 : if (thisChiller.ChillerEIRFTIndex == 0) {
278 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
279 0 : ShowContinueError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
280 0 : ErrorsFound = true;
281 : }
282 :
283 5 : thisChiller.ChillerEIRFPLRIndex = Curve::GetCurveIndex(state, s_ipsc->cAlphaArgs(4));
284 5 : if (thisChiller.ChillerEIRFPLRIndex == 0) {
285 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
286 0 : ShowContinueError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)));
287 0 : ErrorsFound = true;
288 : }
289 :
290 5 : thisChiller.EvapInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
291 5 : s_ipsc->cAlphaArgs(5),
292 : ErrorsFound,
293 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
294 5 : s_ipsc->cAlphaArgs(1),
295 : DataLoopNode::NodeFluidType::Water,
296 : DataLoopNode::ConnectionType::Inlet,
297 : NodeInputManager::CompFluidStream::Primary,
298 : DataLoopNode::ObjectIsNotParent);
299 10 : thisChiller.EvapOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
300 5 : s_ipsc->cAlphaArgs(6),
301 : ErrorsFound,
302 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
303 5 : s_ipsc->cAlphaArgs(1),
304 : DataLoopNode::NodeFluidType::Water,
305 : DataLoopNode::ConnectionType::Outlet,
306 : NodeInputManager::CompFluidStream::Primary,
307 : DataLoopNode::ObjectIsNotParent);
308 10 : BranchNodeConnections::TestCompSet(
309 5 : state, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(5), s_ipsc->cAlphaArgs(6), "Chilled Water Nodes");
310 :
311 5 : if (Util::SameString(s_ipsc->cAlphaArgs(9), "WaterCooled")) {
312 2 : thisChiller.CondenserType = DataPlant::CondenserType::WaterCooled;
313 3 : } else if (Util::SameString(s_ipsc->cAlphaArgs(9), "AirCooled")) {
314 2 : thisChiller.CondenserType = DataPlant::CondenserType::AirCooled;
315 1 : } else if (Util::SameString(s_ipsc->cAlphaArgs(9), "EvaporativelyCooled")) {
316 1 : thisChiller.CondenserType = DataPlant::CondenserType::EvapCooled;
317 : } else {
318 0 : ShowSevereError(state, format("{}{}: {}", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
319 0 : ShowContinueError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(9), s_ipsc->cAlphaArgs(9)));
320 0 : ShowContinueError(state, "Valid entries are AirCooled, WaterCooled, or EvaporativelyCooled");
321 0 : ErrorsFound = true;
322 : }
323 :
324 5 : if (thisChiller.CondenserType == DataPlant::CondenserType::AirCooled || thisChiller.CondenserType == DataPlant::CondenserType::EvapCooled) {
325 : // Connection not required for air or evap cooled condenser
326 : // If the condenser inlet is blank for air cooled and evap cooled condensers then supply a generic name
327 : // since it is not used elsewhere for connection
328 3 : if (s_ipsc->lAlphaFieldBlanks(7)) {
329 0 : if (len(s_ipsc->cAlphaArgs(1)) < Constant::MaxNameLength - 25) { // protect against long name leading to > 100 chars
330 0 : s_ipsc->cAlphaArgs(7) = s_ipsc->cAlphaArgs(1) + " INLET NODE FOR CONDENSER";
331 : } else {
332 0 : s_ipsc->cAlphaArgs(7) = s_ipsc->cAlphaArgs(1).substr(0, 75) + " INLET NODE FOR CONDENSER";
333 : }
334 : }
335 3 : if (s_ipsc->lAlphaFieldBlanks(8)) {
336 0 : if (len(s_ipsc->cAlphaArgs(1)) < Constant::MaxNameLength - 26) { // protect against long name leading to > 100 chars
337 0 : s_ipsc->cAlphaArgs(8) = s_ipsc->cAlphaArgs(1) + " OUTLET NODE FOR CONDENSER";
338 : } else {
339 0 : s_ipsc->cAlphaArgs(8) = s_ipsc->cAlphaArgs(1).substr(0, 74) + " OUTLET NODE FOR CONDENSER";
340 : }
341 : }
342 :
343 3 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
344 3 : s_ipsc->cAlphaArgs(7),
345 : ErrorsFound,
346 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
347 3 : s_ipsc->cAlphaArgs(1),
348 : DataLoopNode::NodeFluidType::Air,
349 : DataLoopNode::ConnectionType::OutsideAirReference,
350 : NodeInputManager::CompFluidStream::Secondary,
351 : DataLoopNode::ObjectIsNotParent);
352 3 : bool Okay = true;
353 3 : OutAirNodeManager::CheckAndAddAirNodeNumber(state, thisChiller.CondInletNodeNum, Okay);
354 3 : if (!Okay) {
355 2 : ShowWarningError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
356 2 : ShowContinueError(state, format("Adding OutdoorAir:Node={}", s_ipsc->cAlphaArgs(7)));
357 : }
358 :
359 3 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
360 3 : s_ipsc->cAlphaArgs(8),
361 : ErrorsFound,
362 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
363 3 : s_ipsc->cAlphaArgs(1),
364 : DataLoopNode::NodeFluidType::Air,
365 : DataLoopNode::ConnectionType::Outlet,
366 : NodeInputManager::CompFluidStream::Secondary,
367 : DataLoopNode::ObjectIsNotParent);
368 :
369 5 : } else if (thisChiller.CondenserType == DataPlant::CondenserType::WaterCooled) {
370 : // Condenser inlet node name is necessary for water-cooled condenser
371 2 : if (s_ipsc->lAlphaFieldBlanks(7) || s_ipsc->lAlphaFieldBlanks(8)) {
372 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
373 0 : ShowContinueError(state, "Condenser Inlet or Outlet Node Name is blank.");
374 0 : ErrorsFound = true;
375 : }
376 :
377 2 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
378 2 : s_ipsc->cAlphaArgs(7),
379 : ErrorsFound,
380 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
381 2 : s_ipsc->cAlphaArgs(1),
382 : DataLoopNode::NodeFluidType::Water,
383 : DataLoopNode::ConnectionType::Inlet,
384 : NodeInputManager::CompFluidStream::Secondary,
385 : DataLoopNode::ObjectIsNotParent);
386 :
387 4 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
388 2 : s_ipsc->cAlphaArgs(8),
389 : ErrorsFound,
390 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
391 2 : s_ipsc->cAlphaArgs(1),
392 : DataLoopNode::NodeFluidType::Water,
393 : DataLoopNode::ConnectionType::Outlet,
394 : NodeInputManager::CompFluidStream::Secondary,
395 : DataLoopNode::ObjectIsNotParent);
396 :
397 6 : BranchNodeConnections::TestCompSet(
398 2 : state, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(7), s_ipsc->cAlphaArgs(8), "Condenser Water Nodes");
399 :
400 : } else {
401 : // Condenser inlet node name is necessary (never should reach this part of code)
402 0 : if (s_ipsc->lAlphaFieldBlanks(7) || s_ipsc->lAlphaFieldBlanks(8)) {
403 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
404 0 : ShowContinueError(state, "Condenser Inlet or Outlet Node Name is blank.");
405 0 : ErrorsFound = true;
406 : }
407 0 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
408 0 : s_ipsc->cAlphaArgs(7),
409 : ErrorsFound,
410 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
411 0 : s_ipsc->cAlphaArgs(1),
412 : DataLoopNode::NodeFluidType::Blank,
413 : DataLoopNode::ConnectionType::Inlet,
414 : NodeInputManager::CompFluidStream::Secondary,
415 : DataLoopNode::ObjectIsNotParent);
416 :
417 0 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
418 0 : s_ipsc->cAlphaArgs(8),
419 : ErrorsFound,
420 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
421 0 : s_ipsc->cAlphaArgs(1),
422 : DataLoopNode::NodeFluidType::Blank,
423 : DataLoopNode::ConnectionType::Outlet,
424 : NodeInputManager::CompFluidStream::Secondary,
425 : DataLoopNode::ObjectIsNotParent);
426 :
427 0 : BranchNodeConnections::TestCompSet(state,
428 0 : s_ipsc->cCurrentModuleObject,
429 0 : s_ipsc->cAlphaArgs(1),
430 0 : s_ipsc->cAlphaArgs(7),
431 0 : s_ipsc->cAlphaArgs(8),
432 : "Condenser (unknown?) Nodes");
433 : }
434 :
435 5 : thisChiller.FlowMode = static_cast<DataPlant::FlowMode>(getEnumValue(DataPlant::FlowModeNamesUC, s_ipsc->cAlphaArgs(10)));
436 5 : if (thisChiller.FlowMode == DataPlant::FlowMode::Invalid) {
437 0 : ShowSevereError(state, format("{}{}=\"{}\",", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
438 0 : ShowContinueError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10)));
439 0 : ShowContinueError(state, "Available choices are ConstantFlow, NotModulated, or LeavingSetpointModulated");
440 0 : ShowContinueError(state, "Flow mode NotModulated is assumed and the simulation continues.");
441 0 : thisChiller.FlowMode = DataPlant::FlowMode::NotModulated;
442 : };
443 :
444 : // Chiller rated performance data
445 5 : thisChiller.RefCap = s_ipsc->rNumericArgs(1);
446 5 : if (thisChiller.RefCap == DataSizing::AutoSize) {
447 5 : thisChiller.RefCapWasAutoSized = true;
448 : }
449 5 : if (s_ipsc->rNumericArgs(1) == 0.0) {
450 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
451 0 : ShowContinueError(state, format("Invalid {}={:.2R}", s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1)));
452 0 : ErrorsFound = true;
453 : }
454 5 : thisChiller.RefCOP = s_ipsc->rNumericArgs(2);
455 5 : if (s_ipsc->rNumericArgs(2) == 0.0) {
456 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
457 0 : ShowContinueError(state, format("Invalid {}={:.2R}", s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2)));
458 0 : ErrorsFound = true;
459 : }
460 5 : thisChiller.TempRefEvapOut = s_ipsc->rNumericArgs(3);
461 5 : thisChiller.TempRefCondIn = s_ipsc->rNumericArgs(4);
462 5 : thisChiller.EvapVolFlowRate = s_ipsc->rNumericArgs(5);
463 5 : if (thisChiller.EvapVolFlowRate == DataSizing::AutoSize) {
464 5 : thisChiller.EvapVolFlowRateWasAutoSized = true;
465 : }
466 5 : thisChiller.CondVolFlowRate = s_ipsc->rNumericArgs(6);
467 5 : if (thisChiller.CondVolFlowRate == DataSizing::AutoSize) {
468 4 : thisChiller.CondVolFlowRateWasAutoSized = true;
469 : }
470 :
471 5 : thisChiller.MinPartLoadRat = s_ipsc->rNumericArgs(7);
472 5 : thisChiller.MaxPartLoadRat = s_ipsc->rNumericArgs(8);
473 5 : thisChiller.OptPartLoadRat = s_ipsc->rNumericArgs(9);
474 5 : thisChiller.MinUnloadRat = s_ipsc->rNumericArgs(10);
475 5 : thisChiller.SizFac = s_ipsc->rNumericArgs(15);
476 5 : if (thisChiller.SizFac <= 0.0) thisChiller.SizFac = 1.0;
477 :
478 5 : if (thisChiller.MinPartLoadRat > thisChiller.MaxPartLoadRat) {
479 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
480 0 : ShowContinueError(state,
481 0 : format("{} [{:.3R}] > {} [{:.3R}]",
482 0 : s_ipsc->cNumericFieldNames(7),
483 0 : s_ipsc->rNumericArgs(7),
484 0 : s_ipsc->cNumericFieldNames(8),
485 0 : s_ipsc->rNumericArgs(8)));
486 0 : ShowContinueError(state, "Minimum part load ratio must be less than or equal to the maximum part load ratio ");
487 0 : ErrorsFound = true;
488 : }
489 :
490 5 : if (thisChiller.MinUnloadRat < thisChiller.MinPartLoadRat || thisChiller.MinUnloadRat > thisChiller.MaxPartLoadRat) {
491 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
492 0 : ShowContinueError(state, format("{} = {:.3R}", s_ipsc->cNumericFieldNames(10), s_ipsc->rNumericArgs(10)));
493 0 : ShowContinueError(state,
494 0 : format("{} must be greater than or equal to the {}", s_ipsc->cNumericFieldNames(10), s_ipsc->cNumericFieldNames(7)));
495 0 : ShowContinueError(state,
496 0 : format("{} must be less than or equal to the {}", s_ipsc->cNumericFieldNames(10), s_ipsc->cNumericFieldNames(8)));
497 0 : ErrorsFound = true;
498 : }
499 :
500 5 : if (thisChiller.OptPartLoadRat < thisChiller.MinPartLoadRat || thisChiller.OptPartLoadRat > thisChiller.MaxPartLoadRat) {
501 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
502 0 : ShowContinueError(state, format("{} = {:.3R}", s_ipsc->cNumericFieldNames(9), s_ipsc->rNumericArgs(9)));
503 0 : ShowContinueError(state,
504 0 : format("{} must be greater than or equal to the {}", s_ipsc->cNumericFieldNames(9), s_ipsc->cNumericFieldNames(7)));
505 0 : ShowContinueError(state, format("{} must be less than or equal to the {}", s_ipsc->cNumericFieldNames(9), s_ipsc->cNumericFieldNames(8)));
506 0 : ErrorsFound = true;
507 : }
508 :
509 5 : thisChiller.CondenserFanPowerRatio = s_ipsc->rNumericArgs(11);
510 5 : thisChiller.CompPowerToCondenserFrac = s_ipsc->rNumericArgs(12);
511 :
512 5 : if (thisChiller.CompPowerToCondenserFrac < 0.0 || thisChiller.CompPowerToCondenserFrac > 1.0) {
513 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
514 0 : ShowContinueError(state, format("{} = {:.3R}", s_ipsc->cNumericFieldNames(12), s_ipsc->rNumericArgs(12)));
515 0 : ShowContinueError(state, format("{} must be greater than or equal to zero", s_ipsc->cNumericFieldNames(12)));
516 0 : ShowContinueError(state, format("{} must be less than or equal to one", s_ipsc->cNumericFieldNames(12)));
517 0 : ErrorsFound = true;
518 : }
519 :
520 5 : thisChiller.TempLowLimitEvapOut = s_ipsc->rNumericArgs(13);
521 :
522 : // These are the heat recovery inputs
523 5 : thisChiller.DesignHeatRecVolFlowRate = s_ipsc->rNumericArgs(14);
524 5 : if (thisChiller.DesignHeatRecVolFlowRate == DataSizing::AutoSize) {
525 1 : thisChiller.DesignHeatRecVolFlowRateWasAutoSized = true;
526 : }
527 5 : if ((thisChiller.DesignHeatRecVolFlowRate > 0.0) || (thisChiller.DesignHeatRecVolFlowRate == DataSizing::AutoSize)) {
528 1 : thisChiller.HeatRecActive = true;
529 1 : thisChiller.HeatRecInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
530 1 : s_ipsc->cAlphaArgs(11),
531 : ErrorsFound,
532 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
533 1 : s_ipsc->cAlphaArgs(1),
534 : DataLoopNode::NodeFluidType::Water,
535 : DataLoopNode::ConnectionType::Inlet,
536 : NodeInputManager::CompFluidStream::Tertiary,
537 : DataLoopNode::ObjectIsNotParent);
538 1 : if (thisChiller.HeatRecInletNodeNum == 0) {
539 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
540 0 : ShowContinueError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaArgs(11)));
541 0 : ErrorsFound = true;
542 : }
543 1 : thisChiller.HeatRecOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
544 1 : s_ipsc->cAlphaArgs(12),
545 : ErrorsFound,
546 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
547 1 : s_ipsc->cAlphaArgs(1),
548 : DataLoopNode::NodeFluidType::Water,
549 : DataLoopNode::ConnectionType::Outlet,
550 : NodeInputManager::CompFluidStream::Tertiary,
551 : DataLoopNode::ObjectIsNotParent);
552 1 : if (thisChiller.HeatRecOutletNodeNum == 0) {
553 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
554 0 : ShowContinueError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(12), s_ipsc->cAlphaArgs(12)));
555 0 : ErrorsFound = true;
556 : }
557 :
558 2 : BranchNodeConnections::TestCompSet(
559 1 : state, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(11), s_ipsc->cAlphaArgs(12), "Heat Recovery Nodes");
560 : // store heat recovery volume flow for plant sizing
561 1 : if (thisChiller.DesignHeatRecVolFlowRate > 0.0) {
562 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, thisChiller.HeatRecInletNodeNum,
563 : thisChiller.DesignHeatRecVolFlowRate); // CR 6953
564 : }
565 1 : if (NumNums > 17) {
566 1 : if (!s_ipsc->lNumericFieldBlanks(18)) {
567 1 : thisChiller.HeatRecCapacityFraction = s_ipsc->rNumericArgs(18);
568 : } else {
569 0 : thisChiller.HeatRecCapacityFraction = 1.0;
570 : }
571 : } else {
572 0 : thisChiller.HeatRecCapacityFraction = 1.0;
573 : }
574 :
575 1 : if (NumAlphas <= 13 || s_ipsc->lAlphaFieldBlanks(14)) {
576 1 : thisChiller.heatRecInletLimitSched = nullptr; // Ok for this schedule to remain null if field is empty
577 0 : } else if ((thisChiller.heatRecInletLimitSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(14))) == nullptr) {
578 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(14), s_ipsc->cAlphaArgs(14));
579 0 : ErrorsFound = true;
580 : }
581 :
582 1 : if (NumAlphas > 14) {
583 1 : if (!s_ipsc->lAlphaFieldBlanks(15)) {
584 2 : thisChiller.HeatRecSetPointNodeNum = NodeInputManager::GetOnlySingleNode(state,
585 1 : s_ipsc->cAlphaArgs(15),
586 : ErrorsFound,
587 : DataLoopNode::ConnectionObjectType::ChillerElectricEIR,
588 1 : s_ipsc->cAlphaArgs(1),
589 : DataLoopNode::NodeFluidType::Water,
590 : DataLoopNode::ConnectionType::Sensor,
591 : NodeInputManager::CompFluidStream::Primary,
592 : DataLoopNode::ObjectIsNotParent);
593 : } else {
594 0 : thisChiller.HeatRecSetPointNodeNum = 0;
595 : }
596 : } else {
597 0 : thisChiller.HeatRecSetPointNodeNum = 0;
598 : }
599 :
600 : } else {
601 4 : thisChiller.HeatRecActive = false;
602 4 : thisChiller.DesignHeatRecMassFlowRate = 0.0;
603 4 : thisChiller.HeatRecInletNodeNum = 0;
604 4 : thisChiller.HeatRecOutletNodeNum = 0;
605 4 : if (!s_ipsc->lAlphaFieldBlanks(11) || !s_ipsc->lAlphaFieldBlanks(12)) {
606 0 : ShowWarningError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
607 0 : ShowContinueError(state, "Since Reference Heat Reclaim Volume Flow Rate = 0.0, heat recovery is inactive.");
608 0 : ShowContinueError(state, "However, node names were specified for heat recovery inlet or outlet nodes.");
609 : }
610 : }
611 :
612 5 : if (NumAlphas > 16) {
613 3 : thisChiller.CondenserFlowControl =
614 3 : static_cast<DataPlant::CondenserFlowControl>(getEnumValue(DataPlant::CondenserFlowControlNamesUC, s_ipsc->cAlphaArgs(17)));
615 : } else {
616 2 : thisChiller.CondenserFlowControl = DataPlant::CondenserFlowControl::ConstantFlow;
617 : }
618 :
619 5 : if (thisChiller.CondenserFlowControl == DataPlant::CondenserFlowControl::Invalid) {
620 0 : ShowSevereError(state, format("{}{}=\"{}\",", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
621 0 : ShowContinueError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(17), s_ipsc->cAlphaArgs(17)));
622 0 : ShowContinueError(state, "Available choices are ConstantFlow, ModulatedChillerPLR, ModulatedLoopPLR, or ModulatedDeltaTemperature");
623 0 : ShowContinueError(state, "Flow mode ConstantFlow is assumed and the simulation continues.");
624 0 : thisChiller.CondenserFlowControl = DataPlant::CondenserFlowControl::ConstantFlow;
625 : };
626 :
627 5 : if (NumAlphas > 17) {
628 3 : thisChiller.ChillerCondLoopFlowFLoopPLRIndex = Curve::GetCurveIndex(state, s_ipsc->cAlphaArgs(18));
629 : }
630 5 : if ((thisChiller.ChillerCondLoopFlowFLoopPLRIndex == 0) &&
631 3 : (thisChiller.CondenserFlowControl == DataPlant::CondenserFlowControl::ModulatedLoopPLR)) {
632 0 : ShowSevereError(state, format("{}{} \"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
633 0 : ShowContinueError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(18), s_ipsc->cAlphaArgs(18)));
634 0 : ErrorsFound = true;
635 : }
636 :
637 5 : if (NumAlphas <= 18 || s_ipsc->lAlphaFieldBlanks(19)) {
638 3 : thisChiller.condDTSched = nullptr; // Okay for this schedule to remain nullptr if field is empty
639 2 : } else if (((thisChiller.condDTSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(19))) == nullptr) &&
640 0 : thisChiller.CondenserFlowControl == DataPlant::CondenserFlowControl::ModulatedDeltaTemperature) {
641 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(19), s_ipsc->cAlphaArgs(19));
642 0 : ErrorsFound = true;
643 : }
644 :
645 5 : if (NumNums > 18) {
646 3 : thisChiller.MinCondFlowRatio = s_ipsc->rNumericArgs(19);
647 : }
648 :
649 : // Check the CAP-FT, EIR-FT, and PLR curves and warn user if different from 1.0 by more than +-10%
650 5 : if (thisChiller.ChillerCapFTIndex > 0) {
651 5 : Real64 CurveVal = Curve::CurveValue(state, thisChiller.ChillerCapFTIndex, thisChiller.TempRefEvapOut, thisChiller.TempRefCondIn);
652 5 : if (CurveVal > 1.10 || CurveVal < 0.90) {
653 0 : ShowWarningError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
654 0 : ShowContinueError(
655 : state, "Capacity ratio as a function of temperature curve output is not equal to 1.0 (+ or - 10%) at reference conditions.");
656 0 : ShowContinueError(state, format("Curve output at reference conditions = {:.3T}", CurveVal));
657 : }
658 : }
659 :
660 5 : if (thisChiller.ChillerEIRFTIndex > 0) {
661 5 : Real64 CurveVal = Curve::CurveValue(state, thisChiller.ChillerEIRFTIndex, thisChiller.TempRefEvapOut, thisChiller.TempRefCondIn);
662 5 : if (CurveVal > 1.10 || CurveVal < 0.90) {
663 0 : ShowWarningError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
664 0 : ShowContinueError(
665 : state, "Energy input ratio as a function of temperature curve output is not equal to 1.0 (+ or - 10%) at reference conditions.");
666 0 : ShowContinueError(state, format("Curve output at reference conditions = {:.3T}", CurveVal));
667 : }
668 : }
669 :
670 5 : if (thisChiller.ChillerEIRFPLRIndex > 0) {
671 5 : Real64 CurveVal = Curve::CurveValue(state, thisChiller.ChillerEIRFPLRIndex, 1.0);
672 :
673 5 : if (CurveVal > 1.10 || CurveVal < 0.90) {
674 0 : ShowWarningError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
675 0 : ShowContinueError(
676 : state,
677 : "Energy input ratio as a function of part-load ratio curve output is not equal to 1.0 (+ or - 10%) at reference conditions.");
678 0 : ShowContinueError(state, format("Curve output at reference conditions = {:.3T}", CurveVal));
679 : }
680 : }
681 :
682 5 : if (thisChiller.ChillerEIRFPLRIndex > 0) {
683 5 : bool FoundNegValue = false;
684 5 : Array1D<Real64> CurveValArray(11); // Used to evaluate PLFFPLR curve objects
685 60 : for (int CurveCheck = 0; CurveCheck <= 10; ++CurveCheck) {
686 55 : Real64 CurveValTmp = Curve::CurveValue(state, thisChiller.ChillerEIRFPLRIndex, double(CurveCheck / 10.0));
687 55 : if (CurveValTmp < 0.0) FoundNegValue = true;
688 55 : CurveValArray(CurveCheck + 1) = int(CurveValTmp * 100.0) / 100.0;
689 : }
690 5 : if (FoundNegValue) {
691 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
692 0 : ShowContinueError(state, "Energy input ratio as a function of part-load ratio curve shows negative values.");
693 0 : ShowContinueError(state, "EIR as a function of PLR curve output at various part-load ratios shown below:");
694 0 : ShowContinueError(state, "PLR = 0.00 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 1.00");
695 0 : ShowContinueError(state, fmt::format("Curve Output = {:7.2F}", fmt::join(CurveValArray, ",")));
696 0 : ErrorsFound = true;
697 : }
698 5 : }
699 : // Basin heater power as a function of temperature must be greater than or equal to 0
700 5 : thisChiller.BasinHeaterPowerFTempDiff = s_ipsc->rNumericArgs(16);
701 5 : if (s_ipsc->rNumericArgs(16) < 0.0) {
702 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
703 0 : ShowContinueError(state, format("{} must be >= 0", s_ipsc->cNumericFieldNames(16)));
704 0 : ErrorsFound = true;
705 : }
706 :
707 5 : thisChiller.BasinHeaterSetPointTemp = s_ipsc->rNumericArgs(17);
708 :
709 5 : if (thisChiller.BasinHeaterPowerFTempDiff > 0.0) {
710 0 : if (NumNums < 17) {
711 0 : thisChiller.BasinHeaterSetPointTemp = 2.0;
712 : }
713 0 : if (thisChiller.BasinHeaterSetPointTemp < 2.0) {
714 0 : ShowWarningError(state, format("{}{} \"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
715 0 : ShowContinueError(state, format("{} is less than 2 deg C. Freezing could occur.", s_ipsc->cNumericFieldNames(17)));
716 : }
717 : }
718 :
719 5 : if (!s_ipsc->lAlphaFieldBlanks(13)) {
720 0 : if ((thisChiller.basinHeaterSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(13))) == nullptr) {
721 0 : ShowWarningItemNotFound(state,
722 : eoh,
723 0 : s_ipsc->cAlphaFieldNames(13),
724 0 : s_ipsc->cAlphaArgs(13),
725 : "Basin heater operation will not be modeled and the simulation continues");
726 : }
727 : }
728 :
729 5 : if (NumAlphas > 15) {
730 3 : thisChiller.EndUseSubcategory = s_ipsc->cAlphaArgs(16);
731 : } else {
732 2 : thisChiller.EndUseSubcategory = "General";
733 : }
734 5 : if (!s_ipsc->lAlphaFieldBlanks(20)) {
735 1 : thisChiller.thermosiphonTempCurveIndex = Curve::GetCurveIndex(state, Util::makeUPPER(s_ipsc->cAlphaArgs(20)));
736 1 : if (thisChiller.thermosiphonTempCurveIndex == 0) {
737 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, s_ipsc->cCurrentModuleObject, thisChiller.Name));
738 0 : ShowContinueError(state, format("Invalid {} = {}", s_ipsc->cAlphaFieldNames(20), s_ipsc->cAlphaArgs(20)));
739 0 : ErrorsFound = true;
740 : }
741 : }
742 5 : thisChiller.thermosiphonMinTempDiff = s_ipsc->rNumericArgs(20);
743 : }
744 :
745 5 : if (ErrorsFound) {
746 0 : ShowFatalError(state, format("Errors found in processing input for {}", s_ipsc->cCurrentModuleObject));
747 : }
748 5 : }
749 :
750 5 : void ElectricEIRChillerSpecs::setupOutputVars(EnergyPlusData &state)
751 : {
752 10 : SetupOutputVariable(state,
753 : "Chiller Part Load Ratio",
754 : Constant::Units::None,
755 5 : this->ChillerPartLoadRatio,
756 : OutputProcessor::TimeStepType::System,
757 : OutputProcessor::StoreType::Average,
758 5 : this->Name);
759 :
760 10 : SetupOutputVariable(state,
761 : "Chiller Cycling Ratio",
762 : Constant::Units::None,
763 5 : this->ChillerCyclingRatio,
764 : OutputProcessor::TimeStepType::System,
765 : OutputProcessor::StoreType::Average,
766 5 : this->Name);
767 :
768 10 : SetupOutputVariable(state,
769 : "Chiller Electricity Rate",
770 : Constant::Units::W,
771 5 : this->Power,
772 : OutputProcessor::TimeStepType::System,
773 : OutputProcessor::StoreType::Average,
774 5 : this->Name);
775 :
776 10 : SetupOutputVariable(state,
777 : "Chiller Electricity Energy",
778 : Constant::Units::J,
779 5 : this->Energy,
780 : OutputProcessor::TimeStepType::System,
781 : OutputProcessor::StoreType::Sum,
782 5 : this->Name,
783 : Constant::eResource::Electricity,
784 : OutputProcessor::Group::Plant,
785 : OutputProcessor::EndUseCat::Cooling,
786 : this->EndUseSubcategory);
787 :
788 10 : SetupOutputVariable(state,
789 : "Chiller Evaporator Cooling Rate",
790 : Constant::Units::W,
791 5 : this->QEvaporator,
792 : OutputProcessor::TimeStepType::System,
793 : OutputProcessor::StoreType::Average,
794 5 : this->Name);
795 :
796 10 : SetupOutputVariable(state,
797 : "Chiller Evaporator Cooling Energy",
798 : Constant::Units::J,
799 5 : this->EvapEnergy,
800 : OutputProcessor::TimeStepType::System,
801 : OutputProcessor::StoreType::Sum,
802 5 : this->Name,
803 : Constant::eResource::EnergyTransfer,
804 : OutputProcessor::Group::Plant,
805 : OutputProcessor::EndUseCat::Chillers);
806 :
807 10 : SetupOutputVariable(state,
808 : "Chiller False Load Heat Transfer Rate",
809 : Constant::Units::W,
810 5 : this->ChillerFalseLoadRate,
811 : OutputProcessor::TimeStepType::System,
812 : OutputProcessor::StoreType::Average,
813 5 : this->Name);
814 :
815 10 : SetupOutputVariable(state,
816 : "Chiller False Load Heat Transfer Energy",
817 : Constant::Units::J,
818 5 : this->ChillerFalseLoad,
819 : OutputProcessor::TimeStepType::System,
820 : OutputProcessor::StoreType::Sum,
821 5 : this->Name);
822 :
823 10 : SetupOutputVariable(state,
824 : "Chiller Evaporator Inlet Temperature",
825 : Constant::Units::C,
826 5 : this->EvapInletTemp,
827 : OutputProcessor::TimeStepType::System,
828 : OutputProcessor::StoreType::Average,
829 5 : this->Name);
830 :
831 10 : SetupOutputVariable(state,
832 : "Chiller Evaporator Outlet Temperature",
833 : Constant::Units::C,
834 5 : this->EvapOutletTemp,
835 : OutputProcessor::TimeStepType::System,
836 : OutputProcessor::StoreType::Average,
837 5 : this->Name);
838 :
839 10 : SetupOutputVariable(state,
840 : "Chiller Evaporator Mass Flow Rate",
841 : Constant::Units::kg_s,
842 5 : this->EvapMassFlowRate,
843 : OutputProcessor::TimeStepType::System,
844 : OutputProcessor::StoreType::Average,
845 5 : this->Name);
846 :
847 10 : SetupOutputVariable(state,
848 : "Chiller Condenser Heat Transfer Rate",
849 : Constant::Units::W,
850 5 : this->QCondenser,
851 : OutputProcessor::TimeStepType::System,
852 : OutputProcessor::StoreType::Average,
853 5 : this->Name);
854 :
855 10 : SetupOutputVariable(state,
856 : "Chiller Condenser Heat Transfer Energy",
857 : Constant::Units::J,
858 5 : this->CondEnergy,
859 : OutputProcessor::TimeStepType::System,
860 : OutputProcessor::StoreType::Sum,
861 5 : this->Name,
862 : Constant::eResource::EnergyTransfer,
863 : OutputProcessor::Group::Plant,
864 : OutputProcessor::EndUseCat::HeatRejection);
865 :
866 10 : SetupOutputVariable(state,
867 : "Chiller COP",
868 : Constant::Units::W_W,
869 5 : this->ActualCOP,
870 : OutputProcessor::TimeStepType::System,
871 : OutputProcessor::StoreType::Average,
872 5 : this->Name);
873 :
874 10 : SetupOutputVariable(state,
875 : "Chiller Capacity Temperature Modifier Multiplier",
876 : Constant::Units::None,
877 5 : this->ChillerCapFT,
878 : OutputProcessor::TimeStepType::System,
879 : OutputProcessor::StoreType::Average,
880 5 : this->Name);
881 :
882 10 : SetupOutputVariable(state,
883 : "Chiller EIR Temperature Modifier Multiplier",
884 : Constant::Units::None,
885 5 : this->ChillerEIRFT,
886 : OutputProcessor::TimeStepType::System,
887 : OutputProcessor::StoreType::Average,
888 5 : this->Name);
889 :
890 10 : SetupOutputVariable(state,
891 : "Chiller EIR Part Load Modifier Multiplier",
892 : Constant::Units::None,
893 5 : this->ChillerEIRFPLR,
894 : OutputProcessor::TimeStepType::System,
895 : OutputProcessor::StoreType::Average,
896 5 : this->Name);
897 :
898 5 : SetupOutputVariable(state,
899 : "Thermosiphon Status",
900 : Constant::Units::None,
901 5 : this->thermosiphonStatus,
902 : OutputProcessor::TimeStepType::System,
903 : OutputProcessor::StoreType::Average,
904 5 : this->Name);
905 :
906 : // Condenser mass flow and outlet temp are valid for water cooled
907 5 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
908 4 : SetupOutputVariable(state,
909 : "Chiller Condenser Inlet Temperature",
910 : Constant::Units::C,
911 2 : this->CondInletTemp,
912 : OutputProcessor::TimeStepType::System,
913 : OutputProcessor::StoreType::Average,
914 2 : this->Name);
915 :
916 4 : SetupOutputVariable(state,
917 : "Chiller Condenser Outlet Temperature",
918 : Constant::Units::C,
919 2 : this->CondOutletTemp,
920 : OutputProcessor::TimeStepType::System,
921 : OutputProcessor::StoreType::Average,
922 2 : this->Name);
923 :
924 4 : SetupOutputVariable(state,
925 : "Chiller Condenser Mass Flow Rate",
926 : Constant::Units::kg_s,
927 2 : this->CondMassFlowRate,
928 : OutputProcessor::TimeStepType::System,
929 : OutputProcessor::StoreType::Average,
930 2 : this->Name);
931 :
932 : // If heat recovery is active then setup report variables
933 2 : if (this->HeatRecActive) {
934 2 : SetupOutputVariable(state,
935 : "Chiller Total Recovered Heat Rate",
936 : Constant::Units::W,
937 1 : this->QHeatRecovered,
938 : OutputProcessor::TimeStepType::System,
939 : OutputProcessor::StoreType::Average,
940 1 : this->Name);
941 :
942 2 : SetupOutputVariable(state,
943 : "Chiller Total Recovered Heat Energy",
944 : Constant::Units::J,
945 1 : this->EnergyHeatRecovery,
946 : OutputProcessor::TimeStepType::System,
947 : OutputProcessor::StoreType::Sum,
948 1 : this->Name,
949 : Constant::eResource::EnergyTransfer,
950 : OutputProcessor::Group::Plant,
951 : OutputProcessor::EndUseCat::HeatRecovery);
952 :
953 2 : SetupOutputVariable(state,
954 : "Chiller Heat Recovery Inlet Temperature",
955 : Constant::Units::C,
956 1 : this->HeatRecInletTemp,
957 : OutputProcessor::TimeStepType::System,
958 : OutputProcessor::StoreType::Average,
959 1 : this->Name);
960 :
961 2 : SetupOutputVariable(state,
962 : "Chiller Heat Recovery Outlet Temperature",
963 : Constant::Units::C,
964 1 : this->HeatRecOutletTemp,
965 : OutputProcessor::TimeStepType::System,
966 : OutputProcessor::StoreType::Average,
967 1 : this->Name);
968 :
969 2 : SetupOutputVariable(state,
970 : "Chiller Heat Recovery Mass Flow Rate",
971 : Constant::Units::kg_s,
972 1 : this->HeatRecMassFlow,
973 : OutputProcessor::TimeStepType::System,
974 : OutputProcessor::StoreType::Average,
975 1 : this->Name);
976 :
977 2 : SetupOutputVariable(state,
978 : "Chiller Effective Heat Rejection Temperature",
979 : Constant::Units::C,
980 1 : this->ChillerCondAvgTemp,
981 : OutputProcessor::TimeStepType::System,
982 : OutputProcessor::StoreType::Average,
983 1 : this->Name);
984 : }
985 :
986 : } else {
987 6 : SetupOutputVariable(state,
988 : "Chiller Condenser Inlet Temperature",
989 : Constant::Units::C,
990 3 : this->CondInletTemp,
991 : OutputProcessor::TimeStepType::System,
992 : OutputProcessor::StoreType::Average,
993 3 : this->Name);
994 :
995 3 : if (this->CondenserFanPowerRatio > 0) {
996 6 : SetupOutputVariable(state,
997 : "Chiller Condenser Fan Electricity Rate",
998 : Constant::Units::W,
999 3 : this->CondenserFanPower,
1000 : OutputProcessor::TimeStepType::System,
1001 : OutputProcessor::StoreType::Average,
1002 3 : this->Name);
1003 :
1004 6 : SetupOutputVariable(state,
1005 : "Chiller Condenser Fan Electricity Energy",
1006 : Constant::Units::J,
1007 3 : this->CondenserFanEnergyConsumption,
1008 : OutputProcessor::TimeStepType::System,
1009 : OutputProcessor::StoreType::Sum,
1010 3 : this->Name,
1011 : Constant::eResource::Electricity,
1012 : OutputProcessor::Group::Plant,
1013 : OutputProcessor::EndUseCat::Cooling);
1014 : }
1015 3 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
1016 2 : SetupOutputVariable(state,
1017 : "Chiller Evaporative Condenser Water Volume",
1018 : Constant::Units::m3,
1019 1 : this->EvapWaterConsump,
1020 : OutputProcessor::TimeStepType::System,
1021 : OutputProcessor::StoreType::Sum,
1022 1 : this->Name,
1023 : Constant::eResource::Water,
1024 : OutputProcessor::Group::HVAC,
1025 : OutputProcessor::EndUseCat::Cooling);
1026 :
1027 2 : SetupOutputVariable(state,
1028 : "Chiller Evaporative Condenser Mains Supply Water Volume",
1029 : Constant::Units::m3,
1030 1 : this->EvapWaterConsump,
1031 : OutputProcessor::TimeStepType::System,
1032 : OutputProcessor::StoreType::Sum,
1033 1 : this->Name,
1034 : Constant::eResource::MainsWater,
1035 : OutputProcessor::Group::HVAC,
1036 : OutputProcessor::EndUseCat::Cooling);
1037 :
1038 1 : if (this->BasinHeaterPowerFTempDiff > 0.0) {
1039 0 : SetupOutputVariable(state,
1040 : "Chiller Basin Heater Electricity Rate",
1041 : Constant::Units::W,
1042 0 : this->BasinHeaterPower,
1043 : OutputProcessor::TimeStepType::System,
1044 : OutputProcessor::StoreType::Average,
1045 0 : this->Name);
1046 :
1047 0 : SetupOutputVariable(state,
1048 : "Chiller Basin Heater Electricity Energy",
1049 : Constant::Units::J,
1050 0 : this->BasinHeaterConsumption,
1051 : OutputProcessor::TimeStepType::System,
1052 : OutputProcessor::StoreType::Sum,
1053 0 : this->Name,
1054 : Constant::eResource::Electricity,
1055 : OutputProcessor::Group::Plant,
1056 : OutputProcessor::EndUseCat::Chillers);
1057 : }
1058 : }
1059 : }
1060 5 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
1061 0 : SetupEMSInternalVariable(state, "Chiller Nominal Capacity", this->Name, "[W]", this->RefCap);
1062 : }
1063 5 : }
1064 :
1065 5 : void ElectricEIRChillerSpecs::oneTimeInit(EnergyPlusData &state)
1066 : {
1067 5 : this->setupOutputVars(state);
1068 :
1069 : // Locate the chillers on the plant loops for later usage
1070 5 : bool errFlag = false;
1071 15 : PlantUtilities::ScanPlantLoopsForObject(state,
1072 : this->Name,
1073 : DataPlant::PlantEquipmentType::Chiller_ElectricEIR,
1074 5 : this->CWPlantLoc,
1075 : errFlag,
1076 5 : this->TempLowLimitEvapOut,
1077 : _,
1078 : _,
1079 5 : this->EvapInletNodeNum,
1080 : _);
1081 5 : if (this->CondenserType != DataPlant::CondenserType::AirCooled && this->CondenserType != DataPlant::CondenserType::EvapCooled) {
1082 6 : PlantUtilities::ScanPlantLoopsForObject(
1083 4 : state, this->Name, DataPlant::PlantEquipmentType::Chiller_ElectricEIR, this->CDPlantLoc, errFlag, _, _, _, this->CondInletNodeNum, _);
1084 2 : PlantUtilities::InterConnectTwoPlantLoopSides(
1085 2 : state, this->CWPlantLoc, this->CDPlantLoc, DataPlant::PlantEquipmentType::Chiller_ElectricEIR, true);
1086 : }
1087 5 : if (this->HeatRecActive) {
1088 3 : PlantUtilities::ScanPlantLoopsForObject(
1089 2 : state, this->Name, DataPlant::PlantEquipmentType::Chiller_ElectricEIR, this->HRPlantLoc, errFlag, _, _, _, this->HeatRecInletNodeNum, _);
1090 1 : PlantUtilities::InterConnectTwoPlantLoopSides(
1091 1 : state, this->CWPlantLoc, this->HRPlantLoc, DataPlant::PlantEquipmentType::Chiller_ElectricEIR, true);
1092 : }
1093 :
1094 5 : if (this->CondenserType != DataPlant::CondenserType::AirCooled && this->CondenserType != DataPlant::CondenserType::EvapCooled &&
1095 2 : this->HeatRecActive) {
1096 1 : PlantUtilities::InterConnectTwoPlantLoopSides(
1097 1 : state, this->CDPlantLoc, this->HRPlantLoc, DataPlant::PlantEquipmentType::Chiller_ElectricEIR, false);
1098 : }
1099 :
1100 5 : if (errFlag) {
1101 0 : ShowFatalError(state, "InitElectricEIRChiller: Program terminated due to previous condition(s).");
1102 : }
1103 :
1104 5 : if (this->FlowMode == DataPlant::FlowMode::Constant) {
1105 : // reset flow priority
1106 1 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
1107 : }
1108 :
1109 5 : if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
1110 : // reset flow priority
1111 0 : DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
1112 : // check if setpoint on outlet node
1113 0 : if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
1114 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == DataLoopNode::SensedNodeFlagValue)) {
1115 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
1116 0 : if (!this->ModulatedFlowErrDone) {
1117 0 : ShowWarningError(state, format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
1118 0 : ShowContinueError(
1119 : state, " A temperature setpoint is needed at the outlet node of a chiller in variable flow mode, use a SetpointManager");
1120 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
1121 0 : this->ModulatedFlowErrDone = true;
1122 : }
1123 : } else {
1124 : // need call to EMS to check node
1125 0 : bool fatalError = false; // but not really fatal yet, but should be.
1126 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->EvapOutletNodeNum, HVAC::CtrlVarType::Temp, fatalError);
1127 0 : state.dataLoopNodes->NodeSetpointCheck(this->EvapOutletNodeNum).needsSetpointChecking = false;
1128 0 : if (fatalError) {
1129 0 : if (!this->ModulatedFlowErrDone) {
1130 0 : ShowWarningError(state,
1131 0 : format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
1132 0 : ShowContinueError(state,
1133 : " A temperature setpoint is needed at the outlet node of a chiller evaporator in variable flow mode");
1134 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the chiller evaporator outlet node ");
1135 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the outlet node ");
1136 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
1137 0 : this->ModulatedFlowErrDone = true;
1138 : }
1139 : }
1140 : }
1141 0 : this->ModulatedFlowSetToLoop = true;
1142 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
1143 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
1144 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
1145 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
1146 : }
1147 : }
1148 5 : }
1149 :
1150 6 : void ElectricEIRChillerSpecs::initEachEnvironment(EnergyPlusData &state)
1151 : {
1152 :
1153 : static constexpr std::string_view RoutineName("ElectricEIRChillerSpecs::initEachEnvironment");
1154 :
1155 6 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
1156 :
1157 6 : this->EvapMassFlowRateMax = this->EvapVolFlowRate * rho;
1158 :
1159 6 : PlantUtilities::InitComponentNodes(state, 0.0, this->EvapMassFlowRateMax, this->EvapInletNodeNum, this->EvapOutletNodeNum);
1160 :
1161 6 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1162 :
1163 2 : rho = this->CDPlantLoc.loop->glycol->getDensity(state, this->TempRefCondIn, RoutineName);
1164 2 : this->CondMassFlowRateMax = rho * this->CondVolFlowRate;
1165 2 : PlantUtilities::InitComponentNodes(state, 0.0, this->CondMassFlowRateMax, this->CondInletNodeNum, this->CondOutletNodeNum);
1166 2 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = this->TempRefCondIn;
1167 : } else { // air or evap air condenser
1168 : // Initialize maximum available condenser flow rate
1169 4 : rho = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, this->TempRefCondIn, 0.0, RoutineName);
1170 4 : this->CondMassFlowRateMax = rho * this->CondVolFlowRate;
1171 :
1172 4 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate = this->CondMassFlowRateMax;
1173 4 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
1174 4 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
1175 4 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
1176 4 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
1177 4 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMinAvail = 0.0;
1178 4 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRateMin = 0.0;
1179 4 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMinAvail = 0.0;
1180 4 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRateMin = 0.0;
1181 4 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = this->TempRefCondIn;
1182 : }
1183 :
1184 6 : if (this->HeatRecActive) {
1185 1 : rho = this->HRPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
1186 1 : this->DesignHeatRecMassFlowRate = rho * this->DesignHeatRecVolFlowRate;
1187 :
1188 1 : PlantUtilities::InitComponentNodes(state, 0.0, this->DesignHeatRecMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
1189 : // overall capacity limit
1190 1 : this->HeatRecMaxCapacityLimit = this->HeatRecCapacityFraction * (this->RefCap + this->RefCap / this->RefCOP);
1191 :
1192 1 : if (this->HeatRecSetPointNodeNum > 0) {
1193 1 : Real64 THeatRecSetPoint(0.0); // tests set point node for proper set point value
1194 1 : switch (this->HRPlantLoc.loop->LoopDemandCalcScheme) {
1195 1 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1196 1 : THeatRecSetPoint = state.dataLoopNodes->Node(this->HeatRecSetPointNodeNum).TempSetPoint;
1197 1 : } break;
1198 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1199 0 : THeatRecSetPoint = state.dataLoopNodes->Node(this->HeatRecSetPointNodeNum).TempSetPointHi;
1200 0 : } break;
1201 0 : default: {
1202 0 : assert(false);
1203 : } break;
1204 : }
1205 1 : if (THeatRecSetPoint == DataLoopNode::SensedNodeFlagValue) {
1206 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
1207 0 : if (!this->HRSPErrDone) {
1208 0 : ShowWarningError(state, format("Missing heat recovery temperature setpoint for chiller named {}", this->Name));
1209 0 : ShowContinueError(state,
1210 : " A temperature setpoint is needed at the heat recovery leaving temperature setpoint node "
1211 : "specified, use a SetpointManager");
1212 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for heat recovery. The simulation continues ...");
1213 0 : this->HeatRecSetPointNodeNum = this->HRPlantLoc.loop->TempSetPointNodeNum;
1214 0 : this->HRSPErrDone = true;
1215 : }
1216 : } else {
1217 : // need call to EMS to check node
1218 0 : bool fatalError = false; // but not really fatal yet, but should be.
1219 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->EvapOutletNodeNum, HVAC::CtrlVarType::Temp, fatalError);
1220 0 : state.dataLoopNodes->NodeSetpointCheck(this->EvapOutletNodeNum).needsSetpointChecking = false;
1221 0 : if (fatalError) {
1222 0 : if (!this->HRSPErrDone) {
1223 0 : ShowWarningError(state, format("Missing heat recovery temperature setpoint for chiller named {}", this->Name));
1224 0 : ShowContinueError(state,
1225 : " A temperature setpoint is needed at the heat recovery leaving temperature setpoint node "
1226 : "specified, use a SetpointManager to establish a setpoint");
1227 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at this node ");
1228 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for heat recovery. The simulation continues ...");
1229 0 : this->HeatRecSetPointNodeNum = this->HRPlantLoc.loop->TempSetPointNodeNum;
1230 0 : this->HRSPErrDone = true;
1231 : }
1232 : }
1233 : } // IF (.NOT. AnyEnergyManagementSystemInModel) THEN
1234 : } // IF(THeatRecSetPoint == SensedNodeFlagValue)THEN
1235 : } // IF(ElectricEIRChiller(EIRChillNum)%HeatRecSetPointNodeNum > 0)THEN
1236 : } // IF (ElectricEIRChiller(EIRChillNum)%HeatRecActive) THEN
1237 6 : }
1238 :
1239 1448 : void ElectricEIRChillerSpecs::initialize(EnergyPlusData &state, bool const RunFlag, Real64 const MyLoad)
1240 : {
1241 :
1242 : // SUBROUTINE INFORMATION:
1243 : // AUTHOR Richard Raustad, FSEC
1244 : // DATE WRITTEN June 2004
1245 :
1246 : // PURPOSE OF THIS SUBROUTINE:
1247 : // This subroutine is for initializations of the Electric EIR Chiller variables
1248 :
1249 : // METHODOLOGY EMPLOYED:
1250 : // Uses the status flags to trigger initializations.
1251 :
1252 : // Init more variables
1253 1448 : if (this->oneTimeFlag) {
1254 5 : this->oneTimeInit(state);
1255 5 : this->oneTimeFlag = false;
1256 : }
1257 :
1258 1448 : this->EquipFlowCtrl = DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowCtrl;
1259 :
1260 1448 : if (this->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
1261 6 : this->initEachEnvironment(state);
1262 6 : this->MyEnvrnFlag = false;
1263 : }
1264 1448 : if (!state.dataGlobal->BeginEnvrnFlag) {
1265 1356 : this->MyEnvrnFlag = true;
1266 : }
1267 :
1268 1448 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) && this->ModulatedFlowSetToLoop) {
1269 : // fix for clumsy old input that worked because loop setpoint was spread.
1270 : // could be removed with transition, testing , model change, period of being obsolete.
1271 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
1272 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
1273 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
1274 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
1275 : }
1276 :
1277 1448 : Real64 mdot = 0.0;
1278 1448 : Real64 mdotCond = 0.0;
1279 1448 : if ((std::abs(MyLoad) > 0.0) && RunFlag) {
1280 11 : mdot = this->EvapMassFlowRateMax;
1281 11 : mdotCond = this->CondMassFlowRateMax;
1282 : }
1283 :
1284 1448 : PlantUtilities::SetComponentFlowRate(state, mdot, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1285 :
1286 1448 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1287 6 : PlantUtilities::SetComponentFlowRate(state, mdotCond, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
1288 : // get minimum condenser plant loop pump mass flow rate
1289 6 : this->VSBranchPumpMinLimitMassFlowCond =
1290 6 : PlantUtilities::MinFlowIfBranchHasVSPump(state, this->CDPlantLoc, this->VSBranchPumpFoundCond, this->VSLoopPumpFoundCond, false);
1291 : }
1292 : // Initialize heat recovery flow rates at node
1293 1448 : if (this->HeatRecActive) {
1294 2 : mdot = RunFlag ? this->DesignHeatRecMassFlowRate : 0.0; // if RunFlag is true, mdot = this->DesignHeatRecMassFlowRate, else mdot = 0.0
1295 2 : PlantUtilities::SetComponentFlowRate(state, mdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1296 : }
1297 :
1298 1448 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
1299 2 : this->BasinHeaterPower = 0.0;
1300 : }
1301 1448 : }
1302 :
1303 11 : void ElectricEIRChillerSpecs::size(EnergyPlusData &state)
1304 : {
1305 :
1306 : // SUBROUTINE INFORMATION:
1307 : // AUTHOR Richard Raustad, FSEC
1308 : // DATE WRITTEN June 2004
1309 : // MODIFIED October 2013 Daeho Kang, add component sizing table entries
1310 :
1311 : // PURPOSE OF THIS SUBROUTINE:
1312 : // This subroutine is for sizing Electric EIR Chiller Components for which capacities and flow rates
1313 : // have not been specified in the input.
1314 :
1315 : // METHODOLOGY EMPLOYED:
1316 : // Obtains evaporator flow rate from the plant sizing array. Calculates reference capacity from
1317 : // the evaporator flow rate and the chilled water loop design delta T. The condenser flow rate
1318 : // is calculated from the reference capacity, the COP, and the condenser loop design delta T.
1319 :
1320 : static constexpr std::string_view RoutineName("SizeElectricEIRChiller");
1321 :
1322 11 : int PltSizCondNum = 0;
1323 11 : bool ErrorsFound = false;
1324 11 : Real64 tmpNomCap = this->RefCap;
1325 11 : Real64 tmpEvapVolFlowRate = this->EvapVolFlowRate;
1326 11 : Real64 tmpCondVolFlowRate = this->CondVolFlowRate;
1327 :
1328 11 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1329 4 : PltSizCondNum = this->CDPlantLoc.loop->PlantSizNum;
1330 : }
1331 :
1332 : // find the appropriate Plant Sizing object
1333 11 : int PltSizNum = this->CWPlantLoc.loop->PlantSizNum;
1334 :
1335 11 : if (PltSizNum > 0) {
1336 11 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1337 10 : tmpEvapVolFlowRate = state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
1338 : } else {
1339 1 : if (this->EvapVolFlowRateWasAutoSized) tmpEvapVolFlowRate = 0.0;
1340 : }
1341 11 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1342 7 : if (this->EvapVolFlowRateWasAutoSized) {
1343 6 : this->EvapVolFlowRate = tmpEvapVolFlowRate;
1344 6 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1345 5 : BaseSizer::reportSizerOutput(
1346 : state, "Chiller:Electric:EIR", this->Name, "Design Size Reference Chilled Water Flow Rate [m3/s]", tmpEvapVolFlowRate);
1347 : }
1348 6 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1349 5 : BaseSizer::reportSizerOutput(state,
1350 : "Chiller:Electric:EIR",
1351 : this->Name,
1352 : "Initial Design Size Reference Chilled Water Flow Rate [m3/s]",
1353 : tmpEvapVolFlowRate);
1354 : }
1355 : } else { // Hard-size with sizing data
1356 1 : if (this->EvapVolFlowRate > 0.0 && tmpEvapVolFlowRate > 0.0) {
1357 1 : Real64 EvapVolFlowRateUser = this->EvapVolFlowRate;
1358 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1359 0 : BaseSizer::reportSizerOutput(state,
1360 : "Chiller:Electric:EIR",
1361 : this->Name,
1362 : "Design Size Reference Chilled Water Flow Rate [m3/s]",
1363 : tmpEvapVolFlowRate,
1364 : "User-Specified Reference Chilled Water Flow Rate [m3/s]",
1365 : EvapVolFlowRateUser);
1366 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1367 0 : if ((std::abs(tmpEvapVolFlowRate - EvapVolFlowRateUser) / EvapVolFlowRateUser) >
1368 0 : state.dataSize->AutoVsHardSizingThreshold) {
1369 0 : ShowMessage(state, format("SizeChillerElectricEIR: Potential issue with equipment sizing for {}", this->Name));
1370 0 : ShowContinueError(state,
1371 0 : format("User-Specified Reference Chilled Water Flow Rate of {:.5R} [m3/s]", EvapVolFlowRateUser));
1372 0 : ShowContinueError(
1373 0 : state, format("differs from Design Size Reference Chilled Water Flow Rate of {:.5R} [m3/s]", tmpEvapVolFlowRate));
1374 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1375 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1376 : }
1377 : }
1378 : }
1379 1 : tmpEvapVolFlowRate = EvapVolFlowRateUser;
1380 : }
1381 : }
1382 : }
1383 : } else {
1384 0 : if (this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1385 0 : ShowSevereError(state, "Autosizing of Electric Chiller evap flow rate requires a loop Sizing:Plant object");
1386 0 : ShowContinueError(state, format("Occurs in Electric Chiller object={}", this->Name));
1387 0 : ErrorsFound = true;
1388 : }
1389 0 : if (!this->EvapVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->EvapVolFlowRate > 0.0)) {
1390 0 : BaseSizer::reportSizerOutput(
1391 : state, "Chiller:Electric:EIR", this->Name, "User-Specified Reference Chilled Water Flow Rate [m3/s]", this->EvapVolFlowRate);
1392 : }
1393 : }
1394 :
1395 11 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->EvapInletNodeNum, tmpEvapVolFlowRate);
1396 :
1397 11 : if (PltSizNum > 0) {
1398 11 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1399 10 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
1400 :
1401 10 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
1402 10 : tmpNomCap = Cp * rho * state.dataSize->PlantSizData(PltSizNum).DeltaT * tmpEvapVolFlowRate;
1403 : } else {
1404 1 : tmpNomCap = 0.0;
1405 : }
1406 11 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1407 7 : if (this->RefCapWasAutoSized) {
1408 6 : this->RefCap = tmpNomCap;
1409 6 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1410 5 : BaseSizer::reportSizerOutput(state, "Chiller:Electric:EIR", this->Name, "Design Size Reference Capacity [W]", tmpNomCap);
1411 : }
1412 6 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1413 5 : BaseSizer::reportSizerOutput(state, "Chiller:Electric:EIR", this->Name, "Initial Design Size Reference Capacity [W]", tmpNomCap);
1414 : }
1415 : } else { // Hard-sized with sizing data
1416 1 : if (this->RefCap > 0.0 && tmpNomCap > 0.0) {
1417 1 : Real64 RefCapUser = this->RefCap;
1418 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1419 0 : BaseSizer::reportSizerOutput(state,
1420 : "Chiller:Electric:EIR",
1421 : this->Name,
1422 : "Design Size Reference Capacity [W]",
1423 : tmpNomCap,
1424 : "User-Specified Reference Capacity [W]",
1425 : RefCapUser);
1426 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1427 0 : if ((std::abs(tmpNomCap - RefCapUser) / RefCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
1428 0 : ShowMessage(state, format("SizeChillerElectricEIR: Potential issue with equipment sizing for {}", this->Name));
1429 0 : ShowContinueError(state, format("User-Specified Reference Capacity of {:.2R} [W]", RefCapUser));
1430 0 : ShowContinueError(state, format("differs from Design Size Reference Capacity of {:.2R} [W]", tmpNomCap));
1431 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1432 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1433 : }
1434 : }
1435 : }
1436 1 : tmpNomCap = RefCapUser;
1437 : }
1438 : }
1439 : }
1440 : } else {
1441 0 : if (this->RefCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1442 0 : ShowSevereError(state, "Autosizing of Electric Chiller reference capacity requires a loop Sizing:Plant object");
1443 0 : ShowContinueError(state, format("Occurs in Electric Chiller object={}", this->Name));
1444 0 : ErrorsFound = true;
1445 : }
1446 0 : if (!this->RefCapWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->RefCap > 0.0)) { // Hard-sized with no sizing data
1447 0 : BaseSizer::reportSizerOutput(state, "Chiller:Electric:EIR", this->Name, "User-Specified Reference Capacity [W]", this->RefCap);
1448 : }
1449 : }
1450 :
1451 11 : if (PltSizCondNum > 0 && PltSizNum > 0) {
1452 4 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow && tmpNomCap > 0.0) {
1453 :
1454 4 : Real64 rho = this->CDPlantLoc.loop->glycol->getDensity(state, this->TempRefCondIn, RoutineName);
1455 4 : Real64 Cp = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, this->TempRefCondIn, RoutineName);
1456 8 : tmpCondVolFlowRate = tmpNomCap * (1.0 + (1.0 / this->RefCOP) * this->CompPowerToCondenserFrac) /
1457 4 : (state.dataSize->PlantSizData(PltSizCondNum).DeltaT * Cp * rho);
1458 :
1459 : } else {
1460 0 : if (this->CondVolFlowRateWasAutoSized) tmpCondVolFlowRate = 0.0;
1461 : }
1462 4 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1463 4 : if (this->CondVolFlowRateWasAutoSized) {
1464 2 : this->CondVolFlowRate = tmpCondVolFlowRate;
1465 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1466 1 : BaseSizer::reportSizerOutput(
1467 : state, "Chiller:Electric:EIR", this->Name, "Design Size Reference Condenser Fluid Flow Rate [m3/s]", tmpCondVolFlowRate);
1468 : }
1469 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1470 2 : BaseSizer::reportSizerOutput(state,
1471 : "Chiller:Electric:EIR",
1472 : this->Name,
1473 : "Initial Design Size Reference Condenser Fluid Flow Rate [m3/s]",
1474 : tmpCondVolFlowRate);
1475 : }
1476 : } else {
1477 2 : if (this->CondVolFlowRate > 0.0 && tmpCondVolFlowRate > 0.0) {
1478 2 : Real64 CondVolFlowRateUser = this->CondVolFlowRate;
1479 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1480 1 : BaseSizer::reportSizerOutput(state,
1481 : "Chiller:Electric:EIR",
1482 : this->Name,
1483 : "Design Size Reference Condenser Fluid Flow Rate [m3/s]",
1484 : tmpCondVolFlowRate,
1485 : "User-Specified Reference Condenser Fluid Flow Rate [m3/s]",
1486 : CondVolFlowRateUser);
1487 1 : if (state.dataGlobal->DisplayExtraWarnings) {
1488 0 : if ((std::abs(tmpCondVolFlowRate - CondVolFlowRateUser) / CondVolFlowRateUser) >
1489 0 : state.dataSize->AutoVsHardSizingThreshold) {
1490 0 : ShowMessage(state, format("SizeChillerElectricEIR: Potential issue with equipment sizing for {}", this->Name));
1491 0 : ShowContinueError(state,
1492 0 : format("User-Specified Reference Condenser Fluid Flow Rate of {:.5R} [m3/s]", CondVolFlowRateUser));
1493 0 : ShowContinueError(
1494 : state,
1495 0 : format("differs from Design Size Reference Condenser Fluid Flow Rate of {:.5R} [m3/s]", tmpCondVolFlowRate));
1496 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1497 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1498 : }
1499 : }
1500 : }
1501 2 : tmpCondVolFlowRate = CondVolFlowRateUser;
1502 : }
1503 : }
1504 : }
1505 4 : } else {
1506 7 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1507 :
1508 0 : if (this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1509 0 : ShowSevereError(state, "Autosizing of Electric EIR Chiller condenser fluid flow rate requires a condenser");
1510 0 : ShowContinueError(state, "loop Sizing:Plant object");
1511 0 : ShowContinueError(state, format("Occurs in Electric EIR Chiller object={}", this->Name));
1512 0 : ErrorsFound = true;
1513 : }
1514 0 : if (!this->CondVolFlowRateWasAutoSized && state.dataPlnt->PlantFinalSizesOkayToReport && (this->CondVolFlowRate > 0.0)) {
1515 0 : BaseSizer::reportSizerOutput(
1516 : state, "Chiller:Electric:EIR", this->Name, "User-Specified Reference Condenser Fluid Flow Rate [m3/s]", this->CondVolFlowRate);
1517 : }
1518 :
1519 : } else {
1520 :
1521 : // Auto size condenser air flow to Total Capacity * 0.000114 m3/s/w (850 cfm/ton)
1522 7 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1523 3 : std::string_view CompType = DataPlant::PlantEquipTypeNames[static_cast<int>(DataPlant::PlantEquipmentType::Chiller_ElectricEIR)];
1524 3 : state.dataSize->DataConstantUsedForSizing = this->RefCap;
1525 3 : state.dataSize->DataFractionUsedForSizing = 0.000114;
1526 3 : Real64 TempSize = this->CondVolFlowRate;
1527 3 : bool bPRINT = true; // TRUE if sizing is reported to output (eio)
1528 3 : AutoCalculateSizer sizerCondAirFlow;
1529 3 : std::string stringOverride = "Reference Condenser Fluid Flow Rate [m3/s]";
1530 3 : if (state.dataGlobal->isEpJSON) stringOverride = "reference_condenser_fluid_flow_rate [m3/s]";
1531 3 : sizerCondAirFlow.overrideSizingString(stringOverride);
1532 3 : sizerCondAirFlow.initializeWithinEP(state, CompType, this->Name, bPRINT, RoutineName);
1533 3 : this->CondVolFlowRate = sizerCondAirFlow.size(state, TempSize, ErrorsFound);
1534 3 : tmpCondVolFlowRate = this->CondVolFlowRate;
1535 3 : }
1536 : }
1537 : }
1538 :
1539 11 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1540 : // save the reference condenser water volumetric flow rate for use by the condenser water loop sizing algorithms
1541 4 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->CondInletNodeNum, tmpCondVolFlowRate);
1542 : }
1543 :
1544 : // now do heat recovery flow rate sizing if active
1545 11 : if (this->HeatRecActive) {
1546 : Real64 tempHeatRecVolFlowRate;
1547 3 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1548 3 : tempHeatRecVolFlowRate = tmpCondVolFlowRate * this->HeatRecCapacityFraction;
1549 : } else {
1550 0 : if (this->EvapVolFlowRateWasAutoSized) {
1551 0 : tempHeatRecVolFlowRate = tmpEvapVolFlowRate;
1552 : } else {
1553 0 : tempHeatRecVolFlowRate = this->EvapVolFlowRate;
1554 : }
1555 0 : tempHeatRecVolFlowRate *= (1.0 + (1.0 / this->RefCOP)) * this->CompPowerToCondenserFrac * this->HeatRecCapacityFraction;
1556 : }
1557 3 : if (this->DesignHeatRecVolFlowRateWasAutoSized) {
1558 :
1559 3 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1560 3 : this->DesignHeatRecVolFlowRate = tempHeatRecVolFlowRate;
1561 3 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1562 1 : BaseSizer::reportSizerOutput(
1563 : state, "Chiller:Electric:EIR", this->Name, "Design Size Heat Recovery Water Flow Rate [m3/s]", tempHeatRecVolFlowRate);
1564 : }
1565 3 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1566 2 : BaseSizer::reportSizerOutput(
1567 : state, "Chiller:Electric:EIR", this->Name, "Intial Design Size Heat Recovery Water Flow Rate [m3/s]", tempHeatRecVolFlowRate);
1568 : }
1569 : }
1570 : } else {
1571 0 : if (this->DesignHeatRecVolFlowRate > 0.0 && tempHeatRecVolFlowRate > 0.0) {
1572 0 : Real64 nomHeatRecVolFlowRateUser = this->DesignHeatRecVolFlowRate;
1573 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1574 0 : if (state.dataGlobal->DoPlantSizing) {
1575 0 : BaseSizer::reportSizerOutput(state,
1576 : "Chiller:Electric:EIR",
1577 : this->Name,
1578 : "Design Size Heat Recovery Water Flow Rate [m3/s]",
1579 : tempHeatRecVolFlowRate,
1580 : "User-Specified Heat Recovery Water Flow Rate [m3/s]",
1581 : nomHeatRecVolFlowRateUser);
1582 : } else {
1583 0 : BaseSizer::reportSizerOutput(state,
1584 : "Chiller:Electric:EIR",
1585 : this->Name,
1586 : "User-Specified Heat Recovery Water Flow Rate [m3/s]",
1587 : nomHeatRecVolFlowRateUser);
1588 : }
1589 :
1590 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1591 0 : if ((std::abs(tempHeatRecVolFlowRate - nomHeatRecVolFlowRateUser) / nomHeatRecVolFlowRateUser) >
1592 0 : state.dataSize->AutoVsHardSizingThreshold) {
1593 0 : ShowMessage(state, format("SizeChillerElectricEIR: Potential issue with equipment sizing for {}", this->Name));
1594 0 : ShowContinueError(state,
1595 0 : format("User-Specified Heat Recovery Water Flow Rate of {:.5R} [m3/s]", nomHeatRecVolFlowRateUser));
1596 0 : ShowContinueError(
1597 0 : state, format("differs from Design Size Heat Recovery Water Flow Rate of {:.5R} [m3/s]", tempHeatRecVolFlowRate));
1598 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1599 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1600 : }
1601 : }
1602 : }
1603 0 : tempHeatRecVolFlowRate = nomHeatRecVolFlowRateUser;
1604 : }
1605 : }
1606 3 : if (!this->DesignHeatRecVolFlowRateWasAutoSized) tempHeatRecVolFlowRate = this->DesignHeatRecVolFlowRate;
1607 3 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->HeatRecInletNodeNum, tempHeatRecVolFlowRate);
1608 : } // Heat recovery active
1609 :
1610 11 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1611 :
1612 5 : Real64 IPLVSI_rpt_std229 = 0.0;
1613 5 : Real64 IPLVIP_rpt_std229 = 0.0;
1614 :
1615 5 : if (this->IPLVFlag) {
1616 5 : Real64 IPLVSI = 0.0;
1617 5 : Real64 IPLVIP = 0.0;
1618 5 : StandardRatings::CalcChillerIPLV(state,
1619 5 : this->Name,
1620 : DataPlant::PlantEquipmentType::Chiller_ElectricEIR,
1621 : this->RefCap,
1622 : this->RefCOP,
1623 : this->CondenserType,
1624 : this->ChillerCapFTIndex,
1625 : this->ChillerEIRFTIndex,
1626 : this->ChillerEIRFPLRIndex,
1627 : this->MinUnloadRat,
1628 : IPLVSI,
1629 : IPLVIP,
1630 10 : ObjexxFCL::Optional<const Real64>(),
1631 10 : ObjexxFCL::Optional_int_const(),
1632 10 : ObjexxFCL::Optional<const Real64>());
1633 :
1634 5 : IPLVSI_rpt_std229 = IPLVSI;
1635 5 : IPLVIP_rpt_std229 = IPLVIP;
1636 :
1637 5 : this->IPLVFlag = false;
1638 : }
1639 : // create predefined report
1640 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "Chiller:Electric:EIR");
1641 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomEff, this->Name, this->RefCOP);
1642 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->RefCap);
1643 :
1644 : // std 229 new Chillers table
1645 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerType, this->Name, "Chiller:Electric:EIR");
1646 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefCap, this->Name, this->RefCap);
1647 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEff, this->Name, this->RefCOP); // Eff == COP?
1648 10 : OutputReportPredefined::PreDefTableEntry(
1649 5 : state, state.dataOutRptPredefined->pdchChillerRatedCap, this->Name, this->RefCap); // did not find rated cap
1650 10 : OutputReportPredefined::PreDefTableEntry(
1651 5 : state, state.dataOutRptPredefined->pdchChillerRatedEff, this->Name, this->RefCOP); // did not find rated eff or cop ; also Eff == COP?
1652 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinSI, this->Name, IPLVSI_rpt_std229);
1653 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinIP, this->Name, IPLVIP_rpt_std229);
1654 10 : OutputReportPredefined::PreDefTableEntry(state,
1655 5 : state.dataOutRptPredefined->pdchChillerPlantloopName,
1656 : this->Name,
1657 10 : (this->CWPlantLoc.loop != nullptr) ? this->CWPlantLoc.loop->Name : "N/A");
1658 10 : OutputReportPredefined::PreDefTableEntry(state,
1659 5 : state.dataOutRptPredefined->pdchChillerPlantloopBranchName,
1660 : this->Name,
1661 10 : (this->CWPlantLoc.branch != nullptr) ? this->CWPlantLoc.branch->Name : "N/A");
1662 10 : OutputReportPredefined::PreDefTableEntry(state,
1663 5 : state.dataOutRptPredefined->pdchChillerCondLoopName,
1664 : this->Name,
1665 13 : (this->CDPlantLoc.loop != nullptr) ? this->CDPlantLoc.loop->Name : "N/A");
1666 10 : OutputReportPredefined::PreDefTableEntry(state,
1667 5 : state.dataOutRptPredefined->pdchChillerCondLoopBranchName,
1668 : this->Name,
1669 13 : (this->CDPlantLoc.loop != nullptr) ? this->CDPlantLoc.branch->Name : "N/A");
1670 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerMinPLR, this->Name, this->MinPartLoadRat);
1671 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerFuelType, this->Name, "Electricity");
1672 10 : OutputReportPredefined::PreDefTableEntry(
1673 5 : state, state.dataOutRptPredefined->pdchChillerRatedEntCondTemp, this->Name, this->TempRefCondIn); // Rated==Ref?
1674 10 : OutputReportPredefined::PreDefTableEntry(
1675 5 : state, state.dataOutRptPredefined->pdchChillerRatedLevEvapTemp, this->Name, this->TempRefEvapOut); // Rated==Ref?
1676 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEntCondTemp, this->Name, this->TempRefCondIn);
1677 5 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefLevEvapTemp, this->Name, this->TempRefEvapOut);
1678 :
1679 10 : OutputReportPredefined::PreDefTableEntry(state,
1680 5 : state.dataOutRptPredefined->pdchChillerDesSizeRefCHWFlowRate,
1681 : this->Name,
1682 : this->EvapMassFlowRateMax); // flowrate Max==DesignSizeRef flowrate?
1683 10 : OutputReportPredefined::PreDefTableEntry(state,
1684 5 : state.dataOutRptPredefined->pdchChillerDesSizeRefCondFluidFlowRate,
1685 : this->Name,
1686 : this->CondMassFlowRateMax); // Cond flowrate Max==DesignSizeRef Cond flowrate?
1687 10 : OutputReportPredefined::PreDefTableEntry(state,
1688 5 : state.dataOutRptPredefined->pdchChillerHeatRecPlantloopName,
1689 : this->Name,
1690 14 : (this->HRPlantLoc.loop != nullptr) ? this->HRPlantLoc.loop->Name : "N/A");
1691 10 : OutputReportPredefined::PreDefTableEntry(state,
1692 5 : state.dataOutRptPredefined->pdchChillerHeatRecPlantloopBranchName,
1693 : this->Name,
1694 14 : (this->HRPlantLoc.loop != nullptr) ? this->HRPlantLoc.branch->Name : "N/A");
1695 10 : OutputReportPredefined::PreDefTableEntry(
1696 5 : state, state.dataOutRptPredefined->pdchChillerRecRelCapFrac, this->Name, this->HeatRecCapacityFraction);
1697 : }
1698 :
1699 11 : if (ErrorsFound) {
1700 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
1701 : }
1702 11 : }
1703 :
1704 1440 : void ElectricEIRChillerSpecs::calculate(EnergyPlusData &state, Real64 &MyLoad, bool const RunFlag)
1705 : {
1706 : // SUBROUTINE INFORMATION:
1707 : // AUTHOR Richard Raustad, FSEC
1708 : // DATE WRITTEN July 2004
1709 : // MODIFIED Feb. 2010, Chandan Sharma, FSEC, Added basin heater
1710 : // Jun. 2016, Rongpeng Zhang, Applied the chiller supply water temperature sensor fault model
1711 : // Nov. 2016, Rongpeng Zhang, LBNL. Added Fouling Chiller fault
1712 :
1713 : // PURPOSE OF THIS SUBROUTINE:
1714 : // Simulate a vapor compression chiller using the DOE-2 model
1715 :
1716 : // METHODOLOGY EMPLOYED:
1717 : // Use empirical curve fits to model performance at off-reference conditions
1718 :
1719 : // REFERENCES:
1720 : // 1. DOE-2 Engineers Manual, Version 2.1A, November 1982, LBL-11353
1721 :
1722 : static constexpr std::string_view RoutineName("CalcElectricEIRChillerModel");
1723 :
1724 1440 : Real64 EvapOutletTempSetPoint(0.0); // Evaporator outlet temperature setpoint [C]
1725 1440 : Real64 EvapDeltaTemp(0.0); // Evaporator temperature difference [C]
1726 1440 : Real64 TempLoad(0.0); // Actual load to be met by chiller. This value is compared to MyLoad
1727 : // and reset when necessary since this chiller can cycle, the load passed
1728 : // should be the actual load. Instead the minimum PLR * RefCap is
1729 : // passed in. [W]
1730 1440 : Real64 CurrentEndTime = 0.0; // end time of time step for current simulation time step
1731 :
1732 : // Set module level inlet and outlet nodes and initialize other local variables
1733 1440 : this->CondMassFlowRate = 0.0;
1734 1440 : Real64 FRAC = 1.0; // Chiller cycling ratio
1735 :
1736 : // Set performance curve outputs to 0.0 when chiller is off
1737 1440 : this->ChillerCapFT = 0.0;
1738 1440 : this->ChillerEIRFT = 0.0;
1739 1440 : this->ChillerEIRFPLR = 0.0;
1740 1440 : this->thermosiphonStatus = 0;
1741 :
1742 : // calculate end time of current time step
1743 1440 : CurrentEndTime = state.dataGlobal->CurrentTime + state.dataHVACGlobal->SysTimeElapsed;
1744 :
1745 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
1746 : // Wait for next time step to print warnings. If simulation iterates, print out
1747 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
1748 : // If a warning occurs and the simulation down shifts, the warning is not valid.
1749 1440 : if (CurrentEndTime > this->CurrentEndTimeLast && state.dataHVACGlobal->TimeStepSys >= this->TimeStepSysLast) {
1750 169 : if (this->PrintMessage) {
1751 0 : ++this->MsgErrorCount;
1752 : // Show single warning and pass additional info to ShowRecurringWarningErrorAtEnd
1753 0 : if (this->MsgErrorCount < 2) {
1754 0 : ShowWarningError(state, format("{}.", this->MsgBuffer1));
1755 0 : ShowContinueError(state, this->MsgBuffer2);
1756 : } else {
1757 0 : ShowRecurringWarningErrorAtEnd(
1758 0 : state, this->MsgBuffer1 + " error continues.", this->ErrCount1, this->MsgDataLast, this->MsgDataLast, _, "[C]", "[C]");
1759 : }
1760 : }
1761 : }
1762 :
1763 : // save last system time step and last end time of current time step (used to determine if warning is valid)
1764 1440 : this->TimeStepSysLast = state.dataHVACGlobal->TimeStepSys;
1765 1440 : this->CurrentEndTimeLast = CurrentEndTime;
1766 :
1767 : // If no loop demand or chiller OFF, return
1768 : // If Chiller load is 0 or chiller is not running then leave the subroutine.Before leaving
1769 : // if the component control is SERIESACTIVE we set the component flow to inlet flow so that
1770 : // flow resolver will not shut down the branch
1771 1440 : if (MyLoad >= 0 || !RunFlag) {
1772 1430 : if (this->EquipFlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive ||
1773 1430 : this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Locked) {
1774 712 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
1775 : }
1776 1430 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1777 0 : if (DataPlant::CompData::getPlantComponent(state, this->CDPlantLoc).FlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive) {
1778 0 : this->CondMassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
1779 : }
1780 : }
1781 1430 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
1782 0 : CalcBasinHeaterPower(
1783 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
1784 : }
1785 1430 : this->PrintMessage = false;
1786 1431 : return;
1787 : }
1788 :
1789 : // initialize outlet air humidity ratio of air or evap cooled chillers
1790 10 : this->CondOutletHumRat = state.dataLoopNodes->Node(this->CondInletNodeNum).HumRat;
1791 :
1792 10 : if (this->CondenserType == DataPlant::CondenserType::AirCooled) { // Condenser inlet temp = outdoor temp
1793 3 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirDryBulb;
1794 :
1795 : // Warn user if entering condenser dry-bulb temperature falls below 0 C
1796 3 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 0.0 && std::abs(MyLoad) > 0 && RunFlag && !state.dataGlobal->WarmupFlag) {
1797 0 : this->PrintMessage = true;
1798 :
1799 : this->MsgBuffer1 =
1800 0 : "ElectricEIRChillerModel - CHILLER:ELECTRIC:EIR \"" + this->Name + "\" - Air Cooled Condenser Inlet Temperature below 0C";
1801 0 : this->MsgBuffer2 = format("... Outdoor Dry-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
1802 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
1803 0 : state.dataEnvrn->EnvironmentName,
1804 0 : state.dataEnvrn->CurMnDy,
1805 0 : General::CreateSysTimeIntervalString(state));
1806 :
1807 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1808 : } else {
1809 3 : this->PrintMessage = false;
1810 : }
1811 7 : } else if (this->CondenserType == DataPlant::CondenserType::EvapCooled) { // Condenser inlet temp = (outdoor wet bulb)
1812 1 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).OutAirWetBulb;
1813 : // line above assumes evaporation pushes condenser inlet air humidity ratio to saturation
1814 1 : this->CondOutletHumRat = Psychrometrics::PsyWFnTdbTwbPb(state,
1815 1 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
1816 1 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
1817 1 : state.dataLoopNodes->Node(this->CondInletNodeNum).Press);
1818 :
1819 : // Warn user if evap condenser wet-bulb temperature falls below 10 C
1820 1 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < 10.0 && std::abs(MyLoad) > 0 && RunFlag && !state.dataGlobal->WarmupFlag) {
1821 0 : this->PrintMessage = true;
1822 : this->MsgBuffer1 =
1823 0 : "ElectricEIRChillerModel - CHILLER:ELECTRIC:EIR \"" + this->Name + "\" - Air Cooled Condenser Inlet Temperature below 10C";
1824 0 : this->MsgBuffer2 = format("... Outdoor Wet-bulb Condition = {:6.2F} C. Occurrence info = {}, {} {}",
1825 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
1826 0 : state.dataEnvrn->EnvironmentName,
1827 0 : state.dataEnvrn->CurMnDy,
1828 0 : General::CreateSysTimeIntervalString(state));
1829 0 : this->MsgDataLast = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1830 : } else {
1831 1 : this->PrintMessage = false;
1832 : }
1833 : } // End of the Air Cooled/Evap Cooled Logic block
1834 :
1835 : // If not air or evap cooled then set to the condenser node that is attached to a cooling tower
1836 10 : Real64 condInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1837 10 : this->CondInletTemp = condInletTemp; // needed for thermosiphon model
1838 :
1839 : // LOAD LOCAL VARIABLES FROM DATA STRUCTURE (for code readability)
1840 10 : Real64 ChillerRefCap = this->RefCap;
1841 10 : Real64 ReferenceCOP = this->RefCOP;
1842 10 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
1843 10 : Real64 TempLowLimitEout = this->TempLowLimitEvapOut;
1844 :
1845 : // If there is a fault of chiller fouling
1846 10 : if (this->FaultyChillerFoulingFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1847 0 : (!state.dataGlobal->KickOffSimulation)) {
1848 0 : int FaultIndex = this->FaultyChillerFoulingIndex;
1849 0 : Real64 NomCap_ff = ChillerRefCap;
1850 0 : Real64 ReferenceCOP_ff = ReferenceCOP;
1851 :
1852 : // calculate the Faulty Chiller Fouling Factor using fault information
1853 0 : this->FaultyChillerFoulingFactor = state.dataFaultsMgr->FaultsChillerFouling(FaultIndex).CalFoulingFactor(state);
1854 :
1855 : // update the Chiller nominal capacity and COP at faulty cases
1856 0 : ChillerRefCap = NomCap_ff * this->FaultyChillerFoulingFactor;
1857 0 : ReferenceCOP = ReferenceCOP_ff * this->FaultyChillerFoulingFactor;
1858 : }
1859 :
1860 : // Set initial mass flow rates
1861 10 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
1862 6 : this->CondMassFlowRate = this->CondMassFlowRateMax;
1863 6 : PlantUtilities::SetComponentFlowRate(state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
1864 6 : PlantUtilities::PullCompInterconnectTrigger(
1865 6 : state, this->CWPlantLoc, this->CondMassFlowIndex, this->CDPlantLoc, DataPlant::CriteriaType::MassFlowRate, this->CondMassFlowRate);
1866 :
1867 6 : if (this->CondMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance) {
1868 : // Shut chiller off if there is no condenser water flow
1869 1 : MyLoad = 0.0;
1870 1 : this->EvapMassFlowRate = 0.0;
1871 : // Use PlantUtilities::SetComponentFlowRate to decide actual flow
1872 1 : PlantUtilities::SetComponentFlowRate(state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1873 1 : return;
1874 : }
1875 : }
1876 :
1877 9 : switch (this->CWPlantLoc.loop->LoopDemandCalcScheme) {
1878 9 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1879 27 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
1880 18 : (DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) ||
1881 9 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint != DataLoopNode::SensedNodeFlagValue)) {
1882 : // there will be a valid setpoint on outlet
1883 4 : EvapOutletTempSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
1884 : } else { // use plant loop overall setpoint
1885 5 : EvapOutletTempSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
1886 : }
1887 9 : } break;
1888 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1889 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
1890 0 : (DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) ||
1891 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi != DataLoopNode::SensedNodeFlagValue)) {
1892 : // there will be a valid setpoint on outlet
1893 0 : EvapOutletTempSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
1894 : } else { // use plant loop overall setpoint
1895 0 : EvapOutletTempSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
1896 : }
1897 0 : } break;
1898 0 : default: {
1899 0 : assert(false);
1900 : } break;
1901 : }
1902 :
1903 : // If there is a fault of Chiller SWT Sensor
1904 9 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) && (!state.dataGlobal->KickOffSimulation)) {
1905 0 : int FaultIndex = this->FaultyChillerSWTIndex;
1906 0 : Real64 EvapOutletTempSetPoint_ff = EvapOutletTempSetPoint;
1907 :
1908 : // calculate the sensor offset using fault information
1909 0 : this->FaultyChillerSWTOffset = state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex).CalFaultOffsetAct(state);
1910 : // update the EvapOutletTempSetPoint
1911 0 : EvapOutletTempSetPoint =
1912 0 : max(this->TempLowLimitEvapOut,
1913 0 : min(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, EvapOutletTempSetPoint_ff - this->FaultyChillerSWTOffset));
1914 0 : this->FaultyChillerSWTOffset = EvapOutletTempSetPoint_ff - EvapOutletTempSetPoint;
1915 : }
1916 :
1917 : // correct temperature if using heat recovery
1918 : // use report values for latest valid calculation, lagged somewhat
1919 9 : Real64 AvgCondSinkTemp = condInletTemp;
1920 9 : if (this->HeatRecActive) {
1921 0 : if ((this->QHeatRecovered + this->QCondenser) > 0.0) { // protect div by zero
1922 0 : AvgCondSinkTemp =
1923 0 : (this->QHeatRecovered * this->HeatRecInletTemp + this->QCondenser * this->CondInletTemp) / (this->QHeatRecovered + this->QCondenser);
1924 : } else {
1925 0 : AvgCondSinkTemp = condInletTemp;
1926 : }
1927 : }
1928 :
1929 : // Get capacity curve info with respect to CW setpoint and entering condenser water temps
1930 9 : this->ChillerCapFT = Curve::CurveValue(state, this->ChillerCapFTIndex, EvapOutletTempSetPoint, AvgCondSinkTemp);
1931 :
1932 9 : if (this->ChillerCapFT < 0) {
1933 0 : if (this->ChillerCapFTError < 1 && this->CWPlantLoc.side->FlowLock != DataPlant::FlowLock::Unlocked && !state.dataGlobal->WarmupFlag) {
1934 0 : ++this->ChillerCapFTError;
1935 0 : ShowWarningError(state, format("CHILLER:ELECTRIC:EIR \"{}\":", this->Name));
1936 0 : ShowContinueError(state, format(" Chiller Capacity as a Function of Temperature curve output is negative ({:.3R}).", this->ChillerCapFT));
1937 0 : ShowContinueError(state,
1938 0 : format(" Negative value occurs using an Evaporator Outlet Temp of {:.1R} and a Condenser Inlet Temp of {:.1R}.",
1939 : EvapOutletTempSetPoint,
1940 : condInletTemp));
1941 0 : ShowContinueErrorTimeStamp(state, " Resetting curve output to zero and continuing simulation.");
1942 0 : } else if (this->CWPlantLoc.side->FlowLock != DataPlant::FlowLock::Unlocked && !state.dataGlobal->WarmupFlag) {
1943 0 : ++this->ChillerCapFTError;
1944 0 : ShowRecurringWarningErrorAtEnd(state,
1945 0 : "CHILLER:ELECTRIC:EIR \"" + this->Name +
1946 : "\": Chiller Capacity as a Function of Temperature curve output is negative warning continues...",
1947 0 : this->ChillerCapFTErrorIndex,
1948 0 : this->ChillerCapFT,
1949 0 : this->ChillerCapFT);
1950 : }
1951 0 : this->ChillerCapFT = 0.0;
1952 : }
1953 :
1954 : // Available chiller capacity as a function of temperature
1955 9 : Real64 AvailChillerCap = ChillerRefCap * this->ChillerCapFT;
1956 :
1957 : // Only perform this check for temperature setpoint control
1958 9 : if (DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) {
1959 : // Calculate water side load
1960 :
1961 0 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, RoutineName);
1962 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
1963 0 : switch (this->CWPlantLoc.loop->LoopDemandCalcScheme) {
1964 0 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1965 0 : TempLoad = this->EvapMassFlowRate * Cp *
1966 0 : (state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint);
1967 0 : } break;
1968 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1969 0 : TempLoad = this->EvapMassFlowRate * Cp *
1970 0 : (state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi);
1971 0 : } break;
1972 0 : default: {
1973 0 : assert(false);
1974 : } break;
1975 : }
1976 0 : TempLoad = max(0.0, TempLoad);
1977 :
1978 : // MyLoad is capped at minimum PLR * RefCap, adjust load to actual water side load because this chiller can cycle
1979 0 : if (std::abs(MyLoad) > TempLoad) {
1980 0 : MyLoad = sign(TempLoad, MyLoad);
1981 : }
1982 : }
1983 :
1984 : // Part load ratio based on load and available chiller capacity, cap at max part load ratio
1985 9 : Real64 PartLoadRat = 0.0; // Operating part load ratio
1986 9 : if (AvailChillerCap > 0) {
1987 9 : PartLoadRat = max(0.0, min(std::abs(MyLoad) / AvailChillerCap, this->MaxPartLoadRat));
1988 : }
1989 :
1990 9 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, RoutineName);
1991 :
1992 9 : if (DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) {
1993 0 : this->PossibleSubcooling = false;
1994 : } else {
1995 9 : this->PossibleSubcooling = true;
1996 : }
1997 : // Set evaporator heat transfer rate
1998 9 : this->QEvaporator = AvailChillerCap * PartLoadRat;
1999 :
2000 : // Either set the flow to the Constant value or calculate the flow for the variable volume
2001 9 : if ((this->FlowMode == DataPlant::FlowMode::Constant) || (this->FlowMode == DataPlant::FlowMode::NotModulated)) {
2002 : // Set the evaporator mass flow rate to design
2003 : // Start by assuming max (design) flow
2004 9 : this->EvapMassFlowRate = this->EvapMassFlowRateMax;
2005 : // Use PlantUtilities::SetComponentFlowRate to decide actual flow
2006 9 : PlantUtilities::SetComponentFlowRate(state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
2007 9 : if (this->EvapMassFlowRate != 0.0) {
2008 9 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
2009 : } else {
2010 0 : EvapDeltaTemp = 0.0;
2011 : }
2012 : // Evaluate outlet temp based on delta
2013 9 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
2014 :
2015 0 : } else if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
2016 :
2017 : // Calculate the Delta Temp from the inlet temp to the chiller outlet setpoint
2018 0 : switch (this->CWPlantLoc.loop->LoopDemandCalcScheme) {
2019 0 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
2020 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
2021 0 : } break;
2022 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
2023 0 : EvapDeltaTemp =
2024 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
2025 0 : } break;
2026 0 : default: {
2027 0 : assert(false);
2028 : } break;
2029 : }
2030 :
2031 0 : if (EvapDeltaTemp != 0) {
2032 : // Calculate desired flow to request based on load
2033 0 : this->EvapMassFlowRate = std::abs(this->QEvaporator / Cp / EvapDeltaTemp);
2034 0 : if ((this->EvapMassFlowRate - this->EvapMassFlowRateMax) > DataBranchAirLoopPlant::MassFlowTolerance) this->PossibleSubcooling = true;
2035 : // Check to see if the Maximum is exceeded, if so set to maximum
2036 0 : this->EvapMassFlowRate = min(this->EvapMassFlowRateMax, this->EvapMassFlowRate);
2037 : // Use PlantUtilities::SetComponentFlowRate to decide actual flow
2038 0 : PlantUtilities::SetComponentFlowRate(state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
2039 : // Should we recalculate this with the corrected setpoint?
2040 0 : switch (this->CWPlantLoc.loop->LoopDemandCalcScheme) {
2041 0 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
2042 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
2043 0 : } break;
2044 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
2045 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
2046 0 : } break;
2047 0 : default:
2048 0 : break;
2049 : }
2050 0 : this->QEvaporator = max(0.0, (this->EvapMassFlowRate * Cp * EvapDeltaTemp));
2051 : } else {
2052 : // Try to request zero flow
2053 0 : this->EvapMassFlowRate = 0.0;
2054 : // Use PlantUtilities::SetComponentFlowRate to decide actual flow
2055 0 : PlantUtilities::SetComponentFlowRate(state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
2056 : // No deltaT since component is not running
2057 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2058 0 : this->QEvaporator = 0.0;
2059 0 : PartLoadRat = 0.0;
2060 0 : this->ChillerPartLoadRatio = PartLoadRat;
2061 :
2062 : // so what if the delta T is zero? On FlowLock==0, the inlet temp could = setpoint, right?
2063 0 : if (this->DeltaTErrCount < 1 && !state.dataGlobal->WarmupFlag) {
2064 0 : ++this->DeltaTErrCount;
2065 0 : ShowWarningError(state, "Evaporator DeltaTemp = 0 in mass flow calculation (Tevapin = Tsetpoint).");
2066 0 : ShowContinueErrorTimeStamp(state, "");
2067 0 : } else if (!state.dataGlobal->WarmupFlag) {
2068 0 : ++this->ChillerCapFTError;
2069 0 : ShowRecurringWarningErrorAtEnd(state,
2070 0 : "CHILLER:ELECTRIC:EIR \"" + this->Name +
2071 : "\": Evaporator DeltaTemp = 0 in mass flow calculation warning continues...",
2072 0 : this->DeltaTErrCountIndex,
2073 : EvapDeltaTemp,
2074 : EvapDeltaTemp);
2075 : }
2076 : }
2077 : } // End of Constant Variable Flow If Block
2078 :
2079 9 : if (this->EvapMassFlowRate == 0.0) {
2080 0 : MyLoad = 0.0;
2081 0 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
2082 0 : CalcBasinHeaterPower(
2083 0 : state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
2084 : }
2085 0 : this->PrintMessage = false;
2086 0 : return;
2087 : }
2088 9 : if (this->PossibleSubcooling) {
2089 9 : this->QEvaporator = std::abs(MyLoad);
2090 9 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
2091 9 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
2092 : } else {
2093 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapOutletTempSetPoint;
2094 0 : this->QEvaporator = max(0.0, (this->EvapMassFlowRate * Cp * EvapDeltaTemp));
2095 0 : this->EvapOutletTemp = EvapOutletTempSetPoint;
2096 : }
2097 :
2098 : // Check that the Evap outlet temp honors both plant loop temp low limit and also the chiller low limit
2099 9 : if (this->EvapOutletTemp < TempLowLimitEout) {
2100 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - TempLowLimitEout) > DataPlant::DeltaTempTol) {
2101 0 : this->EvapOutletTemp = TempLowLimitEout;
2102 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
2103 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
2104 : } else {
2105 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2106 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
2107 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
2108 : }
2109 : }
2110 9 : if (this->EvapOutletTemp < state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) {
2111 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) >
2112 : DataPlant::DeltaTempTol) {
2113 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin;
2114 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
2115 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
2116 : } else {
2117 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2118 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
2119 0 : this->QEvaporator = this->EvapMassFlowRate * Cp * EvapDeltaTemp;
2120 : }
2121 : }
2122 : // If load exceeds the distributed load set to the distributed load
2123 9 : if (this->QEvaporator > std::abs(MyLoad)) {
2124 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
2125 0 : this->QEvaporator = std::abs(MyLoad);
2126 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
2127 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
2128 : } else {
2129 0 : this->QEvaporator = 0.0;
2130 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2131 : }
2132 : }
2133 :
2134 : // If there is a fault of Chiller SWT Sensor
2135 9 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) && (!state.dataGlobal->KickOffSimulation) &&
2136 0 : (this->EvapMassFlowRate > 0)) {
2137 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
2138 0 : int FaultIndex = this->FaultyChillerSWTIndex;
2139 0 : bool VarFlowFlag = (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated);
2140 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
2141 0 : .CalFaultChillerSWT(VarFlowFlag,
2142 : this->FaultyChillerSWTOffset,
2143 : Cp,
2144 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
2145 0 : this->EvapOutletTemp,
2146 0 : this->EvapMassFlowRate,
2147 0 : this->QEvaporator);
2148 : // update corresponding variables at faulty case
2149 0 : PartLoadRat = (AvailChillerCap > 0.0) ? (this->QEvaporator / AvailChillerCap) : 0.0;
2150 0 : PartLoadRat = max(0.0, min(PartLoadRat, this->MaxPartLoadRat));
2151 0 : this->ChillerPartLoadRatio = PartLoadRat;
2152 : }
2153 :
2154 : // Checks QEvaporator on the basis of the machine limits.
2155 9 : if (this->QEvaporator > (AvailChillerCap * this->MaxPartLoadRat)) {
2156 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
2157 0 : this->QEvaporator = AvailChillerCap * this->MaxPartLoadRat;
2158 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / Cp;
2159 : // evaporator outlet temperature is allowed to float upwards (recalculate AvailChillerCap? iterate?)
2160 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
2161 : } else {
2162 0 : this->QEvaporator = 0.0;
2163 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2164 : }
2165 : }
2166 :
2167 9 : if (AvailChillerCap > 0.0) {
2168 9 : PartLoadRat = max(0.0, min((this->QEvaporator / AvailChillerCap), this->MaxPartLoadRat));
2169 : } else {
2170 0 : PartLoadRat = 0.0;
2171 : }
2172 :
2173 : // Chiller cycles below minimum part load ratio, FRAC = amount of time chiller is ON during this time step
2174 9 : if (PartLoadRat < this->MinPartLoadRat) FRAC = min(1.0, (PartLoadRat / this->MinPartLoadRat));
2175 :
2176 : // set the module level variable used for reporting FRAC
2177 9 : this->ChillerCyclingRatio = FRAC;
2178 :
2179 : // Chiller is false loading below PLR = minimum unloading ratio, find PLR used for energy calculation
2180 9 : if (AvailChillerCap > 0.0) {
2181 9 : PartLoadRat = max(PartLoadRat, this->MinUnloadRat);
2182 : } else {
2183 0 : PartLoadRat = 0.0;
2184 : }
2185 :
2186 : // set the module level variable used for reporting PLR
2187 9 : this->ChillerPartLoadRatio = PartLoadRat;
2188 :
2189 : // calculate the load due to false loading on chiller over and above water side load
2190 9 : this->ChillerFalseLoadRate = (AvailChillerCap * PartLoadRat * FRAC) - this->QEvaporator;
2191 9 : if (this->ChillerFalseLoadRate < HVAC::SmallLoad) {
2192 8 : this->ChillerFalseLoadRate = 0.0;
2193 : }
2194 9 : if (this->QEvaporator == 0.0 && this->CondenserType == DataPlant::CondenserType::EvapCooled) {
2195 0 : CalcBasinHeaterPower(state, this->BasinHeaterPowerFTempDiff, this->basinHeaterSched, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
2196 : }
2197 :
2198 9 : this->ChillerEIRFT = Curve::CurveValue(state, this->ChillerEIRFTIndex, this->EvapOutletTemp, AvgCondSinkTemp);
2199 9 : if (this->ChillerEIRFT < 0.0) {
2200 0 : if (this->ChillerEIRFTError < 1 && this->CWPlantLoc.side->FlowLock != DataPlant::FlowLock::Unlocked && !state.dataGlobal->WarmupFlag) {
2201 0 : ++this->ChillerEIRFTError;
2202 0 : ShowWarningError(state, format("CHILLER:ELECTRIC:EIR \"{}\":", this->Name));
2203 0 : ShowContinueError(state, format(" Chiller EIR as a Function of Temperature curve output is negative ({:.3R}).", this->ChillerEIRFT));
2204 0 : ShowContinueError(state,
2205 0 : format(" Negative value occurs using an Evaporator Outlet Temp of {:.1R} and a Condenser Inlet Temp of {:.1R}.",
2206 0 : this->EvapOutletTemp,
2207 : condInletTemp));
2208 0 : ShowContinueErrorTimeStamp(state, " Resetting curve output to zero and continuing simulation.");
2209 0 : } else if (this->CWPlantLoc.side->FlowLock != DataPlant::FlowLock::Unlocked && !state.dataGlobal->WarmupFlag) {
2210 0 : ++this->ChillerEIRFTError;
2211 0 : ShowRecurringWarningErrorAtEnd(state,
2212 0 : "CHILLER:ELECTRIC:EIR \"" + this->Name +
2213 : "\": Chiller EIR as a Function of Temperature curve output is negative warning continues...",
2214 0 : this->ChillerEIRFTErrorIndex,
2215 0 : this->ChillerEIRFT,
2216 0 : this->ChillerEIRFT);
2217 : }
2218 0 : this->ChillerEIRFT = 0.0;
2219 : }
2220 :
2221 9 : this->ChillerEIRFPLR = Curve::CurveValue(state, this->ChillerEIRFPLRIndex, PartLoadRat);
2222 9 : if (this->ChillerEIRFPLR < 0.0) {
2223 0 : if (this->ChillerEIRFPLRError < 1 && this->CWPlantLoc.side->FlowLock != DataPlant::FlowLock::Unlocked && !state.dataGlobal->WarmupFlag) {
2224 0 : ++this->ChillerEIRFPLRError;
2225 0 : ShowWarningError(state, format("CHILLER:ELECTRIC:EIR \"{}\":", this->Name));
2226 0 : ShowContinueError(state, format(" Chiller EIR as a function of PLR curve output is negative ({:.3R}).", this->ChillerEIRFPLR));
2227 0 : ShowContinueError(state, format(" Negative value occurs using a part-load ratio of {:.3R}.", PartLoadRat));
2228 0 : ShowContinueErrorTimeStamp(state, " Resetting curve output to zero and continuing simulation.");
2229 0 : } else if (this->CWPlantLoc.side->FlowLock != DataPlant::FlowLock::Unlocked && !state.dataGlobal->WarmupFlag) {
2230 0 : ++this->ChillerEIRFPLRError;
2231 0 : ShowRecurringWarningErrorAtEnd(state,
2232 0 : "CHILLER:ELECTRIC:EIR \"" + this->Name +
2233 : "\": Chiller EIR as a function of PLR curve output is negative warning continues...",
2234 0 : this->ChillerEIRFPLRErrorIndex,
2235 0 : this->ChillerEIRFPLR,
2236 0 : this->ChillerEIRFPLR);
2237 : }
2238 0 : this->ChillerEIRFPLR = 0.0;
2239 : }
2240 9 : if (this->thermosiphonDisabled(state)) {
2241 8 : this->Power = (AvailChillerCap / ReferenceCOP) * this->ChillerEIRFPLR * this->ChillerEIRFT * FRAC;
2242 : }
2243 :
2244 9 : this->QCondenser = this->Power * this->CompPowerToCondenserFrac + this->QEvaporator + this->ChillerFalseLoadRate;
2245 :
2246 : // set condenser mass flow rate
2247 9 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
2248 5 : switch (this->CondenserFlowControl) {
2249 1 : case DataPlant::CondenserFlowControl::ConstantFlow: {
2250 1 : this->CondMassFlowRate = this->CondMassFlowRateMax;
2251 1 : } break;
2252 2 : case DataPlant::CondenserFlowControl::ModulatedChillerPLR: {
2253 2 : this->CondMassFlowRate = this->CondMassFlowRateMax * PartLoadRat;
2254 2 : } break;
2255 1 : case DataPlant::CondenserFlowControl::ModulatedLoopPLR: {
2256 1 : int PltSizNum = this->CWPlantLoc.loop->PlantSizNum;
2257 1 : int CondPltSizNum = this->CDPlantLoc.loop->PlantSizNum;
2258 1 : if (PltSizNum > 0 && CondPltSizNum > 0) {
2259 1 : Real64 chwLoopCap = state.dataSize->PlantSizData(PltSizNum).DesCapacity;
2260 1 : Real64 chwLoopDemand = std::abs(this->CWPlantLoc.side->UpdatedDemandToLoopSetPoint);
2261 1 : Real64 cwhLoopPLR = 0.0;
2262 1 : if (chwLoopDemand > 0) {
2263 1 : cwhLoopPLR = chwLoopDemand / chwLoopCap;
2264 : }
2265 1 : Real64 condWaterFlowFrac = Curve::CurveValue(state, this->ChillerCondLoopFlowFLoopPLRIndex, cwhLoopPLR);
2266 1 : Real64 cwLoopDesVolFlowRate = state.dataSize->PlantSizData(CondPltSizNum).DesVolFlowRate;
2267 1 : Real64 cwLoopVolFlowRate = condWaterFlowFrac * cwLoopDesVolFlowRate;
2268 1 : Real64 rho = this->CDPlantLoc.loop->glycol->getDensity(state, this->TempRefCondIn, RoutineName);
2269 1 : if (chwLoopDemand > 0) {
2270 1 : this->CondMassFlowRate = cwLoopVolFlowRate * rho * this->QEvaporator / chwLoopDemand;
2271 : } else {
2272 0 : this->CondMassFlowRate = 0.0;
2273 : }
2274 1 : } else {
2275 0 : ShowFatalError(state,
2276 0 : format("{}: The ModulatedLoopPLR condenser flow control requires a Sizing:Plant object for "
2277 : "both loops connected to the condenser and evaporator of the chiller.",
2278 : RoutineName));
2279 : }
2280 1 : } break;
2281 1 : case DataPlant::CondenserFlowControl::ModulatedDeltaTemperature: {
2282 1 : Real64 CpCond = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, this->CondInletTemp, RoutineName);
2283 1 : Real64 condDT = 0.0;
2284 1 : if (this->condDTSched != nullptr) {
2285 1 : condDT = this->condDTSched->getCurrentVal();
2286 : }
2287 1 : this->CondMassFlowRate = this->QCondenser / (CpCond * condDT);
2288 1 : } break;
2289 0 : default: {
2290 0 : this->CondMassFlowRate = this->CondMassFlowRateMax;
2291 0 : } break;
2292 : }
2293 5 : Real64 minCondMassFlowRate = this->MinCondFlowRatio * this->CondMassFlowRateMax;
2294 5 : Real64 minPumpMassFlowRate = this->VSBranchPumpMinLimitMassFlowCond;
2295 5 : Real64 maxCondMassFlowRate = min(this->CondMassFlowRate, this->CondMassFlowRateMax);
2296 5 : this->CondMassFlowRate = max(maxCondMassFlowRate, minCondMassFlowRate, minPumpMassFlowRate);
2297 5 : PlantUtilities::SetComponentFlowRate(state, this->CondMassFlowRate, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
2298 5 : PlantUtilities::PullCompInterconnectTrigger(
2299 5 : state, this->CWPlantLoc, this->CondMassFlowIndex, this->CDPlantLoc, DataPlant::CriteriaType::MassFlowRate, this->CondMassFlowRate);
2300 : }
2301 :
2302 9 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
2303 5 : if (this->CondMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
2304 : // If Heat Recovery specified for this vapor compression chiller, then Qcondenser will be adjusted by this subroutine
2305 5 : if (this->HeatRecActive) this->calcHeatRecovery(state, this->QCondenser, this->CondMassFlowRate, condInletTemp, this->QHeatRecovered);
2306 5 : Real64 CpCond = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, condInletTemp, RoutineName);
2307 :
2308 5 : this->CondOutletTemp = this->QCondenser / this->CondMassFlowRate / CpCond + condInletTemp;
2309 : } else {
2310 0 : ShowSevereError(state, format("CalcElectricEIRChillerModel: Condenser flow = 0, for ElectricEIRChiller={}", this->Name));
2311 0 : ShowContinueErrorTimeStamp(state, "");
2312 : // maybe this could be handled earlier, check if this component has a load and an evap flow rate
2313 : // then if cond flow is zero, just make a request to the condenser,
2314 : // then just say it couldn't run until condenser loop wakes up.
2315 : }
2316 : } else { // Air Cooled or Evap Cooled
2317 :
2318 4 : if (this->QCondenser > 0.0) {
2319 4 : this->CondMassFlowRate = this->CondMassFlowRateMax * PartLoadRat;
2320 : } else {
2321 0 : this->CondMassFlowRate = 0.0;
2322 : }
2323 :
2324 : // If Heat Recovery specified for this vapor compression chiller, then Qcondenser will be adjusted by this subroutine
2325 4 : if (this->HeatRecActive) this->calcHeatRecovery(state, this->QCondenser, this->CondMassFlowRate, condInletTemp, this->QHeatRecovered);
2326 :
2327 4 : if (CondMassFlowRate > 0.0) {
2328 4 : Real64 CpCond = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(this->CondInletNodeNum).HumRat);
2329 4 : CondOutletTemp = CondInletTemp + QCondenser / CondMassFlowRate / CpCond;
2330 : } else {
2331 0 : this->CondOutletTemp = condInletTemp;
2332 : }
2333 :
2334 4 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
2335 1 : Real64 const RhoWater = Psychrometrics::RhoH2O(Constant::InitConvTemp);
2336 : // CondMassFlowRate is already multiplied by PLR, convert to water use rate
2337 1 : this->EvapWaterConsumpRate =
2338 1 : ((this->CondOutletHumRat - state.dataLoopNodes->Node(this->CondInletNodeNum).HumRat) * this->CondMassFlowRate) / RhoWater;
2339 : }
2340 : }
2341 :
2342 : // Calculate condenser fan power
2343 9 : if (this->ChillerCapFT > 0.0) {
2344 9 : this->CondenserFanPower = ChillerRefCap * this->CondenserFanPowerRatio * FRAC;
2345 : } else {
2346 0 : this->CondenserFanPower = 0.0;
2347 : }
2348 : }
2349 :
2350 0 : void ElectricEIRChillerSpecs::calcHeatRecovery(EnergyPlusData &state,
2351 : Real64 &QCond, // Current condenser load [W]
2352 : Real64 const CondMassFlow, // Current condenser mass flow [kg/s]
2353 : Real64 const condInletTemp, // Current condenser inlet temp [C]
2354 : Real64 &QHeatRec // Amount of heat recovered [W]
2355 : )
2356 : {
2357 : // SUBROUTINE INFORMATION:
2358 : // AUTHOR: Richard Liesen
2359 : // DATE WRITTEN: January 2004
2360 : // MODIFIED: Richard Raustad, FSEC (occurrences of EIR only, calcs are identical to electric chiller)
2361 :
2362 : // PURPOSE OF THIS SUBROUTINE:
2363 : // Calculate the heat recovered from the chiller condenser
2364 :
2365 : static constexpr std::string_view RoutineName("EIRChillerHeatRecovery");
2366 :
2367 : // Inlet node to the heat recovery heat exchanger
2368 0 : Real64 heatRecInletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
2369 0 : Real64 HeatRecMassFlowRate = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
2370 :
2371 0 : Real64 CpHeatRec = this->HRPlantLoc.loop->glycol->getSpecificHeat(state, heatRecInletTemp, RoutineName);
2372 : Real64 CpCond;
2373 0 : if (this->CondenserType == DataPlant::CondenserType::WaterCooled) {
2374 0 : CpCond = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, condInletTemp, RoutineName);
2375 : } else {
2376 0 : CpCond = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(this->HeatRecInletNodeNum).HumRat);
2377 : }
2378 :
2379 : // Before we modify the QCondenser, the total or original value is transferred to QTot
2380 0 : Real64 QTotal = QCond;
2381 :
2382 0 : if (this->HeatRecSetPointNodeNum == 0) { // use original algorithm that blends temps
2383 0 : Real64 TAvgIn = (HeatRecMassFlowRate * CpHeatRec * heatRecInletTemp + CondMassFlow * CpCond * condInletTemp) /
2384 0 : (HeatRecMassFlowRate * CpHeatRec + CondMassFlow * CpCond);
2385 :
2386 0 : Real64 TAvgOut = QTotal / (HeatRecMassFlowRate * CpHeatRec + CondMassFlow * CpCond) + TAvgIn;
2387 :
2388 0 : QHeatRec = HeatRecMassFlowRate * CpHeatRec * (TAvgOut - heatRecInletTemp);
2389 0 : QHeatRec = max(QHeatRec, 0.0); // ensure non negative
2390 : // check if heat flow too large for physical size of bundle
2391 0 : QHeatRec = min(QHeatRec, this->HeatRecMaxCapacityLimit);
2392 : } else { // use new algorithm to meet setpoint
2393 0 : Real64 THeatRecSetPoint(0.0); // local value for heat recovery leaving setpoint [C]
2394 0 : switch (this->HRPlantLoc.loop->LoopDemandCalcScheme) {
2395 0 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
2396 0 : THeatRecSetPoint = state.dataLoopNodes->Node(this->HeatRecSetPointNodeNum).TempSetPoint;
2397 0 : } break;
2398 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
2399 0 : THeatRecSetPoint = state.dataLoopNodes->Node(this->HeatRecSetPointNodeNum).TempSetPointHi;
2400 0 : } break;
2401 0 : default: {
2402 0 : assert(false);
2403 : } break;
2404 : }
2405 :
2406 : // load to heat recovery setpoint
2407 0 : Real64 QHeatRecToSetPoint = HeatRecMassFlowRate * CpHeatRec * (THeatRecSetPoint - heatRecInletTemp);
2408 0 : QHeatRecToSetPoint = max(QHeatRecToSetPoint, 0.0);
2409 0 : QHeatRec = min(QTotal, QHeatRecToSetPoint);
2410 : // check if heat flow too large for physical size of bundle
2411 0 : QHeatRec = min(QHeatRec, this->HeatRecMaxCapacityLimit);
2412 : }
2413 :
2414 : // check if limit on inlet is present and exceeded.
2415 0 : if (this->heatRecInletLimitSched != nullptr) {
2416 0 : Real64 HeatRecHighInletLimit = this->heatRecInletLimitSched->getCurrentVal();
2417 0 : if (heatRecInletTemp > HeatRecHighInletLimit) { // shut down heat recovery
2418 0 : QHeatRec = 0.0;
2419 : }
2420 : }
2421 :
2422 0 : QCond = QTotal - QHeatRec;
2423 :
2424 : // Calculate a new Heat Recovery Coil Outlet Temp
2425 0 : if (HeatRecMassFlowRate > 0.0) {
2426 0 : this->HeatRecOutletTemp = QHeatRec / (HeatRecMassFlowRate * CpHeatRec) + heatRecInletTemp;
2427 : } else {
2428 0 : this->HeatRecOutletTemp = heatRecInletTemp;
2429 : }
2430 0 : }
2431 :
2432 1433 : void ElectricEIRChillerSpecs::update(EnergyPlusData &state, Real64 const MyLoad, bool const RunFlag)
2433 : {
2434 :
2435 : // SUBROUTINE INFORMATION:
2436 : // AUTHOR: Richard Raustad, FSEC
2437 : // DATE WRITTEN: June 2004
2438 :
2439 : // PURPOSE OF THIS SUBROUTINE:
2440 : // Reporting
2441 :
2442 : // Number of seconds per HVAC system time step, to convert from W (J/s) to J
2443 1433 : Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
2444 :
2445 1433 : if (MyLoad >= 0 || !RunFlag) { // Chiller not running so pass inlet states to outlet states
2446 : // Set node conditions
2447 1431 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2448 1431 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
2449 1431 : if (this->CondenserType != DataPlant::CondenserType::WaterCooled) {
2450 1430 : state.dataLoopNodes->Node(this->CondOutletNodeNum).HumRat = state.dataLoopNodes->Node(this->CondInletNodeNum).HumRat;
2451 1430 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Enthalpy = state.dataLoopNodes->Node(this->CondInletNodeNum).Enthalpy;
2452 1430 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate = 0.0;
2453 1430 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRate = 0.0;
2454 : }
2455 :
2456 1431 : this->ChillerPartLoadRatio = 0.0;
2457 1431 : this->ChillerCyclingRatio = 0.0;
2458 1431 : this->ChillerFalseLoadRate = 0.0;
2459 1431 : this->ChillerFalseLoad = 0.0;
2460 1431 : this->Power = 0.0;
2461 1431 : this->QEvaporator = 0.0;
2462 1431 : this->QCondenser = 0.0;
2463 1431 : this->Energy = 0.0;
2464 1431 : this->EvapEnergy = 0.0;
2465 1431 : this->CondEnergy = 0.0;
2466 1431 : this->EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2467 1431 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
2468 1431 : this->CondOutletTemp = state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp;
2469 1431 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
2470 1431 : this->ActualCOP = 0.0;
2471 1431 : this->CondenserFanPower = 0.0;
2472 1431 : this->CondenserFanEnergyConsumption = 0.0;
2473 1431 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
2474 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
2475 0 : this->EvapWaterConsump = 0.0;
2476 : }
2477 :
2478 1431 : if (this->HeatRecActive) {
2479 :
2480 0 : PlantUtilities::SafeCopyPlantNode(state, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
2481 :
2482 0 : this->QHeatRecovered = 0.0;
2483 0 : this->EnergyHeatRecovery = 0.0;
2484 0 : this->HeatRecInletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
2485 0 : this->HeatRecOutletTemp = state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp;
2486 0 : this->HeatRecMassFlow = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
2487 : }
2488 :
2489 : } else { // Chiller is running, so pass calculated values
2490 : // Set node temperatures
2491 2 : if (this->CondMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance &&
2492 1 : this->EvapMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance) {
2493 1 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2494 1 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
2495 1 : if (this->CondenserType != DataPlant::CondenserType::WaterCooled) {
2496 1 : state.dataLoopNodes->Node(this->CondOutletNodeNum).HumRat = state.dataLoopNodes->Node(this->CondInletNodeNum).HumRat;
2497 1 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Enthalpy = state.dataLoopNodes->Node(this->CondInletNodeNum).Enthalpy;
2498 1 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate = 0.0;
2499 1 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRate = 0.0;
2500 : }
2501 : } else {
2502 1 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = this->EvapOutletTemp;
2503 1 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp = this->CondOutletTemp;
2504 1 : if (this->CondenserType != DataPlant::CondenserType::WaterCooled) {
2505 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).HumRat = this->CondOutletHumRat;
2506 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).Enthalpy =
2507 0 : Psychrometrics::PsyHFnTdbW(this->CondOutletTemp, this->CondOutletHumRat);
2508 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate = this->CondMassFlowRate;
2509 0 : state.dataLoopNodes->Node(this->CondOutletNodeNum).MassFlowRate = this->CondMassFlowRate;
2510 : }
2511 : }
2512 :
2513 : // Set node flow rates; for these load based models
2514 : // assume that sufficient evaporator flow rate is available
2515 2 : this->ChillerFalseLoad = this->ChillerFalseLoadRate * state.dataHVACGlobal->TimeStepSysSec;
2516 2 : this->Energy = this->Power * state.dataHVACGlobal->TimeStepSysSec;
2517 2 : this->EvapEnergy = this->QEvaporator * state.dataHVACGlobal->TimeStepSysSec;
2518 2 : this->CondEnergy = this->QCondenser * state.dataHVACGlobal->TimeStepSysSec;
2519 2 : this->EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2520 2 : this->CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
2521 2 : this->CondOutletTemp = state.dataLoopNodes->Node(this->CondOutletNodeNum).Temp;
2522 2 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
2523 2 : this->CondenserFanEnergyConsumption = this->CondenserFanPower * state.dataHVACGlobal->TimeStepSysSec;
2524 2 : if (this->Power != 0.0) {
2525 1 : this->ActualCOP = (this->QEvaporator + this->ChillerFalseLoadRate) / this->Power;
2526 : } else {
2527 1 : this->ActualCOP = 0.0;
2528 : }
2529 2 : if (this->CondenserType == DataPlant::CondenserType::EvapCooled) {
2530 0 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
2531 0 : this->EvapWaterConsump = this->EvapWaterConsumpRate * ReportingConstant;
2532 : }
2533 :
2534 2 : if (this->HeatRecActive) {
2535 :
2536 0 : PlantUtilities::SafeCopyPlantNode(state, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
2537 0 : this->EnergyHeatRecovery = this->QHeatRecovered * state.dataHVACGlobal->TimeStepSysSec;
2538 0 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = this->HeatRecOutletTemp;
2539 0 : this->HeatRecInletTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
2540 0 : this->HeatRecMassFlow = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
2541 : }
2542 : }
2543 1433 : }
2544 :
2545 9 : bool ElectricEIRChillerSpecs::thermosiphonDisabled(EnergyPlusData &state)
2546 : {
2547 9 : if (this->thermosiphonTempCurveIndex > 0) {
2548 3 : this->thermosiphonStatus = 0;
2549 3 : Real64 dT = this->EvapOutletTemp - this->CondInletTemp;
2550 3 : if (dT < this->thermosiphonMinTempDiff) {
2551 1 : return true;
2552 : }
2553 2 : Real64 thermosiphonCapFrac = Curve::CurveValue(state, this->thermosiphonTempCurveIndex, dT);
2554 2 : Real64 capFrac = this->ChillerPartLoadRatio * this->ChillerCyclingRatio;
2555 2 : if (thermosiphonCapFrac >= capFrac) {
2556 1 : this->thermosiphonStatus = 1;
2557 1 : this->Power = 0.0;
2558 1 : return false;
2559 : }
2560 1 : return true;
2561 : } else {
2562 6 : return true;
2563 : }
2564 : }
2565 :
2566 : } // namespace EnergyPlus::ChillerElectricEIR
|