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