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 264659 : 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 264659 : if (state.dataPumps->GetInputFlag) {
135 21 : GetPumpInput(state);
136 21 : state.dataPumps->GetInputFlag = false;
137 : }
138 :
139 : // Exit early if no pumps found
140 264659 : if (state.dataPumps->NumPumps == 0) {
141 0 : PumpHeat = 0.0;
142 88208 : return;
143 : }
144 :
145 : // Setup pump component index if needed
146 264659 : if (PumpIndex == 0) {
147 35 : PumpNum = Util::FindItemInList(PumpName, state.dataPumps->PumpEquip); // Determine which pump to simulate
148 35 : if (PumpNum == 0) {
149 0 : ShowFatalError(state, format("ManagePumps: Pump requested not found ={}", PumpName)); // Catch any bad names before crashing
150 : }
151 35 : PumpIndex = PumpNum;
152 : } else {
153 264624 : PumpNum = PumpIndex;
154 264624 : if (state.dataPumps->PumpEquip(PumpNum).CheckEquipName) {
155 35 : 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 35 : 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 35 : state.dataPumps->PumpEquip(PumpNum).CheckEquipName = false;
169 : }
170 : }
171 :
172 : // Perform one-time and begin-environment initialization
173 264659 : 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 264659 : if (state.dataPlnt->PlantLoop(LoopNum).LoopSide(state.dataPumps->PumpEquip(PumpNum).plantLoc.loopSideNum).FlowLock ==
177 : DataPlant::FlowLock::PumpQuery) {
178 88208 : SetupPumpMinMaxFlows(state, LoopNum, PumpNum);
179 88208 : return;
180 : }
181 :
182 : // Set pump flow rate and calculate power
183 176451 : CalcPumps(state, PumpNum, FlowRequest, PumpRunning);
184 :
185 : // Update pump reporting data
186 176451 : ReportPumps(state, PumpNum);
187 :
188 : // Send this up to the calling routine
189 176451 : PumpHeat = state.dataPumps->PumpHeattoFluid;
190 : }
191 :
192 40 : 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 40 : 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 40 : int NumVarSpeedPumps = 0;
238 40 : int NumConstSpeedPumps = 0;
239 40 : int NumCondensatePumps = 0;
240 40 : int NumPumpBankSimpleVar = 0;
241 40 : int NumPumpBankSimpleConst = 0;
242 : Real64 SteamDensity;
243 : Real64 TempWaterDensity;
244 40 : int DummyWaterIndex(1);
245 40 : Real64 constexpr minToMaxRatioMax = 0.99;
246 :
247 40 : ErrorsFound = false;
248 :
249 : // GET NUMBER OF ALL EQUIPMENT TYPES
250 40 : NumVarSpeedPumps = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::VarSpeed)]);
251 40 : NumConstSpeedPumps = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::ConSpeed)]);
252 40 : NumCondensatePumps = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::Cond)]);
253 : NumPumpBankSimpleVar =
254 40 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::Bank_VarSpeed)]);
255 : NumPumpBankSimpleConst =
256 40 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pumpTypeIDFNames[static_cast<int>(PumpType::Bank_ConSpeed)]);
257 40 : state.dataPumps->NumPumps = NumVarSpeedPumps + NumConstSpeedPumps + NumCondensatePumps + NumPumpBankSimpleVar + NumPumpBankSimpleConst;
258 :
259 40 : if (state.dataPumps->NumPumps <= 0) {
260 0 : ShowWarningError(state, "No Pumping Equipment Found");
261 0 : return;
262 : }
263 :
264 40 : state.dataPumps->PumpEquip.allocate(state.dataPumps->NumPumps);
265 40 : state.dataPumps->PumpUniqueNames.reserve(static_cast<unsigned>(state.dataPumps->NumPumps));
266 40 : state.dataPumps->PumpEquipReport.allocate(state.dataPumps->NumPumps);
267 40 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
268 40 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::VarSpeed)];
269 40 : auto &thisInput = state.dataIPShortCut;
270 :
271 71 : for (PumpNum = 1; PumpNum <= NumVarSpeedPumps; ++PumpNum) {
272 31 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
273 62 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
274 : cCurrentModuleObject,
275 : PumpNum,
276 31 : thisInput->cAlphaArgs,
277 : NumAlphas,
278 31 : thisInput->rNumericArgs,
279 : NumNums,
280 : IOStat,
281 31 : thisInput->lNumericFieldBlanks,
282 31 : thisInput->lAlphaFieldBlanks,
283 31 : thisInput->cAlphaFieldNames,
284 31 : thisInput->cNumericFieldNames);
285 :
286 31 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisInput->cAlphaArgs(1)};
287 :
288 31 : GlobalNames::VerifyUniqueInterObjectName(
289 62 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
290 31 : thisPump.Name = thisInput->cAlphaArgs(1);
291 31 : thisPump.pumpType = PumpType::VarSpeed; //'Pump:VariableSpeed'
292 31 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpVariableSpeed;
293 :
294 31 : thisPump.InletNodeNum = GetOnlySingleNode(state,
295 31 : thisInput->cAlphaArgs(2),
296 : ErrorsFound,
297 : DataLoopNode::ConnectionObjectType::PumpVariableSpeed,
298 31 : thisPump.Name,
299 : DataLoopNode::NodeFluidType::Water,
300 : DataLoopNode::ConnectionType::Inlet,
301 : NodeInputManager::CompFluidStream::Primary,
302 : ObjectIsNotParent);
303 :
304 62 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
305 31 : thisInput->cAlphaArgs(3),
306 : ErrorsFound,
307 : DataLoopNode::ConnectionObjectType::PumpVariableSpeed,
308 31 : thisPump.Name,
309 : DataLoopNode::NodeFluidType::Water,
310 : DataLoopNode::ConnectionType::Outlet,
311 : NodeInputManager::CompFluidStream::Primary,
312 : ObjectIsNotParent);
313 31 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
314 :
315 31 : thisPump.PumpControl = static_cast<PumpControlType>(getEnumValue(pumpCtrlTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
316 31 : 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 31 : if (thisInput->cAlphaArgs(5).empty()) {
327 31 : thisPump.flowRateSched = nullptr;
328 0 : } 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 31 : thisPump.NomVolFlowRate = thisInput->rNumericArgs(1);
333 31 : if (thisPump.NomVolFlowRate == AutoSize) {
334 4 : thisPump.NomVolFlowRateWasAutoSized = true;
335 : }
336 31 : thisPump.NomPumpHead = thisInput->rNumericArgs(2);
337 31 : thisPump.NomPowerUse = thisInput->rNumericArgs(3);
338 31 : if (thisPump.NomPowerUse == AutoSize) {
339 9 : thisPump.NomPowerUseWasAutoSized = true;
340 : }
341 31 : thisPump.MotorEffic = thisInput->rNumericArgs(4);
342 31 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(5);
343 31 : thisPump.PartLoadCoef[0] = thisInput->rNumericArgs(6);
344 31 : thisPump.PartLoadCoef[1] = thisInput->rNumericArgs(7);
345 31 : thisPump.PartLoadCoef[2] = thisInput->rNumericArgs(8);
346 31 : thisPump.PartLoadCoef[3] = thisInput->rNumericArgs(9);
347 31 : thisPump.MinVolFlowRate = thisInput->rNumericArgs(10);
348 31 : if (thisPump.MinVolFlowRate == AutoSize) {
349 4 : thisPump.minVolFlowRateWasAutosized = true;
350 27 : } else if (!thisPump.NomVolFlowRateWasAutoSized && (thisPump.MinVolFlowRate > (minToMaxRatioMax * thisPump.NomVolFlowRate))) {
351 : // Check that the minimum isn't greater than the maximum
352 4 : ShowWarningError(
353 4 : state, format("{}{}=\"{}\", Invalid '{}'", RoutineName, cCurrentModuleObject, thisPump.Name, thisInput->cNumericFieldNames(10)));
354 4 : ShowContinueError(state,
355 6 : format("Entered Value=[{:.5T}] is above or too close (equal) to the {}=[{:.5T}].",
356 2 : thisPump.MinVolFlowRate,
357 2 : thisInput->cNumericFieldNames(1),
358 2 : thisPump.NomVolFlowRate));
359 4 : ShowContinueError(
360 : state,
361 4 : 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 2 : 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 31 : if (thisInput->cAlphaArgs(6).empty()) {
370 31 : thisPump.PressureCurve_Index = -1;
371 : } else {
372 0 : TempCurveIndex = GetCurveIndex(state, thisInput->cAlphaArgs(6));
373 0 : if (TempCurveIndex == 0) {
374 0 : thisPump.PressureCurve_Index = -1;
375 : } else {
376 0 : 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 0 : thisInput->cAlphaFieldNames(6)); // Field Name
383 :
384 0 : if (!ErrorsFound) {
385 0 : thisPump.PressureCurve_Index = TempCurveIndex;
386 0 : GetCurveMinMaxValues(state, TempCurveIndex, thisPump.MinPhiValue, thisPump.MaxPhiValue);
387 : }
388 : }
389 : }
390 :
391 : // read in the rest of the pump pressure characteristics
392 31 : thisPump.ImpellerDiameter = thisInput->rNumericArgs(11);
393 :
394 : // Input VFD related data
395 31 : if (thisInput->lAlphaFieldBlanks(7)) {
396 31 : thisPump.HasVFD = false;
397 : } else {
398 0 : thisPump.HasVFD = true;
399 0 : thisPump.VFD.VFDControlType =
400 0 : static_cast<ControlTypeVFD>(getEnumValue(controlTypeVFDNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(7))));
401 :
402 0 : switch (thisPump.VFD.VFDControlType) {
403 :
404 0 : case ControlTypeVFD::VFDManual: {
405 0 : 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 0 : } 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 0 : } 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 31 : 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 31 : if (!thisInput->lAlphaFieldBlanks(14)) {
484 5 : thisPump.powerSizingMethod =
485 5 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(14))));
486 5 : 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 31 : if (!thisInput->lNumericFieldBlanks(13)) {
497 2 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(13);
498 : }
499 :
500 31 : if (!thisInput->lNumericFieldBlanks(14)) {
501 4 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(14);
502 : }
503 :
504 31 : if (!thisInput->lNumericFieldBlanks(15)) {
505 2 : thisPump.MinVolFlowRateFrac = thisInput->rNumericArgs(15);
506 : }
507 :
508 31 : if (NumAlphas > 14) {
509 1 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(15);
510 : } else {
511 30 : thisPump.EndUseSubcategoryName = "General";
512 : }
513 :
514 : // Is this really necessary for each pump GetInput loop?
515 31 : thisPump.Energy = 0.0;
516 31 : thisPump.Power = 0.0;
517 : }
518 :
519 40 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::ConSpeed)];
520 :
521 53 : for (int NumConstPump = 1; NumConstPump <= NumConstSpeedPumps; ++NumConstPump) {
522 13 : PumpNum = NumVarSpeedPumps + NumConstPump;
523 13 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
524 26 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
525 : cCurrentModuleObject,
526 : NumConstPump,
527 13 : thisInput->cAlphaArgs,
528 : NumAlphas,
529 13 : thisInput->rNumericArgs,
530 : NumNums,
531 : IOStat,
532 13 : thisInput->lNumericFieldBlanks,
533 13 : thisInput->lAlphaFieldBlanks,
534 13 : thisInput->cAlphaFieldNames,
535 13 : thisInput->cNumericFieldNames);
536 :
537 13 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
538 :
539 13 : GlobalNames::VerifyUniqueInterObjectName(
540 26 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
541 13 : thisPump.Name = thisInput->cAlphaArgs(1);
542 13 : thisPump.pumpType = PumpType::ConSpeed; //'Pump:ConstantSpeed'
543 13 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpConstantSpeed;
544 :
545 13 : thisPump.InletNodeNum = GetOnlySingleNode(state,
546 13 : thisInput->cAlphaArgs(2),
547 : ErrorsFound,
548 : DataLoopNode::ConnectionObjectType::PumpConstantSpeed,
549 13 : thisPump.Name,
550 : DataLoopNode::NodeFluidType::Water,
551 : DataLoopNode::ConnectionType::Inlet,
552 : NodeInputManager::CompFluidStream::Primary,
553 : ObjectIsNotParent);
554 :
555 26 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
556 13 : thisInput->cAlphaArgs(3),
557 : ErrorsFound,
558 : DataLoopNode::ConnectionObjectType::PumpConstantSpeed,
559 13 : thisPump.Name,
560 : DataLoopNode::NodeFluidType::Water,
561 : DataLoopNode::ConnectionType::Outlet,
562 : NodeInputManager::CompFluidStream::Primary,
563 : ObjectIsNotParent);
564 13 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
565 :
566 13 : thisPump.NomVolFlowRate = thisInput->rNumericArgs(1);
567 13 : if (thisPump.NomVolFlowRate == AutoSize) {
568 4 : thisPump.NomVolFlowRateWasAutoSized = true;
569 : }
570 13 : thisPump.NomPumpHead = thisInput->rNumericArgs(2);
571 13 : thisPump.NomPowerUse = thisInput->rNumericArgs(3);
572 13 : if (thisPump.NomPowerUse == AutoSize) {
573 7 : thisPump.NomPowerUseWasAutoSized = true;
574 : }
575 13 : thisPump.MotorEffic = thisInput->rNumericArgs(4);
576 13 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(5);
577 13 : thisPump.PartLoadCoef[0] = 1.0;
578 13 : thisPump.PartLoadCoef[1] = 0.0;
579 13 : thisPump.PartLoadCoef[2] = 0.0;
580 13 : 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 13 : thisPump.MinVolFlowRate = 0.0;
584 13 : thisPump.Energy = 0.0;
585 13 : thisPump.Power = 0.0;
586 :
587 13 : thisPump.PumpControl = static_cast<PumpControlType>(getEnumValue(pumpCtrlTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
588 :
589 13 : 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 13 : if (thisInput->lAlphaFieldBlanks(5)) {
600 13 : thisPump.flowRateSched = nullptr;
601 0 : } else if ((thisPump.flowRateSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(5))) == nullptr) {
602 0 : 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 13 : if (thisInput->cAlphaArgs(6).empty()) {
607 13 : thisPump.PressureCurve_Index = -1;
608 : } else {
609 0 : TempCurveIndex = GetCurveIndex(state, thisInput->cAlphaArgs(6));
610 0 : if (TempCurveIndex == 0) {
611 0 : thisPump.PressureCurve_Index = -1;
612 : } else {
613 0 : 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 0 : thisInput->cAlphaFieldNames(6)); // Field Name
620 :
621 0 : if (!ErrorsFound) {
622 0 : thisPump.PressureCurve_Index = TempCurveIndex;
623 0 : GetCurveMinMaxValues(state, TempCurveIndex, thisPump.MinPhiValue, thisPump.MaxPhiValue);
624 : }
625 : }
626 : }
627 :
628 : // read in the rest of the pump pressure characteristics
629 13 : thisPump.ImpellerDiameter = thisInput->rNumericArgs(6);
630 13 : thisPump.RotSpeed_RPM = thisInput->rNumericArgs(7); // retrieve the input rotational speed, in revs/min
631 13 : thisPump.RotSpeed = thisPump.RotSpeed_RPM / 60.0; // convert input[rpm] to calculation units[rps]
632 :
633 13 : 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 13 : if (!thisInput->lAlphaFieldBlanks(8)) {
652 3 : thisPump.powerSizingMethod =
653 3 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
654 3 : 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 13 : if (!thisInput->lNumericFieldBlanks(9)) {
665 2 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(9);
666 : }
667 :
668 13 : if (!thisInput->lNumericFieldBlanks(10)) {
669 2 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(10);
670 : }
671 :
672 13 : if (NumAlphas > 8) {
673 2 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(9);
674 : } else {
675 11 : thisPump.EndUseSubcategoryName = "General";
676 : }
677 : }
678 :
679 : // pumps for steam system pumping condensate
680 40 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::Cond)];
681 43 : for (int NumCondPump = 1; NumCondPump <= NumCondensatePumps; ++NumCondPump) {
682 3 : PumpNum = NumCondPump + NumVarSpeedPumps + NumConstSpeedPumps;
683 3 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
684 6 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
685 : cCurrentModuleObject,
686 : NumCondPump,
687 3 : thisInput->cAlphaArgs,
688 : NumAlphas,
689 3 : thisInput->rNumericArgs,
690 : NumNums,
691 : IOStat,
692 3 : thisInput->lNumericFieldBlanks,
693 3 : thisInput->lAlphaFieldBlanks,
694 3 : thisInput->cAlphaFieldNames,
695 3 : thisInput->cNumericFieldNames);
696 :
697 3 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisInput->cAlphaArgs(1)};
698 :
699 3 : GlobalNames::VerifyUniqueInterObjectName(
700 6 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
701 3 : thisPump.Name = thisInput->cAlphaArgs(1);
702 3 : thisPump.pumpType = PumpType::Cond; //'Pump:VariableSpeed:Condensate'
703 3 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpCondensate;
704 :
705 3 : thisPump.InletNodeNum = GetOnlySingleNode(state,
706 3 : thisInput->cAlphaArgs(2),
707 : ErrorsFound,
708 : DataLoopNode::ConnectionObjectType::PumpVariableSpeedCondensate,
709 3 : thisPump.Name,
710 : DataLoopNode::NodeFluidType::Steam,
711 : DataLoopNode::ConnectionType::Inlet,
712 : NodeInputManager::CompFluidStream::Primary,
713 : ObjectIsNotParent);
714 :
715 6 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
716 3 : thisInput->cAlphaArgs(3),
717 : ErrorsFound,
718 : DataLoopNode::ConnectionObjectType::PumpVariableSpeedCondensate,
719 3 : thisPump.Name,
720 : DataLoopNode::NodeFluidType::Steam,
721 : DataLoopNode::ConnectionType::Outlet,
722 : NodeInputManager::CompFluidStream::Primary,
723 : ObjectIsNotParent);
724 3 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
725 :
726 3 : thisPump.PumpControl = PumpControlType::Intermittent;
727 :
728 : // Input the optional schedule for the pump
729 3 : if (thisInput->cAlphaArgs(4).empty()) {
730 3 : 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 3 : thisPump.NomSteamVolFlowRate = thisInput->rNumericArgs(1);
736 3 : if (thisPump.NomSteamVolFlowRate == AutoSize) {
737 0 : thisPump.NomSteamVolFlowRateWasAutoSized = true;
738 : }
739 3 : thisPump.NomPumpHead = thisInput->rNumericArgs(2);
740 3 : thisPump.NomPowerUse = thisInput->rNumericArgs(3);
741 3 : if (thisPump.NomPowerUse == AutoSize) {
742 3 : thisPump.NomPowerUseWasAutoSized = true;
743 : }
744 3 : thisPump.MotorEffic = thisInput->rNumericArgs(4);
745 3 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(5);
746 3 : thisPump.PartLoadCoef[0] = thisInput->rNumericArgs(6);
747 3 : thisPump.PartLoadCoef[1] = thisInput->rNumericArgs(7);
748 3 : thisPump.PartLoadCoef[2] = thisInput->rNumericArgs(8);
749 3 : thisPump.PartLoadCoef[3] = thisInput->rNumericArgs(9);
750 :
751 3 : 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 3 : thisPump.MinVolFlowRate = 0.0;
770 3 : thisPump.Energy = 0.0;
771 3 : thisPump.Power = 0.0;
772 :
773 3 : if (thisPump.NomSteamVolFlowRateWasAutoSized) {
774 0 : thisPump.NomVolFlowRate = AutoSize;
775 0 : 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 3 : if (!thisInput->lAlphaFieldBlanks(6)) {
784 2 : thisPump.powerSizingMethod =
785 2 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(6))));
786 2 : 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 3 : if (!thisInput->lNumericFieldBlanks(11)) {
797 1 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(11);
798 : }
799 :
800 3 : if (!thisInput->lNumericFieldBlanks(12)) {
801 1 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(12);
802 : }
803 :
804 3 : if (NumAlphas > 6) {
805 1 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(7);
806 : } else {
807 2 : thisPump.EndUseSubcategoryName = "General";
808 : }
809 : }
810 :
811 : // LOAD Variable Speed Pump Bank ARRAYS WITH VARIABLE SPEED CURVE FIT PUMP DATA
812 40 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::Bank_VarSpeed)];
813 44 : for (int NumVarPumpBankSimple = 1; NumVarPumpBankSimple <= NumPumpBankSimpleVar; ++NumVarPumpBankSimple) {
814 4 : PumpNum = NumVarPumpBankSimple + NumVarSpeedPumps + NumConstSpeedPumps + NumCondensatePumps;
815 4 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
816 8 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
817 : cCurrentModuleObject,
818 : NumVarPumpBankSimple,
819 4 : thisInput->cAlphaArgs,
820 : NumAlphas,
821 4 : thisInput->rNumericArgs,
822 : NumNums,
823 : IOStat,
824 4 : thisInput->lNumericFieldBlanks,
825 4 : thisInput->lAlphaFieldBlanks,
826 4 : thisInput->cAlphaFieldNames,
827 4 : thisInput->cNumericFieldNames);
828 :
829 4 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisInput->cAlphaArgs(1)};
830 :
831 4 : GlobalNames::VerifyUniqueInterObjectName(
832 8 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
833 4 : thisPump.Name = thisInput->cAlphaArgs(1);
834 4 : thisPump.pumpType = PumpType::Bank_VarSpeed; //'HeaderedPumps:VariableSpeed'
835 4 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpBankVariableSpeed;
836 :
837 4 : thisPump.InletNodeNum = GetOnlySingleNode(state,
838 4 : thisInput->cAlphaArgs(2),
839 : ErrorsFound,
840 : DataLoopNode::ConnectionObjectType::HeaderedPumpsVariableSpeed,
841 4 : thisPump.Name,
842 : DataLoopNode::NodeFluidType::Water,
843 : DataLoopNode::ConnectionType::Inlet,
844 : NodeInputManager::CompFluidStream::Primary,
845 : ObjectIsNotParent);
846 :
847 8 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
848 4 : thisInput->cAlphaArgs(3),
849 : ErrorsFound,
850 : DataLoopNode::ConnectionObjectType::HeaderedPumpsVariableSpeed,
851 4 : thisPump.Name,
852 : DataLoopNode::NodeFluidType::Water,
853 : DataLoopNode::ConnectionType::Outlet,
854 : NodeInputManager::CompFluidStream::Primary,
855 : ObjectIsNotParent);
856 4 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
857 :
858 4 : if (Util::SameString(thisInput->cAlphaArgs(4), "Optimal")) {
859 0 : thisPump.SequencingScheme = PumpBankControlSeq::OptimalScheme;
860 4 : } else if (Util::SameString(thisInput->cAlphaArgs(4), "Sequential")) {
861 4 : 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 4 : thisPump.PumpControl = static_cast<PumpControlType>(getEnumValue(pumpCtrlTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(5))));
874 4 : 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 4 : if (thisInput->cAlphaArgs(6).empty()) { // Initialized to zero, don't get a schedule for an empty
885 0 : thisPump.flowRateSched = nullptr;
886 4 : } else if ((thisPump.flowRateSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(6))) == nullptr) {
887 4 : ShowWarningItemNotFound(state, eoh, thisInput->cAlphaFieldNames(6), thisInput->cAlphaArgs(6));
888 : }
889 :
890 4 : thisPump.NomVolFlowRate = thisInput->rNumericArgs(1);
891 4 : if (thisPump.NomVolFlowRate == AutoSize) {
892 0 : thisPump.NomVolFlowRateWasAutoSized = true;
893 : }
894 4 : thisPump.NumPumpsInBank = thisInput->rNumericArgs(2);
895 4 : thisPump.NomPumpHead = thisInput->rNumericArgs(3);
896 4 : thisPump.NomPowerUse = thisInput->rNumericArgs(4);
897 4 : if (thisPump.NomPowerUse == AutoSize) {
898 4 : thisPump.NomPowerUseWasAutoSized = true;
899 : }
900 4 : thisPump.MotorEffic = thisInput->rNumericArgs(5);
901 4 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(6);
902 4 : thisPump.PartLoadCoef[0] = thisInput->rNumericArgs(7);
903 4 : thisPump.PartLoadCoef[1] = thisInput->rNumericArgs(8);
904 4 : thisPump.PartLoadCoef[2] = thisInput->rNumericArgs(9);
905 4 : thisPump.PartLoadCoef[3] = thisInput->rNumericArgs(10);
906 4 : thisPump.MinVolFlowRateFrac = thisInput->rNumericArgs(11);
907 4 : thisPump.MinVolFlowRate = thisPump.NomVolFlowRate * thisPump.MinVolFlowRateFrac;
908 :
909 4 : 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 4 : if (!thisInput->lAlphaFieldBlanks(8)) {
928 3 : thisPump.powerSizingMethod =
929 3 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
930 3 : 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 4 : if (!thisInput->lNumericFieldBlanks(13)) {
941 0 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(13);
942 : }
943 :
944 4 : if (!thisInput->lNumericFieldBlanks(14)) {
945 2 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(14);
946 : }
947 :
948 4 : if (NumAlphas > 8) {
949 2 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(9);
950 : } else {
951 2 : thisPump.EndUseSubcategoryName = "General";
952 : }
953 :
954 4 : thisPump.Energy = 0.0;
955 4 : thisPump.Power = 0.0;
956 : }
957 :
958 40 : cCurrentModuleObject = pumpTypeIDFNames[static_cast<int>(PumpType::Bank_ConSpeed)];
959 43 : for (int NumConstPumpBankSimple = 1; NumConstPumpBankSimple <= NumPumpBankSimpleConst; ++NumConstPumpBankSimple) {
960 3 : PumpNum = NumConstPumpBankSimple + NumVarSpeedPumps + NumConstSpeedPumps + NumCondensatePumps + NumPumpBankSimpleVar;
961 3 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
962 6 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
963 : cCurrentModuleObject,
964 : NumConstPumpBankSimple,
965 3 : thisInput->cAlphaArgs,
966 : NumAlphas,
967 3 : thisInput->rNumericArgs,
968 : NumNums,
969 : IOStat,
970 3 : thisInput->lNumericFieldBlanks,
971 3 : thisInput->lAlphaFieldBlanks,
972 3 : thisInput->cAlphaFieldNames,
973 3 : thisInput->cNumericFieldNames);
974 :
975 3 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisInput->cAlphaArgs(1)};
976 :
977 3 : GlobalNames::VerifyUniqueInterObjectName(
978 6 : state, state.dataPumps->PumpUniqueNames, thisInput->cAlphaArgs(1), cCurrentModuleObject, thisInput->cAlphaFieldNames(1), ErrorsFound);
979 3 : thisPump.Name = thisInput->cAlphaArgs(1);
980 3 : thisPump.pumpType = PumpType::Bank_ConSpeed; //'HeaderedPumps:ConstantSpeed'
981 3 : thisPump.TypeOf_Num = DataPlant::PlantEquipmentType::PumpBankConstantSpeed;
982 :
983 3 : thisPump.InletNodeNum = GetOnlySingleNode(state,
984 3 : thisInput->cAlphaArgs(2),
985 : ErrorsFound,
986 : DataLoopNode::ConnectionObjectType::HeaderedPumpsConstantSpeed,
987 3 : thisPump.Name,
988 : DataLoopNode::NodeFluidType::Water,
989 : DataLoopNode::ConnectionType::Inlet,
990 : NodeInputManager::CompFluidStream::Primary,
991 : ObjectIsNotParent);
992 :
993 6 : thisPump.OutletNodeNum = GetOnlySingleNode(state,
994 3 : thisInput->cAlphaArgs(3),
995 : ErrorsFound,
996 : DataLoopNode::ConnectionObjectType::HeaderedPumpsConstantSpeed,
997 3 : thisPump.Name,
998 : DataLoopNode::NodeFluidType::Water,
999 : DataLoopNode::ConnectionType::Outlet,
1000 : NodeInputManager::CompFluidStream::Primary,
1001 : ObjectIsNotParent);
1002 3 : TestCompSet(state, cCurrentModuleObject, thisPump.Name, thisInput->cAlphaArgs(2), thisInput->cAlphaArgs(3), "Water Nodes");
1003 :
1004 3 : if (Util::SameString(thisInput->cAlphaArgs(4), "Optimal")) {
1005 0 : thisPump.SequencingScheme = PumpBankControlSeq::OptimalScheme;
1006 3 : } else if (Util::SameString(thisInput->cAlphaArgs(4), "Sequential")) {
1007 3 : 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 3 : thisPump.PumpControl = static_cast<PumpControlType>(getEnumValue(pumpCtrlTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(5))));
1018 :
1019 3 : 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 3 : if (thisInput->lAlphaFieldBlanks(6)) {
1030 0 : thisPump.flowRateSched = nullptr;
1031 3 : } else if ((thisPump.flowRateSched = Sched::GetSchedule(state, thisInput->cAlphaArgs(6))) == nullptr) {
1032 3 : ShowWarningItemNotFound(state, eoh, thisInput->cAlphaFieldNames(6), thisInput->cAlphaArgs(6), "");
1033 : }
1034 :
1035 3 : thisPump.NomVolFlowRate = thisInput->rNumericArgs(1);
1036 3 : if (thisPump.NomVolFlowRate == AutoSize) {
1037 0 : thisPump.NomVolFlowRateWasAutoSized = true;
1038 : }
1039 3 : thisPump.NumPumpsInBank = thisInput->rNumericArgs(2);
1040 3 : thisPump.NomPumpHead = thisInput->rNumericArgs(3);
1041 3 : thisPump.NomPowerUse = thisInput->rNumericArgs(4);
1042 3 : if (thisPump.NomPowerUse == AutoSize) {
1043 3 : thisPump.NomPowerUseWasAutoSized = true;
1044 : }
1045 3 : thisPump.MotorEffic = thisInput->rNumericArgs(5);
1046 3 : thisPump.FracMotorLossToFluid = thisInput->rNumericArgs(6);
1047 3 : thisPump.PartLoadCoef[0] = 1.0;
1048 3 : thisPump.PartLoadCoef[1] = 0.0;
1049 3 : thisPump.PartLoadCoef[2] = 0.0;
1050 3 : thisPump.PartLoadCoef[3] = 0.0;
1051 :
1052 3 : 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 3 : if (!thisInput->lAlphaFieldBlanks(8)) {
1070 2 : thisPump.powerSizingMethod =
1071 2 : static_cast<PowerSizingMethod>(getEnumValue(powerSizingMethodNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
1072 2 : 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 3 : if (!thisInput->lNumericFieldBlanks(8)) {
1083 1 : thisPump.powerPerFlowScalingFactor = thisInput->rNumericArgs(8);
1084 : }
1085 :
1086 3 : if (!thisInput->lNumericFieldBlanks(9)) {
1087 1 : thisPump.powerPerFlowPerPressureScalingFactor = thisInput->rNumericArgs(9);
1088 : }
1089 :
1090 3 : if (NumAlphas > 8) {
1091 1 : thisPump.EndUseSubcategoryName = thisInput->cAlphaArgs(9);
1092 : } else {
1093 2 : thisPump.EndUseSubcategoryName = "General";
1094 : }
1095 :
1096 3 : thisPump.MinVolFlowRate = 0.0;
1097 3 : thisPump.Energy = 0.0;
1098 3 : thisPump.Power = 0.0;
1099 : }
1100 :
1101 40 : if (ErrorsFound) {
1102 0 : ShowFatalError(state, "Errors found in getting Pump input");
1103 : }
1104 :
1105 94 : for (PumpNum = 1; PumpNum <= state.dataPumps->NumPumps; ++PumpNum) { // CurrentModuleObject='Pumps'
1106 54 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
1107 54 : auto &thisPumpRep = state.dataPumps->PumpEquipReport(PumpNum);
1108 54 : switch (thisPump.pumpType) {
1109 47 : case PumpType::VarSpeed:
1110 : case PumpType::ConSpeed:
1111 : case PumpType::Cond: {
1112 :
1113 94 : SetupOutputVariable(state,
1114 : "Pump Electricity Energy",
1115 : Constant::Units::J,
1116 47 : thisPump.Energy,
1117 : OutputProcessor::TimeStepType::System,
1118 : OutputProcessor::StoreType::Sum,
1119 47 : thisPump.Name,
1120 : Constant::eResource::Electricity,
1121 : OutputProcessor::Group::Plant,
1122 : OutputProcessor::EndUseCat::Pumps,
1123 : thisPump.EndUseSubcategoryName);
1124 94 : SetupOutputVariable(state,
1125 : "Pump Electricity Rate",
1126 : Constant::Units::W,
1127 47 : thisPump.Power,
1128 : OutputProcessor::TimeStepType::System,
1129 : OutputProcessor::StoreType::Average,
1130 47 : thisPump.Name);
1131 94 : SetupOutputVariable(state,
1132 : "Pump Shaft Power",
1133 : Constant::Units::W,
1134 47 : thisPumpRep.ShaftPower,
1135 : OutputProcessor::TimeStepType::System,
1136 : OutputProcessor::StoreType::Average,
1137 47 : thisPump.Name);
1138 94 : SetupOutputVariable(state,
1139 : "Pump Fluid Heat Gain Rate",
1140 : Constant::Units::W,
1141 47 : thisPumpRep.PumpHeattoFluid,
1142 : OutputProcessor::TimeStepType::System,
1143 : OutputProcessor::StoreType::Average,
1144 47 : thisPump.Name);
1145 94 : SetupOutputVariable(state,
1146 : "Pump Fluid Heat Gain Energy",
1147 : Constant::Units::J,
1148 47 : thisPumpRep.PumpHeattoFluidEnergy,
1149 : OutputProcessor::TimeStepType::System,
1150 : OutputProcessor::StoreType::Sum,
1151 47 : thisPump.Name);
1152 94 : SetupOutputVariable(state,
1153 : "Pump Outlet Temperature",
1154 : Constant::Units::C,
1155 47 : thisPumpRep.OutletTemp,
1156 : OutputProcessor::TimeStepType::System,
1157 : OutputProcessor::StoreType::Average,
1158 47 : thisPump.Name);
1159 94 : SetupOutputVariable(state,
1160 : "Pump Mass Flow Rate",
1161 : Constant::Units::kg_s,
1162 47 : thisPumpRep.PumpMassFlowRate,
1163 : OutputProcessor::TimeStepType::System,
1164 : OutputProcessor::StoreType::Average,
1165 47 : thisPump.Name);
1166 47 : } 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 54 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
1238 1 : SetupEMSInternalVariable(state, "Pump Maximum Mass Flow Rate", thisPump.Name, "[kg/s]", thisPump.MassFlowRateMax);
1239 1 : SetupEMSActuator(
1240 1 : state, "Pump", thisPump.Name, "Pump Mass Flow Rate", "[kg/s]", thisPump.EMSMassFlowOverrideOn, thisPump.EMSMassFlowValue);
1241 1 : SetupEMSActuator(
1242 1 : state, "Pump", thisPump.Name, "Pump Pressure Rise", "[Pa]", thisPump.EMSPressureOverrideOn, thisPump.EMSPressureOverrideValue);
1243 : }
1244 :
1245 54 : 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 264659 : 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 264659 : Real64 constexpr StartTemp(100.0); // Standard Temperature across code to calculated Steam density
1356 264659 : 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 264659 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
1369 264659 : int InletNode = thisPump.InletNodeNum;
1370 264659 : int OutletNode = thisPump.OutletNodeNum;
1371 :
1372 : // One time inits
1373 264659 : if (thisPump.PumpOneTimeFlag) {
1374 :
1375 35 : bool errFlag = false;
1376 35 : ScanPlantLoopsForObject(state, thisPump.Name, thisPump.TypeOf_Num, thisPump.plantLoc, errFlag, _, _, _, _, _);
1377 35 : int plloopnum = thisPump.plantLoc.loopNum;
1378 35 : lsnum = thisPump.plantLoc.loopSideNum;
1379 35 : int brnum = thisPump.plantLoc.branchNum;
1380 35 : int cpnum = thisPump.plantLoc.compNum;
1381 35 : if (plloopnum > 0 && lsnum != DataPlant::LoopSideLocation::Invalid && brnum > 0 && cpnum > 0) {
1382 35 : auto &thisPumpLoc = state.dataPlnt->PlantLoop(plloopnum).LoopSide(lsnum).Branch(brnum);
1383 35 : 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 35 : } 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 35 : if (errFlag) {
1402 0 : ShowFatalError(state, "InitializePumps: Program terminated due to previous condition(s).");
1403 : }
1404 35 : DataPlant::CompData::getPlantComponent(state, thisPump.plantLoc).CompNum = PumpNum;
1405 :
1406 35 : 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 35 : if (thisPump.NomPowerUse > ZeroPowerTol && thisPump.MotorEffic > ZeroPowerTol) {
1412 35 : TotalEffic = thisPump.NomVolFlowRate * thisPump.NomPumpHead / thisPump.NomPowerUse;
1413 35 : thisPump.PumpEffic = TotalEffic / thisPump.MotorEffic;
1414 35 : if (thisPump.PumpEffic < 0.50) {
1415 12 : ShowWarningError(state,
1416 12 : format("Check input. Calculated Pump Efficiency={:.2R}% which is less than 50%, for pump={}",
1417 0 : thisPump.PumpEffic * 100.0,
1418 6 : thisPump.Name));
1419 12 : ShowContinueError(state,
1420 12 : format("Calculated Pump_Efficiency % =Total_Efficiency % [{:.1R}] / Motor_Efficiency % [{:.1R}]",
1421 0 : TotalEffic * 100.0,
1422 6 : thisPump.MotorEffic * 100.0));
1423 12 : ShowContinueError(
1424 : state,
1425 12 : format("Total_Efficiency % =(Rated_Volume_Flow_Rate [{:.3R}] * Rated_Pump_Head [{:.1R}] / Rated_Power_Use [{:.1R}]) * 100.",
1426 6 : thisPump.NomVolFlowRate,
1427 6 : thisPump.NomPumpHead,
1428 6 : thisPump.NomPowerUse));
1429 29 : } 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 29 : } 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 0 : ShowWarningError(state, format("Check input. Pump nominal power or motor efficiency is set to 0, for pump={}", thisPump.Name));
1463 : }
1464 :
1465 35 : 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 35 : if (thisPump.PumpControl == PumpControlType::Continuous) {
1470 : // reset flow priority appropriately (default was for Intermittent)
1471 0 : DataPlant::CompData::getPlantComponent(state, thisPump.plantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyAndTurnsLoopOn;
1472 : }
1473 :
1474 35 : thisPump.PumpOneTimeFlag = false;
1475 : }
1476 :
1477 : // HVAC Sizing Simulation resizing calls if needed
1478 264659 : if (state.dataGlobal->RedoSizesHVACSimulation && !state.dataPlnt->PlantReSizingCompleted) {
1479 0 : SizePump(state, PumpNum);
1480 : }
1481 :
1482 : // Begin environment inits
1483 264659 : if (thisPump.PumpInitFlag && state.dataGlobal->BeginEnvrnFlag) {
1484 86 : if (thisPump.pumpType == PumpType::Cond) {
1485 0 : TempWaterDensity = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, RoutineName);
1486 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, StartTemp, 1.0, RoutineName);
1487 0 : thisPump.NomVolFlowRate = (thisPump.NomSteamVolFlowRate * SteamDensity) / TempWaterDensity;
1488 :
1489 : // set the maximum flow rate on the outlet node
1490 0 : 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 0 : mdotMin = 0.0;
1499 0 : InitComponentNodes(state, mdotMin, mdotMax, InletNode, OutletNode);
1500 0 : thisPump.MassFlowRateMax = mdotMax;
1501 0 : thisPump.MassFlowRateMin = thisPump.MinVolFlowRate * SteamDensity;
1502 :
1503 : } else {
1504 86 : auto &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
1505 86 : TempWaterDensity = thisPumpPlant.glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
1506 86 : mdotMax = thisPump.NomVolFlowRate * TempWaterDensity;
1507 : // mdotMin = PumpEquip(PumpNum)%MinVolFlowRate * TempWaterDensity
1508 : // see note above
1509 86 : mdotMin = 0.0;
1510 86 : InitComponentNodes(state, mdotMin, mdotMax, InletNode, OutletNode);
1511 86 : thisPump.MassFlowRateMax = mdotMax;
1512 86 : thisPump.MassFlowRateMin = thisPump.MinVolFlowRate * TempWaterDensity;
1513 : }
1514 : // zero out report variables
1515 86 : thisPump.Energy = 0.0;
1516 86 : thisPump.Power = 0.0;
1517 86 : new (&(state.dataPumps->PumpEquipReport(PumpNum))) ReportVars();
1518 86 : thisPump.PumpInitFlag = false;
1519 : }
1520 :
1521 : // Reset the local environment flag for the next environment
1522 264659 : if (!state.dataGlobal->BeginEnvrnFlag) thisPump.PumpInitFlag = true;
1523 :
1524 : // zero out module level working variables
1525 264659 : auto const &daPumps = state.dataPumps;
1526 264659 : daPumps->PumpMassFlowRate = 0.0;
1527 264659 : daPumps->PumpHeattoFluid = 0.0;
1528 264659 : daPumps->Power = 0.0;
1529 264659 : daPumps->ShaftPower = 0.0;
1530 264659 : }
1531 :
1532 : //*************************************************************************!
1533 :
1534 : //*************************************************************************!
1535 :
1536 88208 : void SetupPumpMinMaxFlows(EnergyPlusData &state, int const LoopNum, int const PumpNum)
1537 : {
1538 :
1539 : // SUBROUTINE INFORMATION:
1540 : // AUTHOR: Edwin Lee
1541 : // DATE WRITTEN: Aug 2010
1542 : // MODIFIED Based on the Flow control portion of what was previously Pumps::InitSimVars, by:
1543 : // Dan Fisher October 1998
1544 : // Richard Liesen July 2001
1545 : // July 2001, Rick Strand (implemented new pump controls)
1546 : // May 2009, Brent Griffith (added EMS override capability)
1547 : // B. Griffith, Nov 2011 Pump control: Intermittent vs Continuous
1548 : // RE-ENGINEERED
1549 :
1550 : // PURPOSE OF THIS SUBROUTINE:
1551 : // This subroutine initializes the pump minAvail and maxAvail flow rates, and assigns them to the
1552 : // outlet min/max avail according to inlet min/max constraints and zero flow request
1553 : // The loop solver then uses this information to set up the flow bounds for the loop side
1554 : // for the current iteration.
1555 :
1556 : // METHODOLOGY EMPLOYED:
1557 : // Design flow rate and user specified minimum flow rate is compared in the inlet node
1558 : // min/maxavail. The pump output is appropriately constrained.
1559 : // Design flow is rated flow times schedule fraction
1560 : // Inlet node max will represent the rated flow rate according to pump init routines.
1561 : // These values are bounded by hardware min constraints on the inlet node, which is likely zero.
1562 : // These values are also bounded by EMS overridable limit of max flow rate.
1563 :
1564 : // Using/Aliasing
1565 : using PlantPressureSystem::ResolveLoopFlowVsPressure;
1566 : using PlantUtilities::BoundValueToWithinTwoValues;
1567 :
1568 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1569 : int InletNode; // pump inlet node number
1570 : int OutletNode; // pump outlet node number
1571 : Real64 InletNodeMax;
1572 : Real64 InletNodeMin;
1573 : Real64 PumpMassFlowRateMax; // max allowable flow rate at the pump
1574 : Real64 PumpMassFlowRateMin; // min allowable flow rate at the pump
1575 : Real64 PumpSchedFraction;
1576 : Real64 PumpOverridableMaxLimit;
1577 : Real64 PumpMassFlowRateMinLimit;
1578 : Real64 PumpSchedRPM; // Pump RPM Optional Input
1579 :
1580 88208 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
1581 :
1582 : // Inlet/Outlet Node Numbers
1583 88208 : InletNode = thisPump.InletNodeNum;
1584 88208 : OutletNode = thisPump.OutletNodeNum;
1585 88208 : auto &thisInNode = state.dataLoopNodes->Node(InletNode);
1586 88208 : auto &thisOutNode = state.dataLoopNodes->Node(OutletNode);
1587 :
1588 : // Inlet node Min/MaxAvail
1589 88208 : InletNodeMax = thisInNode.MassFlowRateMaxAvail;
1590 88208 : InletNodeMin = thisInNode.MassFlowRateMinAvail;
1591 :
1592 : // Retrieve the pump speed fraction from the pump schedule (if any)
1593 88208 : PumpSchedFraction = (thisPump.flowRateSched != nullptr) ? std::clamp(thisPump.flowRateSched->getCurrentVal(), 0.0, 1.0) : 1.0;
1594 :
1595 : // User specified min/max mass flow rates for pump
1596 88208 : PumpOverridableMaxLimit = thisPump.MassFlowRateMax;
1597 :
1598 : // override the user specified min to allow pump to turn off when no flow is required.
1599 88208 : if (thisPump.LoopSolverOverwriteFlag) {
1600 32004 : PumpMassFlowRateMinLimit = 0.0;
1601 : } else {
1602 56204 : PumpMassFlowRateMinLimit = thisPump.MassFlowRateMin;
1603 : }
1604 :
1605 : // The pump outlet node Min/MaxAvail
1606 88208 : PumpMassFlowRateMin = max(InletNodeMin, PumpMassFlowRateMinLimit);
1607 88208 : PumpMassFlowRateMax = min(InletNodeMax, PumpOverridableMaxLimit * PumpSchedFraction);
1608 :
1609 : // Check for conflicts (MaxAvail < MinAvail)
1610 88208 : if (PumpMassFlowRateMin > PumpMassFlowRateMax) { // the demand side wants to operate outside of the pump range
1611 : // shut the pump (and the loop) down
1612 0 : PumpMassFlowRateMin = 0.0;
1613 0 : PumpMassFlowRateMax = 0.0;
1614 : // Let the user know that his input file is overconstrained
1615 : }
1616 :
1617 88208 : auto const &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
1618 :
1619 88208 : switch (thisPump.pumpType) {
1620 68156 : case PumpType::VarSpeed: {
1621 68156 : if (thisPump.HasVFD) {
1622 0 : switch (thisPump.VFD.VFDControlType) {
1623 0 : case ControlTypeVFD::VFDManual: {
1624 : // Evaluate the schedule if it exists and put the fraction into a local variable
1625 0 : PumpSchedRPM = thisPump.VFD.manualRPMSched->getCurrentVal();
1626 : // Convert the RPM to rot/sec for calculation routine
1627 0 : thisPump.RotSpeed = PumpSchedRPM / 60.0;
1628 : // Resolve the new mass flow rate based on current pressure characteristics
1629 0 : if (thisPumpPlant.UsePressureForPumpCalcs && thisPumpPlant.PressureSimType == DataPlant::PressSimType::FlowCorrection &&
1630 0 : thisPumpPlant.PressureDrop > 0.0) {
1631 :
1632 0 : state.dataPumps->PumpMassFlowRate = ResolveLoopFlowVsPressure(state,
1633 : thisPump.plantLoc.loopNum,
1634 0 : state.dataLoopNodes->Node(thisPump.InletNodeNum).MassFlowRate,
1635 : thisPump.PressureCurve_Index,
1636 : thisPump.RotSpeed,
1637 : thisPump.ImpellerDiameter,
1638 : thisPump.MinPhiValue,
1639 : thisPump.MaxPhiValue);
1640 :
1641 0 : PumpMassFlowRateMax = state.dataPumps->PumpMassFlowRate;
1642 0 : PumpMassFlowRateMin = state.dataPumps->PumpMassFlowRate;
1643 : }
1644 0 : } break;
1645 0 : case ControlTypeVFD::VFDAutomatic: {
1646 0 : if (thisPumpPlant.UsePressureForPumpCalcs && thisPumpPlant.PressureSimType == DataPlant::PressSimType::FlowCorrection &&
1647 0 : thisPumpPlant.PressureDrop > 0.0) {
1648 :
1649 0 : GetRequiredMassFlowRate(state,
1650 : LoopNum,
1651 : PumpNum,
1652 0 : state.dataLoopNodes->Node(thisPump.InletNodeNum).MassFlowRate,
1653 0 : state.dataPumps->PumpMassFlowRate,
1654 : PumpMassFlowRateMin,
1655 : PumpMassFlowRateMax);
1656 : }
1657 0 : } break;
1658 0 : default:
1659 0 : break;
1660 : } // VFDControlType
1661 : }
1662 :
1663 68156 : if (thisPump.PumpControl == PumpControlType::Continuous) {
1664 0 : thisInNode.MassFlowRateRequest = PumpMassFlowRateMin;
1665 : }
1666 68156 : } break;
1667 20052 : case PumpType::ConSpeed: {
1668 20052 : if (thisPump.PumpControl == PumpControlType::Continuous) {
1669 0 : PumpMassFlowRateMin = PumpMassFlowRateMax;
1670 0 : thisInNode.MassFlowRateRequest = PumpMassFlowRateMin;
1671 : }
1672 :
1673 : // Override (lock down flow) for pressure drop if applicable
1674 20052 : if (thisPump.plantLoc.loopNum > 0) {
1675 20052 : if (thisPumpPlant.UsePressureForPumpCalcs && thisPumpPlant.PressureSimType == DataPlant::PressSimType::FlowCorrection &&
1676 0 : thisPumpPlant.PressureDrop > 0.0) {
1677 0 : state.dataPumps->PumpMassFlowRate = ResolveLoopFlowVsPressure(state,
1678 : thisPump.plantLoc.loopNum,
1679 0 : state.dataLoopNodes->Node(thisPump.InletNodeNum).MassFlowRate,
1680 : thisPump.PressureCurve_Index,
1681 : thisPump.RotSpeed,
1682 : thisPump.ImpellerDiameter,
1683 : thisPump.MinPhiValue,
1684 : thisPump.MaxPhiValue);
1685 0 : PumpMassFlowRateMax = state.dataPumps->PumpMassFlowRate;
1686 0 : PumpMassFlowRateMin = state.dataPumps->PumpMassFlowRate;
1687 : }
1688 : }
1689 20052 : } break;
1690 0 : default:
1691 0 : break;
1692 : }
1693 :
1694 : // Override pump operation based on System Availability Managers, should be done elsewhere? I suppose this should be OK though
1695 88208 : if (allocated(state.dataAvail->PlantAvailMgr)) {
1696 88208 : if (state.dataAvail->PlantAvailMgr(LoopNum).availStatus == Avail::Status::ForceOff) {
1697 712 : PumpMassFlowRateMax = 0.0;
1698 712 : PumpMassFlowRateMin = 0.0;
1699 : }
1700 : }
1701 :
1702 : // Check if EMS is overriding flow
1703 88208 : if (thisPump.EMSMassFlowOverrideOn) {
1704 0 : PumpMassFlowRateMax = thisPump.EMSMassFlowValue;
1705 0 : PumpMassFlowRateMin = thisPump.EMSMassFlowValue;
1706 : }
1707 :
1708 : // Update outlet node to allow loop solver to get data
1709 : // could avoid this by passing data in/out to avoid putting things on nodes
1710 88208 : thisOutNode.MassFlowRateMinAvail = PumpMassFlowRateMin;
1711 88208 : thisOutNode.MassFlowRateMaxAvail = PumpMassFlowRateMax;
1712 88208 : }
1713 :
1714 176452 : void CalcPumps(EnergyPlusData &state, int const PumpNum, Real64 const FlowRequest, bool &PumpRunning)
1715 : {
1716 :
1717 : // SUBROUTINE INFORMATION:
1718 : // AUTHOR Dan Fisher
1719 : // DATE WRITTEN Sept. 1998
1720 : // MODIFIED July 2001, Rick Strand
1721 : // RE-ENGINEERED Sept 2010, Edwin Lee
1722 :
1723 : // PURPOSE OF THIS SUBROUTINE:
1724 : // This subroutines simulates a pump following
1725 : // the methodology oulined in ASHRAE's secondary toolkit.
1726 :
1727 : // METHODOLOGY EMPLOYED:
1728 : // Calculates power and updates other pump things.
1729 :
1730 : // REFERENCES:
1731 : // HVAC 2 Toolkit: A Toolkit for Secondary HVAC System
1732 : // Energy Calculations, ASHRAE, 1993, pp2-10 to 2-15
1733 :
1734 : // Using/Aliasing
1735 : using PlantUtilities::SetComponentFlowRate;
1736 :
1737 : // SUBROUTINE PARAMETER DEFINITIONS:
1738 : static constexpr std::string_view RoutineName("PlantPumps:CalcPumps: ");
1739 :
1740 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1741 : int InletNode;
1742 : int OutletNode;
1743 : Real64 LoopDensity;
1744 176452 : Real64 VolFlowRate = 0.0;
1745 : Real64 PartLoadRatio;
1746 : Real64 FracFullLoadPower;
1747 : Real64 FullLoadVolFlowRate;
1748 : Real64 PartLoadVolFlowRate;
1749 : Real64 FullLoadPower;
1750 : Real64 FullLoadPowerRatio;
1751 : Real64 TotalEffic;
1752 : PumpType pumpType;
1753 : Real64 RotSpeed_Min;
1754 : Real64 RotSpeed_Max;
1755 : Real64 PumpActualRPMValueOne;
1756 : Real64 PumpActualRPMValueTwo;
1757 :
1758 176452 : auto &daPumps = state.dataPumps;
1759 176452 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
1760 :
1761 176452 : InletNode = thisPump.InletNodeNum;
1762 176452 : OutletNode = thisPump.OutletNodeNum;
1763 176452 : pumpType = thisPump.pumpType;
1764 :
1765 176452 : auto &thisInNode = state.dataLoopNodes->Node(InletNode);
1766 176452 : auto &thisOutNode = state.dataLoopNodes->Node(OutletNode);
1767 :
1768 : //****************************!
1769 : //** SETTING PUMP FLOW RATE **!
1770 : //****************************!
1771 : // So the loop solver always passes in the full loop side flow request to each pump called
1772 : // The pump will try to use this value according to its inlet conditions via the SetComponentFlowRate routine.
1773 : // If the loop solver is doing branch pumps, then individual parallel branch inlet nodes would have been previously
1774 : // constrained, so even though we pass in a full flow request, each pump will "pull down" to the min/max avail.
1775 : // Also, on flowlock == locked, we will just use the inlet node flow rate
1776 : // The flow resolver can take care of argument resolution beyond that.
1777 : // For a typical situation, the flow request should be within the values of min/max avail, so the pump will get this flow rate.
1778 176452 : if (FlowRequest > DataBranchAirLoopPlant::MassFlowTolerance) {
1779 94317 : daPumps->PumpMassFlowRate = FlowRequest;
1780 : } else {
1781 82135 : daPumps->PumpMassFlowRate = 0.0;
1782 : }
1783 :
1784 : // For variable speed branch pumps, with other components
1785 : // on the branch, we are not going to assign a request.
1786 : // Other components on this branch will request flow for this branch
1787 :
1788 : // ! If this is a variable speed pump
1789 176452 : if (thisPump.pumpType == PumpType::VarSpeed || thisPump.pumpType == PumpType::Bank_VarSpeed || thisPump.pumpType == PumpType::Cond) {
1790 136338 : if (DataPlant::CompData::getPlantComponent(state, thisPump.plantLoc).FlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive) {
1791 0 : daPumps->PumpMassFlowRate = 0.0;
1792 : }
1793 : }
1794 :
1795 : // 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
1796 176452 : daPumps->PumpMassFlowRate = min(thisPump.MassFlowRateMax, daPumps->PumpMassFlowRate);
1797 176452 : daPumps->PumpMassFlowRate = max(thisPump.MassFlowRateMin, daPumps->PumpMassFlowRate);
1798 :
1799 176452 : SetComponentFlowRate(state, daPumps->PumpMassFlowRate, InletNode, OutletNode, thisPump.plantLoc);
1800 :
1801 176452 : auto &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
1802 :
1803 : // Get RPM value for reporting as output
1804 : // RPM is calculated using pump affinity laws for rotation speed
1805 176452 : if (thisPumpPlant.UsePressureForPumpCalcs && thisPump.HasVFD) {
1806 0 : RotSpeed_Min = thisPump.VFD.minRPMSched ? thisPump.VFD.minRPMSched->getCurrentVal() : 0.0;
1807 0 : RotSpeed_Max = thisPump.VFD.maxRPMSched ? thisPump.VFD.maxRPMSched->getCurrentVal() : 0.0;
1808 0 : if (thisPump.PumpMassFlowRateMaxRPM < DataBranchAirLoopPlant::MassFlowTolerance ||
1809 0 : thisPump.PumpMassFlowRateMinRPM < DataBranchAirLoopPlant::MassFlowTolerance) {
1810 0 : thisPump.VFD.PumpActualRPM = 0.0;
1811 : } else {
1812 0 : PumpActualRPMValueOne = (daPumps->PumpMassFlowRate / thisPump.PumpMassFlowRateMaxRPM) * RotSpeed_Max;
1813 0 : PumpActualRPMValueTwo = (daPumps->PumpMassFlowRate / thisPump.PumpMassFlowRateMinRPM) * RotSpeed_Min;
1814 0 : thisPump.VFD.PumpActualRPM = (PumpActualRPMValueOne + PumpActualRPMValueTwo) / 2;
1815 : }
1816 : }
1817 :
1818 : //****************************!
1819 : //** DETERMINE IF PUMP IS ON *!
1820 : //****************************!
1821 : // Since we don't allow series pumping, if there is ANY flow rate for this pump, THIS PUMP is driving the flow! Therefore...
1822 176452 : PumpRunning = (daPumps->PumpMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance);
1823 :
1824 : //****************************!
1825 : //** UPDATE PUMP BANK USAGE **!
1826 : //****************************!
1827 176452 : switch (thisPump.pumpType) {
1828 1 : case PumpType::Bank_VarSpeed:
1829 : case PumpType::Bank_ConSpeed: {
1830 : // previously, pumps did whatever they wanted
1831 : // because of this a constant speed pump bank could adjust the flow rate as-desired
1832 : // even if it was not allowed
1833 : // since pumps now must behave nicely like all other components, the calculation of number
1834 : // of running pumps in a pump bank is the same for both bank types
1835 : // the pumps are loaded sequentially, and the last pump can have full or non-full part load
1836 : // status...this is just how it works now. The pump cannot *bump* up the flow on the loop
1837 : // to make sure the last running pump is fully loaded anymore for constant speed pumps...sorry
1838 1 : if (daPumps->PumpMassFlowRate >= thisPump.MassFlowRateMax) {
1839 : // running full on
1840 1 : daPumps->NumPumpsRunning = thisPump.NumPumpsInBank;
1841 : } else {
1842 : // running at some sort of part load
1843 0 : daPumps->NumPumpsRunning = CEILING((daPumps->PumpMassFlowRate / (thisPump.MassFlowRateMax) * thisPump.NumPumpsInBank));
1844 0 : daPumps->NumPumpsRunning = min(daPumps->NumPumpsRunning, thisPump.NumPumpsInBank);
1845 : }
1846 1 : } break;
1847 176451 : default:
1848 176451 : break;
1849 : }
1850 :
1851 : //****************************!
1852 : //***** EXIT IF NO FLOW ******!
1853 : //****************************!
1854 176452 : if (daPumps->PumpMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) {
1855 82135 : thisOutNode.Temp = thisInNode.Temp;
1856 82135 : thisOutNode.Press = thisInNode.Press;
1857 82135 : thisOutNode.Quality = thisInNode.Quality;
1858 82135 : return;
1859 : }
1860 :
1861 : // density used for volumetric flow calculations
1862 94317 : LoopDensity = thisPumpPlant.glycol->getDensity(state, thisInNode.Temp, RoutineName);
1863 :
1864 : //****************************!
1865 : //***** CALCULATE POWER (1) **!
1866 : //****************************!
1867 94317 : switch (pumpType) {
1868 94316 : case PumpType::ConSpeed:
1869 : case PumpType::VarSpeed:
1870 : case PumpType::Cond: {
1871 94316 : VolFlowRate = daPumps->PumpMassFlowRate / LoopDensity;
1872 94316 : PartLoadRatio = min(1.0, (VolFlowRate / thisPump.NomVolFlowRate));
1873 94316 : FracFullLoadPower = thisPump.PartLoadCoef[0] + thisPump.PartLoadCoef[1] * PartLoadRatio + thisPump.PartLoadCoef[2] * pow_2(PartLoadRatio) +
1874 94316 : thisPump.PartLoadCoef[3] * pow_3(PartLoadRatio);
1875 94316 : daPumps->Power = FracFullLoadPower * thisPump.NomPowerUse;
1876 :
1877 94316 : } break;
1878 1 : case PumpType::Bank_ConSpeed:
1879 : case PumpType::Bank_VarSpeed: {
1880 : // now just assume the last one is (or is not) running at part load
1881 : // if it is actually at full load, the calculations work out to PLR = 1
1882 : // for the last pump, so all is OK
1883 1 : daPumps->NumPumpsFullLoad = daPumps->NumPumpsRunning - 1;
1884 1 : FullLoadVolFlowRate = thisPump.NomVolFlowRate / thisPump.NumPumpsInBank;
1885 1 : PartLoadVolFlowRate = daPumps->PumpMassFlowRate / LoopDensity - FullLoadVolFlowRate * daPumps->NumPumpsFullLoad;
1886 1 : FullLoadPower = thisPump.NomPowerUse / thisPump.NumPumpsInBank;
1887 1 : FullLoadPowerRatio = thisPump.PartLoadCoef[0] + thisPump.PartLoadCoef[1] + thisPump.PartLoadCoef[2] + thisPump.PartLoadCoef[3];
1888 1 : PartLoadRatio = min(1.0, (PartLoadVolFlowRate / FullLoadVolFlowRate));
1889 1 : FracFullLoadPower = thisPump.PartLoadCoef[0] + thisPump.PartLoadCoef[1] * PartLoadRatio + thisPump.PartLoadCoef[2] * pow_2(PartLoadRatio) +
1890 1 : thisPump.PartLoadCoef[3] * pow_3(PartLoadRatio);
1891 1 : daPumps->Power = (FullLoadPowerRatio * daPumps->NumPumpsFullLoad + FracFullLoadPower) * FullLoadPower;
1892 1 : if (thisPump.EMSPressureOverrideOn) {
1893 1 : VolFlowRate = PartLoadVolFlowRate;
1894 : }
1895 1 : } break;
1896 0 : default: {
1897 0 : assert(false);
1898 : } break;
1899 : }
1900 :
1901 : //****************************!
1902 : //***** CALCULATE POWER (2) **!
1903 : //****************************!
1904 94317 : if (daPumps->Power < 0.0) {
1905 0 : if (thisPump.PowerErrIndex1 == 0) {
1906 0 : ShowWarningMessage(
1907 : state,
1908 0 : format("{} Calculated Pump Power < 0, Type={}, Name={}", RoutineName, pumpTypeIDFNames[static_cast<int>(pumpType)], thisPump.Name));
1909 0 : ShowContinueErrorTimeStamp(state, "");
1910 0 : ShowContinueError(state, format("...PartLoadRatio=[{:.4R}], Fraction Full Load Power={:.4R}]", PartLoadRatio, FracFullLoadPower));
1911 0 : ShowContinueError(state, "...Power is set to 0 for continuing the simulation.");
1912 0 : ShowContinueError(state, "...Pump coefficients should be checked for producing this negative value.");
1913 : }
1914 0 : daPumps->Power = 0.0;
1915 0 : ShowRecurringWarningErrorAtEnd(
1916 : state,
1917 0 : format("{} Calculated Pump Power < 0, {}, Name={}, PLR=", RoutineName, pumpTypeIDFNames[static_cast<int>(pumpType)], thisPump.Name),
1918 0 : thisPump.PowerErrIndex1,
1919 : PartLoadRatio,
1920 : PartLoadRatio);
1921 0 : ShowRecurringContinueErrorAtEnd(state, "...Fraction Full Load Power=", thisPump.PowerErrIndex2, FracFullLoadPower, FracFullLoadPower);
1922 : }
1923 :
1924 : //****************************!
1925 : //***** CALCULATE POWER (3) **!
1926 : //****************************!
1927 : // Now if we are doing pressure-based simulation, then we have a means to calculate power exactly based on current
1928 : // simulation conditions (flow rate and pressure drop) along with knowledge about pump impeller and motor efficiencies
1929 : // Thus we will override the power that was calculated based on nominal values with the corrected pressure-based power
1930 94317 : if (thisPump.plantLoc.loopNum > 0) {
1931 94317 : if (thisPumpPlant.UsePressureForPumpCalcs) {
1932 0 : TotalEffic = thisPump.PumpEffic * thisPump.MotorEffic;
1933 : // Efficiency errors are caught previously, but it doesn't hurt to add another catch before dividing by zero!!!
1934 0 : if (TotalEffic == 0.0) {
1935 0 : ShowSevereError(state,
1936 0 : format("{} Plant pressure simulation encountered a pump with zero efficiency: {}", RoutineName, thisPump.Name));
1937 0 : ShowContinueError(state, "Check efficiency inputs for this pump component.");
1938 0 : ShowFatalError(state, "Errors in plant calculation would result in divide-by-zero cause program termination.");
1939 : }
1940 0 : daPumps->Power = VolFlowRate * thisPumpPlant.PressureDrop / TotalEffic;
1941 : }
1942 : }
1943 :
1944 : // if user has specified a pressure value, then use it, same as for pressure-based simulation
1945 94317 : if (thisPump.EMSPressureOverrideOn) {
1946 1 : TotalEffic = thisPump.PumpEffic * thisPump.MotorEffic;
1947 : // Efficiency errors are caught previously, but it doesn't hurt to add another catch before dividing by zero!!!
1948 1 : if (TotalEffic == 0.0) {
1949 0 : ShowSevereError(state, format("{} Plant pump simulation encountered a pump with zero efficiency: {}", RoutineName, thisPump.Name));
1950 0 : ShowContinueError(state, "Check efficiency inputs for this pump component.");
1951 0 : ShowFatalError(state, "Errors in plant calculation would result in divide-by-zero cause program termination.");
1952 : }
1953 1 : daPumps->Power = VolFlowRate * thisPump.EMSPressureOverrideValue / TotalEffic;
1954 : }
1955 :
1956 : //****************************!
1957 : //***** CALCULATE POWER (4) **!
1958 : //****************************!
1959 : // This adds the pump heat based on User input for the pump
1960 : // We assume that all of the heat ends up in the fluid eventually since this is a closed loop
1961 94317 : daPumps->ShaftPower = daPumps->Power * thisPump.MotorEffic;
1962 94317 : daPumps->PumpHeattoFluid = daPumps->ShaftPower + (daPumps->Power - daPumps->ShaftPower) * thisPump.FracMotorLossToFluid;
1963 :
1964 : //****************************!
1965 : //***** UPDATE INFORMATION ***!
1966 : //****************************!
1967 : // Update data structure variables
1968 94317 : thisPump.Power = daPumps->Power;
1969 :
1970 : // Update outlet node conditions
1971 94317 : thisOutNode.Temp = thisInNode.Temp;
1972 94317 : thisOutNode.Press = thisInNode.Press;
1973 94317 : thisOutNode.Quality = thisInNode.Quality;
1974 : }
1975 :
1976 52 : void SizePump(EnergyPlusData &state, int const PumpNum)
1977 : {
1978 :
1979 : // SUBROUTINE INFORMATION:
1980 : // AUTHOR Fred Buhl
1981 : // DATE WRITTEN December 2001
1982 : // MODIFIED na
1983 : // RE-ENGINEERED na
1984 :
1985 : // PURPOSE OF THIS SUBROUTINE:
1986 : // This subroutine is for sizing Pump Components for which flow rates have not been
1987 : // specified in the input.
1988 :
1989 : // METHODOLOGY EMPLOYED:
1990 : // Obtains flow rates from the plant sizing array.
1991 :
1992 : // SUBROUTINE PARAMETER DEFINITIONS:
1993 52 : Real64 constexpr StartTemp(100.0); // Standard Temperature across code to calculated Steam density
1994 : static constexpr std::string_view RoutineName("PlantPumps::InitSimVars ");
1995 : static constexpr std::string_view RoutineNameSizePumps("SizePumps");
1996 :
1997 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1998 : int PlantSizNum; // index of Plant Sizing array
1999 : bool ErrorsFound;
2000 52 : Real64 TotalEffic = 0.0; // pump total efficiency
2001 : Real64 PumpSizFac; // pump sizing factor
2002 : Real64 SteamDensity;
2003 : Real64 TempWaterDensity;
2004 52 : int DummyWaterIndex(1);
2005 : Real64 DesVolFlowRatePerBranch; // local temporary for split of branch pumps
2006 :
2007 52 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
2008 52 : bool thisOkToReport = state.dataPlnt->PlantFinalSizesOkayToReport;
2009 :
2010 : // Calculate density at InitConvTemp once here, to remove RhoH2O calls littered throughout
2011 52 : if (thisPump.plantLoc.loopNum > 0) {
2012 35 : auto &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
2013 35 : TempWaterDensity = thisPumpPlant.glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
2014 : } else {
2015 17 : TempWaterDensity = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, RoutineName);
2016 : }
2017 :
2018 52 : PlantSizNum = 0;
2019 52 : PumpSizFac = 1.0;
2020 52 : ErrorsFound = false;
2021 :
2022 52 : if (thisPump.plantLoc.loopNum > 0) {
2023 35 : PlantSizNum = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum).PlantSizNum;
2024 : }
2025 : // use pump sizing factor stored in plant sizing data structure
2026 52 : if (PlantSizNum > 0) {
2027 15 : PumpSizFac = state.dataSize->PlantSizData(PlantSizNum).PlantSizFac;
2028 : } else {
2029 : // might be able to remove this next block
2030 37 : if (thisPump.plantLoc.loopNum > 0) {
2031 40 : for (DataPlant::LoopSideLocation Side : DataPlant::LoopSideKeys) {
2032 40 : auto &thisPumpLoop = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum).LoopSide(Side);
2033 114 : for (int BranchNum = 1; BranchNum <= thisPumpLoop.TotalBranches; ++BranchNum) {
2034 94 : auto &thisPumpBranch = thisPumpLoop.Branch(BranchNum);
2035 168 : for (int CompNum = 1; CompNum <= thisPumpBranch.TotalComponents; ++CompNum) {
2036 94 : auto const &thisPumpComp = thisPumpBranch.Comp(CompNum);
2037 94 : if (thisPump.InletNodeNum == thisPumpComp.NodeNumIn && thisPump.OutletNodeNum == thisPumpComp.NodeNumOut) {
2038 20 : if (thisPumpBranch.PumpSizFac > 0.0) {
2039 20 : PumpSizFac = thisPumpBranch.PumpSizFac;
2040 : } else {
2041 0 : PumpSizFac = 1.0;
2042 : }
2043 20 : goto SideLoop_exit;
2044 : }
2045 : }
2046 : }
2047 : }
2048 20 : SideLoop_exit:;
2049 : }
2050 : }
2051 :
2052 52 : if (thisPump.NomVolFlowRateWasAutoSized) {
2053 :
2054 8 : if (PlantSizNum > 0) {
2055 8 : auto &thisPumpPlant = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
2056 8 : auto &thisPlantSize = state.dataSize->PlantSizData(PlantSizNum);
2057 8 : if (thisPlantSize.DesVolFlowRate >= SmallWaterVolFlow) {
2058 8 : if (!thisPumpPlant.LoopSide(thisPump.plantLoc.loopSideNum).BranchPumpsExist) {
2059 : // size pump to full flow of plant loop
2060 8 : if (thisPump.pumpType == PumpType::Cond) {
2061 0 : TempWaterDensity = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, RoutineName);
2062 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, StartTemp, 1.0, RoutineNameSizePumps);
2063 0 : thisPump.NomSteamVolFlowRate = thisPlantSize.DesVolFlowRate * PumpSizFac;
2064 0 : thisPump.NomVolFlowRate = thisPump.NomSteamVolFlowRate * SteamDensity / TempWaterDensity;
2065 : } else {
2066 8 : thisPump.NomVolFlowRate = thisPlantSize.DesVolFlowRate * PumpSizFac;
2067 : }
2068 : } else {
2069 : // Distribute sizes evenly across all branch pumps
2070 0 : DesVolFlowRatePerBranch = thisPlantSize.DesVolFlowRate / thisPumpPlant.LoopSide(thisPump.plantLoc.loopSideNum).TotalPumps;
2071 0 : if (thisPump.pumpType == PumpType::Cond) {
2072 0 : TempWaterDensity = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, RoutineName);
2073 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, StartTemp, 1.0, RoutineNameSizePumps);
2074 0 : thisPump.NomSteamVolFlowRate = DesVolFlowRatePerBranch * PumpSizFac;
2075 0 : thisPump.NomVolFlowRate = thisPump.NomSteamVolFlowRate * SteamDensity / TempWaterDensity;
2076 : } else {
2077 0 : thisPump.NomVolFlowRate = DesVolFlowRatePerBranch * PumpSizFac;
2078 : }
2079 : }
2080 :
2081 : } else {
2082 0 : if (thisOkToReport) {
2083 0 : thisPump.NomVolFlowRate = 0.0;
2084 0 : ShowWarningError(
2085 : state,
2086 0 : format("SizePump: Calculated Pump Nominal Volume Flow Rate=[{:.2R}] is too small. Set to 0.0", thisPlantSize.DesVolFlowRate));
2087 0 : ShowContinueError(state, format("..occurs for Pump={}", thisPump.Name));
2088 : }
2089 : }
2090 8 : if (thisOkToReport) {
2091 16 : BaseSizer::reportSizerOutput(
2092 8 : state, pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)], thisPump.Name, "Design Flow Rate [m3/s]", thisPump.NomVolFlowRate);
2093 : }
2094 8 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2095 0 : BaseSizer::reportSizerOutput(state,
2096 0 : pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)],
2097 : thisPump.Name,
2098 : "Initial Design Flow Rate [m3/s]",
2099 : thisPump.NomVolFlowRate);
2100 : }
2101 : } else {
2102 0 : if (thisOkToReport) {
2103 0 : ShowSevereError(state, "Autosizing of plant loop pump flow rate requires a loop Sizing:Plant object");
2104 0 : ShowContinueError(state, format("Occurs in plant pump object={}", thisPump.Name));
2105 0 : ErrorsFound = true;
2106 : }
2107 : }
2108 : }
2109 :
2110 : // Note that autocalculation of power is based on nominal volume flow, regardless of whether the flow was
2111 : // auto-sized or manually sized. Thus, this must go after the flow sizing block above.
2112 52 : if (thisPump.NomPowerUseWasAutoSized) {
2113 26 : if (thisPump.NomVolFlowRate >= SmallWaterVolFlow) {
2114 26 : switch (thisPump.powerSizingMethod) {
2115 :
2116 5 : case PowerSizingMethod::SizePowerPerFlow: {
2117 5 : TotalEffic = thisPump.NomPumpHead / thisPump.powerPerFlowScalingFactor;
2118 5 : break;
2119 : }
2120 :
2121 21 : case PowerSizingMethod::SizePowerPerFlowPerPressure: {
2122 21 : TotalEffic = (1 / thisPump.powerPerFlowPerPressureScalingFactor) * thisPump.MotorEffic;
2123 21 : break;
2124 : }
2125 0 : default:
2126 0 : assert(false);
2127 : }
2128 :
2129 26 : thisPump.NomPowerUse = (thisPump.NomPumpHead * thisPump.NomVolFlowRate) / TotalEffic;
2130 : } else {
2131 0 : thisPump.NomPowerUse = 0.0;
2132 : }
2133 26 : if (thisOkToReport) {
2134 18 : BaseSizer::reportSizerOutput(
2135 9 : state, pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)], thisPump.Name, "Design Power Consumption [W]", thisPump.NomPowerUse);
2136 : }
2137 26 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2138 0 : BaseSizer::reportSizerOutput(state,
2139 0 : pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)],
2140 : thisPump.Name,
2141 : "Initial Design Power Consumption [W]",
2142 : thisPump.NomPowerUse);
2143 : }
2144 : }
2145 :
2146 52 : if (thisPump.minVolFlowRateWasAutosized) {
2147 4 : thisPump.MinVolFlowRate = thisPump.NomVolFlowRate * thisPump.MinVolFlowRateFrac;
2148 4 : if (thisOkToReport) {
2149 0 : BaseSizer::reportSizerOutput(state,
2150 0 : pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)],
2151 : thisPump.Name,
2152 : "Design Minimum Flow Rate [m3/s]",
2153 : thisPump.MinVolFlowRate);
2154 : }
2155 4 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2156 0 : BaseSizer::reportSizerOutput(state,
2157 0 : pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)],
2158 : thisPump.Name,
2159 : "Initial Design Minimum Flow Rate [m3/s]",
2160 : thisPump.MinVolFlowRate);
2161 : }
2162 : }
2163 :
2164 52 : if (thisOkToReport) {
2165 35 : PumpDataForTable(state, PumpNum);
2166 : }
2167 :
2168 52 : if (ErrorsFound) {
2169 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
2170 : }
2171 52 : }
2172 :
2173 176451 : void ReportPumps(EnergyPlusData &state, int const PumpNum)
2174 : {
2175 :
2176 : // SUBROUTINE INFORMATION:
2177 : // AUTHOR: Dan Fisher
2178 : // DATE WRITTEN: October 1998
2179 : // MODIFIED July 2001, Rick Strand (revision of pump module)
2180 : // RE-ENGINEERED na
2181 :
2182 : // PURPOSE OF THIS SUBROUTINE:
2183 : // This subroutine sets the pump reporting variables.
2184 :
2185 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2186 : int OutletNode; // pump outlet node number
2187 : PumpType PumpType; // Current pump type
2188 :
2189 176451 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
2190 176451 : auto &thisPumpRep = state.dataPumps->PumpEquipReport(PumpNum);
2191 :
2192 176451 : PumpType = thisPump.pumpType;
2193 176451 : OutletNode = thisPump.OutletNodeNum;
2194 176451 : auto const &thisOutNode = state.dataLoopNodes->Node(OutletNode);
2195 176451 : auto const &daPumps = state.dataPumps;
2196 :
2197 176451 : if (daPumps->PumpMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) {
2198 82135 : new (&(state.dataPumps->PumpEquipReport(PumpNum))) ReportVars();
2199 82135 : thisPumpRep.OutletTemp = thisOutNode.Temp;
2200 82135 : thisPump.Power = 0.0;
2201 82135 : thisPump.Energy = 0.0;
2202 : } else {
2203 94316 : thisPumpRep.PumpMassFlowRate = daPumps->PumpMassFlowRate;
2204 94316 : thisPumpRep.PumpHeattoFluid = daPumps->PumpHeattoFluid;
2205 94316 : thisPumpRep.OutletTemp = thisOutNode.Temp;
2206 94316 : thisPump.Power = daPumps->Power;
2207 94316 : thisPump.Energy = thisPump.Power * state.dataHVACGlobal->TimeStepSysSec;
2208 94316 : thisPumpRep.ShaftPower = daPumps->ShaftPower;
2209 94316 : thisPumpRep.PumpHeattoFluidEnergy = daPumps->PumpHeattoFluid * state.dataHVACGlobal->TimeStepSysSec;
2210 94316 : switch (PumpType) {
2211 94316 : case PumpType::ConSpeed:
2212 : case PumpType::VarSpeed:
2213 : case PumpType::Cond:
2214 94316 : thisPumpRep.NumPumpsOperating = 1;
2215 94316 : break;
2216 :
2217 0 : case PumpType::Bank_ConSpeed:
2218 : case PumpType::Bank_VarSpeed:
2219 0 : thisPumpRep.NumPumpsOperating = daPumps->NumPumpsRunning;
2220 0 : break;
2221 0 : default:
2222 0 : assert(false);
2223 : break;
2224 : }
2225 94316 : thisPumpRep.ZoneTotalGainRate = daPumps->Power - daPumps->PumpHeattoFluid;
2226 94316 : thisPumpRep.ZoneTotalGainEnergy = thisPumpRep.ZoneTotalGainRate * state.dataHVACGlobal->TimeStepSysSec;
2227 94316 : thisPumpRep.ZoneConvGainRate = (1 - thisPump.SkinLossRadFraction) * thisPumpRep.ZoneTotalGainRate;
2228 94316 : thisPumpRep.ZoneRadGainRate = thisPump.SkinLossRadFraction * thisPumpRep.ZoneTotalGainRate;
2229 : }
2230 176451 : }
2231 :
2232 35 : void PumpDataForTable(EnergyPlusData &state, int const NumPump)
2233 : {
2234 :
2235 : // SUBROUTINE INFORMATION:
2236 : // AUTHOR: Jason Glazer
2237 : // DATE WRITTEN: September 2006
2238 : // MODIFIED na
2239 : // RE-ENGINEERED na
2240 :
2241 : // PURPOSE OF THIS SUBROUTINE:
2242 : // Pull data together for predefined tables.
2243 :
2244 : // Using/Aliasing
2245 : using namespace OutputReportPredefined;
2246 :
2247 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2248 35 : std::string equipName;
2249 :
2250 35 : auto &thisPump = state.dataPumps->PumpEquip(NumPump);
2251 35 : auto &thisReport = state.dataOutRptPredefined;
2252 :
2253 35 : equipName = thisPump.Name;
2254 35 : PreDefTableEntry(state, thisReport->pdchPumpType, equipName, pumpTypeIDFNames[static_cast<int>(thisPump.pumpType)]);
2255 35 : if (thisPump.PumpControl == PumpControlType::Continuous) {
2256 0 : PreDefTableEntry(state, thisReport->pdchPumpControl, equipName, "Continuous");
2257 35 : } else if (thisPump.PumpControl == PumpControlType::Intermittent) {
2258 35 : PreDefTableEntry(state, thisReport->pdchPumpControl, equipName, "Intermittent");
2259 : } else {
2260 0 : PreDefTableEntry(state, thisReport->pdchPumpControl, equipName, "Unknown");
2261 : }
2262 35 : PreDefTableEntry(state, thisReport->pdchPumpHead, equipName, thisPump.NomPumpHead);
2263 35 : PreDefTableEntry(state, thisReport->pdchPumpFlow, equipName, thisPump.NomVolFlowRate, 6);
2264 35 : PreDefTableEntry(state, thisReport->pdchPumpPower, equipName, thisPump.NomPowerUse);
2265 35 : if (thisPump.NomVolFlowRate != 0) {
2266 35 : PreDefTableEntry(state, thisReport->pdchPumpPwrPerFlow, equipName, thisPump.NomPowerUse / thisPump.NomVolFlowRate);
2267 : } else {
2268 0 : PreDefTableEntry(state, thisReport->pdchPumpPwrPerFlow, equipName, "-");
2269 : }
2270 35 : PreDefTableEntry(state, thisReport->pdchPumpEndUse, equipName, thisPump.EndUseSubcategoryName);
2271 35 : PreDefTableEntry(state, thisReport->pdchMotEff, equipName, thisPump.MotorEffic);
2272 : // Std 229
2273 35 : PreDefTableEntry(state, thisReport->pdchPumpAutosized, equipName, thisPump.NomVolFlowRateWasAutoSized ? "Yes" : "No");
2274 70 : PreDefTableEntry(state,
2275 35 : thisReport->pdchPumpPlantloopName,
2276 : equipName,
2277 70 : thisPump.plantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum).Name : "N/A");
2278 70 : PreDefTableEntry(
2279 : state,
2280 35 : thisReport->pdchPumpPlantloopBranchName,
2281 : equipName,
2282 35 : thisPump.plantLoc.loopNum > 0
2283 70 : ? state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum).LoopSide(thisPump.plantLoc.loopSideNum).Branch(thisPump.plantLoc.branchNum).Name
2284 : : "N/A");
2285 35 : }
2286 :
2287 0 : void GetRequiredMassFlowRate(EnergyPlusData &state,
2288 : int const LoopNum,
2289 : int const PumpNum,
2290 : Real64 const InletNodeMassFlowRate,
2291 : Real64 &ActualFlowRate,
2292 : Real64 &PumpMinMassFlowRateVFDRange,
2293 : Real64 &PumpMaxMassFlowRateVFDRange)
2294 : {
2295 : // Using/Aliasing
2296 : using PlantPressureSystem::ResolveLoopFlowVsPressure;
2297 : using PlantUtilities::SetComponentFlowRate;
2298 :
2299 0 : Real64 PumpMassFlowRateMaxPress(0.0); // Maximum mass flow rate associated with maximum pressure limit
2300 0 : Real64 PumpMassFlowRateMinPress(0.0); // Minimum mass flow rate associated with minimum pressure limit
2301 0 : Real64 RotSpeed_Max(0.0); // Maximum rotational speed in rps
2302 0 : Real64 RotSpeed_Min(0.0); // Minimum rotational speed in rps
2303 0 : Real64 MinPress(0.0); // Minimum pressure
2304 0 : Real64 MaxPress(0.0); // Maximum pressure
2305 :
2306 0 : auto &thisPump = state.dataPumps->PumpEquip(PumpNum);
2307 :
2308 0 : RotSpeed_Min = thisPump.VFD.minRPMSched->getCurrentVal();
2309 0 : RotSpeed_Max = thisPump.VFD.maxRPMSched->getCurrentVal();
2310 0 : MinPress = thisPump.VFD.lowerPsetSched->getCurrentVal();
2311 0 : MaxPress = thisPump.VFD.upperPsetSched->getCurrentVal();
2312 :
2313 : // Calculate maximum and minimum mass flow rate associated with maximun and minimum RPM
2314 0 : if (thisPump.plantLoc.loopNum > 0) {
2315 0 : auto const &thisPlantLoop = state.dataPlnt->PlantLoop(thisPump.plantLoc.loopNum);
2316 0 : if (thisPlantLoop.UsePressureForPumpCalcs && thisPlantLoop.PressureSimType == DataPlant::PressSimType::FlowCorrection &&
2317 0 : thisPlantLoop.PressureDrop > 0.0) {
2318 0 : thisPump.PumpMassFlowRateMaxRPM = ResolveLoopFlowVsPressure(state,
2319 : thisPump.plantLoc.loopNum,
2320 : InletNodeMassFlowRate,
2321 : thisPump.PressureCurve_Index,
2322 : RotSpeed_Max,
2323 : thisPump.ImpellerDiameter,
2324 : thisPump.MinPhiValue,
2325 : thisPump.MaxPhiValue);
2326 0 : thisPump.PumpMassFlowRateMinRPM = ResolveLoopFlowVsPressure(state,
2327 : thisPump.plantLoc.loopNum,
2328 : InletNodeMassFlowRate,
2329 : thisPump.PressureCurve_Index,
2330 : RotSpeed_Min,
2331 : thisPump.ImpellerDiameter,
2332 : thisPump.MinPhiValue,
2333 : thisPump.MaxPhiValue);
2334 : }
2335 : }
2336 :
2337 : // Not correct necessarily, but values are coming out way wrong here, maxRPMmdot~3, minRPMmdot~62!
2338 0 : if (thisPump.PumpMassFlowRateMaxRPM < thisPump.PumpMassFlowRateMinRPM) {
2339 0 : thisPump.PumpMassFlowRateMaxRPM = thisPump.PumpMassFlowRateMinRPM;
2340 : }
2341 :
2342 : // Calculate maximum and minimum mass flow rate associated with operating pressure range
2343 0 : if (thisPump.plantLoc.loopNum > 0) {
2344 0 : auto const &thisPlantLoop = state.dataPlnt->PlantLoop(LoopNum);
2345 0 : if (thisPlantLoop.PressureEffectiveK > 0.0) {
2346 0 : PumpMassFlowRateMaxPress = std::sqrt(MaxPress / thisPlantLoop.PressureEffectiveK);
2347 0 : PumpMassFlowRateMinPress = std::sqrt(MinPress / thisPlantLoop.PressureEffectiveK);
2348 : }
2349 : }
2350 :
2351 : // Decide operating range for mass flow rate
2352 : // Maximum mass flow rate value of the range
2353 0 : if (thisPump.PumpMassFlowRateMaxRPM > PumpMassFlowRateMaxPress) {
2354 : // Maximum pressure value governs maximum VFD range value
2355 0 : PumpMaxMassFlowRateVFDRange = PumpMassFlowRateMaxPress;
2356 : } else {
2357 : // Maximum RPM value governs maximum VFD range value
2358 0 : PumpMaxMassFlowRateVFDRange = thisPump.PumpMassFlowRateMaxRPM;
2359 : }
2360 :
2361 : // Minimum mass flow rate value of the range
2362 0 : if (thisPump.PumpMassFlowRateMinRPM > PumpMassFlowRateMinPress) {
2363 : // Minimum pressure value governs minimum VFD range value
2364 0 : PumpMinMassFlowRateVFDRange = thisPump.PumpMassFlowRateMinRPM;
2365 : } else {
2366 : // Minimum pressure range value governs minimum VFD range value
2367 0 : PumpMinMassFlowRateVFDRange = PumpMassFlowRateMinPress;
2368 : }
2369 :
2370 : // Set the mass flow rate within VFD operating range
2371 0 : if (InletNodeMassFlowRate > PumpMinMassFlowRateVFDRange) {
2372 0 : if (InletNodeMassFlowRate < PumpMaxMassFlowRateVFDRange) {
2373 : // Flow request is within VFD operating range
2374 0 : ActualFlowRate = InletNodeMassFlowRate;
2375 : } else {
2376 : // Flow request is outside VFD operating range
2377 : // Flow is set to maximum VFD operating range
2378 0 : ActualFlowRate = PumpMaxMassFlowRateVFDRange;
2379 : }
2380 : } else {
2381 : // Flow request is outside VFD operating range
2382 : // Flow is set to minimum VFD operating Range
2383 0 : ActualFlowRate = PumpMinMassFlowRateVFDRange;
2384 : }
2385 0 : }
2386 :
2387 : } // namespace EnergyPlus::Pumps
|