Buildings.Fluid.Movers.BaseClasses

Package with base classes for Buildings.Fluid.Movers

Information

This package contains base classes that are used to construct the models in Buildings.Fluid.Movers.

Extends from Modelica.Icons.BasesPackage (Icon for packages containing base classes).

Package Content

Name Description
Buildings.Fluid.Movers.BaseClasses.FlowMachineInterface FlowMachineInterface Partial model with performance curves for fans or pumps
Buildings.Fluid.Movers.BaseClasses.IdealSource IdealSource Base class for pressure and mass flow source with optional power input
Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine PartialFlowMachine Partial model to interface fan or pump models with the medium
Buildings.Fluid.Movers.BaseClasses.PowerInterface PowerInterface Partial model to compute power draw and heat dissipation of fans and pumps
Buildings.Fluid.Movers.BaseClasses.Characteristics Characteristics Functions for fan or pump characteristics
Buildings.Fluid.Movers.BaseClasses.Types Types Package with type definitions
Buildings.Fluid.Movers.BaseClasses.Validation Validation Collection of validation models

Buildings.Fluid.Movers.BaseClasses.FlowMachineInterface Buildings.Fluid.Movers.BaseClasses.FlowMachineInterface

Partial model with performance curves for fans or pumps

Buildings.Fluid.Movers.BaseClasses.FlowMachineInterface

Information

This is an interface that implements the functions to compute the head, power draw and efficiency of fans and pumps.

The nominal hydraulic characteristic (volume flow rate versus total pressure) is given by a set of data points using the data record per, which is an instance of Buildings.Fluid.Movers.Data.Generic. A cubic hermite spline with linear extrapolation is used to compute the performance at other operating points.

The fan or pump energy balance can be specified in two alternative ways:

For exceptions to this general rule, check the User's Guide for more information.

Implementation

For numerical reasons, the user-provided data points for volume flow rate versus pressure rise are modified to add a fan internal flow resistance. Because this flow resistance is subtracted during the simulation when computing the fan pressure rise, the model reproduces the exact points that were provided by the user.

Also for numerical reasons, the pressure rise at zero flow rate and the flow rate at zero pressure rise is added to the user-provided data, unless the user already provides these data points. Since Modelica 3.2 does not allow dynamic memory allocation, this implementation required the use of three different arrays for the situation where no additional point is added, where one additional point is added and where two additional points are added. The parameter curve causes the correct data record to be used during the simulation.

In order to prevent the model from producing negative mover power when either the flow rate or pressure rise is forced to be negative, the flow work flo is constrained to be non-negative. The regularisation starts around 0.01% of the characteristic maximum power max = V̇max Δpmax. See discussions and an example of this situation in IBPSA, #1621.

Extends from Modelica.Blocks.Icons.Block (Basic graphical layout of input/output block).

Parameters

TypeNameDefaultDescription
Genericper Record with performance data
PrescribedVariablepreVarBuildings.Fluid.Movers.BaseC...Type of prescribed variable
BooleancomputePowerUsingSimilarityLaws = true, compute power exactly, using similarity laws. Otherwise approximate.
Densityrho_default Fluid density at medium default state [kg/m3]
BooleanhaveVMax Flag, true if user specified data that contain V_flow_max
VolumeFlowRateV_flow_max Maximum volume flow rate, used for smoothing [m3/s]
IntegernOri Number of data points for pressure curve

Connectors

TypeNameDescription
input RealInputy_inPrescribed mover speed [1]
output RealOutputy_outMover speed (prescribed or computed) [1]
input RealInputm_flowMass flow rate [kg/s]
input RealInputrhoMedium density [kg/m3]
output RealOutputV_flowVolume flow rate [m3/s]
input RealInputdp_inPrescribed pressure increase [Pa]
output RealOutputdpPressure increase (computed or prescribed) [Pa]
output RealOutputWFloFlow work [W]
output RealOutputPEleElectrical power consumed [W]
output RealOutputetaOverall efficiency [1]
output RealOutputetaHydHydraulic efficiency [1]
output RealOutputetaMotMotor efficiency [1]
output RealOutputr_NRatio N_actual/N_nominal [1]

Modelica definition

model FlowMachineInterface "Partial model with performance curves for fans or pumps" extends Modelica.Blocks.Icons.Block; import cha = Buildings.Fluid.Movers.BaseClasses.Characteristics; constant Boolean homotopyInitialization = true "= true, use homotopy method"; parameter Buildings.Fluid.Movers.Data.Generic per "Record with performance data"; parameter Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable preVar= Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.Speed "Type of prescribed variable"; parameter Boolean computePowerUsingSimilarityLaws "= true, compute power exactly, using similarity laws. Otherwise approximate."; final parameter Modelica.Units.SI.VolumeFlowRate V_flow_nominal=per.pressure.V_flow[ nOri] "Nominal volume flow rate, used for homotopy"; parameter Modelica.Units.SI.Density rho_default "Fluid density at medium default state"; parameter Boolean haveVMax "Flag, true if user specified data that contain V_flow_max"; parameter Modelica.Units.SI.VolumeFlowRate V_flow_max "Maximum volume flow rate, used for smoothing"; parameter Integer nOri(min=1) "Number of data points for pressure curve"; // Normalized speed Modelica.Blocks.Interfaces.RealInput y_in(final unit="1") if preSpe "Prescribed mover speed"; Modelica.Blocks.Interfaces.RealOutput y_out( final unit="1") "Mover speed (prescribed or computed)"; Modelica.Blocks.Interfaces.RealInput m_flow( final quantity="MassFlowRate", final unit="kg/s") "Mass flow rate"; Modelica.Blocks.Interfaces.RealInput rho( final quantity="Density", final unit="kg/m3", min=0.0) "Medium density"; Modelica.Blocks.Interfaces.RealOutput V_flow( quantity="VolumeFlowRate", final unit="m3/s") "Volume flow rate"; Modelica.Blocks.Interfaces.RealInput dp_in( quantity="PressureDifference", final unit="Pa") if prePre "Prescribed pressure increase"; Modelica.Blocks.Interfaces.RealOutput dp( quantity="Pressure", final unit="Pa") if not prePre "Pressure increase (computed or prescribed)"; Modelica.Blocks.Interfaces.RealOutput WFlo( quantity="Power", final unit="W") "Flow work"; Modelica.Blocks.Interfaces.RealOutput PEle( quantity="Power", final unit="W") "Electrical power consumed"; Modelica.Blocks.Interfaces.RealOutput eta( final quantity="Efficiency", final unit="1") "Overall efficiency"; Modelica.Blocks.Interfaces.RealOutput etaHyd( final quantity="Efficiency", final unit="1") "Hydraulic efficiency"; Modelica.Blocks.Interfaces.RealOutput etaMot( final quantity="Efficiency", final unit="1") "Motor efficiency"; // "Shaft rotational speed"; Modelica.Blocks.Interfaces.RealOutput r_N(unit="1") "Ratio N_actual/N_nominal"; Real r_V(start=1, unit="1") "Ratio V_flow/V_flow_max"; protected final parameter Boolean preSpe= preVar == Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.Speed "True if speed is a prescribed variable of this block"; final parameter Boolean prePre= preVar == Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.PressureDifference or preVar == Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.FlowRate "True if pressure head is a prescribed variable of this block"; // Derivatives for cubic spline final parameter Real motDer[size(per.motorEfficiency.V_flow, 1)](each fixed=false) "Coefficients for polynomial of motor efficiency vs. volume flow rate"; final parameter Real hydDer[size(per.hydraulicEfficiency.V_flow,1)](each fixed=false) "Coefficients for polynomial of hydraulic efficiency vs. volume flow rate"; parameter Modelica.Units.SI.PressureDifference dpMax(displayUnit="Pa") = if haveDPMax then per.pressure.dp[1] else per.pressure.dp[1] - ((per.pressure.dp[ 2] - per.pressure.dp[1])/(per.pressure.V_flow[2] - per.pressure.V_flow[1])) *per.pressure.V_flow[1] "Maximum head"; parameter Real delta = 0.05 "Small value used to for regularization and to approximate an internal flow resistance of the fan"; parameter Real kRes(min=0, unit="kg/(s.m4)") = dpMax/V_flow_max*delta^2/10 "Coefficient for internal pressure drop of fan or pump"; parameter Integer curve= if (haveVMax and haveDPMax) or (nOri == 2) then 1 elseif haveVMax or haveDPMax then 2 else 3 "Flag, used to pick the right representatio of the fan or pump pressure curve"; final parameter Buildings.Fluid.Movers.BaseClasses.Characteristics.flowParametersInternal pCur1( final n = nOri, final V_flow = if (haveVMax and haveDPMax) or (nOri == 2) then {per.pressure.V_flow[i] for i in 1:nOri} else zeros(nOri), final dp = if (haveVMax and haveDPMax) or (nOri == 2) then {(per.pressure.dp[i] + per.pressure.V_flow[i] * kRes) for i in 1:nOri} else zeros(nOri)) "Volume flow rate vs. total pressure rise with correction for pump resistance added"; parameter Buildings.Fluid.Movers.BaseClasses.Characteristics.flowParametersInternal pCur2( final n = nOri + 1, V_flow = if (haveVMax and haveDPMax) or (nOri == 2) then zeros(nOri + 1) elseif haveVMax then cat(1, {0}, {per.pressure.V_flow[i] for i in 1:nOri}) elseif haveDPMax then cat(1, { per.pressure.V_flow[i] for i in 1:nOri}, {V_flow_max}) else zeros(nOri + 1), dp = if (haveVMax and haveDPMax) or (nOri == 2) then zeros(nOri + 1) elseif haveVMax then cat(1, {dpMax}, {per.pressure.dp[i] + per.pressure.V_flow[i] * kRes for i in 1:nOri}) elseif haveDPMax then cat(1, {per.pressure.dp[i] + per.pressure.V_flow[i] * kRes for i in 1:nOri}, {0}) else zeros(nOri+1)) "Volume flow rate vs. total pressure rise with correction for pump resistance added"; parameter Buildings.Fluid.Movers.BaseClasses.Characteristics.flowParametersInternal pCur3( final n = nOri + 2, V_flow = if (haveVMax and haveDPMax) or (nOri == 2) then zeros(nOri + 2) elseif haveVMax or haveDPMax then zeros(nOri + 2) else cat(1, {0}, {per.pressure.V_flow[i] for i in 1:nOri}, {V_flow_max}), dp = if (haveVMax and haveDPMax) or (nOri == 2) then zeros(nOri + 2) elseif haveVMax or haveDPMax then zeros(nOri + 2) else cat(1, {dpMax}, {per.pressure.dp[i] + per.pressure.V_flow[i] * kRes for i in 1:nOri}, {0})) "Volume flow rate vs. total pressure rise with correction for pump resistance added"; parameter Real preDer1[nOri](each fixed=false) "Derivatives of flow rate vs. pressure at the support points"; parameter Real preDer2[nOri+1](each fixed=false) "Derivatives of flow rate vs. pressure at the support points"; parameter Real preDer3[nOri+2](each fixed=false) "Derivatives of flow rate vs. pressure at the support points"; parameter Real powDer[size(per.power.V_flow,1)]= if per.use_powerCharacteristic then Buildings.Utilities.Math.Functions.splineDerivatives( x=per.power.V_flow, y=per.power.P, ensureMonotonicity=Buildings.Utilities.Math.Functions.isMonotonic(x=per.power.P, strict=false)) else zeros(size(per.power.V_flow,1)) "Coefficients for polynomial of power vs. flow rate"; parameter Boolean haveMinimumDecrease= Modelica.Math.BooleanVectors.allTrue({(per.pressure.dp[i + 1] - per.pressure.dp[i])/(per.pressure.V_flow[i + 1] - per.pressure.V_flow[ i]) < -kRes for i in 1:nOri - 1}) "Flag used for reporting"; parameter Boolean haveDPMax = (abs(per.pressure.V_flow[1]) < Modelica.Constants.eps) "Flag, true if user specified data that contain dpMax"; Modelica.Blocks.Interfaces.RealOutput dp_internal "If dp is prescribed, use dp_in and solve for r_N, otherwise compute dp using r_N"; function getPerformanceDataAsString input Buildings.Fluid.Movers.BaseClasses.Characteristics.flowParameters pressure "Performance data"; input Real derivative[:](unit="kg/(s.m4)") "Derivative"; input Integer minimumLength = 6 "Minimum width of result"; input Integer significantDigits = 6 "Number of significant digits"; output String str "String representation"; algorithm str :=""; for i in 1:size(derivative, 1) loop str :=str + " V_flow[" + String(i) + "]=" + String( pressure.V_flow[i], minimumLength=minimumLength, significantDigits=significantDigits) + "\t" + "dp[" + String(i) + "]=" + String( pressure.dp[i], minimumLength=minimumLength, significantDigits=significantDigits) + "\tResulting derivative dp/dV_flow = " + String( derivative[i], minimumLength=minimumLength, significantDigits=significantDigits) + "\n"; end for; end getPerformanceDataAsString; function getArrayAsString input Real array[:] "Array to be printed"; input String varName "Variable name"; input Integer minimumLength = 6 "Minimum width of result"; input Integer significantDigits = 6 "Number of significant digits"; output String str "String representation"; algorithm str :=""; for i in 1:size(array, 1) loop str :=str + " " + varName + "[" + String(i) + "]=" + String( array[i], minimumLength=minimumLength, significantDigits=significantDigits) + "\n"; end for; end getArrayAsString; initial equation // Check validity of data assert(nOri > 1, "Must have at least two data points for pressure.V_flow."); assert(Buildings.Utilities.Math.Functions.isMonotonic(x=per.pressure.V_flow, strict=true) and per.pressure.V_flow[1] > -Modelica.Constants.eps, "The fan pressure rise must be a strictly decreasing sequence with respect to the volume flow rate, with the first element for the fan pressure raise being non-zero. The following performance data have been entered: " + getArrayAsString(per.pressure.V_flow, "pressure.V_flow")); if not haveVMax then assert((per.pressure.V_flow[nOri]-per.pressure.V_flow[nOri-1]) /((per.pressure.dp[nOri]-per.pressure.dp[nOri-1]))<0, "The last two pressure points for the fan or pump performance curve must be decreasing. You need to set more reasonable parameters. Received " + getArrayAsString(per.pressure.dp, "dp")); end if; // Write warning if the volumetric flow rate versus pressure curve does not satisfy // the minimum decrease condition if (not haveMinimumDecrease) then Modelica.Utilities.Streams.print(" Warning: ======== It is recommended that the volume flow rate versus pressure relation of the fan or pump satisfies the minimum decrease condition (per.pressure.dp[i+1]-per.pressure.dp[i]) d[i] = ------------------------------------------------- < " + String(-kRes) + " (per.pressure.V_flow[i+1]-per.pressure.V_flow[i]) is " + getArrayAsString({(per.pressure.dp[i+1]-per.pressure.dp[i]) /(per.pressure.V_flow[i+1]-per.pressure.V_flow[i]) for i in 1:nOri-1}, "d") + " Otherwise, a solution to the equations may not exist if the fan or pump speed is reduced. In this situation, the solver will fail due to non-convergence and the simulation stops."); end if; // Correction for flow resistance of pump or fan if (haveVMax and haveDPMax) or (nOri == 2) then // ----- Curve 1 // V_flow_max and dpMax are provided by the user, or we only have two data points preDer1= Buildings.Utilities.Math.Functions.splineDerivatives(x=pCur1.V_flow, y=pCur1.dp); preDer2= zeros(nOri + 1); preDer3= zeros(nOri + 2); elseif haveVMax or haveDPMax then // ----- Curve 2 // V_flow_max or dpMax is provided by the user, but not both preDer1= zeros(nOri); preDer2= Buildings.Utilities.Math.Functions.splineDerivatives(x=pCur2.V_flow, y=pCur2.dp); preDer3= zeros(nOri + 2); else // ----- Curve 3 // Neither V_flow_max nor dpMax are provided by the user preDer1= zeros(nOri); preDer2= zeros(nOri + 1); preDer3= Buildings.Utilities.Math.Functions.splineDerivatives(x=pCur3.V_flow, y=pCur3.dp); end if; // Compute derivatives for cubic spline motDer = if per.use_powerCharacteristic then zeros(size(per.motorEfficiency.V_flow, 1)) elseif (size(per.motorEfficiency.V_flow, 1) == 1) then {0} else Buildings.Utilities.Math.Functions.splineDerivatives( x=per.motorEfficiency.V_flow, y=per.motorEfficiency.eta, ensureMonotonicity=Buildings.Utilities.Math.Functions.isMonotonic(x=per.motorEfficiency.eta, strict=false)); hydDer = if per.use_powerCharacteristic then zeros(size(per.hydraulicEfficiency.V_flow, 1)) elseif (size(per.hydraulicEfficiency.V_flow, 1) == 1) then {0} else Buildings.Utilities.Math.Functions.splineDerivatives(x=per.hydraulicEfficiency.V_flow, y=per.hydraulicEfficiency.eta); assert(homotopyInitialization, "In " + getInstanceName() + ": The constant homotopyInitialization has been modified from its default value. This constant will be removed in future releases.", level = AssertionLevel.warning); equation //assign values of dp and r_N, depending on which variable exists and is prescribed connect(dp_internal,dp); connect(dp_internal,dp_in); connect(r_N, y_in); y_out=r_N; V_flow = m_flow/rho; // Hydraulic equations r_V = V_flow/V_flow_max; // If the speed is not prescribed and we do not require exact power computations, we set r_N = 1. // Similarity laws are then not used, meaning the power computation is less accurate. // This however has the advantage that no non-linear algebraic loop is formed and // it allows an implementation when the pressure curve is unknown. if (computePowerUsingSimilarityLaws == false) and preVar <> Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.Speed then r_N=1; else // For the homotopy method, we approximate dp by an equation // that is linear in V_flow, and that goes linearly to 0 as r_N goes to 0. // The three branches below are identical, except that we pass either // pCur1, pCur2 or pCur3, and preDer1, preDer2 or preDer3 if (curve == 1) then if homotopyInitialization then V_flow*kRes + dp_internal = homotopy(actual=cha.pressure( V_flow=V_flow, r_N=r_N, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer1, per=pCur1), simplified=r_N * (cha.pressure( V_flow=V_flow_nominal, r_N=1, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer1, per=pCur1) +(V_flow-V_flow_nominal) * (cha.pressure( V_flow=(1+delta)*V_flow_nominal, r_N=1, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer1, per=pCur1) -cha.pressure(V_flow=(1-delta)*V_flow_nominal, r_N=1, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer1, per=pCur1)) /(2*delta*V_flow_nominal))); else V_flow*kRes + dp_internal= cha.pressure(V_flow=V_flow, r_N=r_N, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer1, per=pCur1); end if; // end of computation for this branch elseif (curve == 2) then if homotopyInitialization then V_flow*kRes + dp_internal = homotopy(actual=cha.pressure( V_flow=V_flow, r_N=r_N, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer2, per=pCur2), simplified=r_N * (cha.pressure( V_flow=V_flow_nominal, r_N=1, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer2, per=pCur2) +(V_flow-V_flow_nominal) * (cha.pressure( V_flow=(1+delta)*V_flow_nominal, r_N=1, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer2, per=pCur2) -cha.pressure(V_flow=(1-delta)*V_flow_nominal, r_N=1, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer2, per=pCur2)) /(2*delta*V_flow_nominal))); else V_flow*kRes + dp_internal= cha.pressure(V_flow=V_flow, r_N=r_N, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer2, per=pCur2); end if; // end of computation for this branch else if homotopyInitialization then V_flow*kRes + dp_internal = homotopy(actual=cha.pressure( V_flow=V_flow, r_N=r_N, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer3, per=pCur3), simplified=r_N * (cha.pressure( V_flow=V_flow_nominal, r_N=1, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer3, per=pCur3) +(V_flow-V_flow_nominal)* (cha.pressure(V_flow=(1+delta)*V_flow_nominal, r_N=1, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer3, per=pCur3) -cha.pressure(V_flow=(1-delta)*V_flow_nominal, r_N=1, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer3, per=pCur3)) /(2*delta*V_flow_nominal))); else V_flow*kRes + dp_internal= cha.pressure(V_flow=V_flow, r_N=r_N, dpMax=dpMax, V_flow_max=V_flow_max, d=preDer3, per=pCur3); end if; // end of computation for this branch end if; // end of if/else choosing between exact/simplified power computation end if; // Flow work WFlo = Buildings.Utilities.Math.Functions.smoothMax( x1=dp_internal*V_flow, x2=0, deltaX=1E-4*dpMax*V_flow_max); // Power consumption if per.use_powerCharacteristic then // For the homotopy, we want P/V_flow to be bounded as V_flow -> 0 to avoid a very high medium // temperature near zero flow. if homotopyInitialization then PEle = homotopy(actual=cha.power(per=per.power, V_flow=V_flow, r_N=r_N, d=powDer, delta=delta), simplified=V_flow/V_flow_nominal* cha.power(per=per.power, V_flow=V_flow_nominal, r_N=1, d=powDer, delta=delta)); else PEle = (rho/rho_default)*cha.power(per=per.power, V_flow=V_flow, r_N=r_N, d=powDer, delta=delta); end if; // To compute the efficiency, we set a lower bound on the electricity consumption. // This is needed because WFlo can be close to zero when P is zero, thereby // causing a division by zero. // Earlier versions of the model computed WFlo = eta * P, but this caused // a division by zero. eta = WFlo / Buildings.Utilities.Math.Functions.smoothMax(x1=PEle, x2=1E-5, deltaX=1E-6); // In this configuration, we only know the total power consumption. // Because nothing is known about etaMot versus etaHyd, we set etaHyd=1. This will // cause etaMot=eta, because eta=etaHyd*etaMot. // Earlier versions used etaMot=sqrt(eta), but as eta->0, this function has // and infinite derivative. etaHyd = 1; etaMot = eta; else if homotopyInitialization then etaHyd = homotopy(actual=cha.efficiency(per=per.hydraulicEfficiency, V_flow=V_flow, d=hydDer, r_N=r_N, delta=delta), simplified=cha.efficiency(per=per.hydraulicEfficiency, V_flow=V_flow_max, d=hydDer, r_N=r_N, delta=delta)); etaMot = homotopy(actual=cha.efficiency(per=per.motorEfficiency, V_flow=V_flow, d=motDer, r_N=r_N, delta=delta), simplified=cha.efficiency(per=per.motorEfficiency, V_flow=V_flow_max, d=motDer, r_N=r_N, delta=delta)); else etaHyd = cha.efficiency(per=per.hydraulicEfficiency, V_flow=V_flow, d=hydDer, r_N=r_N, delta=delta); etaMot = cha.efficiency(per=per.motorEfficiency, V_flow=V_flow, d=motDer, r_N=r_N, delta=delta); end if; // To compute the electrical power, we set a lower bound for eta to avoid // a division by zero. PEle = WFlo / Buildings.Utilities.Math.Functions.smoothMax(x1=eta, x2=1E-5, deltaX=1E-6); eta = etaHyd * etaMot; end if; end FlowMachineInterface;

Buildings.Fluid.Movers.BaseClasses.IdealSource Buildings.Fluid.Movers.BaseClasses.IdealSource

Base class for pressure and mass flow source with optional power input

Buildings.Fluid.Movers.BaseClasses.IdealSource

Information

Model of a fictitious pipe that is used as a base class for a pressure source or to prescribe a mass flow rate.

Note that for fans and pumps with dynamic balance, both the heat and the flow work are added to the volume of air or water. This simplifies the equations compared to adding heat to the volume, and flow work to this model.

Typically either control_m_flow or control_dp should be true to avoid a singular system. If control_m_flow = true, then the mass flow rate is set to the value of the input connector m_flow_in. Otherwise, this model does not specify the mass flow rate. Similarly, if control_dp = true, the head is equal to the value of the input connector dp_in. Otherwise, this model does not specify the head.

Extends from Buildings.Fluid.Interfaces.PartialTwoPortTransport (Partial element transporting fluid between two ports without storage of mass or energy).

Parameters

TypeNameDefaultDescription
replaceable package MediumPartialMediumMedium in the component
Booleancontrol_m_flow if true, then the mass flow rate is equal to the value of m_flow_in
Booleancontrol_dpnot control_m_flowif true, then the head is equal to the value of dp_in
Assumptions
BooleanallowFlowReversaltrue= false to simplify equations, assuming, but not enforcing, no flow reversal
Advanced
PressureDifferencedp_start0Guess value of dp = port_a.p - port_b.p [Pa]
MassFlowRatem_flow_start0Guess value of m_flow = port_a.m_flow [kg/s]
MassFlowRatem_flow_small Small mass flow rate for regularization of zero flow [kg/s]
Diagnostics
Booleanshow_Tfalse= true, if temperatures at port_a and port_b are computed
Booleanshow_V_flowtrue= true, if volume flow rate at inflowing port is computed

Connectors

TypeNameDescription
FluidPort_aport_aFluid connector a (positive design flow direction is from port_a to port_b)
FluidPort_bport_bFluid connector b (positive design flow direction is from port_a to port_b)
input RealInputm_flow_inPrescribed mass flow rate [kg/s]
input RealInputdp_inPrescribed pressure difference port_a.p-port_b.p [Pa]

Modelica definition

model IdealSource "Base class for pressure and mass flow source with optional power input" extends Buildings.Fluid.Interfaces.PartialTwoPortTransport(show_T=false); // Quantity to control parameter Boolean control_m_flow "if true, then the mass flow rate is equal to the value of m_flow_in"; parameter Boolean control_dp = not control_m_flow "if true, then the head is equal to the value of dp_in"; Modelica.Blocks.Interfaces.RealInput m_flow_in(unit="kg/s") if control_m_flow "Prescribed mass flow rate"; Modelica.Blocks.Interfaces.RealInput dp_in(unit="Pa") if control_dp "Prescribed pressure difference port_a.p-port_b.p"; protected Modelica.Blocks.Interfaces.RealInput m_flow_internal(unit="kg/s") "Needed to connect to conditional connector"; Modelica.Blocks.Interfaces.RealInput dp_internal(unit="Pa") "Needed to connect to conditional connector"; equation // Ideal control if control_m_flow then m_flow = m_flow_internal; else m_flow_internal = 0; end if; if control_dp then dp = dp_internal; else dp_internal = 0; end if; connect(dp_internal, dp_in); connect(m_flow_internal, m_flow_in); // Energy balance (no storage) port_a.h_outflow = if allowFlowReversal then inStream(port_b.h_outflow) else Medium.h_default; port_b.h_outflow = inStream(port_a.h_outflow); end IdealSource;

Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine

Partial model to interface fan or pump models with the medium

Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine

Information

This is the base model for fans and pumps. It provides an interface between the equations that compute head and power consumption, and the implementation of the energy and pressure balance of the fluid.

Optionally, the fluid volume is computed using a dynamic balance or a steady-state balance.

The parameter addPowerToMedium determines whether any power is added to the fluid. The default is addPowerToMedium=true, and hence the outlet enthalpy is higher than the inlet enthalpy if the flow device is operating. The setting addPowerToMedium=false is physically incorrect (since the flow work, the flow friction and the fan heat do not increase the enthalpy of the medium), but this setting does in some cases lead to simpler equations and more robust simulation, in particular if the mass flow is equal to zero.

Extends from Buildings.Fluid.Interfaces.LumpedVolumeDeclarations (Declarations for lumped volumes), Buildings.Fluid.Interfaces.PartialTwoPortInterface (Partial model transporting fluid between two ports without storing mass or energy).

Parameters

TypeNameDefaultDescription
replaceable package MediumPartialMediumMedium in the component
Genericperredeclare parameter Building...Record with performance data
BooleancomputePowerUsingSimilarityLaws = true, compute power exactly, using similarity laws. Otherwise approximate.
BooleanaddPowerToMediumtrueSet to false to avoid any power (=heat and flow work) being added to medium (may give simpler equations)
BooleannominalValuesDefineDefaultPressureCurvefalseSet to true to avoid warning if m_flow_nominal and dp_nominal are used to construct the default pressure curve
Control
InputTypeinputTypeBuildings.Fluid.Types.InputT...Control input type
RealconstInput0Constant input set point
RealstageInputs[:] Vector of input set points corresponding to stages
Dynamics
Conservation equations
DynamicsenergyDynamicsModelica.Fluid.Types.Dynamic...Type of energy balance: dynamic (3 initialization options) or steady state
RealmSenFac1Factor for scaling the sensible thermal mass of the volume
Nominal condition
Timetau1Time constant of fluid volume for nominal flow, used if energy or mass balance is dynamic [s]
Filtered speed
Booleanuse_inputFiltertrue= true, if speed is filtered with a 2nd order CriticalDamping filter
TimeriseTime30Rise time of the filter (time to reach 99.6 % of the speed) [s]
InitinitModelica.Blocks.Types.Init.I...Type of initialization (no init/steady state/initial state/initial output)
Advanced
Dynamics
DynamicsmassDynamicsenergyDynamicsType of mass balance: dynamic (3 initialization options) or steady state, must be steady state if energyDynamics is steady state
MassFlowRatem_flow_small1E-4*abs(m_flow_nominal)Small mass flow rate for regularization of zero flow [kg/s]
Diagnostics
Booleanshow_Tfalse= true, if actual temperature at port is computed
Initialization
AbsolutePressurep_startMedium.p_defaultStart value of pressure [Pa]
TemperatureT_startMedium.T_defaultStart value of temperature [K]
MassFractionX_start[Medium.nX]Medium.X_defaultStart value of mass fractions m_i/m [kg/kg]
ExtraPropertyC_start[Medium.nC]fill(0, Medium.nC)Start value of trace substances
ExtraPropertyC_nominal[Medium.nC]fill(1E-2, Medium.nC)Nominal value of trace substances. (Set to typical order of magnitude.)
Assumptions
BooleanallowFlowReversaltrue= false to simplify equations, assuming, but not enforcing, no flow reversal

Connectors

TypeNameDescription
FluidPort_aport_aFluid connector a (positive design flow direction is from port_a to port_b)
FluidPort_bport_bFluid connector b (positive design flow direction is from port_a to port_b)
input IntegerInputstageStage input signal for the pressure head
output RealOutputy_actualActual normalised pump speed that is used for computations [1]
output RealOutputPElectrical power consumed [W]
HeatPort_aheatPortHeat dissipation to environment

Modelica definition

partial model PartialFlowMachine "Partial model to interface fan or pump models with the medium" extends Buildings.Fluid.Interfaces.LumpedVolumeDeclarations( final massDynamics=energyDynamics, final mSenFac=1); extends Buildings.Fluid.Interfaces.PartialTwoPortInterface( m_flow_nominal(final min=Modelica.Constants.small), show_T=false, port_a( h_outflow(start=h_outflow_start)), port_b( h_outflow(start=h_outflow_start), p(start=p_start), final m_flow(max = if allowFlowReversal then +Modelica.Constants.inf else 0))); replaceable parameter Buildings.Fluid.Movers.Data.Generic per constrainedby Buildings.Fluid.Movers.Data.Generic "Record with performance data"; parameter Buildings.Fluid.Types.InputType inputType = Buildings.Fluid.Types.InputType.Continuous "Control input type"; parameter Real constInput = 0 "Constant input set point"; parameter Real stageInputs[:] "Vector of input set points corresponding to stages"; parameter Boolean computePowerUsingSimilarityLaws "= true, compute power exactly, using similarity laws. Otherwise approximate."; parameter Boolean addPowerToMedium=true "Set to false to avoid any power (=heat and flow work) being added to medium (may give simpler equations)"; parameter Boolean nominalValuesDefineDefaultPressureCurve = false "Set to true to avoid warning if m_flow_nominal and dp_nominal are used to construct the default pressure curve"; parameter Modelica.Units.SI.Time tau=1 "Time constant of fluid volume for nominal flow, used if energy or mass balance is dynamic"; // Classes used to implement the filtered speed parameter Boolean use_inputFilter=true "= true, if speed is filtered with a 2nd order CriticalDamping filter"; parameter Modelica.Units.SI.Time riseTime=30 "Rise time of the filter (time to reach 99.6 % of the speed)"; parameter Modelica.Blocks.Types.Init init=Modelica.Blocks.Types.Init.InitialOutput "Type of initialization (no init/steady state/initial state/initial output)"; // Connectors and ports Modelica.Blocks.Interfaces.IntegerInput stage if inputType == Buildings.Fluid.Types.InputType.Stages "Stage input signal for the pressure head"; Modelica.Blocks.Interfaces.RealOutput y_actual( final unit="1") "Actual normalised pump speed that is used for computations"; Modelica.Blocks.Interfaces.RealOutput P( quantity="Power", final unit="W") "Electrical power consumed"; Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort "Heat dissipation to environment"; // Variables Modelica.Units.SI.VolumeFlowRate VMachine_flow(start=_VMachine_flow) = eff.V_flow "Volume flow rate"; Modelica.Units.SI.PressureDifference dpMachine(displayUnit="Pa") = -preSou.dp "Pressure difference"; Real eta(unit="1", final quantity="Efficiency") = eff.eta "Global efficiency"; Real etaHyd(unit="1", final quantity="Efficiency") = eff.etaHyd "Hydraulic efficiency"; Real etaMot(unit="1", final quantity="Efficiency") = eff.etaMot "Motor efficiency"; // Quantity to control protected final parameter Modelica.Units.SI.VolumeFlowRate _VMachine_flow=0 "Start value for VMachine_flow, used to avoid a warning if not specified"; parameter Types.PrescribedVariable preVar "Type of prescribed variable"; // The parameter speedIsInput is required to conditionally remove the instance gain. // If the conditional removal of this instance where to use the test // preVar == Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.Speed, // then OpenModelica fails to translate the model with the message // .../PartialFlowMachine.mo:185:3-189:70:writable] // Error: Variable Types.PrescribedVariable.Speed not found in scope // Buildings.Fluid.Movers.SpeedControlled_y$floMac1. final parameter Boolean speedIsInput= (preVar == Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.Speed) "Parameter that is true if speed is the controlled variables"; final parameter Integer nOri = size(per.pressure.V_flow, 1) "Number of data points for pressure curve"; final parameter Boolean haveVMax = (abs(per.pressure.dp[nOri]) < Modelica.Constants.eps) "Flag, true if user specified data that contain V_flow_max"; final parameter Modelica.Units.SI.VolumeFlowRate V_flow_max=if per.havePressureCurve then (if haveVMax then per.pressure.V_flow[nOri] else per.pressure.V_flow[ nOri] - (per.pressure.V_flow[nOri] - per.pressure.V_flow[nOri - 1])/((per.pressure.dp[ nOri] - per.pressure.dp[nOri - 1]))*per.pressure.dp[nOri]) else m_flow_nominal/rho_default "Maximum volume flow rate, used for smoothing"; final parameter Modelica.Units.SI.Density rho_default=Medium.density_pTX( p=Medium.p_default, T=Medium.T_default, X=Medium.X_default) "Default medium density"; final parameter Medium.ThermodynamicState sta_start=Medium.setState_pTX( T=T_start, p=p_start, X=X_start) "Medium state at start values"; final parameter Modelica.Units.SI.SpecificEnthalpy h_outflow_start= Medium.specificEnthalpy(sta_start) "Start value for outflowing enthalpy"; final parameter Modelica.Units.SI.Frequency fCut=5/(2*Modelica.Constants.pi* riseTime) "Cut-off frequency of filter"; Modelica.Blocks.Sources.Constant[size(stageInputs, 1)] stageValues( final k=stageInputs) if inputType == Buildings.Fluid.Types.InputType.Stages "Stage input values"; Modelica.Blocks.Sources.Constant setConst( final k=constInput) if inputType == Buildings.Fluid.Types.InputType.Constant "Constant input set point"; Extractor extractor(final nin=size(stageInputs,1)) if inputType == Buildings.Fluid.Types.InputType.Stages "Stage input extractor"; Modelica.Blocks.Routing.RealPassThrough inputSwitch "Dummy connection for easy connection of input options"; Buildings.Fluid.Delays.DelayFirstOrder vol( redeclare final package Medium = Medium, final tau=tau, final energyDynamics=energyDynamics, final T_start=T_start, final X_start=X_start, final C_start=C_start, final m_flow_nominal=m_flow_nominal, final m_flow_small=m_flow_small, final p_start=p_start, final prescribedHeatFlowRate=true, final allowFlowReversal=allowFlowReversal, nPorts=2) "Fluid volume for dynamic model"; Buildings.Fluid.BaseClasses.ActuatorFilter filter( final n=2, final f=fCut, final normalized=true, final initType=init) if use_inputFilter "Second order filter to approximate dynamics of pump speed, and to improve numerics"; Modelica.Blocks.Math.Gain gaiSpe(y(final unit="1")) if inputType == Buildings.Fluid.Types.InputType.Continuous and speedIsInput "Gain to normalized speed using speed_nominal or speed_rpm_nominal"; Buildings.Fluid.Movers.BaseClasses.IdealSource preSou( redeclare final package Medium = Medium, final m_flow_small=m_flow_small, final allowFlowReversal=allowFlowReversal, final control_m_flow= (preVar == Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.FlowRate)) "Pressure source"; Buildings.Fluid.Movers.BaseClasses.PowerInterface heaDis( final motorCooledByFluid=per.motorCooledByFluid, final delta_V_flow=1E-3*V_flow_max) if addPowerToMedium "Heat dissipation into medium"; Modelica.Blocks.Math.Add PToMed(final k1=1, final k2=1) if addPowerToMedium "Heat and work input into medium"; Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow prePow( final alpha=0) if addPowerToMedium "Prescribed power (=heat and flow work) flow for dynamic model"; Modelica.Blocks.Sources.RealExpression rho_inlet(y= Medium.density( Medium.setState_phX(port_a.p, inStream(port_a.h_outflow), inStream(port_a.Xi_outflow)))) "Density of the inflowing fluid"; Buildings.Fluid.Sensors.MassFlowRate senMasFlo( redeclare final package Medium = Medium) "Mass flow rate sensor"; Sensors.RelativePressure senRelPre( redeclare final package Medium = Medium) "Head of mover"; // Because the speed data are not used by FlowMachineInterface, we set them // to zero. FlowMachineInterface eff( per( final hydraulicEfficiency = per.hydraulicEfficiency, final motorEfficiency = per.motorEfficiency, final motorCooledByFluid = per.motorCooledByFluid, final speed_nominal = 0, final constantSpeed = 0, final speeds = {0}, final power = per.power), final nOri = nOri, final rho_default=rho_default, final computePowerUsingSimilarityLaws=computePowerUsingSimilarityLaws, final haveVMax=haveVMax, final V_flow_max=V_flow_max, r_V(start=m_flow_nominal/rho_default), final preVar=preVar) "Flow machine"; protected block Extractor "Extract scalar signal out of signal vector dependent on IntegerRealInput index" extends Modelica.Blocks.Interfaces.MISO; Modelica.Blocks.Interfaces.IntegerInput index "Integer input for control input"; equation y = sum({if index == i then u[i] else 0 for i in 1:nin}); end Extractor; initial equation // Check incorrect value of m_flow_nominal assert(m_flow_nominal >= Modelica.Constants.small, "In "+ getInstanceName()+ ": The value of parameter m_flow_nominal should be greater or equal than " + String(Modelica.Constants.small) + " but it equals " + String(m_flow_nominal)); // The control signal is dp or m_flow but the user did not provide a pump curve. // Hence, the speed is computed using default values, which likely are wrong. // Therefore, scaling the power using the speed is inaccurate. assert(nominalValuesDefineDefaultPressureCurve or per.havePressureCurve or (preVar == Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.Speed), "*** Warning: You are using a flow or pressure controlled mover with the default pressure curve. This leads to approximate calculations of the electrical power consumption. Add the correct pressure curve in the record per to obtain an accurate computation. Setting nominalValuesDefineDefaultPressureCurve=true will suppress this warning.", level=AssertionLevel.warning); // The control signal is dp or m_flow but the user did not provide a pump curve. // Hence, the speed is computed using default values, which likely are wrong. // In addition, the user wants to use (V_flow, P) to compute the power. // This can lead to using a power that is less than the flow work. We avoid // this by ignoring the setting of per.use_powerCharacteristics. // The comment is split into two parts since otherwise the JModelica C-compiler // throws warnings. assert(nominalValuesDefineDefaultPressureCurve or (per.havePressureCurve or (preVar == Buildings.Fluid.Movers.BaseClasses.Types.PrescribedVariable.Speed)) or per.use_powerCharacteristic == false, "*** Warning: You are using a flow or pressure controlled mover with the default pressure curve and you set use_powerCharacteristic = true. Since this can cause wrong power consumption, the model will overwrite this setting and use instead use_powerCharacteristic = false." + "Since this causes the efficiency curve to be used, make sure that the efficiency curves in the performance record per are correct or add the pressure curve of the mover. Setting nominalValuesDefineDefaultPressureCurve=true will suppress this warning.", level=AssertionLevel.warning); equation connect(prePow.port, vol.heatPort); connect(vol.heatPort, heatPort); connect(preSou.port_b, port_b); connect(stageValues.y, extractor.u); connect(extractor.y, inputSwitch.u); connect(setConst.y, inputSwitch.u); connect(extractor.index, stage); connect(PToMed.y, prePow.Q_flow); connect(PToMed.u1, heaDis.Q_flow); connect(senRelPre.port_b, preSou.port_a); connect(senRelPre.port_a, preSou.port_b); connect(heaDis.etaHyd,eff. etaHyd); connect(heaDis.V_flow,eff. V_flow); connect(eff.PEle, heaDis.PEle); connect(eff.WFlo, heaDis.WFlo); connect(rho_inlet.y,eff. rho); connect(eff.m_flow, senMasFlo.m_flow); connect(eff.PEle, P); connect(eff.WFlo, PToMed.u2); connect(inputSwitch.y, filter.u); connect(senRelPre.p_rel, eff.dp_in); connect(eff.y_out, y_actual); connect(port_a, vol.ports[1]); connect(vol.ports[2], senMasFlo.port_a); connect(senMasFlo.port_b, preSou.port_a); end PartialFlowMachine;

Buildings.Fluid.Movers.BaseClasses.PowerInterface Buildings.Fluid.Movers.BaseClasses.PowerInterface

Partial model to compute power draw and heat dissipation of fans and pumps

Buildings.Fluid.Movers.BaseClasses.PowerInterface

Information

Block that implements the functions to compute the heat dissipation of fans and pumps. It is used by the model Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine.

Extends from Modelica.Blocks.Icons.Block (Basic graphical layout of input/output block).

Parameters

TypeNameDefaultDescription
BooleanmotorCooledByFluid Flag, true if the motor is cooled by the fluid stream
VolumeFlowRatedelta_V_flow Factor used for setting heat input into medium to zero at very small flows [m3/s]

Connectors

TypeNameDescription
input RealInputetaHydHydraulic efficiency [1]
input RealInputV_flowVolume flow rate [m3/s]
input RealInputWFloFlow work [W]
input RealInputPEleElectrical power consumed [W]
output RealOutputQ_flowHeat input from fan or pump to medium [W]

Modelica definition

model PowerInterface "Partial model to compute power draw and heat dissipation of fans and pumps" extends Modelica.Blocks.Icons.Block; constant Boolean homotopyInitialization = true "= true, use homotopy method"; parameter Boolean motorCooledByFluid "Flag, true if the motor is cooled by the fluid stream"; parameter Modelica.Units.SI.VolumeFlowRate delta_V_flow "Factor used for setting heat input into medium to zero at very small flows"; Modelica.Blocks.Interfaces.RealInput etaHyd( final quantity="Efficiency", final unit="1") "Hydraulic efficiency"; Modelica.Blocks.Interfaces.RealInput V_flow( final quantity="VolumeFlowRate", final unit="m3/s") "Volume flow rate"; Modelica.Blocks.Interfaces.RealInput WFlo( final quantity="Power", final unit="W") "Flow work"; Modelica.Blocks.Interfaces.RealInput PEle( final quantity="Power", final unit="W") "Electrical power consumed"; Modelica.Blocks.Interfaces.RealOutput Q_flow( quantity="Power", final unit="W") "Heat input from fan or pump to medium"; Modelica.Units.SI.Power WHyd "Hydraulic power input (converted to flow work and heat)"; protected Modelica.Units.SI.HeatFlowRate QThe_flow "Heat input from fan or pump to medium"; initial equation assert(homotopyInitialization, "In " + getInstanceName() + ": The constant homotopyInitialization has been modified from its default value. This constant will be removed in future releases.", level = AssertionLevel.warning); equation // Hydraulic power (transmitted by shaft), etaHyd = WFlo/WHyd etaHyd * WHyd = WFlo; // Heat input into medium QThe_flow + WFlo = if motorCooledByFluid then PEle else WHyd; // At m_flow = 0, the solver may still obtain positive values for QThe_flow. // The next statement sets the heat input into the medium to zero for very small flow rates. Q_flow = if homotopyInitialization then homotopy(actual=Buildings.Utilities.Math.Functions.regStep( y1=QThe_flow, y2=0, x=noEvent(abs(V_flow))-2*delta_V_flow, x_small=delta_V_flow), simplified=0) else Buildings.Utilities.Math.Functions.regStep( y1=QThe_flow, y2=0, x=noEvent(abs(V_flow))-2*delta_V_flow, x_small=delta_V_flow); end PowerInterface;

Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine.Extractor Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine.Extractor

Extract scalar signal out of signal vector dependent on IntegerRealInput index

Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine.Extractor

Information

Extends from Modelica.Blocks.Interfaces.MISO (Multiple Input Single Output continuous control block).

Parameters

TypeNameDefaultDescription
Integernin1Number of inputs

Connectors

TypeNameDescription
input RealInputu[nin]Connector of Real input signals
output RealOutputyConnector of Real output signal
input IntegerInputindexInteger input for control input

Modelica definition

block Extractor "Extract scalar signal out of signal vector dependent on IntegerRealInput index" extends Modelica.Blocks.Interfaces.MISO; Modelica.Blocks.Interfaces.IntegerInput index "Integer input for control input"; equation y = sum({if index == i then u[i] else 0 for i in 1:nin}); end Extractor;