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.Euler Euler Functions and data record templates for Euler number
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 (total pressure rise versus volume flow rate) 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 model computes the power and efficiency items in the list below.

See Buildings.Fluid.Movers.UsersGuide for how the user can provide power and efficiency information to the model.

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]
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 RealOutputWHydHydraulic work (shaft work, brake horsepower) [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"; 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.V_flow_max>Modelica.Constants.eps then per.V_flow_max else V_flow_nominal "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 WHyd( quantity="Power", final unit="W") "Hydraulic work (shaft work, brake horsepower)"; Modelica.Blocks.Interfaces.RealOutput PEle( quantity="Power", final unit="W") "Electrical power consumed"; Modelica.Blocks.Interfaces.RealOutput eta( final quantity="Efficiency", final unit="1", start = 0.49) "Overall efficiency"; // A start value is given to suppress the following translation warning: // "Some variables are iteration variables of the initialization problem: // but they are not given any explicit start values. Zero will be used." 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 etaDer[size(per.efficiency.V_flow,1)]= if not per.etaHydMet==Buildings.Fluid.Movers.BaseClasses.Types.HydraulicEfficiencyMethod.Efficiency_VolumeFlowRate then zeros(size(per.efficiency.V_flow,1)) elseif (size(per.efficiency.V_flow, 1) == 1) then {0} else Buildings.Utilities.Math.Functions.splineDerivatives( x=per.efficiency.V_flow, y=per.efficiency.eta, ensureMonotonicity=Buildings.Utilities.Math.Functions.isMonotonic( x=per.efficiency.eta, strict=false)) "Coefficients for cubic spline of total or hydraulic efficiency vs. volume flow rate"; final parameter Real motDer[size(per.motorEfficiency.V_flow, 1)]= if not per.etaMotMet==Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.Efficiency_VolumeFlowRate 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)) "Coefficients for cubic spline of motor efficiency vs. volume flow rate"; final parameter Real motDer_yMot[size(per.motorEfficiency_yMot.y,1)]= if not per.etaMotMet== Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.Efficiency_MotorPartLoadRatio then zeros(size(per.motorEfficiency_yMot.y,1)) elseif (size(per.motorEfficiency_yMot.y,1) == 1) then {0} else Buildings.Utilities.Math.Functions.splineDerivatives( x=per.motorEfficiency_yMot.y, y=per.motorEfficiency_yMot.eta, ensureMonotonicity=Buildings.Utilities.Math.Functions.isMonotonic( x=per.motorEfficiency_yMot.eta, strict=false)) "Coefficients for cubic spline of motor efficiency vs. motor PLR"; final parameter Real motDer_yMot_generic[9]= if per.etaMotMet== Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.GenericCurve or (per.etaMotMet== Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.NotProvided and per.haveWMot_nominal) then Buildings.Utilities.Math.Functions.splineDerivatives( x=per.motorEfficiency_yMot_generic.y, y=per.motorEfficiency_yMot_generic.eta, ensureMonotonicity=true) else zeros(9) "Coefficients for cubic spline of motor efficiency vs. motor PLR with generic curves"; final parameter Modelica.Units.SI.PressureDifference dpMax( displayUnit="Pa")= per.dpMax "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 the 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 representation of the fan or pump's 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 fan or pump's 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 fan or pump's 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 fan or pump's 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.etaHydMet== Buildings.Fluid.Movers.BaseClasses.Types.HydraulicEfficiencyMethod.Power_VolumeFlowRate 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"; final parameter Buildings.Fluid.Movers.BaseClasses.Euler.powerWithDerivative powEu_internal= if (curve == 1) then Buildings.Fluid.Movers.BaseClasses.Euler.power(peak=per.peak,pressure=pCur1) elseif (curve == 2) then Buildings.Fluid.Movers.BaseClasses.Euler.power(peak=per.peak,pressure=pCur2) else Buildings.Fluid.Movers.BaseClasses.Euler.power(peak=per.peak,pressure=pCur3) "Intermediate parameter"; final parameter Buildings.Fluid.Movers.BaseClasses.Characteristics.powerParameters powEu( V_flow = powEu_internal.V_flow, P = powEu_internal.P) "Power vs. volumetric flow rate computed from Euler number"; final parameter Real powEuDer[:] = powEu_internal.d "Power derivative with respect to volumetric flow rate computed from Euler number"; parameter Boolean haveMinimumDecrease= if nOri<2 then false else 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"; Modelica.Units.SI.Efficiency eta_internal "Either eta or etaHyd"; Modelica.Units.SI.Power P_internal "Either PEle or WHyd"; parameter Real deltaP = 1E-4 * V_flow_max * dpMax "Small value for regularisation of power"; Real yMot(final min=0, final start=0.833)= if per.haveWMot_nominal then WHyd/per.WMot_nominal else 1 "Motor part load ratio"; 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(nOri>=2, "When the maximum flow is not specified, at least two points are needed for the power curve."); if nOri>=2 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's performance curve must be decreasing. Received " + getArrayAsString(per.pressure.dp, "dp")); end if; 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 satisfy 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's 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 the fan or pump if curve == 1 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 curve == 2 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; assert(not ((per.etaMotMet== Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.Efficiency_MotorPartLoadRatio or per.etaMotMet== Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.GenericCurve) and not per.haveWMot_nominal), "In " + getInstanceName() + ": etaMotMet is set to .Efficiency_MotorPartLoadRatio or .GenericCurve which requires the motor's rated power, but per.WMot_nominal is not assigned or cannot be estimated because no power curve is provided."); assert(max(per.power.P)<1E-6 or per.WMot_nominal>max(per.power.P)*0.99, "In " + getInstanceName() + ": The rated motor power provided in per.WMot_nominal is smaller than the maximum power provided in per.power. Use a larger value for per.WMot_nominal or leave it blank to allow the model to assume a default value."); 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; // Flow rate conversion 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; // Power and efficiency WFlo = Buildings.Utilities.Math.Functions.smoothMax( x1=dp_internal*V_flow, x2=0, deltaX=deltaP/2); if per.powerOrEfficiencyIsHydraulic then eta = etaHyd * etaMot; else etaHyd = Buildings.Utilities.Math.Functions.smoothMin( x1=eta/etaMot, x2=1, deltaX=1E-3); end if; // Hydraulic efficiency etaHyd and hydraulic work WHyd // or total efficiency eta and total electric power PEle // depending on the information provided if per.powerOrEfficiencyIsHydraulic then P_internal=WHyd; eta_internal=etaHyd; PEle = WFlo / Buildings.Utilities.Math.Functions.smoothMax( x1=eta, x2=1E-2, deltaX=1E-3); else P_internal=PEle; eta_internal=eta; WHyd = WFlo / Buildings.Utilities.Math.Functions.smoothMax( x1=etaMot, x2=1E-2, deltaX=1E-3); end if; if per.etaHydMet== Buildings.Fluid.Movers.BaseClasses.Types.HydraulicEfficiencyMethod.Power_VolumeFlowRate then if homotopyInitialization then P_internal = 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 P_internal = (rho/rho_default)*cha.power(per=per.power, V_flow=V_flow, r_N=r_N, d=powDer, delta=delta); end if; eta_internal = WFlo/Buildings.Utilities.Math.Functions.smoothMax( x1=P_internal, x2=deltaP, deltaX=deltaP/2); elseif per.etaHydMet== Buildings.Fluid.Movers.BaseClasses.Types.HydraulicEfficiencyMethod.EulerNumber then if homotopyInitialization then P_internal = homotopy(actual=cha.power(per=powEu, V_flow=V_flow, r_N=r_N, d=powEuDer, delta=delta), simplified=V_flow/V_flow_nominal* cha.power(per=powEu, V_flow=V_flow_nominal, r_N=1, d=powEuDer, delta=delta)); else P_internal = (rho/rho_default)*cha.power(per=powEu, V_flow=V_flow, r_N=r_N, d=powEuDer, delta=delta); end if; eta_internal = WFlo / Buildings.Utilities.Math.Functions.smoothMax( x1=P_internal, x2=deltaP, deltaX=deltaP/2); elseif per.etaHydMet == Buildings.Fluid.Movers.BaseClasses.Types.HydraulicEfficiencyMethod.Efficiency_VolumeFlowRate then if homotopyInitialization then eta_internal = homotopy(actual=cha.efficiency(per=per.efficiency, V_flow=V_flow, d=etaDer, r_N=r_N, delta=delta), simplified=cha.efficiency(per=per.efficiency, V_flow=V_flow_max, d=etaDer, r_N=r_N, delta=delta)); else eta_internal = cha.efficiency(per=per.efficiency, V_flow=V_flow, d=etaDer, r_N=r_N, delta=delta); end if; if per.powerOrEfficiencyIsHydraulic then P_internal=WFlo/Buildings.Utilities.Math.Functions.smoothMax( x1=eta_internal, x2=1E-2, deltaX=1E-3); else P_internal=WHyd/Buildings.Utilities.Math.Functions.smoothMax( x1=eta_internal, x2=1E-2, deltaX=1E-3); end if; else // Not provided if per.powerOrEfficiencyIsHydraulic then eta_internal=0.7; P_internal=WFlo/eta_internal; else eta_internal=0.49; P_internal=WHyd/eta_internal; end if; end if; // Motor efficiency etaMot if per.etaMotMet == Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.Efficiency_VolumeFlowRate then if homotopyInitialization then 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 etaMot = cha.efficiency(per=per.motorEfficiency, V_flow=V_flow, d=motDer, r_N=r_N, delta=delta); end if; elseif per.etaMotMet== Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.Efficiency_MotorPartLoadRatio then if homotopyInitialization then etaMot =homotopy(actual=cha.efficiency_yMot( per=per.motorEfficiency_yMot, y=yMot, d=motDer_yMot), simplified=cha.efficiency_yMot( per=per.motorEfficiency_yMot, y=1, d=motDer_yMot)); else etaMot =cha.efficiency_yMot( per=per.motorEfficiency_yMot, y=yMot, d=motDer_yMot); end if; elseif per.etaMotMet== Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.GenericCurve then if homotopyInitialization then etaMot =homotopy(actual=cha.efficiency_yMot( per=per.motorEfficiency_yMot_generic, y=yMot, d=motDer_yMot_generic), simplified=cha.efficiency_yMot( per=per.motorEfficiency_yMot_generic, y=1, d=motDer_yMot_generic)); else etaMot =cha.efficiency_yMot( per=per.motorEfficiency_yMot_generic, y=yMot, d=motDer_yMot_generic); end if; else // Not provided etaMot = 0.7; 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.

In the previous implementation, this model extends from Buildings.Fluid.Interfaces.PartialTwoPortInterface. Now it copies much of the code instead. This is to resolve a potential circular parameter binding that occurs when Buildings.Fluid.Movers.Preconfigured.SpeedControlled_y extends from Buildings.Fluid.Movers.SpeedControlled_y. The former uses the nominal flow rate provided by user to construct the pressure curve, whilst the latter uses the user-provided pressure curve to determine the nominal flow rate. The new implementation removes the original declaration of nominal flow rate from Buildings.Fluid.Interfaces.PartialTwoPortInterface and hides it (protected _m_flow_nominal) from the user. This way, A higher-level model (e.g. Buildings.Fluid.Movers.FlowControlled_dp), can still provide a default but not the other way around. See discussions in #1705.

Extends from Buildings.Fluid.Interfaces.LumpedVolumeDeclarations (Declarations for lumped volumes), Buildings.Fluid.Interfaces.PartialTwoPort (Partial component with two ports).

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 fan or 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.PartialTwoPort( port_a( p(start=Medium.p_default), h_outflow(start=h_outflow_start)), port_b( p(start=p_start), h_outflow(start=h_outflow_start))); 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 fan or 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 // Copied from Fluid.Interfaces.PartialTwoPortInterface parameter Modelica.Units.SI.MassFlowRate m_flow_small(min=0) = 1E-4*abs( _m_flow_nominal) "Small mass flow rate for regularization of zero flow"; // Diagnostics parameter Boolean show_T = false "= true, if actual temperature at port is computed"; Modelica.Units.SI.MassFlowRate m_flow(start=_m_flow_start) = port_a.m_flow "Mass flow rate from port_a to port_b (m_flow > 0 is design flow direction)"; Modelica.Units.SI.PressureDifference dp( start=_dp_start, displayUnit="Pa") = port_a.p - port_b.p "Pressure difference between port_a and port_b"; Medium.ThermodynamicState sta_a= if allowFlowReversal then Medium.setState_phX(port_a.p, noEvent(actualStream(port_a.h_outflow)), noEvent(actualStream(port_a.Xi_outflow))) else Medium.setState_phX(port_a.p, noEvent(inStream(port_a.h_outflow)), noEvent(inStream(port_a.Xi_outflow))) if show_T "Medium properties in port_a"; Medium.ThermodynamicState sta_b= if allowFlowReversal then Medium.setState_phX(port_b.p, noEvent(actualStream(port_b.h_outflow)), noEvent(actualStream(port_b.Xi_outflow))) else Medium.setState_phX(port_b.p, noEvent(port_b.h_outflow), noEvent(port_b.Xi_outflow)) if show_T "Medium properties in port_b"; // - Copy continues in protected section protected parameter Modelica.Units.SI.MassFlowRate _m_flow_nominal= max(eff.per.pressure.V_flow)*rho_default "Nominal mass flow rate"; // Copied from Fluid.Interfaces.PartialTwoPortInterface final parameter Modelica.Units.SI.MassFlowRate _m_flow_start=0 "Start value for m_flow, used to avoid a warning if not set in m_flow, and to avoid m_flow.start in parameter window"; final parameter Modelica.Units.SI.PressureDifference _dp_start(displayUnit= "Pa") = 0 "Start value for dp, used to avoid a warning if not set in dp, and to avoid dp.start in parameter window"; // - End of copy final parameter Modelica.Units.SI.VolumeFlowRate _VMachine_flow=0 "Start value for VMachine_flow, used to avoid a warning if not specified"; parameter Buildings.Fluid.Movers.BaseClasses.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 = eff.haveVMax "Flag, true if user specified data that contain V_flow_max"; final parameter Modelica.Units.SI.VolumeFlowRate V_flow_max=eff.V_flow_max; 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 the fan or pump's speed, and to improve numerics"; 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"; Buildings.Fluid.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. Buildings.Fluid.Movers.BaseClasses.FlowMachineInterface eff( per( final powerOrEfficiencyIsHydraulic = per.powerOrEfficiencyIsHydraulic, final efficiency = per.efficiency, final motorEfficiency = per.motorEfficiency, final motorEfficiency_yMot = per.motorEfficiency_yMot, final motorCooledByFluid = per.motorCooledByFluid, final speed_nominal = 0, final constantSpeed = 0, final speeds = {0}, final power = per.power, final peak = per.peak), final nOri = nOri, final rho_default=rho_default, final computePowerUsingSimilarityLaws=computePowerUsingSimilarityLaws, 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 algorithm // The control signal is dp or m_flow but the user did not provide a fan or 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 in " + getInstanceName() + ": Mover is flow or pressure controlled and uses default pressure curve. This leads to an approximate power consumption. Set nominalValuesDefineDefaultPressureCurve=true to suppress this warning.", level=AssertionLevel.warning); // The control signal is dp or m_flow but the user did not provide a fan or 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.etaHydMet. // 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.etaHydMet<> Buildings.Fluid.Movers.BaseClasses.Types.HydraulicEfficiencyMethod.Power_VolumeFlowRate, "*** Warning in " + getInstanceName() + ": Mover is flow or pressure controlled, uses default pressure curve and has per.etaHydMet=.Power_VolumeFlowRate. As this can cause wrong power consumption, the model overrides this setting by using per.etaHydMet=.NotProvided. Set nominalValuesDefineDefaultPressureCurve=true to suppress this warning.", level=AssertionLevel.warning); assert(per.havePressureCurve or not (per.etaHydMet == Buildings.Fluid.Movers.BaseClasses.Types.HydraulicEfficiencyMethod.Power_VolumeFlowRate or per.etaHydMet == Buildings.Fluid.Movers.BaseClasses.Types.HydraulicEfficiencyMethod.EulerNumber), "*** Warning in " + getInstanceName() + ": Mover has per.etaHydMet=.Power_VolumeFlowRate or per.etaHydMet=.EulerNumber. This requires per.pressure to be provided. Because it is not, the model overrides this setting by using per.etaHydMet=.NotProvided. Also consider using models under Movers.Preconfigured which autopopulate a pressure curve.", level=AssertionLevel.warning); assert(per.havePressureCurve or per.haveWMot_nominal or not (per.etaMotMet == Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.Efficiency_MotorPartLoadRatio or per.etaMotMet == Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.GenericCurve), "*** Warning in " + getInstanceName() + ": Mover has per.etaMotMet=.Efficiency_MotorPartLoadRatio or per.etaMotMet=.GenericCurve. This requires per.WMot_nominal or per.pressure to be provided. Because neither is provided, the model overrides this setting and by using per.etaMotMet=.NotProvided. Also consider using models under Movers.Preconfigured which autopopulate a pressure curve.", level=AssertionLevel.warning); assert(per.powerOrEfficiencyIsHydraulic or not (per.etaMotMet == Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.Efficiency_MotorPartLoadRatio or per.etaMotMet == Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.GenericCurve), "*** Warning in " + getInstanceName() + ": Mover has per.etaMotMet=.Efficiency_MotorPartLoadRatio or per.etaMotMet=.GenericCurve and provides information for total electric power instead of hydraulic power. This forms an algebraic loop. If simulation fails to converge, see the \"Motor efficiency\" section in the users guide for how to correct it.", 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.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.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); connect(eff.WHyd, heaDis.WHyd); connect(eff.PEle, P); 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 RealInputV_flowVolume flow rate [m3/s]
input RealInputWFloFlow work [W]
input RealInputWHydHydraulic work (converted to flow work and heat) [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 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 WHyd(final quantity="Power", final unit="W") "Hydraulic work (converted to flow work and heat)"; 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"; protected Modelica.Units.SI.HeatFlowRate QThe_flow "Heat input from fan or pump to medium"; Modelica.Units.SI.Efficiency etaHyd "Hydraulic efficiency"; 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 = WFlo / Buildings.Utilities.Math.Functions.smoothMax( x1=WHyd, x2=1E-5, deltaX=1E-6); // 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;