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