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