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 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : // #include <ObjexxFCL/Fmath.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/Autosizing/Base.hh>
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/CurveManager.hh>
60 : #include <EnergyPlus/Data/EnergyPlusData.hh>
61 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
62 : #include <EnergyPlus/DataHVACGlobals.hh>
63 : #include <EnergyPlus/DataHeatBalance.hh>
64 : #include <EnergyPlus/DataIPShortCuts.hh>
65 : #include <EnergyPlus/DataLoopNode.hh>
66 : #include <EnergyPlus/DataSizing.hh>
67 : #include <EnergyPlus/EMSManager.hh>
68 : #include <EnergyPlus/FluidProperties.hh>
69 : #include <EnergyPlus/General.hh>
70 : #include <EnergyPlus/GlobalNames.hh>
71 : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
72 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
73 : #include <EnergyPlus/NodeInputManager.hh>
74 : #include <EnergyPlus/OutputProcessor.hh>
75 : #include <EnergyPlus/OutputReportPredefined.hh>
76 : #include <EnergyPlus/Plant/DataPlant.hh>
77 : #include <EnergyPlus/PlantPressureSystem.hh>
78 : #include <EnergyPlus/PlantUtilities.hh>
79 : #include <EnergyPlus/Pumps.hh>
80 : #include <EnergyPlus/ScheduleManager.hh>
81 : #include <EnergyPlus/UtilityRoutines.hh>
82 :
83 : namespace EnergyPlus::Pumps {
84 :
85 : // MODULE INFORMATION:
86 : // AUTHOR Dan Fisher
87 : // DATE WRITTEN Sept 1998
88 : // MODIFIED July 2001, Richard Liesen
89 : // July 2001, Rick Strand (new "local" pump control method)
90 : // Feb 2005, Rahul Chillar(added condensate pump for steam systems)
91 : // Jan 2006, Sankaranarayanan (Added pump banks to the library of pumps)
92 : // May 2009, Brent Griffith (added support for EMS override of massflow)
93 : // Aug 2010, Edwin Lee (refactored code, significant clean-up)
94 : // RE-ENGINEERED na
95 :
96 : // PURPOSE OF THIS MODULE:
97 : // Encapsulates the data and algorithms to simulate pumps.
98 :
99 : // REFERENCES:
100 : // HVAC 2 Toolkit: A Toolkit for Secondary HVAC System
101 : // Energy Calculations, ASHRAE, 1993, pp2-10 to 2-15
102 :
103 : // Using/Aliasing
104 : using DataLoopNode::ObjectIsNotParent;
105 : using HVAC::SmallWaterVolFlow;
106 :
107 : static constexpr std::array<std::string_view, static_cast<int>(PumpType::Num)> pumpTypeIDFNames = {
108 : "Pump:VariableSpeed", "Pump:ConstantSpeed", "Pump:VariableSpeed:Condensate", "HeaderedPumps:VariableSpeed", "HeaderedPumps:ConstantSpeed"};
109 :
110 56466326 : void SimPumps(EnergyPlusData &state,
111 : std::string const &PumpName, // Name of pump to be managed
112 : int const LoopNum, // Plant loop number
113 : Real64 const FlowRequest, // requested flow from adjacent demand side
114 : bool &PumpRunning, // .TRUE. if the loop pump is actually operating
115 : int &PumpIndex,
116 : Real64 &PumpHeat)
117 : {
118 :
119 : // SUBROUTINE INFORMATION:
120 : // AUTHOR Rick Strand
121 : // DATE WRITTEN July 2001
122 : // MODIFIED na
123 : // RE-ENGINEERED na
124 :
125 : // PURPOSE OF THIS SUBROUTINE:
126 : // This subroutine manages the pump operation based on the type of
127 : // pump and the pump controls (continuous, intermittent, etc.). The
128 : // result of this subroutine is that the pump has been simulated for
129 : // the necessary loop and the PumpRunning has been correctly set.
130 :
131 : int PumpNum; // Pump index within PumpEquip derived type
132 :
133 : // Get input from IDF one time
134 56466326 : if (state.dataPumps->GetInputFlag) {
135 462 : GetPumpInput(state);
136 462 : state.dataPumps->GetInputFlag = false;
137 : }
138 :
139 : // Exit early if no pumps found
140 56466326 : if (state.dataPumps->NumPumps == 0) {
141 0 : PumpHeat = 0.0;
142 18821701 : return;
143 : }
144 :
145 : // Setup pump component index if needed
146 56466326 : if (PumpIndex == 0) {
147 1179 : PumpNum = Util::FindItemInList(PumpName, state.dataPumps->PumpEquip); // Determine which pump to simulate
148 1179 : if (PumpNum == 0) {
149 0 : ShowFatalError(state, format("ManagePumps: Pump requested not found ={}", PumpName)); // Catch any bad names before crashing
150 : }
151 1179 : PumpIndex = PumpNum;
152 : } else {
153 56465147 : PumpNum = PumpIndex;
154 56465147 : if (state.dataPumps->PumpEquip(PumpNum).CheckEquipName) {
155 1179 : if (PumpNum > state.dataPumps->NumPumps || PumpNum < 1) {
156 0 : ShowFatalError(
157 : state,
158 0 : format(
159 0 : "ManagePumps: Invalid PumpIndex passed={}, Number of Pumps={}, Pump name={}", PumpNum, state.dataPumps->NumPumps, PumpName));
160 : }
161 1179 : if (PumpName != state.dataPumps->PumpEquip(PumpNum).Name) {
162 0 : ShowFatalError(state,
163 0 : format("ManagePumps: Invalid PumpIndex passed={}, Pump name={}, stored Pump Name for that index={}",
164 : PumpNum,
165 : PumpName,
166 0 : state.dataPumps->PumpEquip(PumpNum).Name));
167 : }
168 1179 : state.dataPumps->PumpEquip(PumpNum).CheckEquipName = false;
169 : }
170 : }
171 :
172 : // Perform one-time and begin-environment initialization
173 56466326 : InitializePumps(state, PumpNum);
174 :
175 : // If all we need is to set outlet min/max avail, then just do it and get out. Also, we only do min/max avail on flow query
176 56466326 : if (state.dataPlnt->PlantLoop(LoopNum).LoopSide(state.dataPumps->PumpEquip(PumpNum).plantLoc.loopSideNum).FlowLock ==
177 : DataPlant::FlowLock::PumpQuery) {
178 18821701 : SetupPumpMinMaxFlows(state, LoopNum, PumpNum);
179 18821701 : return;
180 : }
181 :
182 : // Set pump flow rate and calculate power
183 37644625 : CalcPumps(state, PumpNum, FlowRequest, PumpRunning);
184 :
185 : // Update pump reporting data
186 37644625 : ReportPumps(state, PumpNum);
187 :
188 : // Send this up to the calling routine
189 37644625 : PumpHeat = state.dataPumps->PumpHeattoFluid;
190 : }
191 :
192 462 : void GetPumpInput(EnergyPlusData &state)
193 : {
194 :
195 : // SUBROUTINE INFORMATION:
196 : // AUTHOR: Dan Fisher
197 : // DATE WRITTEN: April 1998
198 : // MODIFIED: July 2001, Rick Strand (addition of pump controls)
199 : // May 2009, Brent Griffith (added EMS calls)
200 :
201 : // PURPOSE OF THIS SUBROUTINE:
202 : // This routine will get the input
203 : // required by the pump simulation.
204 :
205 : // PUMP:VARIABLE SPEED,
206 : // This pump model is described in the ASHRAE secondary HVAC toolkit.
207 :
208 : // REFERENCES:
209 : // HVAC 2 Toolkit: A Toolkit for Secondary HVAC System
210 : // Energy Calculations, ASHRAE, 1993, pp2-10 to 2-15
211 :
212 : // Using/Aliasing
213 : using BranchNodeConnections::TestCompSet;
214 : using Curve::GetCurveIndex;
215 : using Curve::GetCurveMinMaxValues;
216 : using DataSizing::AutoSize;
217 : using NodeInputManager::GetOnlySingleNode;
218 :
219 : // SUBROUTINE PARAMETER DEFINITIONS:
220 462 : Real64 constexpr StartTemp(100.0); // Standard Temperature across code to calculated Steam density
221 : static constexpr std::string_view RoutineName("GetPumpInput: ");
222 : static constexpr std::string_view routineName = "GetPumpInput";
223 :
224 : static constexpr std::array<std::string_view, static_cast<int>(PumpControlType::Num)> pumpCtrlTypeNamesUC{"CONTINUOUS", "INTERMITTENT"};
225 : static constexpr std::array<std::string_view, static_cast<int>(ControlTypeVFD::Num)> controlTypeVFDNamesUC{"MANUALCONTROL",
226 : "PRESSURESETPOINTCONTROL"};
227 : static constexpr std::array<std::string_view, static_cast<int>(PowerSizingMethod::Num)> powerSizingMethodNamesUC{"POWERPERFLOW",
228 : "POWERPERFLOWPERPRESSURE"};
229 :
230 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
231 : int PumpNum;
232 : int NumAlphas; // Number of elements in the alpha array
233 : int NumNums; // Number of elements in the numeric array
234 : int IOStat; // IO Status when calling get input subroutine
235 : bool ErrorsFound;
236 : int TempCurveIndex;
237 462 : int NumVarSpeedPumps = 0;
238 462 : int NumConstSpeedPumps = 0;
239 462 : int NumCondensatePumps = 0;
240 462 : int NumPumpBankSimpleVar = 0;
241 462 : int NumPumpBankSimpleConst = 0;
242 : Real64 SteamDensity;
243 : Real64 TempWaterDensity;
244 462 : int DummyWaterIndex(1);
245 462 : Real64 constexpr minToMaxRatioMax = 0.99;
246 :
247 462 : ErrorsFound = false;
248 :
249 : // GET NUMBER OF ALL EQUIPMENT TYPES
250 462 : NumVarSpeedPumps = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::VarSpeed)]);
251 462 : NumConstSpeedPumps = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::ConSpeed)]);
252 462 : NumCondensatePumps = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::Cond)]);
253 : NumPumpBankSimpleVar =
254 462 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::Bank_VarSpeed)]);
255 : NumPumpBankSimpleConst =
256 462 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::Bank_ConSpeed)]);
257 462 : state.dataPumps->NumPumps = NumVarSpeedPumps + NumConstSpeedPumps + NumCondensatePumps + NumPumpBankSimpleVar + NumPumpBankSimpleConst;
258 :
259 462 : if (state.dataPumps->NumPumps <= 0) {
260 0 : ShowWarningError(state, "No Pumping Equipment Found");
261 0 : return;
262 : }
263 :
264 462 : state.dataPumps->PumpEquip.allocate(state.dataPumps->NumPumps);
265 462 : state.dataPumps->PumpUniqueNames.reserve(static_cast<unsigned>(state.dataPumps->NumPumps));
266 462 : state.dataPumps->PumpEquipReport.allocate(state.dataPumps->NumPumps);
267 462 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
268 462 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::VarSpeed)];
269 462 : auto &thisInput = state.dataIPShortCut;
270 :
271 1414 : for (PumpNum = 1; PumpNum <= NumVarSpeedPumps; ++PumpNum) {
272 952 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
273 1904 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
274 : cCurrentModuleObject,
275 : PumpNum,
276 952 : thisInput->cAlphaArgs,
277 : NumAlphas,
278 952 : thisInput->rNumericArgs,
279 : NumNums,
280 : IOStat,
281 952 : thisInput->lNumericFieldBlanks,
282 952 : thisInput->lAlphaFieldBlanks,
283 952 : thisInput->cAlphaFieldNames,
284 952 : thisInput->cNumericFieldNames);
285 :
286 952 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisInput->cAlphaArgs(1)};
287 :
288 952 : GlobalNames::VerifyUniqueInterObjectName(
289 1904 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
290 952 : thisPump.Name = thisInput->cAlphaArgs(1);
291 952 : thisPump.pumpType = PumpType::VarSpeed; //'Pump:VariableSpeed'
292 952 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpVariableSpeed;
293 :
294 952 : thisPump.InletNodeNum = GetOnlySingleNode(state,
295 952 : thisInput->cAlphaArgs(2),
296 : ErrorsFound,
297 : DataLoopNode::ConnectionObjectType::PumpVariableSpeed,
298 952 : thisPump.Name,
299 : DataLoopNode::NodeFluidType::Water,
300 : DataLoopNode::ConnectionType::Inlet,
301 : NodeInputManager::CompFluidStream::Primary,
302 : ObjectIsNotParent);
303 :
304 1904 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
305 952 : thisInput->cAlphaArgs(3),
306 : ErrorsFound,
307 : DataLoopNode::ConnectionObjectType::PumpVariableSpeed,
308 952 : thisPump.Name,
309 : DataLoopNode::NodeFluidType::Water,
310 : DataLoopNode::ConnectionType::Outlet,
311 : NodeInputManager::CompFluidStream::Primary,
312 : ObjectIsNotParent);
313 952 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
314 :
315 952 : thisPump.PumpControl = static_cast<PumpControlType>(getEnumValue(pumpCtrlTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
316 952 : if (thisPump.PumpControl == PumpControlType::Invalid) {
317 0 : ShowWarningError(state,
318 0 : format("{}{}=\"{}\", Invalid {}", RoutineName, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaFieldNames(4)));
319 0 : ShowContinueError(
320 : state,
321 0 : format("Entered Value=[{}]. {} has been set to Continuous for this pump.", thisInput->cAlphaArgs(4), thisInput->cAlphaFieldNames(4)));
322 0 : thisPump.PumpControl = PumpControlType::Continuous;
323 : }
324 :
325 : // Input the optional schedule for the pump, this is a flow modifier schedule so blank/missing means Always On.
326 952 : if (thisInput->cAlphaArgs(5).empty()) {
327 766 : thisPump.flowRateSched = nullptr;
328 186 : } else if ((thisPump.flowRateSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(5))) == nullptr) {
329 0 : ShowWarningItemNotFound(state, eoh, thisInput->cAlphaFieldNames(5), thisInput->cAlphaArgs(5), "");
330 : }
331 :
332 952 : thisPump.NomVolFlowRate = thisInput->rNumericArgs(1);
333 952 : if (thisPump.NomVolFlowRate == AutoSize) {
334 555 : thisPump.NomVolFlowRateWasAutoSized = true;
335 : }
336 952 : thisPump.NomPumpHead = thisInput->rNumericArgs(2);
337 952 : thisPump.NomPowerUse = thisInput->rNumericArgs(3);
338 952 : if (thisPump.NomPowerUse == AutoSize) {
339 559 : thisPump.NomPowerUseWasAutoSized = true;
340 : }
341 952 : thisPump.MotorEffic = thisInput->rNumericArgs(4);
342 952 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(5);
343 952 : thisPump.PartLoadCoef[0] = thisInput->rNumericArgs(6);
344 952 : thisPump.PartLoadCoef[1] = thisInput->rNumericArgs(7);
345 952 : thisPump.PartLoadCoef[2] = thisInput->rNumericArgs(8);
346 952 : thisPump.PartLoadCoef[3] = thisInput->rNumericArgs(9);
347 952 : thisPump.MinVolFlowRate = thisInput->rNumericArgs(10);
348 952 : if (thisPump.MinVolFlowRate == AutoSize) {
349 15 : thisPump.minVolFlowRateWasAutosized = true;
350 937 : } else if (!thisPump.NomVolFlowRateWasAutoSized && (thisPump.MinVolFlowRate > (minToMaxRatioMax * thisPump.NomVolFlowRate))) {
351 : // Check that the minimum isn't greater than the maximum
352 0 : ShowWarningError(
353 0 : state, format("{}{}=\"{}\", Invalid '{}'", RoutineName, cCurrentModuleObject, thisPump.Name, thisInput->cNumericFieldNames(10)));
354 0 : ShowContinueError(state,
355 0 : format("Entered Value=[{:.5T}] is above or too close (equal) to the {}=[{:.5T}].",
356 0 : thisPump.MinVolFlowRate,
357 0 : thisInput->cNumericFieldNames(1),
358 0 : thisPump.NomVolFlowRate));
359 0 : ShowContinueError(
360 : state,
361 0 : format("Reseting value of '{}' to the value of 99% of '{}'.", thisInput->cNumericFieldNames(10), thisInput->cNumericFieldNames(1)));
362 : // Set min to roughly max, but not quite, otherwise it can't turn on, ever
363 0 : thisPump.MinVolFlowRate = minToMaxRatioMax * thisPump.NomVolFlowRate;
364 : }
365 : // Probably the following two lines will be used if the team agrees on changing the F10 value from min flow rate to
366 : // minimum flow as a fraction of nominal flow.
367 :
368 : // Input pressure related data such as pressure curve and impeller size/rotational speed
369 952 : if (thisInput->cAlphaArgs(6).empty()) {
370 951 : thisPump.PressureCurve_Index = -1;
371 : } else {
372 1 : TempCurveIndex = GetCurveIndex(state, thisInput->cAlphaArgs(6));
373 1 : if (TempCurveIndex == 0) {
374 0 : thisPump.PressureCurve_Index = -1;
375 : } else {
376 2 : ErrorsFound |= Curve::CheckCurveDims(state,
377 : TempCurveIndex, // Curve index
378 : {1}, // Valid dimensions
379 : RoutineName, // Routine name
380 : cCurrentModuleObject, // Object Type
381 : thisPump.Name, // Object Name
382 1 : thisInput->cAlphaFieldNames(6)); // Field Name
383 :
384 1 : if (!ErrorsFound) {
385 1 : thisPump.PressureCurve_Index = TempCurveIndex;
386 1 : GetCurveMinMaxValues(state, TempCurveIndex, thisPump.MinPhiValue, thisPump.MaxPhiValue);
387 : }
388 : }
389 : }
390 :
391 : // read in the rest of the pump pressure characteristics
392 952 : thisPump.ImpellerDiameter = thisInput->rNumericArgs(11);
393 :
394 : // Input VFD related data
395 952 : if (thisInput->lAlphaFieldBlanks(7)) {
396 951 : thisPump.HasVFD = false;
397 : } else {
398 1 : thisPump.HasVFD = true;
399 1 : thisPump.VFD.VFDControlType =
400 1 : static_cast<ControlTypeVFD>(getEnumValue(controlTypeVFDNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(7))));
401 :
402 1 : switch (thisPump.VFD.VFDControlType) {
403 :
404 1 : case ControlTypeVFD::VFDManual: {
405 1 : if ((thisPump.VFD.manualRPMSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(8))) == nullptr) {
406 0 : ShowSevereItemNotFound(state, eoh, thisInput->cAlphaFieldNames(8), thisInput->cAlphaArgs(8));
407 0 : ErrorsFound = true;
408 1 : } else if (!thisPump.VFD.manualRPMSched->checkMinVal(state, Clusive::Ex, 0.0)) {
409 0 : Sched::ShowSevereBadMin(state, eoh, thisInput->cAlphaFieldNames(8), thisInput->cAlphaArgs(8), Clusive::Ex, 0.0);
410 0 : ErrorsFound = true;
411 : }
412 1 : } break;
413 :
414 0 : case ControlTypeVFD::VFDAutomatic: {
415 0 : if (thisInput->lAlphaFieldBlanks(9)) {
416 0 : ShowSevereEmptyField(state, eoh, thisInput->cAlphaFieldNames(9));
417 0 : ErrorsFound = true;
418 0 : } else if ((thisPump.VFD.lowerPsetSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(9))) == nullptr) {
419 0 : ShowSevereItemNotFound(state, eoh, thisInput->cAlphaFieldNames(9), thisInput->cAlphaArgs(9));
420 0 : ErrorsFound = true;
421 : }
422 :
423 0 : if (thisInput->lAlphaFieldBlanks(10)) {
424 0 : ShowSevereEmptyField(state, eoh, thisInput->cAlphaFieldNames(10));
425 0 : ErrorsFound = true;
426 0 : } else if ((thisPump.VFD.upperPsetSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(10))) == nullptr) {
427 0 : ShowSevereItemNotFound(state, eoh, thisInput->cAlphaFieldNames(10), thisInput->cAlphaArgs(10));
428 0 : ErrorsFound = true;
429 : }
430 :
431 0 : if (thisInput->lAlphaFieldBlanks(11)) {
432 0 : ShowSevereEmptyField(state, eoh, thisInput->cAlphaFieldNames(11));
433 0 : ErrorsFound = true;
434 0 : } else if ((thisPump.VFD.minRPMSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(11))) == nullptr) {
435 0 : ShowSevereItemNotFound(state, eoh, thisInput->cAlphaFieldNames(11), thisInput->cAlphaArgs(11));
436 0 : ErrorsFound = true;
437 0 : } else if (!thisPump.VFD.minRPMSched->checkMinVal(state, Clusive::Ex, 0.0)) {
438 0 : Sched::ShowSevereBadMin(state, eoh, thisInput->cAlphaFieldNames(11), thisInput->cAlphaArgs(11), Clusive::Ex, 0.0);
439 0 : ErrorsFound = true;
440 : }
441 :
442 0 : if (thisInput->lAlphaFieldBlanks(12)) {
443 0 : ShowSevereEmptyField(state, eoh, thisInput->cAlphaFieldNames(12));
444 0 : ErrorsFound = true;
445 0 : } else if ((thisPump.VFD.maxRPMSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(12))) == nullptr) {
446 0 : ShowSevereItemNotFound(state, eoh, thisInput->cAlphaFieldNames(12), thisInput->cAlphaArgs(12));
447 0 : ErrorsFound = true;
448 0 : } else if (!thisPump.VFD.maxRPMSched->checkMinVal(state, Clusive::Ex, 0.0)) {
449 0 : Sched::ShowSevereBadMin(state, eoh, thisInput->cAlphaFieldNames(12), thisInput->cAlphaArgs(12), Clusive::Ex, 0.0);
450 0 : ErrorsFound = true;
451 : }
452 0 : } break;
453 :
454 0 : default: {
455 0 : ShowSevereError(state,
456 0 : format("{}{}=\"{}\", VFD Control type entered is invalid. Use one of the key choice entries.",
457 : RoutineName,
458 : cCurrentModuleObject,
459 0 : thisPump.Name));
460 0 : ErrorsFound = true;
461 0 : } break;
462 : }
463 : }
464 :
465 952 : if (!thisInput->lAlphaFieldBlanks(13)) { // zone named for pump skin losses
466 0 : thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(13), state.dataHeatBal->Zone);
467 0 : if (thisPump.ZoneNum > 0) {
468 0 : thisPump.HeatLossesToZone = true;
469 0 : if (!thisInput->lNumericFieldBlanks(12)) {
470 0 : thisPump.SkinLossRadFraction = thisInput->rNumericArgs(12);
471 : }
472 : } else {
473 0 : ShowSevereError(state,
474 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
475 : cCurrentModuleObject,
476 0 : thisPump.Name,
477 0 : thisInput->cAlphaFieldNames(13),
478 0 : thisInput->cAlphaArgs(13)));
479 0 : ErrorsFound = true;
480 : }
481 : }
482 :
483 952 : if (!thisInput->lAlphaFieldBlanks(14)) {
484 23 : thisPump.powerSizingMethod =
485 23 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(14))));
486 23 : if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) {
487 0 : ShowSevereError(state,
488 0 : format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.",
489 : RoutineName,
490 : cCurrentModuleObject,
491 0 : thisPump.Name));
492 0 : ErrorsFound = true;
493 : }
494 : }
495 :
496 952 : if (!thisInput->lNumericFieldBlanks(13)) {
497 23 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(13);
498 : }
499 :
500 952 : if (!thisInput->lNumericFieldBlanks(14)) {
501 23 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(14);
502 : }
503 :
504 952 : if (!thisInput->lNumericFieldBlanks(15)) {
505 23 : thisPump.MinVolFlowRateFrac = thisInput->rNumericArgs(15);
506 : }
507 :
508 952 : if (NumAlphas > 14) {
509 15 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(15);
510 : } else {
511 937 : thisPump.EndUseSubcategoryName = "General";
512 : }
513 :
514 : // Is this really necessary for each pump GetInput loop?
515 952 : thisPump.Energy = 0.0;
516 952 : thisPump.Power = 0.0;
517 : }
518 :
519 462 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::ConSpeed)];
520 :
521 673 : for (int NumConstPump = 1; NumConstPump <= NumConstSpeedPumps; ++NumConstPump) {
522 211 : PumpNum = NumVarSpeedPumps + NumConstPump;
523 211 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
524 422 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
525 : cCurrentModuleObject,
526 : NumConstPump,
527 211 : thisInput->cAlphaArgs,
528 : NumAlphas,
529 211 : thisInput->rNumericArgs,
530 : NumNums,
531 : IOStat,
532 211 : thisInput->lNumericFieldBlanks,
533 211 : thisInput->lAlphaFieldBlanks,
534 211 : thisInput->cAlphaFieldNames,
535 211 : thisInput->cNumericFieldNames);
536 :
537 211 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
538 :
539 211 : GlobalNames::VerifyUniqueInterObjectName(
540 422 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
541 211 : thisPump.Name = thisInput->cAlphaArgs(1);
542 211 : thisPump.pumpType = PumpType::ConSpeed; //'Pump:ConstantSpeed'
543 211 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpConstantSpeed;
544 :
545 211 : thisPump.InletNodeNum = GetOnlySingleNode(state,
546 211 : thisInput->cAlphaArgs(2),
547 : ErrorsFound,
548 : DataLoopNode::ConnectionObjectType::PumpConstantSpeed,
549 211 : thisPump.Name,
550 : DataLoopNode::NodeFluidType::Water,
551 : DataLoopNode::ConnectionType::Inlet,
552 : NodeInputManager::CompFluidStream::Primary,
553 : ObjectIsNotParent);
554 :
555 422 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
556 211 : thisInput->cAlphaArgs(3),
557 : ErrorsFound,
558 : DataLoopNode::ConnectionObjectType::PumpConstantSpeed,
559 211 : thisPump.Name,
560 : DataLoopNode::NodeFluidType::Water,
561 : DataLoopNode::ConnectionType::Outlet,
562 : NodeInputManager::CompFluidStream::Primary,
563 : ObjectIsNotParent);
564 211 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
565 :
566 211 : thisPump.NomVolFlowRate = thisInput->rNumericArgs(1);
567 211 : if (thisPump.NomVolFlowRate == AutoSize) {
568 164 : thisPump.NomVolFlowRateWasAutoSized = true;
569 : }
570 211 : thisPump.NomPumpHead = thisInput->rNumericArgs(2);
571 211 : thisPump.NomPowerUse = thisInput->rNumericArgs(3);
572 211 : if (thisPump.NomPowerUse == AutoSize) {
573 167 : thisPump.NomPowerUseWasAutoSized = true;
574 : }
575 211 : thisPump.MotorEffic = thisInput->rNumericArgs(4);
576 211 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(5);
577 211 : thisPump.PartLoadCoef[0] = 1.0;
578 211 : thisPump.PartLoadCoef[1] = 0.0;
579 211 : thisPump.PartLoadCoef[2] = 0.0;
580 211 : thisPump.PartLoadCoef[3] = 0.0;
581 : // In a constant volume pump we previously set the minimum to the nominal capacity
582 : // Now we model the pump as constant speed and set flow by riding the pump curve.
583 211 : thisPump.MinVolFlowRate = 0.0;
584 211 : thisPump.Energy = 0.0;
585 211 : thisPump.Power = 0.0;
586 :
587 211 : thisPump.PumpControl = static_cast<PumpControlType>(getEnumValue(pumpCtrlTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
588 :
589 211 : if (thisPump.PumpControl == PumpControlType::Invalid) {
590 0 : ShowWarningError(state,
591 0 : format("{}{}=\"{}\", Invalid {}", RoutineName, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaFieldNames(4)));
592 0 : ShowContinueError(
593 : state,
594 0 : format("Entered Value=[{}]. {} has been set to Continuous for this pump.", thisInput->cAlphaArgs(4), thisInput->cAlphaFieldNames(4)));
595 0 : thisPump.PumpControl = PumpControlType::Continuous;
596 : }
597 :
598 : // Input the optional schedule for the pump
599 211 : if (thisInput->lAlphaFieldBlanks(5)) {
600 200 : thisPump.flowRateSched = nullptr;
601 11 : } else if ((thisPump.flowRateSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(5))) == nullptr) {
602 1 : ShowWarningItemNotFound(state, eoh, thisInput->cAlphaFieldNames(5), thisInput->cAlphaArgs(5), "");
603 : }
604 :
605 : // Input pressure related data such as pressure curve and impeller size/rotational speed
606 211 : if (thisInput->cAlphaArgs(6).empty()) {
607 210 : thisPump.PressureCurve_Index = -1;
608 : } else {
609 1 : TempCurveIndex = GetCurveIndex(state, thisInput->cAlphaArgs(6));
610 1 : if (TempCurveIndex == 0) {
611 0 : thisPump.PressureCurve_Index = -1;
612 : } else {
613 2 : ErrorsFound |= Curve::CheckCurveDims(state,
614 : TempCurveIndex, // Curve index
615 : {1}, // Valid dimensions
616 : RoutineName, // Routine name
617 : cCurrentModuleObject, // Object Type
618 : thisPump.Name, // Object Name
619 1 : thisInput->cAlphaFieldNames(6)); // Field Name
620 :
621 1 : if (!ErrorsFound) {
622 1 : thisPump.PressureCurve_Index = TempCurveIndex;
623 1 : GetCurveMinMaxValues(state, TempCurveIndex, thisPump.MinPhiValue, thisPump.MaxPhiValue);
624 : }
625 : }
626 : }
627 :
628 : // read in the rest of the pump pressure characteristics
629 211 : thisPump.ImpellerDiameter = thisInput->rNumericArgs(6);
630 211 : thisPump.RotSpeed_RPM = thisInput->rNumericArgs(7); // retrieve the input rotational speed, in revs/min
631 211 : thisPump.RotSpeed = thisPump.RotSpeed_RPM / 60.0; // convert input[rpm] to calculation units[rps]
632 :
633 211 : if (!thisInput->lAlphaFieldBlanks(7)) { // zone named for pump skin losses
634 0 : thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(7), state.dataHeatBal->Zone);
635 0 : if (thisPump.ZoneNum > 0) {
636 0 : thisPump.HeatLossesToZone = true;
637 0 : if (!thisInput->lNumericFieldBlanks(8)) {
638 0 : thisPump.SkinLossRadFraction = thisInput->rNumericArgs(8);
639 : }
640 : } else {
641 0 : ShowSevereError(state,
642 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
643 : cCurrentModuleObject,
644 0 : thisPump.Name,
645 0 : thisInput->cAlphaFieldNames(7),
646 0 : thisInput->cAlphaArgs(7)));
647 0 : ErrorsFound = true;
648 : }
649 : }
650 :
651 211 : if (!thisInput->lAlphaFieldBlanks(8)) {
652 8 : thisPump.powerSizingMethod =
653 8 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
654 8 : if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) {
655 0 : ShowSevereError(state,
656 0 : format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.",
657 : RoutineName,
658 : cCurrentModuleObject,
659 0 : thisPump.Name));
660 0 : ErrorsFound = true;
661 : }
662 : }
663 :
664 211 : if (!thisInput->lNumericFieldBlanks(9)) {
665 8 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(9);
666 : }
667 :
668 211 : if (!thisInput->lNumericFieldBlanks(10)) {
669 0 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(10);
670 : }
671 :
672 211 : if (NumAlphas > 8) {
673 1 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(9);
674 : } else {
675 210 : thisPump.EndUseSubcategoryName = "General";
676 : }
677 : }
678 :
679 : // pumps for steam system pumping condensate
680 462 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::Cond)];
681 471 : for (int NumCondPump = 1; NumCondPump <= NumCondensatePumps; ++NumCondPump) {
682 9 : PumpNum = NumCondPump + NumVarSpeedPumps + NumConstSpeedPumps;
683 9 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
684 18 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
685 : cCurrentModuleObject,
686 : NumCondPump,
687 9 : thisInput->cAlphaArgs,
688 : NumAlphas,
689 9 : thisInput->rNumericArgs,
690 : NumNums,
691 : IOStat,
692 9 : thisInput->lNumericFieldBlanks,
693 9 : thisInput->lAlphaFieldBlanks,
694 9 : thisInput->cAlphaFieldNames,
695 9 : thisInput->cNumericFieldNames);
696 :
697 9 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisInput->cAlphaArgs(1)};
698 :
699 9 : GlobalNames::VerifyUniqueInterObjectName(
700 18 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
701 9 : thisPump.Name = thisInput->cAlphaArgs(1);
702 9 : thisPump.pumpType = PumpType::Cond; //'Pump:VariableSpeed:Condensate'
703 9 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpCondensate;
704 :
705 9 : thisPump.InletNodeNum = GetOnlySingleNode(state,
706 9 : thisInput->cAlphaArgs(2),
707 : ErrorsFound,
708 : DataLoopNode::ConnectionObjectType::PumpVariableSpeedCondensate,
709 9 : thisPump.Name,
710 : DataLoopNode::NodeFluidType::Steam,
711 : DataLoopNode::ConnectionType::Inlet,
712 : NodeInputManager::CompFluidStream::Primary,
713 : ObjectIsNotParent);
714 :
715 18 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
716 9 : thisInput->cAlphaArgs(3),
717 : ErrorsFound,
718 : DataLoopNode::ConnectionObjectType::PumpVariableSpeedCondensate,
719 9 : thisPump.Name,
720 : DataLoopNode::NodeFluidType::Steam,
721 : DataLoopNode::ConnectionType::Outlet,
722 : NodeInputManager::CompFluidStream::Primary,
723 : ObjectIsNotParent);
724 9 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
725 :
726 9 : thisPump.PumpControl = PumpControlType::Intermittent;
727 :
728 : // Input the optional schedule for the pump
729 9 : if (thisInput->cAlphaArgs(4).empty()) {
730 9 : thisPump.flowRateSched = nullptr;
731 0 : } else if ((thisPump.flowRateSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(4))) == nullptr) {
732 0 : ShowWarningItemNotFound(state, eoh, thisInput->cAlphaFieldNames(4), thisInput->cAlphaArgs(4));
733 : }
734 :
735 9 : thisPump.NomSteamVolFlowRate = thisInput->rNumericArgs(1);
736 9 : if (thisPump.NomSteamVolFlowRate == AutoSize) {
737 6 : thisPump.NomSteamVolFlowRateWasAutoSized = true;
738 : }
739 9 : thisPump.NomPumpHead = thisInput->rNumericArgs(2);
740 9 : thisPump.NomPowerUse = thisInput->rNumericArgs(3);
741 9 : if (thisPump.NomPowerUse == AutoSize) {
742 8 : thisPump.NomPowerUseWasAutoSized = true;
743 : }
744 9 : thisPump.MotorEffic = thisInput->rNumericArgs(4);
745 9 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(5);
746 9 : thisPump.PartLoadCoef[0] = thisInput->rNumericArgs(6);
747 9 : thisPump.PartLoadCoef[1] = thisInput->rNumericArgs(7);
748 9 : thisPump.PartLoadCoef[2] = thisInput->rNumericArgs(8);
749 9 : thisPump.PartLoadCoef[3] = thisInput->rNumericArgs(9);
750 :
751 9 : if (!thisInput->lAlphaFieldBlanks(5)) { // zone named for pump skin losses
752 0 : thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(5), state.dataHeatBal->Zone);
753 0 : if (thisPump.ZoneNum > 0) {
754 0 : thisPump.HeatLossesToZone = true;
755 0 : if (!thisInput->lNumericFieldBlanks(10)) {
756 0 : thisPump.SkinLossRadFraction = thisInput->rNumericArgs(10);
757 : }
758 : } else {
759 0 : ShowSevereError(state,
760 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
761 : cCurrentModuleObject,
762 0 : thisPump.Name,
763 0 : thisInput->cAlphaFieldNames(5),
764 0 : thisInput->cAlphaArgs(5)));
765 0 : ErrorsFound = true;
766 : }
767 : }
768 :
769 9 : thisPump.MinVolFlowRate = 0.0;
770 9 : thisPump.Energy = 0.0;
771 9 : thisPump.Power = 0.0;
772 :
773 9 : if (thisPump.NomSteamVolFlowRateWasAutoSized) {
774 6 : thisPump.NomVolFlowRate = AutoSize;
775 6 : thisPump.NomVolFlowRateWasAutoSized = true;
776 : } else {
777 : // Calc Condensate Pump Water Volume Flow Rate
778 3 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, StartTemp, 1.0, routineName);
779 3 : TempWaterDensity = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, routineName);
780 3 : thisPump.NomVolFlowRate = (thisPump.NomSteamVolFlowRate * SteamDensity) / TempWaterDensity;
781 : }
782 :
783 9 : if (!thisInput->lAlphaFieldBlanks(6)) {
784 1 : thisPump.powerSizingMethod =
785 1 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(6))));
786 1 : if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) {
787 0 : ShowSevereError(state,
788 0 : format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.",
789 : RoutineName,
790 : cCurrentModuleObject,
791 0 : thisPump.Name));
792 0 : ErrorsFound = true;
793 : }
794 : }
795 :
796 9 : if (!thisInput->lNumericFieldBlanks(11)) {
797 1 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(11);
798 : }
799 :
800 9 : if (!thisInput->lNumericFieldBlanks(12)) {
801 1 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(12);
802 : }
803 :
804 9 : if (NumAlphas > 6) {
805 0 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(7);
806 : } else {
807 9 : thisPump.EndUseSubcategoryName = "General";
808 : }
809 : }
810 :
811 : // LOAD Variable Speed Pump Bank ARRAYS WITH VARIABLE SPEED CURVE FIT PUMP DATA
812 462 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::Bank_VarSpeed)];
813 468 : for (int NumVarPumpBankSimple = 1; NumVarPumpBankSimple <= NumPumpBankSimpleVar; ++NumVarPumpBankSimple) {
814 6 : PumpNum = NumVarPumpBankSimple + NumVarSpeedPumps + NumConstSpeedPumps + NumCondensatePumps;
815 6 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
816 12 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
817 : cCurrentModuleObject,
818 : NumVarPumpBankSimple,
819 6 : thisInput->cAlphaArgs,
820 : NumAlphas,
821 6 : thisInput->rNumericArgs,
822 : NumNums,
823 : IOStat,
824 6 : thisInput->lNumericFieldBlanks,
825 6 : thisInput->lAlphaFieldBlanks,
826 6 : thisInput->cAlphaFieldNames,
827 6 : thisInput->cNumericFieldNames);
828 :
829 6 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisInput->cAlphaArgs(1)};
830 :
831 6 : GlobalNames::VerifyUniqueInterObjectName(
832 12 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
833 6 : thisPump.Name = thisInput->cAlphaArgs(1);
834 6 : thisPump.pumpType = PumpType::Bank_VarSpeed; //'HeaderedPumps:VariableSpeed'
835 6 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpBankVariableSpeed;
836 :
837 6 : thisPump.InletNodeNum = GetOnlySingleNode(state,
838 6 : thisInput->cAlphaArgs(2),
839 : ErrorsFound,
840 : DataLoopNode::ConnectionObjectType::HeaderedPumpsVariableSpeed,
841 6 : thisPump.Name,
842 : DataLoopNode::NodeFluidType::Water,
843 : DataLoopNode::ConnectionType::Inlet,
844 : NodeInputManager::CompFluidStream::Primary,
845 : ObjectIsNotParent);
846 :
847 12 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
848 6 : thisInput->cAlphaArgs(3),
849 : ErrorsFound,
850 : DataLoopNode::ConnectionObjectType::HeaderedPumpsVariableSpeed,
851 6 : thisPump.Name,
852 : DataLoopNode::NodeFluidType::Water,
853 : DataLoopNode::ConnectionType::Outlet,
854 : NodeInputManager::CompFluidStream::Primary,
855 : ObjectIsNotParent);
856 6 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
857 :
858 6 : if (Util::SameString(thisInput->cAlphaArgs(4), "Optimal")) {
859 0 : thisPump.SequencingScheme = PumpBankControlSeq::OptimalScheme;
860 6 : } else if (Util::SameString(thisInput->cAlphaArgs(4), "Sequential")) {
861 6 : thisPump.SequencingScheme = PumpBankControlSeq::SequentialScheme;
862 0 : } else if (Util::SameString(thisInput->cAlphaArgs(4), "SupplyEquipmentAssigned")) {
863 0 : thisPump.SequencingScheme = PumpBankControlSeq::UserDefined;
864 : } else {
865 0 : ShowWarningError(state,
866 0 : format("{}{}=\"{}\", Invalid {}", RoutineName, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaFieldNames(4)));
867 0 : ShowContinueError(
868 : state,
869 0 : format("Entered Value=[{}]. {} has been set to Sequential for this pump.", thisInput->cAlphaArgs(4), thisInput->cAlphaFieldNames(4)));
870 0 : thisPump.SequencingScheme = PumpBankControlSeq::SequentialScheme;
871 : }
872 :
873 6 : thisPump.PumpControl = static_cast<PumpControlType>(getEnumValue(pumpCtrlTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(5))));
874 6 : if (thisPump.PumpControl == PumpControlType::Invalid) {
875 0 : ShowWarningError(state,
876 0 : format("{}{}=\"{}\", Invalid {}", RoutineName, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaFieldNames(5)));
877 0 : ShowContinueError(
878 : state,
879 0 : format("Entered Value=[{}]. {} has been set to Continuous for this pump.", thisInput->cAlphaArgs(5), thisInput->cAlphaFieldNames(5)));
880 0 : thisPump.PumpControl = PumpControlType::Continuous;
881 : }
882 :
883 : // Input the optional schedule for the pump
884 6 : if (thisInput->cAlphaArgs(6).empty()) { // Initialized to zero, don't get a schedule for an empty
885 5 : thisPump.flowRateSched = nullptr;
886 1 : } else if ((thisPump.flowRateSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(6))) == nullptr) {
887 0 : ShowWarningItemNotFound(state, eoh, thisInput->cAlphaFieldNames(6), thisInput->cAlphaArgs(6));
888 : }
889 :
890 6 : thisPump.NomVolFlowRate = thisInput->rNumericArgs(1);
891 6 : if (thisPump.NomVolFlowRate == AutoSize) {
892 6 : thisPump.NomVolFlowRateWasAutoSized = true;
893 : }
894 6 : thisPump.NumPumpsInBank = thisInput->rNumericArgs(2);
895 6 : thisPump.NomPumpHead = thisInput->rNumericArgs(3);
896 6 : thisPump.NomPowerUse = thisInput->rNumericArgs(4);
897 6 : if (thisPump.NomPowerUse == AutoSize) {
898 6 : thisPump.NomPowerUseWasAutoSized = true;
899 : }
900 6 : thisPump.MotorEffic = thisInput->rNumericArgs(5);
901 6 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(6);
902 6 : thisPump.PartLoadCoef[0] = thisInput->rNumericArgs(7);
903 6 : thisPump.PartLoadCoef[1] = thisInput->rNumericArgs(8);
904 6 : thisPump.PartLoadCoef[2] = thisInput->rNumericArgs(9);
905 6 : thisPump.PartLoadCoef[3] = thisInput->rNumericArgs(10);
906 6 : thisPump.MinVolFlowRateFrac = thisInput->rNumericArgs(11);
907 6 : thisPump.MinVolFlowRate = thisPump.NomVolFlowRate * thisPump.MinVolFlowRateFrac;
908 :
909 6 : if (!thisInput->lAlphaFieldBlanks(7)) { // zone named for pump skin losses
910 0 : thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(7), state.dataHeatBal->Zone);
911 0 : if (thisPump.ZoneNum > 0) {
912 0 : thisPump.HeatLossesToZone = true;
913 0 : if (!thisInput->lNumericFieldBlanks(12)) {
914 0 : thisPump.SkinLossRadFraction = thisInput->rNumericArgs(12);
915 : }
916 : } else {
917 0 : ShowSevereError(state,
918 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
919 : cCurrentModuleObject,
920 0 : thisPump.Name,
921 0 : thisInput->cAlphaFieldNames(7),
922 0 : thisInput->cAlphaArgs(7)));
923 0 : ErrorsFound = true;
924 : }
925 : }
926 :
927 6 : if (!thisInput->lAlphaFieldBlanks(8)) {
928 1 : thisPump.powerSizingMethod =
929 1 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
930 1 : if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) {
931 0 : ShowSevereError(state,
932 0 : format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.",
933 : RoutineName,
934 : cCurrentModuleObject,
935 0 : thisPump.Name));
936 0 : ErrorsFound = true;
937 : }
938 : }
939 :
940 6 : if (!thisInput->lNumericFieldBlanks(13)) {
941 0 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(13);
942 : }
943 :
944 6 : if (!thisInput->lNumericFieldBlanks(14)) {
945 0 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(14);
946 : }
947 :
948 6 : if (NumAlphas > 8) {
949 1 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(9);
950 : } else {
951 5 : thisPump.EndUseSubcategoryName = "General";
952 : }
953 :
954 6 : thisPump.Energy = 0.0;
955 6 : thisPump.Power = 0.0;
956 : }
957 :
958 462 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::Bank_ConSpeed)];
959 463 : for (int NumConstPumpBankSimple = 1; NumConstPumpBankSimple <= NumPumpBankSimpleConst; ++NumConstPumpBankSimple) {
960 1 : PumpNum = NumConstPumpBankSimple + NumVarSpeedPumps + NumConstSpeedPumps + NumCondensatePumps + NumPumpBankSimpleVar;
961 1 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
962 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
963 : cCurrentModuleObject,
964 : NumConstPumpBankSimple,
965 1 : thisInput->cAlphaArgs,
966 : NumAlphas,
967 1 : thisInput->rNumericArgs,
968 : NumNums,
969 : IOStat,
970 1 : thisInput->lNumericFieldBlanks,
971 1 : thisInput->lAlphaFieldBlanks,
972 1 : thisInput->cAlphaFieldNames,
973 1 : thisInput->cNumericFieldNames);
974 :
975 1 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisInput->cAlphaArgs(1)};
976 :
977 1 : GlobalNames::VerifyUniqueInterObjectName(
978 2 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
979 1 : thisPump.Name = thisInput->cAlphaArgs(1);
980 1 : thisPump.pumpType = PumpType::Bank_ConSpeed; //'HeaderedPumps:ConstantSpeed'
981 1 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpBankConstantSpeed;
982 :
983 1 : thisPump.InletNodeNum = GetOnlySingleNode(state,
984 1 : thisInput->cAlphaArgs(2),
985 : ErrorsFound,
986 : DataLoopNode::ConnectionObjectType::HeaderedPumpsConstantSpeed,
987 1 : thisPump.Name,
988 : DataLoopNode::NodeFluidType::Water,
989 : DataLoopNode::ConnectionType::Inlet,
990 : NodeInputManager::CompFluidStream::Primary,
991 : ObjectIsNotParent);
992 :
993 2 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
994 1 : thisInput->cAlphaArgs(3),
995 : ErrorsFound,
996 : DataLoopNode::ConnectionObjectType::HeaderedPumpsConstantSpeed,
997 1 : thisPump.Name,
998 : DataLoopNode::NodeFluidType::Water,
999 : DataLoopNode::ConnectionType::Outlet,
1000 : NodeInputManager::CompFluidStream::Primary,
1001 : ObjectIsNotParent);
1002 1 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
1003 :
1004 1 : if (Util::SameString(thisInput->cAlphaArgs(4), "Optimal")) {
1005 0 : thisPump.SequencingScheme = PumpBankControlSeq::OptimalScheme;
1006 1 : } else if (Util::SameString(thisInput->cAlphaArgs(4), "Sequential")) {
1007 1 : thisPump.SequencingScheme = PumpBankControlSeq::SequentialScheme;
1008 : } else {
1009 0 : ShowWarningError(state,
1010 0 : format("{}{}=\"{}\", Invalid {}", RoutineName, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaFieldNames(4)));
1011 0 : ShowContinueError(
1012 : state,
1013 0 : format("Entered Value=[{}]. {} has been set to Sequential for this pump.", thisInput->cAlphaArgs(4), thisInput->cAlphaFieldNames(4)));
1014 0 : thisPump.SequencingScheme = PumpBankControlSeq::SequentialScheme;
1015 : }
1016 :
1017 1 : thisPump.PumpControl = static_cast<PumpControlType>(getEnumValue(pumpCtrlTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(5))));
1018 :
1019 1 : if (thisPump.PumpControl == PumpControlType::Invalid) {
1020 0 : ShowWarningError(state,
1021 0 : format("{}{}=\"{}\", Invalid {}", RoutineName, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaFieldNames(5)));
1022 0 : ShowContinueError(
1023 : state,
1024 0 : format("Entered Value=[{}]. {} has been set to Continuous for this pump.", thisInput->cAlphaArgs(5), thisInput->cAlphaFieldNames(5)));
1025 0 : thisPump.PumpControl = PumpControlType::Continuous;
1026 : }
1027 :
1028 : // Input the optional schedule for the pump
1029 1 : if (thisInput->lAlphaFieldBlanks(6)) {
1030 0 : thisPump.flowRateSched = nullptr;
1031 1 : } else if ((thisPump.flowRateSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(6))) == nullptr) {
1032 0 : ShowWarningItemNotFound(state, eoh, thisInput->cAlphaFieldNames(6), thisInput->cAlphaArgs(6), "");
1033 : }
1034 :
1035 1 : thisPump.NomVolFlowRate = thisInput->rNumericArgs(1);
1036 1 : if (thisPump.NomVolFlowRate == AutoSize) {
1037 1 : thisPump.NomVolFlowRateWasAutoSized = true;
1038 : }
1039 1 : thisPump.NumPumpsInBank = thisInput->rNumericArgs(2);
1040 1 : thisPump.NomPumpHead = thisInput->rNumericArgs(3);
1041 1 : thisPump.NomPowerUse = thisInput->rNumericArgs(4);
1042 1 : if (thisPump.NomPowerUse == AutoSize) {
1043 1 : thisPump.NomPowerUseWasAutoSized = true;
1044 : }
1045 1 : thisPump.MotorEffic = thisInput->rNumericArgs(5);
1046 1 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(6);
1047 1 : thisPump.PartLoadCoef[0] = 1.0;
1048 1 : thisPump.PartLoadCoef[1] = 0.0;
1049 1 : thisPump.PartLoadCoef[2] = 0.0;
1050 1 : thisPump.PartLoadCoef[3] = 0.0;
1051 :
1052 1 : if (!thisInput->lAlphaFieldBlanks(7)) { // zone named for pump skin losses
1053 0 : thisPump.ZoneNum = Util::FindItemInList(thisInput->cAlphaArgs(7), state.dataHeatBal->Zone);
1054 0 : if (thisPump.ZoneNum > 0) {
1055 0 : thisPump.HeatLossesToZone = true;
1056 0 : if (!thisInput->lNumericFieldBlanks(7)) {
1057 0 : thisPump.SkinLossRadFraction = thisInput->rNumericArgs(7);
1058 : }
1059 : } else {
1060 0 : ShowSevereError(state,
1061 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
1062 : cCurrentModuleObject,
1063 0 : thisPump.Name,
1064 0 : thisInput->cAlphaFieldNames(7),
1065 0 : thisInput->cAlphaArgs(7)));
1066 0 : ErrorsFound = true;
1067 : }
1068 : }
1069 1 : if (!thisInput->lAlphaFieldBlanks(8)) {
1070 1 : thisPump.powerSizingMethod =
1071 1 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
1072 1 : if (thisPump.powerSizingMethod == PowerSizingMethod::Invalid) {
1073 0 : ShowSevereError(state,
1074 0 : format("{}{}=\"{}\", sizing method type entered is invalid. Use one of the key choice entries.",
1075 : RoutineName,
1076 : cCurrentModuleObject,
1077 0 : thisPump.Name));
1078 0 : ErrorsFound = true;
1079 : }
1080 : }
1081 :
1082 1 : if (!thisInput->lNumericFieldBlanks(8)) {
1083 0 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(8);
1084 : }
1085 :
1086 1 : if (!thisInput->lNumericFieldBlanks(9)) {
1087 1 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(9);
1088 : }
1089 :
1090 1 : if (NumAlphas > 8) {
1091 1 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(9);
1092 : } else {
1093 0 : thisPump.EndUseSubcategoryName = "General";
1094 : }
1095 :
1096 1 : thisPump.MinVolFlowRate = 0.0;
1097 1 : thisPump.Energy = 0.0;
1098 1 : thisPump.Power = 0.0;
1099 : }
1100 :
1101 462 : if (ErrorsFound) {
1102 0 : ShowFatalError(state, "Errors found in getting Pump input");
1103 : }
1104 :
1105 1641 : for (PumpNum = 1; PumpNum <= state.dataPumps->NumPumps; ++PumpNum) { // CurrentModuleObject='Pumps'
1106 1179 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
1107 1179 : auto &thisPumpRep = state.dataPumps->PumpEquipReport(PumpNum);
1108 1179 : switch (thisPump.pumpType) {
1109 1172 : case PumpType::VarSpeed:
1110 : case PumpType::ConSpeed:
1111 : case PumpType::Cond: {
1112 :
1113 2344 : SetupOutputVariable(state,
1114 : "Pump Electricity Energy",
1115 : Constant::Units::J,
1116 1172 : thisPump.Energy,
1117 : OutputProcessor::TimeStepType::System,
1118 : OutputProcessor::StoreType::Sum,
1119 1172 : thisPump.Name,
1120 : Constant::eResource::Electricity,
1121 : OutputProcessor::Group::Plant,
1122 : OutputProcessor::EndUseCat::Pumps,
1123 : thisPump.EndUseSubcategoryName);
1124 2344 : SetupOutputVariable(state,
1125 : "Pump Electricity Rate",
1126 : Constant::Units::W,
1127 1172 : thisPump.Power,
1128 : OutputProcessor::TimeStepType::System,
1129 : OutputProcessor::StoreType::Average,
1130 1172 : thisPump.Name);
1131 2344 : SetupOutputVariable(state,
1132 : "Pump Shaft Power",
1133 : Constant::Units::W,
1134 1172 : thisPumpRep.ShaftPower,
1135 : OutputProcessor::TimeStepType::System,
1136 : OutputProcessor::StoreType::Average,
1137 1172 : thisPump.Name);
1138 2344 : SetupOutputVariable(state,
1139 : "Pump Fluid Heat Gain Rate",
1140 : Constant::Units::W,
1141 1172 : thisPumpRep.PumpHeattoFluid,
1142 : OutputProcessor::TimeStepType::System,
1143 : OutputProcessor::StoreType::Average,
1144 1172 : thisPump.Name);
1145 2344 : SetupOutputVariable(state,
1146 : "Pump Fluid Heat Gain Energy",
1147 : Constant::Units::J,
1148 1172 : thisPumpRep.PumpHeattoFluidEnergy,
1149 : OutputProcessor::TimeStepType::System,
1150 : OutputProcessor::StoreType::Sum,
1151 1172 : thisPump.Name);
1152 2344 : SetupOutputVariable(state,
1153 : "Pump Outlet Temperature",
1154 : Constant::Units::C,
1155 1172 : thisPumpRep.OutletTemp,
1156 : OutputProcessor::TimeStepType::System,
1157 : OutputProcessor::StoreType::Average,
1158 1172 : thisPump.Name);
1159 2344 : SetupOutputVariable(state,
1160 : "Pump Mass Flow Rate",
1161 : Constant::Units::kg_s,
1162 1172 : thisPumpRep.PumpMassFlowRate,
1163 : OutputProcessor::TimeStepType::System,
1164 : OutputProcessor::StoreType::Average,
1165 1172 : thisPump.Name);
1166 1172 : } break;
1167 :
1168 7 : case PumpType::Bank_VarSpeed:
1169 : case PumpType::Bank_ConSpeed: { // CurrentModuleObject='HeaderedPumps'
1170 :
1171 14 : SetupOutputVariable(state,
1172 : "Pump Electricity Energy",
1173 : Constant::Units::J,
1174 7 : thisPump.Energy,
1175 : OutputProcessor::TimeStepType::System,
1176 : OutputProcessor::StoreType::Sum,
1177 7 : thisPump.Name,
1178 : Constant::eResource::Electricity,
1179 : OutputProcessor::Group::Plant,
1180 : OutputProcessor::EndUseCat::Pumps,
1181 : thisPump.EndUseSubcategoryName);
1182 14 : SetupOutputVariable(state,
1183 : "Pump Electricity Rate",
1184 : Constant::Units::W,
1185 7 : thisPump.Power,
1186 : OutputProcessor::TimeStepType::System,
1187 : OutputProcessor::StoreType::Average,
1188 7 : thisPump.Name);
1189 14 : SetupOutputVariable(state,
1190 : "Pump Shaft Power",
1191 : Constant::Units::W,
1192 7 : thisPumpRep.ShaftPower,
1193 : OutputProcessor::TimeStepType::System,
1194 : OutputProcessor::StoreType::Average,
1195 7 : thisPump.Name);
1196 14 : SetupOutputVariable(state,
1197 : "Pump Fluid Heat Gain Rate",
1198 : Constant::Units::W,
1199 7 : thisPumpRep.PumpHeattoFluid,
1200 : OutputProcessor::TimeStepType::System,
1201 : OutputProcessor::StoreType::Average,
1202 7 : thisPump.Name);
1203 14 : SetupOutputVariable(state,
1204 : "Pump Fluid Heat Gain Energy",
1205 : Constant::Units::J,
1206 7 : thisPumpRep.PumpHeattoFluidEnergy,
1207 : OutputProcessor::TimeStepType::System,
1208 : OutputProcessor::StoreType::Sum,
1209 7 : thisPump.Name);
1210 14 : SetupOutputVariable(state,
1211 : "Pump Outlet Temperature",
1212 : Constant::Units::C,
1213 7 : thisPumpRep.OutletTemp,
1214 : OutputProcessor::TimeStepType::System,
1215 : OutputProcessor::StoreType::Average,
1216 7 : thisPump.Name);
1217 14 : SetupOutputVariable(state,
1218 : "Pump Mass Flow Rate",
1219 : Constant::Units::kg_s,
1220 7 : thisPumpRep.PumpMassFlowRate,
1221 : OutputProcessor::TimeStepType::System,
1222 : OutputProcessor::StoreType::Average,
1223 7 : thisPump.Name);
1224 7 : SetupOutputVariable(state,
1225 : "Pump Operating Pumps Count",
1226 : Constant::Units::None,
1227 7 : thisPumpRep.NumPumpsOperating,
1228 : OutputProcessor::TimeStepType::System,
1229 : OutputProcessor::StoreType::Average,
1230 7 : thisPump.Name);
1231 7 : } break;
1232 0 : default: {
1233 0 : assert(false);
1234 : } break;
1235 : }
1236 :
1237 1179 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
1238 134 : SetupEMSInternalVariable(state, "Pump Maximum Mass Flow Rate", thisPump.Name, "[kg/s]", thisPump.MassFlowRateMax);
1239 134 : SetupEMSActuator(
1240 134 : state, "Pump", thisPump.Name, "Pump Mass Flow Rate", "[kg/s]", thisPump.EMSMassFlowOverrideOn, thisPump.EMSMassFlowValue);
1241 134 : SetupEMSActuator(
1242 134 : state, "Pump", thisPump.Name, "Pump Pressure Rise", "[Pa]", thisPump.EMSPressureOverrideOn, thisPump.EMSPressureOverrideValue);
1243 : }
1244 :
1245 1179 : if (thisPump.HeatLossesToZone) {
1246 : // setup skin loss output vars
1247 0 : SetupOutputVariable(state,
1248 : "Pump Zone Total Heating Rate",
1249 : Constant::Units::W,
1250 0 : thisPumpRep.ZoneTotalGainRate,
1251 : OutputProcessor::TimeStepType::System,
1252 : OutputProcessor::StoreType::Average,
1253 0 : thisPump.Name);
1254 0 : SetupOutputVariable(state,
1255 : "Pump Zone Total Heating Energy",
1256 : Constant::Units::J,
1257 0 : thisPumpRep.ZoneTotalGainEnergy,
1258 : OutputProcessor::TimeStepType::System,
1259 : OutputProcessor::StoreType::Sum,
1260 0 : thisPump.Name);
1261 0 : SetupOutputVariable(state,
1262 : "Pump Zone Convective Heating Rate",
1263 : Constant::Units::W,
1264 0 : thisPumpRep.ZoneConvGainRate,
1265 : OutputProcessor::TimeStepType::System,
1266 : OutputProcessor::StoreType::Average,
1267 0 : thisPump.Name);
1268 0 : SetupOutputVariable(state,
1269 : "Pump Zone Radiative Heating Rate",
1270 : Constant::Units::W,
1271 0 : thisPumpRep.ZoneRadGainRate,
1272 : OutputProcessor::TimeStepType::System,
1273 : OutputProcessor::StoreType::Average,
1274 0 : thisPump.Name);
1275 :
1276 : // setup internal gains
1277 0 : switch (thisPump.pumpType) {
1278 0 : case PumpType::VarSpeed: {
1279 0 : SetupZoneInternalGain(state,
1280 : thisPump.ZoneNum,
1281 : thisPump.Name,
1282 : DataHeatBalance::IntGainType::Pump_VarSpeed,
1283 : &thisPumpRep.ZoneConvGainRate,
1284 : nullptr,
1285 : &thisPumpRep.ZoneRadGainRate);
1286 0 : } break;
1287 0 : case PumpType::ConSpeed: {
1288 0 : SetupZoneInternalGain(state,
1289 : thisPump.ZoneNum,
1290 : thisPump.Name,
1291 : DataHeatBalance::IntGainType::Pump_ConSpeed,
1292 : &thisPumpRep.ZoneConvGainRate,
1293 : nullptr,
1294 : &thisPumpRep.ZoneRadGainRate);
1295 0 : } break;
1296 0 : case PumpType::Cond: {
1297 0 : SetupZoneInternalGain(state,
1298 : thisPump.ZoneNum,
1299 : thisPump.Name,
1300 : DataHeatBalance::IntGainType::Pump_Cond,
1301 : &thisPumpRep.ZoneConvGainRate,
1302 : nullptr,
1303 : &thisPumpRep.ZoneRadGainRate);
1304 0 : } break;
1305 0 : case PumpType::Bank_VarSpeed: {
1306 0 : SetupZoneInternalGain(state,
1307 : thisPump.ZoneNum,
1308 : thisPump.Name,
1309 : DataHeatBalance::IntGainType::PumpBank_VarSpeed,
1310 : &thisPumpRep.ZoneConvGainRate,
1311 : nullptr,
1312 : &thisPumpRep.ZoneRadGainRate);
1313 0 : } break;
1314 0 : case PumpType::Bank_ConSpeed: {
1315 0 : SetupZoneInternalGain(state,
1316 : thisPump.ZoneNum,
1317 : thisPump.Name,
1318 : DataHeatBalance::IntGainType::PumpBank_ConSpeed,
1319 : &thisPumpRep.ZoneConvGainRate,
1320 : nullptr,
1321 : &thisPumpRep.ZoneRadGainRate);
1322 0 : } break;
1323 0 : default:
1324 0 : break;
1325 : }
1326 : }
1327 : }
1328 : }
1329 :
1330 56466326 : void InitializePumps(EnergyPlusData &state, int const PumpNum)
1331 : {
1332 :
1333 : // SUBROUTINE INFORMATION:
1334 : // AUTHOR: Edwin Lee
1335 : // DATE WRITTEN: August 2010
1336 : // MODIFIED Based on the INIT section of InitSimVars, credits here:
1337 : // Author:
1338 : // Oct 1998 Dan Fisher
1339 : // Modifications:
1340 : // Jul 2001 Richard Liesen
1341 : // July 2001, Rick Strand (implemented new pump controls)
1342 : // May 2009, Brent Griffith (added EMS override capability)
1343 : // Nov 2010, Brent Griffith (call InitComponentNodes, generalize fluid props)
1344 : // RE-ENGINEERED na
1345 :
1346 : // PURPOSE OF THIS SUBROUTINE:
1347 : // This subroutine does one-time and begin-envrn inits for the pump
1348 :
1349 : // Using/Aliasing
1350 :
1351 : using PlantUtilities::InitComponentNodes;
1352 : using PlantUtilities::ScanPlantLoopsForObject;
1353 :
1354 : // SUBROUTINE PARAMETER DEFINITIONS:
1355 56466326 : Real64 constexpr StartTemp(100.0); // Standard Temperature across code to calculated Steam density
1356 56466326 : Real64 constexpr ZeroPowerTol(0.0000001);
1357 : static constexpr std::string_view RoutineName("PlantPumps::InitializePumps ");
1358 :
1359 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1360 : Real64 TotalEffic;
1361 : Real64 SteamDensity; // Density of working fluid
1362 : Real64 TempWaterDensity;
1363 : Real64 mdotMax; // local fluid mass flow rate maximum
1364 : Real64 mdotMin; // local fluid mass flow rate minimum
1365 : DataPlant::LoopSideLocation lsnum;
1366 :
1367 : // Set some variables for convenience
1368 56466326 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
1369 56466326 : int InletNode = thisPump.InletNodeNum;
1370 56466326 : int OutletNode = thisPump.OutletNodeNum;
1371 :
1372 : // One time inits
1373 56466326 : if (thisPump.PumpOneTimeFlag) {
1374 :
1375 1179 : bool errFlag = false;
1376 1179 : ScanPlantLoopsForObject(state, thisPump.Name, thisPump.TypeOf_Num, thisPump.plantLoc, errFlag, _, _, _, _, _);
1377 1179 : int plloopnum = thisPump.plantLoc.loopNum;
1378 1179 : lsnum = thisPump.plantLoc.loopSideNum;
1379 1179 : int brnum = thisPump.plantLoc.branchNum;
1380 1179 : int cpnum = thisPump.plantLoc.compNum;
1381 1179 : if (plloopnum > 0 && lsnum != DataPlant::LoopSideLocation::Invalid && brnum > 0 && cpnum > 0) {
1382 1179 : auto &thisPumpLoc = state.dataPlnt->PlantLoop(plloopnum).LoopSide(lsnum).Branch(brnum);
1383 1179 : if (thisPumpLoc.Comp(cpnum).NodeNumIn != InletNode || thisPumpLoc.Comp(cpnum).NodeNumOut != OutletNode) {
1384 0 : ShowSevereError(
1385 : state,
1386 0 : format("InitializePumps: {}=\"{}\", non-matching nodes.", pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)], thisPump.Name));
1387 0 : ShowContinueError(state, format("...in Branch={}, Component referenced with:", thisPumpLoc.Name));
1388 0 : ShowContinueError(state, format("...Inlet Node={}", state.dataLoopNodes->NodeID(thisPumpLoc.Comp(cpnum).NodeNumIn)));
1389 0 : ShowContinueError(state, format("...Outlet Node={}", state.dataLoopNodes->NodeID(thisPumpLoc.Comp(cpnum).NodeNumOut)));
1390 0 : ShowContinueError(state, format("...Pump Inlet Node={}", state.dataLoopNodes->NodeID(InletNode)));
1391 0 : ShowContinueError(state, format("...Pump Outlet Node={}", state.dataLoopNodes->NodeID(OutletNode)));
1392 0 : errFlag = true;
1393 : }
1394 1179 : } else { // CR9292
1395 0 : ShowSevereError(
1396 : state,
1397 0 : format("InitializePumps: {}=\"{}\", component missing.", pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)], thisPump.Name));
1398 0 : errFlag = true; // should have received warning/severe earlier, will reiterate
1399 : }
1400 :
1401 1179 : if (errFlag) {
1402 0 : ShowFatalError(state, "InitializePumps: Program terminated due to previous condition(s).");
1403 : }
1404 1179 : DataPlant::CompData::getPlantComponent(state, thisPump.plantLoc).CompNum = PumpNum;
1405 :
1406 1179 : SizePump(state, PumpNum);
1407 :
1408 : // calculate the efficiency for each pump
1409 : // by calculating the efficiency for each pump being simulated. The calculation
1410 : // is based on the PMPSIM code in the ASHRAE Secondary Toolkit
1411 1179 : if (thisPump.NomPowerUse > ZeroPowerTol && thisPump.MotorEffic > ZeroPowerTol) {
1412 1144 : TotalEffic = thisPump.NomVolFlowRate * thisPump.NomPumpHead / thisPump.NomPowerUse;
1413 1144 : thisPump.PumpEffic = TotalEffic / thisPump.MotorEffic;
1414 1144 : if (thisPump.PumpEffic < 0.50) {
1415 2 : ShowWarningError(state,
1416 2 : format("Check input. Calculated Pump Efficiency={:.2R}% which is less than 50%, for pump={}",
1417 0 : thisPump.PumpEffic * 100.0,
1418 1 : thisPump.Name));
1419 2 : ShowContinueError(state,
1420 2 : format("Calculated Pump_Efficiency % =Total_Efficiency % [{:.1R}] / Motor_Efficiency % [{:.1R}]",
1421 0 : TotalEffic * 100.0,
1422 1 : thisPump.MotorEffic * 100.0));
1423 2 : ShowContinueError(
1424 : state,
1425 2 : format("Total_Efficiency % =(Rated_Volume_Flow_Rate [{:.3R}] * Rated_Pump_Head [{:.1R}] / Rated_Power_Use [{:.1R}]) * 100.",
1426 1 : thisPump.NomVolFlowRate,
1427 1 : thisPump.NomPumpHead,
1428 1 : thisPump.NomPowerUse));
1429 1143 : } else if ((thisPump.PumpEffic > 0.95) && (thisPump.PumpEffic <= 1.0)) {
1430 0 : ShowWarningError(state,
1431 0 : format("Check input. Calculated Pump Efficiency={:.2R}% is approaching 100%, for pump={}",
1432 0 : thisPump.PumpEffic * 100.0,
1433 0 : thisPump.Name));
1434 0 : ShowContinueError(state,
1435 0 : format("Calculated Pump_Efficiency % =Total_Efficiency % [{:.1R}] / Motor_Efficiency % [{:.1R}]",
1436 0 : TotalEffic * 100.0,
1437 0 : thisPump.MotorEffic * 100.0));
1438 0 : ShowContinueError(
1439 : state,
1440 0 : format("Total_Efficiency % =(Rated_Volume_Flow_Rate [{:.3R}] * Rated_Pump_Head [{:.1R}] / Rated_Power_Use [{:.1R}]) * 100.",
1441 0 : thisPump.NomVolFlowRate,
1442 0 : thisPump.NomPumpHead,
1443 0 : thisPump.NomPowerUse));
1444 1143 : } else if (thisPump.PumpEffic > 1.0) {
1445 0 : ShowSevereError(state,
1446 0 : format("Check input. Calculated Pump Efficiency={:.3R}% which is bigger than 100%, for pump={}",
1447 0 : thisPump.PumpEffic * 100.0,
1448 0 : thisPump.Name));
1449 0 : ShowContinueError(state,
1450 0 : format("Calculated Pump_Efficiency % =Total_Efficiency % [{:.1R}] / Motor_Efficiency % [{:.1R}]",
1451 0 : TotalEffic * 100.0,
1452 0 : thisPump.MotorEffic * 100.0));
1453 0 : ShowContinueError(
1454 : state,
1455 0 : format("Total_Efficiency % =(Rated_Volume_Flow_Rate [{:.3R}] * Rated_Pump_Head [{:.1R}] / Rated_Power_Use [{:.1R}]) * 100.",
1456 0 : thisPump.NomVolFlowRate,
1457 0 : thisPump.NomPumpHead,
1458 0 : thisPump.NomPowerUse));
1459 0 : ShowFatalError(state, "Errors found in Pump input");
1460 : }
1461 : } else {
1462 35 : ShowWarningError(state, format("Check input. Pump nominal power or motor efficiency is set to 0, for pump={}", thisPump.Name));
1463 : }
1464 :
1465 1179 : if (thisPump.NomVolFlowRate <= SmallWaterVolFlow) {
1466 0 : ShowWarningError(state, format("Check input. Pump nominal flow rate is set or calculated = 0, for pump={}", thisPump.Name));
1467 : }
1468 :
1469 1179 : if (thisPump.PumpControl == PumpControlType::Continuous) {
1470 : // reset flow priority appropriately (default was for Intermittent)
1471 40 : DataPlant::CompData::getPlantComponent(state, thisPump.plantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyAndTurnsLoopOn;
1472 : }
1473 :
1474 1179 : thisPump.PumpOneTimeFlag = false;
1475 : }
1476 :
1477 : // HVAC Sizing Simulation resizing calls if needed
1478 56466326 : if (state.dataGlobal->RedoSizesHVACSimulation && !state.dataPlnt->PlantReSizingCompleted) {
1479 44 : SizePump(state, PumpNum);
1480 : }
1481 :
1482 : // Begin environment inits
1483 56466326 : if (thisPump.PumpInitFlag && state.dataGlobal->BeginEnvrnFlag) {
1484 7237 : if (thisPump.pumpType == PumpType::Cond) {
1485 53 : TempWaterDensity = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, RoutineName);
1486 53 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, StartTemp, 1.0, RoutineName);
1487 53 : thisPump.NomVolFlowRate = (thisPump.NomSteamVolFlowRate * SteamDensity) / TempWaterDensity;
1488 :
1489 : // set the maximum flow rate on the outlet node
1490 53 : mdotMax = thisPump.NomSteamVolFlowRate * SteamDensity;
1491 : // mdotMin = PumpEquip(PumpNum)%MinVolFlowRate * SteamDensity
1492 : // On a pump the 'hardware min' (MassFlowRateMin) must be defined as zero and not
1493 : // confused with the desired pump operating scheme or the user specified
1494 : //'minimum flow rate'. The user specified 'minimum flow rate' determines the minimum
1495 : // flow rate under normal operating conditions. For cases when 'MaxAvail' on the pump
1496 : // inlet node actually less than the 'minimum flow rate' specified by the user, than a
1497 : // loop shutdown must be triggered.
1498 53 : mdotMin = 0.0;
1499 53 : InitComponentNodes(state, mdotMin, mdotMax, InletNode, OutletNode);
1500 53 : thisPump.MassFlowRateMax = mdotMax;
1501 53 : thisPump.MassFlowRateMin = thisPump.MinVolFlowRate * SteamDensity;
1502 :
1503 : } else {
1504 7184 : auto &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
1505 7184 : TempWaterDensity = thisPumpPlant.glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
1506 7184 : mdotMax = thisPump.NomVolFlowRate * TempWaterDensity;
1507 : // mdotMin = PumpEquip(PumpNum)%MinVolFlowRate * TempWaterDensity
1508 : // see note above
1509 7184 : mdotMin = 0.0;
1510 7184 : InitComponentNodes(state, mdotMin, mdotMax, InletNode, OutletNode);
1511 7184 : thisPump.MassFlowRateMax = mdotMax;
1512 7184 : thisPump.MassFlowRateMin = thisPump.MinVolFlowRate * TempWaterDensity;
1513 : }
1514 : // zero out report variables
1515 7237 : thisPump.Energy = 0.0;
1516 7237 : thisPump.Power = 0.0;
1517 7237 : new (&(state.dataPumps->PumpEquipReport(PumpNum))) ReportVars();
1518 7237 : thisPump.PumpInitFlag = false;
1519 : }
1520 :
1521 : // Reset the local environment flag for the next environment
1522 56466326 : if (!state.dataGlobal->BeginEnvrnFlag) {
1523 56094693 : thisPump.PumpInitFlag = true;
1524 : }
1525 :
1526 : // zero out module level working variables
1527 56466326 : auto const &daPumps = state.dataPumps;
1528 56466326 : daPumps->PumpMassFlowRate = 0.0;
1529 56466326 : daPumps->PumpHeattoFluid = 0.0;
1530 56466326 : daPumps->Power = 0.0;
1531 56466326 : daPumps->ShaftPower = 0.0;
1532 56466326 : }
1533 :
1534 : //*************************************************************************!
1535 :
1536 : //*************************************************************************!
1537 :
1538 18821701 : void SetupPumpMinMaxFlows(EnergyPlusData &state, int const LoopNum, int const PumpNum)
1539 : {
1540 :
1541 : // SUBROUTINE INFORMATION:
1542 : // AUTHOR: Edwin Lee
1543 : // DATE WRITTEN: Aug 2010
1544 : // MODIFIED Based on the Flow control portion of what was previously Pumps::InitSimVars, by:
1545 : // Dan Fisher October 1998
1546 : // Richard Liesen July 2001
1547 : // July 2001, Rick Strand (implemented new pump controls)
1548 : // May 2009, Brent Griffith (added EMS override capability)
1549 : // B. Griffith, Nov 2011 Pump control: Intermittent vs Continuous
1550 : // RE-ENGINEERED
1551 :
1552 : // PURPOSE OF THIS SUBROUTINE:
1553 : // This subroutine initializes the pump minAvail and maxAvail flow rates, and assigns them to the
1554 : // outlet min/max avail according to inlet min/max constraints and zero flow request
1555 : // The loop solver then uses this information to set up the flow bounds for the loop side
1556 : // for the current iteration.
1557 :
1558 : // METHODOLOGY EMPLOYED:
1559 : // Design flow rate and user specified minimum flow rate is compared in the inlet node
1560 : // min/maxavail. The pump output is appropriately constrained.
1561 : // Design flow is rated flow times schedule fraction
1562 : // Inlet node max will represent the rated flow rate according to pump init routines.
1563 : // These values are bounded by hardware min constraints on the inlet node, which is likely zero.
1564 : // These values are also bounded by EMS overridable limit of max flow rate.
1565 :
1566 : // Using/Aliasing
1567 : using PlantPressureSystem::ResolveLoopFlowVsPressure;
1568 : using PlantUtilities::BoundValueToWithinTwoValues;
1569 :
1570 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1571 : int InletNode; // pump inlet node number
1572 : int OutletNode; // pump outlet node number
1573 : Real64 InletNodeMax;
1574 : Real64 InletNodeMin;
1575 : Real64 PumpMassFlowRateMax; // max allowable flow rate at the pump
1576 : Real64 PumpMassFlowRateMin; // min allowable flow rate at the pump
1577 : Real64 PumpSchedFraction;
1578 : Real64 PumpOverridableMaxLimit;
1579 : Real64 PumpMassFlowRateMinLimit;
1580 : Real64 PumpSchedRPM; // Pump RPM Optional Input
1581 :
1582 18821701 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
1583 :
1584 : // Inlet/Outlet Node Numbers
1585 18821701 : InletNode = thisPump.InletNodeNum;
1586 18821701 : OutletNode = thisPump.OutletNodeNum;
1587 18821701 : auto &thisInNode = state.dataLoopNodes->Node(InletNode);
1588 18821701 : auto &thisOutNode = state.dataLoopNodes->Node(OutletNode);
1589 :
1590 : // Inlet node Min/MaxAvail
1591 18821701 : InletNodeMax = thisInNode.MassFlowRateMaxAvail;
1592 18821701 : InletNodeMin = thisInNode.MassFlowRateMinAvail;
1593 :
1594 : // Retrieve the pump speed fraction from the pump schedule (if any)
1595 18821701 : PumpSchedFraction = (thisPump.flowRateSched != nullptr) ? std::clamp(thisPump.flowRateSched->getCurrentVal(), 0.0, 1.0) : 1.0;
1596 :
1597 : // User specified min/max mass flow rates for pump
1598 18821701 : PumpOverridableMaxLimit = thisPump.MassFlowRateMax;
1599 :
1600 : // override the user specified min to allow pump to turn off when no flow is required.
1601 18821701 : if (thisPump.LoopSolverOverwriteFlag) {
1602 7214848 : PumpMassFlowRateMinLimit = 0.0;
1603 : } else {
1604 11606853 : PumpMassFlowRateMinLimit = thisPump.MassFlowRateMin;
1605 : }
1606 :
1607 : // The pump outlet node Min/MaxAvail
1608 18821701 : PumpMassFlowRateMin = max(InletNodeMin, PumpMassFlowRateMinLimit);
1609 18821701 : PumpMassFlowRateMax = min(InletNodeMax, PumpOverridableMaxLimit * PumpSchedFraction);
1610 :
1611 : // Check for conflicts (MaxAvail < MinAvail)
1612 18821701 : if (PumpMassFlowRateMin > PumpMassFlowRateMax) { // the demand side wants to operate outside of the pump range
1613 : // shut the pump (and the loop) down
1614 379 : PumpMassFlowRateMin = 0.0;
1615 379 : PumpMassFlowRateMax = 0.0;
1616 : // Let the user know that his input file is overconstrained
1617 : }
1618 :
1619 18821701 : auto const &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
1620 :
1621 18821701 : switch (thisPump.pumpType) {
1622 15033743 : case PumpType::VarSpeed: {
1623 15033743 : if (thisPump.HasVFD) {
1624 2340 : switch (thisPump.VFD.VFDControlType) {
1625 2340 : case ControlTypeVFD::VFDManual: {
1626 : // Evaluate the schedule if it exists and put the fraction into a local variable
1627 2340 : PumpSchedRPM = thisPump.VFD.manualRPMSched->getCurrentVal();
1628 : // Convert the RPM to rot/sec for calculation routine
1629 2340 : thisPump.RotSpeed = PumpSchedRPM / 60.0;
1630 : // Resolve the new mass flow rate based on current pressure characteristics
1631 2340 : if (thisPumpPlant.UsePressureForPumpCalcs && thisPumpPlant.PressureSimType == DataPlant::PressSimType::FlowCorrection &&
1632 1170 : thisPumpPlant.PressureDrop > 0.0) {
1633 :
1634 1164 : state.dataPumps->PumpMassFlowRate = ResolveLoopFlowVsPressure(state,
1635 : thisPump.plantLoc.loopNum,
1636 1164 : state.dataLoopNodes->Node(thisPump.InletNodeNum).MassFlowRate,
1637 : thisPump.PressureCurve_Index,
1638 : thisPump.RotSpeed,
1639 : thisPump.ImpellerDiameter,
1640 : thisPump.MinPhiValue,
1641 : thisPump.MaxPhiValue);
1642 :
1643 1164 : PumpMassFlowRateMax = state.dataPumps->PumpMassFlowRate;
1644 1164 : PumpMassFlowRateMin = state.dataPumps->PumpMassFlowRate;
1645 : }
1646 2340 : } break;
1647 0 : case ControlTypeVFD::VFDAutomatic: {
1648 0 : if (thisPumpPlant.UsePressureForPumpCalcs && thisPumpPlant.PressureSimType == DataPlant::PressSimType::FlowCorrection &&
1649 0 : thisPumpPlant.PressureDrop > 0.0) {
1650 :
1651 0 : GetRequiredMassFlowRate(state,
1652 : LoopNum,
1653 : PumpNum,
1654 0 : state.dataLoopNodes->Node(thisPump.InletNodeNum).MassFlowRate,
1655 0 : state.dataPumps->PumpMassFlowRate,
1656 : PumpMassFlowRateMin,
1657 : PumpMassFlowRateMax);
1658 : }
1659 0 : } break;
1660 0 : default:
1661 0 : break;
1662 : } // VFDControlType
1663 : }
1664 :
1665 15033743 : if (thisPump.PumpControl == PumpControlType::Continuous) {
1666 60127 : thisInNode.MassFlowRateRequest = PumpMassFlowRateMin;
1667 : }
1668 15033743 : } break;
1669 3646277 : case PumpType::ConSpeed: {
1670 3646277 : if (thisPump.PumpControl == PumpControlType::Continuous) {
1671 549291 : PumpMassFlowRateMin = PumpMassFlowRateMax;
1672 549291 : thisInNode.MassFlowRateRequest = PumpMassFlowRateMin;
1673 : }
1674 :
1675 : // Override (lock down flow) for pressure drop if applicable
1676 3646277 : if (thisPump.plantLoc.loopNum > 0) {
1677 3646277 : if (thisPumpPlant.UsePressureForPumpCalcs && thisPumpPlant.PressureSimType == DataPlant::PressSimType::FlowCorrection &&
1678 2925 : thisPumpPlant.PressureDrop > 0.0) {
1679 2910 : state.dataPumps->PumpMassFlowRate = ResolveLoopFlowVsPressure(state,
1680 : thisPump.plantLoc.loopNum,
1681 2910 : state.dataLoopNodes->Node(thisPump.InletNodeNum).MassFlowRate,
1682 : thisPump.PressureCurve_Index,
1683 : thisPump.RotSpeed,
1684 : thisPump.ImpellerDiameter,
1685 : thisPump.MinPhiValue,
1686 : thisPump.MaxPhiValue);
1687 2910 : PumpMassFlowRateMax = state.dataPumps->PumpMassFlowRate;
1688 2910 : PumpMassFlowRateMin = state.dataPumps->PumpMassFlowRate;
1689 : }
1690 : }
1691 3646277 : } break;
1692 141681 : default:
1693 141681 : break;
1694 : }
1695 :
1696 : // Override pump operation based on System Availability Managers, should be done elsewhere? I suppose this should be OK though
1697 18821701 : if (allocated(state.dataAvail->PlantAvailMgr)) {
1698 18821701 : if (state.dataAvail->PlantAvailMgr(LoopNum).availStatus == Avail::Status::ForceOff) {
1699 248526 : PumpMassFlowRateMax = 0.0;
1700 248526 : PumpMassFlowRateMin = 0.0;
1701 : }
1702 : }
1703 :
1704 : // Check if EMS is overriding flow
1705 18821701 : if (thisPump.EMSMassFlowOverrideOn) {
1706 148632 : PumpMassFlowRateMax = thisPump.EMSMassFlowValue;
1707 148632 : PumpMassFlowRateMin = thisPump.EMSMassFlowValue;
1708 : }
1709 :
1710 : // Update outlet node to allow loop solver to get data
1711 : // could avoid this by passing data in/out to avoid putting things on nodes
1712 18821701 : thisOutNode.MassFlowRateMinAvail = PumpMassFlowRateMin;
1713 18821701 : thisOutNode.MassFlowRateMaxAvail = PumpMassFlowRateMax;
1714 18821701 : }
1715 :
1716 37644625 : void CalcPumps(EnergyPlusData &state, int const PumpNum, Real64 const FlowRequest, bool &PumpRunning)
1717 : {
1718 :
1719 : // SUBROUTINE INFORMATION:
1720 : // AUTHOR Dan Fisher
1721 : // DATE WRITTEN Sept. 1998
1722 : // MODIFIED July 2001, Rick Strand
1723 : // RE-ENGINEERED Sept 2010, Edwin Lee
1724 :
1725 : // PURPOSE OF THIS SUBROUTINE:
1726 : // This subroutines simulates a pump following
1727 : // the methodology oulined in ASHRAE's secondary toolkit.
1728 :
1729 : // METHODOLOGY EMPLOYED:
1730 : // Calculates power and updates other pump things.
1731 :
1732 : // REFERENCES:
1733 : // HVAC 2 Toolkit: A Toolkit for Secondary HVAC System
1734 : // Energy Calculations, ASHRAE, 1993, pp2-10 to 2-15
1735 :
1736 : // Using/Aliasing
1737 : using PlantUtilities::SetComponentFlowRate;
1738 :
1739 : // SUBROUTINE PARAMETER DEFINITIONS:
1740 : static constexpr std::string_view RoutineName("PlantPumps:CalcPumps: ");
1741 :
1742 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1743 : int InletNode;
1744 : int OutletNode;
1745 : Real64 LoopDensity;
1746 37644625 : Real64 VolFlowRate = 0.0;
1747 : Real64 PartLoadRatio;
1748 : Real64 FracFullLoadPower;
1749 : Real64 FullLoadVolFlowRate;
1750 : Real64 PartLoadVolFlowRate;
1751 : Real64 FullLoadPower;
1752 : Real64 FullLoadPowerRatio;
1753 : Real64 TotalEffic;
1754 : PumpType pumpType;
1755 : Real64 RotSpeed_Min;
1756 : Real64 RotSpeed_Max;
1757 : Real64 PumpActualRPMValueOne;
1758 : Real64 PumpActualRPMValueTwo;
1759 :
1760 37644625 : auto &daPumps = state.dataPumps;
1761 37644625 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
1762 :
1763 37644625 : InletNode = thisPump.InletNodeNum;
1764 37644625 : OutletNode = thisPump.OutletNodeNum;
1765 37644625 : pumpType = thisPump.pumpType;
1766 :
1767 37644625 : auto &thisInNode = state.dataLoopNodes->Node(InletNode);
1768 37644625 : auto &thisOutNode = state.dataLoopNodes->Node(OutletNode);
1769 :
1770 : //****************************!
1771 : //** SETTING PUMP FLOW RATE **!
1772 : //****************************!
1773 : // So the loop solver always passes in the full loop side flow request to each pump called
1774 : // The pump will try to use this value according to its inlet conditions via the SetComponentFlowRate routine.
1775 : // If the loop solver is doing branch pumps, then individual parallel branch inlet nodes would have been previously
1776 : // constrained, so even though we pass in a full flow request, each pump will "pull down" to the min/max avail.
1777 : // Also, on flowlock == locked, we will just use the inlet node flow rate
1778 : // The flow resolver can take care of argument resolution beyond that.
1779 : // For a typical situation, the flow request should be within the values of min/max avail, so the pump will get this flow rate.
1780 37644625 : if (FlowRequest > DataBranchAirLoopPlant::MassFlowTolerance) {
1781 20483989 : daPumps->PumpMassFlowRate = FlowRequest;
1782 : } else {
1783 17160636 : daPumps->PumpMassFlowRate = 0.0;
1784 : }
1785 :
1786 : // For variable speed branch pumps, with other components
1787 : // on the branch, we are not going to assign a request.
1788 : // Other components on this branch will request flow for this branch
1789 :
1790 : // ! If this is a variable speed pump
1791 37644625 : if (thisPump.pumpType == PumpType::VarSpeed || thisPump.pumpType == PumpType::Bank_VarSpeed || thisPump.pumpType == PumpType::Cond) {
1792 30337332 : if (DataPlant::CompData::getPlantComponent(state, thisPump.plantLoc).FlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive) {
1793 631338 : daPumps->PumpMassFlowRate = 0.0;
1794 : }
1795 : }
1796 :
1797 : // bound flow request by pump max limit, the Flow Request is total loop flow and if this is a branch pump that is not appropriate
1798 37644625 : daPumps->PumpMassFlowRate = min(thisPump.MassFlowRateMax, daPumps->PumpMassFlowRate);
1799 37644625 : daPumps->PumpMassFlowRate = max(thisPump.MassFlowRateMin, daPumps->PumpMassFlowRate);
1800 :
1801 37644625 : SetComponentFlowRate(state, daPumps->PumpMassFlowRate, InletNode, OutletNode, thisPump.plantLoc);
1802 :
1803 37644625 : auto &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
1804 :
1805 : // Get RPM value for reporting as output
1806 : // RPM is calculated using pump affinity laws for rotation speed
1807 37644625 : if (thisPumpPlant.UsePressureForPumpCalcs && thisPump.HasVFD) {
1808 2340 : RotSpeed_Min = thisPump.VFD.minRPMSched ? thisPump.VFD.minRPMSched->getCurrentVal() : 0.0;
1809 2340 : RotSpeed_Max = thisPump.VFD.maxRPMSched ? thisPump.VFD.maxRPMSched->getCurrentVal() : 0.0;
1810 2340 : if (thisPump.PumpMassFlowRateMaxRPM < DataBranchAirLoopPlant::MassFlowTolerance ||
1811 0 : thisPump.PumpMassFlowRateMinRPM < DataBranchAirLoopPlant::MassFlowTolerance) {
1812 2340 : thisPump.VFD.PumpActualRPM = 0.0;
1813 : } else {
1814 0 : PumpActualRPMValueOne = (daPumps->PumpMassFlowRate / thisPump.PumpMassFlowRateMaxRPM) * RotSpeed_Max;
1815 0 : PumpActualRPMValueTwo = (daPumps->PumpMassFlowRate / thisPump.PumpMassFlowRateMinRPM) * RotSpeed_Min;
1816 0 : thisPump.VFD.PumpActualRPM = (PumpActualRPMValueOne + PumpActualRPMValueTwo) / 2;
1817 : }
1818 : }
1819 :
1820 : //****************************!
1821 : //** DETERMINE IF PUMP IS ON *!
1822 : //****************************!
1823 : // Since we don't allow series pumping, if there is ANY flow rate for this pump, THIS PUMP is driving the flow! Therefore...
1824 37644625 : PumpRunning = (daPumps->PumpMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance);
1825 :
1826 : //****************************!
1827 : //** UPDATE PUMP BANK USAGE **!
1828 : //****************************!
1829 37644625 : switch (thisPump.pumpType) {
1830 161101 : case PumpType::Bank_VarSpeed:
1831 : case PumpType::Bank_ConSpeed: {
1832 : // previously, pumps did whatever they wanted
1833 : // because of this a constant speed pump bank could adjust the flow rate as-desired
1834 : // even if it was not allowed
1835 : // since pumps now must behave nicely like all other components, the calculation of number
1836 : // of running pumps in a pump bank is the same for both bank types
1837 : // the pumps are loaded sequentially, and the last pump can have full or non-full part load
1838 : // status...this is just how it works now. The pump cannot *bump* up the flow on the loop
1839 : // to make sure the last running pump is fully loaded anymore for constant speed pumps...sorry
1840 161101 : if (daPumps->PumpMassFlowRate >= thisPump.MassFlowRateMax) {
1841 : // running full on
1842 0 : daPumps->NumPumpsRunning = thisPump.NumPumpsInBank;
1843 : } else {
1844 : // running at some sort of part load
1845 161101 : daPumps->NumPumpsRunning = CEILING((daPumps->PumpMassFlowRate / (thisPump.MassFlowRateMax) * thisPump.NumPumpsInBank));
1846 161101 : daPumps->NumPumpsRunning = min(daPumps->NumPumpsRunning, thisPump.NumPumpsInBank);
1847 : }
1848 161101 : } break;
1849 37483524 : default:
1850 37483524 : break;
1851 : }
1852 :
1853 : //****************************!
1854 : //***** EXIT IF NO FLOW ******!
1855 : //****************************!
1856 37644625 : if (daPumps->PumpMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) {
1857 17271724 : thisOutNode.Temp = thisInNode.Temp;
1858 17271724 : thisOutNode.Press = thisInNode.Press;
1859 17271724 : thisOutNode.Quality = thisInNode.Quality;
1860 17271724 : return;
1861 : }
1862 :
1863 : // density used for volumetric flow calculations
1864 20372901 : LoopDensity = thisPumpPlant.glycol->getDensity(state, thisInNode.Temp, RoutineName);
1865 :
1866 : //****************************!
1867 : //***** CALCULATE POWER (1) **!
1868 : //****************************!
1869 20372901 : switch (pumpType) {
1870 20282695 : case PumpType::ConSpeed:
1871 : case PumpType::VarSpeed:
1872 : case PumpType::Cond: {
1873 20282695 : VolFlowRate = daPumps->PumpMassFlowRate / LoopDensity;
1874 20282695 : PartLoadRatio = min(1.0, (VolFlowRate / thisPump.NomVolFlowRate));
1875 20282695 : FracFullLoadPower = thisPump.PartLoadCoef[0] + thisPump.PartLoadCoef[1] * PartLoadRatio + thisPump.PartLoadCoef[2] * pow_2(PartLoadRatio) +
1876 20282695 : thisPump.PartLoadCoef[3] * pow_3(PartLoadRatio);
1877 20282695 : daPumps->Power = FracFullLoadPower * thisPump.NomPowerUse;
1878 :
1879 20282695 : } break;
1880 90206 : case PumpType::Bank_ConSpeed:
1881 : case PumpType::Bank_VarSpeed: {
1882 : // now just assume the last one is (or is not) running at part load
1883 : // if it is actually at full load, the calculations work out to PLR = 1
1884 : // for the last pump, so all is OK
1885 90206 : daPumps->NumPumpsFullLoad = daPumps->NumPumpsRunning - 1;
1886 90206 : FullLoadVolFlowRate = thisPump.NomVolFlowRate / thisPump.NumPumpsInBank;
1887 90206 : PartLoadVolFlowRate = daPumps->PumpMassFlowRate / LoopDensity - FullLoadVolFlowRate * daPumps->NumPumpsFullLoad;
1888 90206 : FullLoadPower = thisPump.NomPowerUse / thisPump.NumPumpsInBank;
1889 90206 : FullLoadPowerRatio = thisPump.PartLoadCoef[0] + thisPump.PartLoadCoef[1] + thisPump.PartLoadCoef[2] + thisPump.PartLoadCoef[3];
1890 90206 : PartLoadRatio = min(1.0, (PartLoadVolFlowRate / FullLoadVolFlowRate));
1891 90206 : FracFullLoadPower = thisPump.PartLoadCoef[0] + thisPump.PartLoadCoef[1] * PartLoadRatio + thisPump.PartLoadCoef[2] * pow_2(PartLoadRatio) +
1892 90206 : thisPump.PartLoadCoef[3] * pow_3(PartLoadRatio);
1893 90206 : daPumps->Power = (FullLoadPowerRatio * daPumps->NumPumpsFullLoad + FracFullLoadPower) * FullLoadPower;
1894 90206 : if (thisPump.EMSPressureOverrideOn) {
1895 0 : VolFlowRate = PartLoadVolFlowRate;
1896 : }
1897 90206 : } break;
1898 0 : default: {
1899 0 : assert(false);
1900 : } break;
1901 : }
1902 :
1903 : //****************************!
1904 : //***** CALCULATE POWER (2) **!
1905 : //****************************!
1906 20372901 : if (daPumps->Power < 0.0) {
1907 0 : if (thisPump.PowerErrIndex1 == 0) {
1908 0 : ShowWarningMessage(
1909 : state,
1910 0 : format("{} Calculated Pump Power < 0, Type={}, Name={}", RoutineName, pumpTypeIDFNames[static_cast<int>(pumpType)], thisPump.Name));
1911 0 : ShowContinueErrorTimeStamp(state, "");
1912 0 : ShowContinueError(state, format("...PartLoadRatio=[{:.4R}], Fraction Full Load Power={:.4R}]", PartLoadRatio, FracFullLoadPower));
1913 0 : ShowContinueError(state, "...Power is set to 0 for continuing the simulation.");
1914 0 : ShowContinueError(state, "...Pump coefficients should be checked for producing this negative value.");
1915 : }
1916 0 : daPumps->Power = 0.0;
1917 0 : ShowRecurringWarningErrorAtEnd(
1918 : state,
1919 0 : format("{} Calculated Pump Power < 0, {}, Name={}, PLR=", RoutineName, pumpTypeIDFNames[static_cast<int>(pumpType)], thisPump.Name),
1920 0 : thisPump.PowerErrIndex1,
1921 : PartLoadRatio,
1922 : PartLoadRatio);
1923 0 : ShowRecurringContinueErrorAtEnd(state, "...Fraction Full Load Power=", thisPump.PowerErrIndex2, FracFullLoadPower, FracFullLoadPower);
1924 : }
1925 :
1926 : //****************************!
1927 : //***** CALCULATE POWER (3) **!
1928 : //****************************!
1929 : // Now if we are doing pressure-based simulation, then we have a means to calculate power exactly based on current
1930 : // simulation conditions (flow rate and pressure drop) along with knowledge about pump impeller and motor efficiencies
1931 : // Thus we will override the power that was calculated based on nominal values with the corrected pressure-based power
1932 20372901 : if (thisPump.plantLoc.loopNum > 0) {
1933 20372901 : if (thisPumpPlant.UsePressureForPumpCalcs) {
1934 10476 : TotalEffic = thisPump.PumpEffic * thisPump.MotorEffic;
1935 : // Efficiency errors are caught previously, but it doesn't hurt to add another catch before dividing by zero!!!
1936 10476 : if (TotalEffic == 0.0) {
1937 0 : ShowSevereError(state,
1938 0 : format("{} Plant pressure simulation encountered a pump with zero efficiency: {}", RoutineName, thisPump.Name));
1939 0 : ShowContinueError(state, "Check efficiency inputs for this pump component.");
1940 0 : ShowFatalError(state, "Errors in plant calculation would result in divide-by-zero cause program termination.");
1941 : }
1942 10476 : daPumps->Power = VolFlowRate * thisPumpPlant.PressureDrop / TotalEffic;
1943 : }
1944 : }
1945 :
1946 : // if user has specified a pressure value, then use it, same as for pressure-based simulation
1947 20372901 : if (thisPump.EMSPressureOverrideOn) {
1948 744 : TotalEffic = thisPump.PumpEffic * thisPump.MotorEffic;
1949 : // Efficiency errors are caught previously, but it doesn't hurt to add another catch before dividing by zero!!!
1950 744 : if (TotalEffic == 0.0) {
1951 0 : ShowSevereError(state, format("{} Plant pump simulation encountered a pump with zero efficiency: {}", RoutineName, thisPump.Name));
1952 0 : ShowContinueError(state, "Check efficiency inputs for this pump component.");
1953 0 : ShowFatalError(state, "Errors in plant calculation would result in divide-by-zero cause program termination.");
1954 : }
1955 744 : daPumps->Power = VolFlowRate * thisPump.EMSPressureOverrideValue / TotalEffic;
1956 : }
1957 :
1958 : //****************************!
1959 : //***** CALCULATE POWER (4) **!
1960 : //****************************!
1961 : // This adds the pump heat based on User input for the pump
1962 : // We assume that all of the heat ends up in the fluid eventually since this is a closed loop
1963 20372901 : daPumps->ShaftPower = daPumps->Power * thisPump.MotorEffic;
1964 20372901 : daPumps->PumpHeattoFluid = daPumps->ShaftPower + (daPumps->Power - daPumps->ShaftPower) * thisPump.FracMotorLossToFluid;
1965 :
1966 : //****************************!
1967 : //***** UPDATE INFORMATION ***!
1968 : //****************************!
1969 : // Update data structure variables
1970 20372901 : thisPump.Power = daPumps->Power;
1971 :
1972 : // Update outlet node conditions
1973 20372901 : thisOutNode.Temp = thisInNode.Temp;
1974 20372901 : thisOutNode.Press = thisInNode.Press;
1975 20372901 : thisOutNode.Quality = thisInNode.Quality;
1976 : }
1977 :
1978 1223 : void SizePump(EnergyPlusData &state, int const PumpNum)
1979 : {
1980 :
1981 : // SUBROUTINE INFORMATION:
1982 : // AUTHOR Fred Buhl
1983 : // DATE WRITTEN December 2001
1984 : // MODIFIED na
1985 : // RE-ENGINEERED na
1986 :
1987 : // PURPOSE OF THIS SUBROUTINE:
1988 : // This subroutine is for sizing Pump Components for which flow rates have not been
1989 : // specified in the input.
1990 :
1991 : // METHODOLOGY EMPLOYED:
1992 : // Obtains flow rates from the plant sizing array.
1993 :
1994 : // SUBROUTINE PARAMETER DEFINITIONS:
1995 1223 : Real64 constexpr StartTemp(100.0); // Standard Temperature across code to calculated Steam density
1996 : static constexpr std::string_view RoutineName("PlantPumps::InitSimVars ");
1997 : static constexpr std::string_view RoutineNameSizePumps("SizePumps");
1998 :
1999 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2000 : int PlantSizNum; // index of Plant Sizing array
2001 : bool ErrorsFound;
2002 1223 : Real64 TotalEffic = 0.0; // pump total efficiency
2003 : Real64 PumpSizFac; // pump sizing factor
2004 : Real64 SteamDensity;
2005 : Real64 TempWaterDensity;
2006 1223 : int DummyWaterIndex(1);
2007 : Real64 DesVolFlowRatePerBranch; // local temporary for split of branch pumps
2008 :
2009 1223 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
2010 1223 : bool thisOkToReport = state.dataPlnt->PlantFinalSizesOkayToReport;
2011 :
2012 : // Calculate density at InitConvTemp once here, to remove RhoH2O calls littered throughout
2013 1223 : if (thisPump.plantLoc.loopNum > 0) {
2014 1223 : auto &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
2015 1223 : TempWaterDensity = thisPumpPlant.glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
2016 : } else {
2017 0 : TempWaterDensity = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, RoutineName);
2018 : }
2019 :
2020 1223 : PlantSizNum = 0;
2021 1223 : PumpSizFac = 1.0;
2022 1223 : ErrorsFound = false;
2023 :
2024 1223 : if (thisPump.plantLoc.loopNum > 0) {
2025 1223 : PlantSizNum = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum).PlantSizNum;
2026 : }
2027 : // use pump sizing factor stored in plant sizing data structure
2028 1223 : if (PlantSizNum > 0) {
2029 859 : PumpSizFac = state.dataSize->PlantSizData(PlantSizNum).PlantSizFac;
2030 : } else {
2031 : // might be able to remove this next block
2032 364 : if (thisPump.plantLoc.loopNum > 0) {
2033 725 : for (DataPlant::LoopSideLocation Side : DataPlant::LoopSideKeys) {
2034 725 : auto &thisPumpLoop = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum).LoopSide(Side);
2035 2532 : for (int BranchNum = 1; BranchNum <= thisPumpLoop.TotalBranches; ++BranchNum) {
2036 2171 : auto &thisPumpBranch = thisPumpLoop.Branch(BranchNum);
2037 3985 : for (int CompNum = 1; CompNum <= thisPumpBranch.TotalComponents; ++CompNum) {
2038 2178 : auto const &thisPumpComp = thisPumpBranch.Comp(CompNum);
2039 2178 : if (thisPump.InletNodeNum == thisPumpComp.NodeNumIn && thisPump.OutletNodeNum == thisPumpComp.NodeNumOut) {
2040 364 : if (thisPumpBranch.PumpSizFac > 0.0) {
2041 364 : PumpSizFac = thisPumpBranch.PumpSizFac;
2042 : } else {
2043 0 : PumpSizFac = 1.0;
2044 : }
2045 364 : goto SideLoop_exit;
2046 : }
2047 : }
2048 : }
2049 : }
2050 364 : SideLoop_exit:;
2051 : }
2052 : }
2053 :
2054 1223 : if (thisPump.NomVolFlowRateWasAutoSized) {
2055 :
2056 775 : if (PlantSizNum > 0) {
2057 775 : auto &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
2058 775 : auto &thisPlantSize = state.dataSize->PlantSizData(PlantSizNum);
2059 775 : if (thisPlantSize.DesVolFlowRate >= SmallWaterVolFlow) {
2060 775 : if (!thisPumpPlant.LoopSide(thisPump.plantLoc.loopSideNum).BranchPumpsExist) {
2061 : // size pump to full flow of plant loop
2062 763 : if (thisPump.pumpType == PumpType::Cond) {
2063 6 : TempWaterDensity = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, RoutineName);
2064 6 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, StartTemp, 1.0, RoutineNameSizePumps);
2065 6 : thisPump.NomSteamVolFlowRate = thisPlantSize.DesVolFlowRate * PumpSizFac;
2066 6 : thisPump.NomVolFlowRate = thisPump.NomSteamVolFlowRate * SteamDensity / TempWaterDensity;
2067 : } else {
2068 757 : thisPump.NomVolFlowRate = thisPlantSize.DesVolFlowRate * PumpSizFac;
2069 : }
2070 : } else {
2071 : // Distribute sizes evenly across all branch pumps
2072 12 : DesVolFlowRatePerBranch = thisPlantSize.DesVolFlowRate / thisPumpPlant.LoopSide(thisPump.plantLoc.loopSideNum).TotalPumps;
2073 12 : if (thisPump.pumpType == PumpType::Cond) {
2074 0 : TempWaterDensity = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, RoutineName);
2075 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, StartTemp, 1.0, RoutineNameSizePumps);
2076 0 : thisPump.NomSteamVolFlowRate = DesVolFlowRatePerBranch * PumpSizFac;
2077 0 : thisPump.NomVolFlowRate = thisPump.NomSteamVolFlowRate * SteamDensity / TempWaterDensity;
2078 : } else {
2079 12 : thisPump.NomVolFlowRate = DesVolFlowRatePerBranch * PumpSizFac;
2080 : }
2081 : }
2082 :
2083 : } else {
2084 0 : if (thisOkToReport) {
2085 0 : thisPump.NomVolFlowRate = 0.0;
2086 0 : ShowWarningError(
2087 : state,
2088 0 : format("SizePump: Calculated Pump Nominal Volume Flow Rate=[{:.2R}] is too small. Set to 0.0", thisPlantSize.DesVolFlowRate));
2089 0 : ShowContinueError(state, format("..occurs for Pump={}", thisPump.Name));
2090 : }
2091 : }
2092 775 : if (thisOkToReport) {
2093 1464 : BaseSizer::reportSizerOutput(
2094 732 : state, pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)], thisPump.Name, "Design Flow Rate [m3/s]", thisPump.NomVolFlowRate);
2095 : }
2096 775 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2097 86 : BaseSizer::reportSizerOutput(state,
2098 43 : pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)],
2099 : thisPump.Name,
2100 : "Initial Design Flow Rate [m3/s]",
2101 : thisPump.NomVolFlowRate);
2102 : }
2103 : } else {
2104 0 : if (thisOkToReport) {
2105 0 : ShowSevereError(state, "Autosizing of plant loop pump flow rate requires a loop Sizing:Plant object");
2106 0 : ShowContinueError(state, format("Occurs in plant pump object={}", thisPump.Name));
2107 0 : ErrorsFound = true;
2108 : }
2109 : }
2110 : }
2111 :
2112 : // Note that autocalculation of power is based on nominal volume flow, regardless of whether the flow was
2113 : // auto-sized or manually sized. Thus, this must go after the flow sizing block above.
2114 1223 : if (thisPump.NomPowerUseWasAutoSized) {
2115 784 : if (thisPump.NomVolFlowRate >= SmallWaterVolFlow) {
2116 784 : switch (thisPump.powerSizingMethod) {
2117 :
2118 25 : case PowerSizingMethod::SizePowerPerFlow: {
2119 25 : TotalEffic = thisPump.NomPumpHead / thisPump.powerPerFlowScalingFactor;
2120 25 : break;
2121 : }
2122 :
2123 759 : case PowerSizingMethod::SizePowerPerFlowPerPressure: {
2124 759 : TotalEffic = (1 / thisPump.powerPerFlowPerPressureScalingFactor) * thisPump.MotorEffic;
2125 759 : break;
2126 : }
2127 0 : default:
2128 0 : assert(false);
2129 : }
2130 :
2131 784 : thisPump.NomPowerUse = (thisPump.NomPumpHead * thisPump.NomVolFlowRate) / TotalEffic;
2132 : } else {
2133 0 : thisPump.NomPowerUse = 0.0;
2134 : }
2135 784 : if (thisOkToReport) {
2136 1482 : BaseSizer::reportSizerOutput(
2137 741 : state, pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)], thisPump.Name, "Design Power Consumption [W]", thisPump.NomPowerUse);
2138 : }
2139 784 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2140 86 : BaseSizer::reportSizerOutput(state,
2141 43 : pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)],
2142 : thisPump.Name,
2143 : "Initial Design Power Consumption [W]",
2144 : thisPump.NomPowerUse);
2145 : }
2146 : }
2147 :
2148 1223 : if (thisPump.minVolFlowRateWasAutosized) {
2149 19 : thisPump.MinVolFlowRate = thisPump.NomVolFlowRate * thisPump.MinVolFlowRateFrac;
2150 19 : if (thisOkToReport) {
2151 30 : BaseSizer::reportSizerOutput(state,
2152 15 : pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)],
2153 : thisPump.Name,
2154 : "Design Minimum Flow Rate [m3/s]",
2155 : thisPump.MinVolFlowRate);
2156 : }
2157 19 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2158 8 : BaseSizer::reportSizerOutput(state,
2159 4 : pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)],
2160 : thisPump.Name,
2161 : "Initial Design Minimum Flow Rate [m3/s]",
2162 : thisPump.MinVolFlowRate);
2163 : }
2164 : }
2165 :
2166 1223 : if (thisOkToReport) {
2167 1179 : PumpDataForTable(state, PumpNum);
2168 : }
2169 :
2170 1223 : if (ErrorsFound) {
2171 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
2172 : }
2173 1223 : }
2174 :
2175 37644625 : void ReportPumps(EnergyPlusData &state, int const PumpNum)
2176 : {
2177 :
2178 : // SUBROUTINE INFORMATION:
2179 : // AUTHOR: Dan Fisher
2180 : // DATE WRITTEN: October 1998
2181 : // MODIFIED July 2001, Rick Strand (revision of pump module)
2182 : // RE-ENGINEERED na
2183 :
2184 : // PURPOSE OF THIS SUBROUTINE:
2185 : // This subroutine sets the pump reporting variables.
2186 :
2187 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2188 : int OutletNode; // pump outlet node number
2189 : PumpType PumpType; // Current pump type
2190 :
2191 37644625 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
2192 37644625 : auto &thisPumpRep = state.dataPumps->PumpEquipReport(PumpNum);
2193 :
2194 37644625 : PumpType = thisPump.pumpType;
2195 37644625 : OutletNode = thisPump.OutletNodeNum;
2196 37644625 : auto const &thisOutNode = state.dataLoopNodes->Node(OutletNode);
2197 37644625 : auto const &daPumps = state.dataPumps;
2198 :
2199 37644625 : if (daPumps->PumpMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) {
2200 17271724 : new (&(state.dataPumps->PumpEquipReport(PumpNum))) ReportVars();
2201 17271724 : thisPumpRep.OutletTemp = thisOutNode.Temp;
2202 17271724 : thisPump.Power = 0.0;
2203 17271724 : thisPump.Energy = 0.0;
2204 : } else {
2205 20372901 : thisPumpRep.PumpMassFlowRate = daPumps->PumpMassFlowRate;
2206 20372901 : thisPumpRep.PumpHeattoFluid = daPumps->PumpHeattoFluid;
2207 20372901 : thisPumpRep.OutletTemp = thisOutNode.Temp;
2208 20372901 : thisPump.Power = daPumps->Power;
2209 20372901 : thisPump.Energy = thisPump.Power * state.dataHVACGlobal->TimeStepSysSec;
2210 20372901 : thisPumpRep.ShaftPower = daPumps->ShaftPower;
2211 20372901 : thisPumpRep.PumpHeattoFluidEnergy = daPumps->PumpHeattoFluid * state.dataHVACGlobal->TimeStepSysSec;
2212 20372901 : switch (PumpType) {
2213 20282695 : case PumpType::ConSpeed:
2214 : case PumpType::VarSpeed:
2215 : case PumpType::Cond:
2216 20282695 : thisPumpRep.NumPumpsOperating = 1;
2217 20282695 : break;
2218 :
2219 90206 : case PumpType::Bank_ConSpeed:
2220 : case PumpType::Bank_VarSpeed:
2221 90206 : thisPumpRep.NumPumpsOperating = daPumps->NumPumpsRunning;
2222 90206 : break;
2223 0 : default:
2224 0 : assert(false);
2225 : break;
2226 : }
2227 20372901 : thisPumpRep.ZoneTotalGainRate = daPumps->Power - daPumps->PumpHeattoFluid;
2228 20372901 : thisPumpRep.ZoneTotalGainEnergy = thisPumpRep.ZoneTotalGainRate * state.dataHVACGlobal->TimeStepSysSec;
2229 20372901 : thisPumpRep.ZoneConvGainRate = (1 - thisPump.SkinLossRadFraction) * thisPumpRep.ZoneTotalGainRate;
2230 20372901 : thisPumpRep.ZoneRadGainRate = thisPump.SkinLossRadFraction * thisPumpRep.ZoneTotalGainRate;
2231 : }
2232 37644625 : }
2233 :
2234 1179 : void PumpDataForTable(EnergyPlusData &state, int const NumPump)
2235 : {
2236 :
2237 : // SUBROUTINE INFORMATION:
2238 : // AUTHOR: Jason Glazer
2239 : // DATE WRITTEN: September 2006
2240 : // MODIFIED na
2241 : // RE-ENGINEERED na
2242 :
2243 : // PURPOSE OF THIS SUBROUTINE:
2244 : // Pull data together for predefined tables.
2245 :
2246 : // Using/Aliasing
2247 : using namespace OutputReportPredefined;
2248 :
2249 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2250 1179 : std::string equipName;
2251 :
2252 1179 : auto &thisPump = state.dataPumps->PumpEquip(NumPump);
2253 1179 : auto &thisReport = state.dataOutRptPredefined;
2254 :
2255 1179 : equipName = thisPump.Name;
2256 1179 : PreDefTableEntry(state, thisReport->pdchPumpType, equipName, pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)]);
2257 1179 : if (thisPump.PumpControl == PumpControlType::Continuous) {
2258 40 : PreDefTableEntry(state, thisReport->pdchPumpControl, equipName, "Continuous");
2259 1139 : } else if (thisPump.PumpControl == PumpControlType::Intermittent) {
2260 1139 : PreDefTableEntry(state, thisReport->pdchPumpControl, equipName, "Intermittent");
2261 : } else {
2262 0 : PreDefTableEntry(state, thisReport->pdchPumpControl, equipName, "Unknown");
2263 : }
2264 1179 : PreDefTableEntry(state, thisReport->pdchPumpHead, equipName, thisPump.NomPumpHead);
2265 1179 : PreDefTableEntry(state, thisReport->pdchPumpFlow, equipName, thisPump.NomVolFlowRate, 6);
2266 1179 : PreDefTableEntry(state, thisReport->pdchPumpPower, equipName, thisPump.NomPowerUse);
2267 1179 : if (thisPump.NomVolFlowRate != 0) {
2268 1179 : PreDefTableEntry(state, thisReport->pdchPumpPwrPerFlow, equipName, thisPump.NomPowerUse / thisPump.NomVolFlowRate);
2269 : } else {
2270 0 : PreDefTableEntry(state, thisReport->pdchPumpPwrPerFlow, equipName, "-");
2271 : }
2272 1179 : PreDefTableEntry(state, thisReport->pdchPumpEndUse, equipName, thisPump.EndUseSubcategoryName);
2273 1179 : PreDefTableEntry(state, thisReport->pdchMotEff, equipName, thisPump.MotorEffic);
2274 : // Std 229
2275 1179 : PreDefTableEntry(state, thisReport->pdchPumpAutosized, equipName, thisPump.NomVolFlowRateWasAutoSized ? "Yes" : "No");
2276 2358 : PreDefTableEntry(state,
2277 1179 : thisReport->pdchPumpPlantloopName,
2278 : equipName,
2279 2358 : thisPump.plantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum).Name : "N/A");
2280 2358 : PreDefTableEntry(
2281 : state,
2282 1179 : thisReport->pdchPumpPlantloopBranchName,
2283 : equipName,
2284 1179 : thisPump.plantLoc.loopNum > 0
2285 2358 : ? state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum).LoopSide(thisPump.plantLoc.loopSideNum).Branch(thisPump.plantLoc.branchNum).Name
2286 : : "N/A");
2287 1179 : }
2288 :
2289 0 : void GetRequiredMassFlowRate(EnergyPlusData &state,
2290 : int const LoopNum,
2291 : int const PumpNum,
2292 : Real64 const InletNodeMassFlowRate,
2293 : Real64 &ActualFlowRate,
2294 : Real64 &PumpMinMassFlowRateVFDRange,
2295 : Real64 &PumpMaxMassFlowRateVFDRange)
2296 : {
2297 : // Using/Aliasing
2298 : using PlantPressureSystem::ResolveLoopFlowVsPressure;
2299 : using PlantUtilities::SetComponentFlowRate;
2300 :
2301 0 : Real64 PumpMassFlowRateMaxPress(0.0); // Maximum mass flow rate associated with maximum pressure limit
2302 0 : Real64 PumpMassFlowRateMinPress(0.0); // Minimum mass flow rate associated with minimum pressure limit
2303 0 : Real64 RotSpeed_Max(0.0); // Maximum rotational speed in rps
2304 0 : Real64 RotSpeed_Min(0.0); // Minimum rotational speed in rps
2305 0 : Real64 MinPress(0.0); // Minimum pressure
2306 0 : Real64 MaxPress(0.0); // Maximum pressure
2307 :
2308 0 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
2309 :
2310 0 : RotSpeed_Min = thisPump.VFD.minRPMSched->getCurrentVal();
2311 0 : RotSpeed_Max = thisPump.VFD.maxRPMSched->getCurrentVal();
2312 0 : MinPress = thisPump.VFD.lowerPsetSched->getCurrentVal();
2313 0 : MaxPress = thisPump.VFD.upperPsetSched->getCurrentVal();
2314 :
2315 : // Calculate maximum and minimum mass flow rate associated with maximun and minimum RPM
2316 0 : if (thisPump.plantLoc.loopNum > 0) {
2317 0 : auto const &thisPlantLoop = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
2318 0 : if (thisPlantLoop.UsePressureForPumpCalcs && thisPlantLoop.PressureSimType == DataPlant::PressSimType::FlowCorrection &&
2319 0 : thisPlantLoop.PressureDrop > 0.0) {
2320 0 : thisPump.PumpMassFlowRateMaxRPM = ResolveLoopFlowVsPressure(state,
2321 : thisPump.plantLoc.loopNum,
2322 : InletNodeMassFlowRate,
2323 : thisPump.PressureCurve_Index,
2324 : RotSpeed_Max,
2325 : thisPump.ImpellerDiameter,
2326 : thisPump.MinPhiValue,
2327 : thisPump.MaxPhiValue);
2328 0 : thisPump.PumpMassFlowRateMinRPM = ResolveLoopFlowVsPressure(state,
2329 : thisPump.plantLoc.loopNum,
2330 : InletNodeMassFlowRate,
2331 : thisPump.PressureCurve_Index,
2332 : RotSpeed_Min,
2333 : thisPump.ImpellerDiameter,
2334 : thisPump.MinPhiValue,
2335 : thisPump.MaxPhiValue);
2336 : }
2337 : }
2338 :
2339 : // Not correct necessarily, but values are coming out way wrong here, maxRPMmdot~3, minRPMmdot~62!
2340 0 : if (thisPump.PumpMassFlowRateMaxRPM < thisPump.PumpMassFlowRateMinRPM) {
2341 0 : thisPump.PumpMassFlowRateMaxRPM = thisPump.PumpMassFlowRateMinRPM;
2342 : }
2343 :
2344 : // Calculate maximum and minimum mass flow rate associated with operating pressure range
2345 0 : if (thisPump.plantLoc.loopNum > 0) {
2346 0 : auto const &thisPlantLoop = state.dataPlnt->PlantLoop(LoopNum);
2347 0 : if (thisPlantLoop.PressureEffectiveK > 0.0) {
2348 0 : PumpMassFlowRateMaxPress = std::sqrt(MaxPress / thisPlantLoop.PressureEffectiveK);
2349 0 : PumpMassFlowRateMinPress = std::sqrt(MinPress / thisPlantLoop.PressureEffectiveK);
2350 : }
2351 : }
2352 :
2353 : // Decide operating range for mass flow rate
2354 : // Maximum mass flow rate value of the range
2355 0 : if (thisPump.PumpMassFlowRateMaxRPM > PumpMassFlowRateMaxPress) {
2356 : // Maximum pressure value governs maximum VFD range value
2357 0 : PumpMaxMassFlowRateVFDRange = PumpMassFlowRateMaxPress;
2358 : } else {
2359 : // Maximum RPM value governs maximum VFD range value
2360 0 : PumpMaxMassFlowRateVFDRange = thisPump.PumpMassFlowRateMaxRPM;
2361 : }
2362 :
2363 : // Minimum mass flow rate value of the range
2364 0 : if (thisPump.PumpMassFlowRateMinRPM > PumpMassFlowRateMinPress) {
2365 : // Minimum pressure value governs minimum VFD range value
2366 0 : PumpMinMassFlowRateVFDRange = thisPump.PumpMassFlowRateMinRPM;
2367 : } else {
2368 : // Minimum pressure range value governs minimum VFD range value
2369 0 : PumpMinMassFlowRateVFDRange = PumpMassFlowRateMinPress;
2370 : }
2371 :
2372 : // Set the mass flow rate within VFD operating range
2373 0 : if (InletNodeMassFlowRate > PumpMinMassFlowRateVFDRange) {
2374 0 : if (InletNodeMassFlowRate < PumpMaxMassFlowRateVFDRange) {
2375 : // Flow request is within VFD operating range
2376 0 : ActualFlowRate = InletNodeMassFlowRate;
2377 : } else {
2378 : // Flow request is outside VFD operating range
2379 : // Flow is set to maximum VFD operating range
2380 0 : ActualFlowRate = PumpMaxMassFlowRateVFDRange;
2381 : }
2382 : } else {
2383 : // Flow request is outside VFD operating range
2384 : // Flow is set to minimum VFD operating Range
2385 0 : ActualFlowRate = PumpMinMassFlowRateVFDRange;
2386 : }
2387 0 : }
2388 :
2389 : } // namespace EnergyPlus::Pumps
|