Name | Description |
---|---|
ClosedVolume | Volume of fixed size, closed to the ambient, with inlet/outlet ports |
PartialLumpedVessel | Lumped volume with a vector of fluid ports and replaceable heat transfer model |
PartialMixingVolumeWaterPort | Partial mixing volume that allows adding or subtracting water vapor |
Ideally mixed volume of constant size with two fluid ports and one medium model.
The flow properties are computed from the upstream quantities, pressures are equal in both nodes and the medium model if use_portsData=false
.
Heat transfer through a thermal port is possible, it equals zero if the port remains unconnected.
A spherical shape is assumed for the heat transfer area, with V=4/3*pi*r^3, A=4*pi*r^2.
Ideal heat transfer is assumed per default; the thermal port temperature is equal to the medium temperature.
If use_portsData=true
, the port pressures represent the pressures just after the outlet (or just before the inlet) in the attached pipe.
The hydraulic resistances portsData.zeta_in and portsData.zeta_out determine the dissipative pressure drop between volume and port depending on
the direction of mass flow. See VesselPortsData and [Idelchik, Handbook of Hydraulic Resistance, 2004].
Note: This model is identical to Modelica.Fluid.Vessels.ClosedVolume, except that is extends Buildings.Fluid.MixingVolumes.BaseClasses.PartialLumpedVessel instead of Modelica.Fluid.Vessels.BaseClasses.PartialLumpedVessel to avoid an assert statement.
Extends from Buildings.Fluid.MixingVolumes.BaseClasses.PartialLumpedVessel (Lumped volume with a vector of fluid ports and replaceable heat transfer model).
Type | Name | Default | Description |
---|---|---|---|
replaceable package Medium | PartialMedium | Medium in the component | |
Volume | fluidVolume | V | Volume [m3] |
Volume | V | Volume [m3] | |
Ports | |||
Boolean | use_portsData | true | = false to neglect pressure loss and kinetic energy |
VesselPortsData | portsData[nPorts] | Data of inlet/outlet ports | |
Assumptions | |||
Dynamics | |||
Dynamics | energyDynamics | system.energyDynamics | Formulation of energy balance |
Dynamics | massDynamics | system.massDynamics | Formulation of mass balance |
Dynamics | substanceDynamics | energyDynamics | Formulation of substance balance |
Dynamics | traceDynamics | energyDynamics | Formulation of trace substance balance |
Heat transfer | |||
Boolean | use_HeatTransfer | false | = true to use the HeatTransfer model |
replaceable model HeatTransfer | IdealHeatTransfer | Wall heat transfer | |
Initialization | |||
AbsolutePressure | p_start | system.p_start | Start value of pressure [Pa] |
Boolean | use_T_start | true | = true, use T_start, otherwise h_start |
Temperature | T_start | if use_T_start then system.T... | Start value of temperature [K] |
SpecificEnthalpy | h_start | if use_T_start then Medium.s... | Start value of specific enthalpy [J/kg] |
MassFraction | X_start[Medium.nX] | Medium.X_default | Start value of mass fractions m_i/m [kg/kg] |
ExtraProperty | C_start[Medium.nC] | fill(0, Medium.nC) | Start value of trace substances |
Advanced | |||
Port properties | |||
MassFlowRate | m_flow_small | system.m_flow_small | Regularization range at zero mass flow rate [kg/s] |
Type | Name | Description |
---|---|---|
VesselFluidPorts_b | ports[nPorts] | Fluid inlets and outlets |
HeatPort_a | heatPort |
model ClosedVolume "Volume of fixed size, closed to the ambient, with inlet/outlet ports" import Modelica.Constants.pi; // Mass and energy balance, ports extends Buildings.Fluid.MixingVolumes.BaseClasses.PartialLumpedVessel( final fluidVolume = V, vesselArea = pi*(3/4*V)^(2/3), heatTransfer(surfaceAreas={4*pi*(3/4*V/pi)^(2/3)})); parameter Modelica.SIunits.Volume V "Volume"; equation Wb_flow = 0; for i in 1:nPorts loop vessel_ps_static[i] = medium.p; end for;end ClosedVolume;
This base class extends PartialLumpedVolume with a vector of fluid ports and a replaceable wall HeatTransfer model.
The following modeling assumption are made:
The following variables need to be defined by an extending model:
Note: This model is identical to Modelica.Fluid.Vessels.BaseClasses.PartialLumpedVessel, except that it extends Buildings.Fluid.Interfaces.PartialLumpedVolume instead of Modelica.Fluid.Interfaces.PartialLumpedVolume to avoid the assert statement.
Extends from Buildings.Fluid.Interfaces.PartialLumpedVolume (Lumped volume with mass and energy balance).
Type | Name | Default | Description |
---|---|---|---|
replaceable package Medium | PartialMedium | Medium in the component | |
Ports | |||
Boolean | use_portsData | true | = false to neglect pressure loss and kinetic energy |
VesselPortsData | portsData[nPorts] | Data of inlet/outlet ports | |
Assumptions | |||
Dynamics | |||
Dynamics | energyDynamics | system.energyDynamics | Formulation of energy balance |
Dynamics | massDynamics | system.massDynamics | Formulation of mass balance |
Dynamics | substanceDynamics | energyDynamics | Formulation of substance balance |
Dynamics | traceDynamics | energyDynamics | Formulation of trace substance balance |
Heat transfer | |||
Boolean | use_HeatTransfer | false | = true to use the HeatTransfer model |
Initialization | |||
AbsolutePressure | p_start | system.p_start | Start value of pressure [Pa] |
Boolean | use_T_start | true | = true, use T_start, otherwise h_start |
Temperature | T_start | if use_T_start then system.T... | Start value of temperature [K] |
SpecificEnthalpy | h_start | if use_T_start then Medium.s... | Start value of specific enthalpy [J/kg] |
MassFraction | X_start[Medium.nX] | Medium.X_default | Start value of mass fractions m_i/m [kg/kg] |
ExtraProperty | C_start[Medium.nC] | fill(0, Medium.nC) | Start value of trace substances |
Advanced | |||
Port properties | |||
MassFlowRate | m_flow_small | system.m_flow_small | Regularization range at zero mass flow rate [kg/s] |
Type | Name | Description |
---|---|---|
VesselFluidPorts_b | ports[nPorts] | Fluid inlets and outlets |
HeatPort_a | heatPort |
partial model PartialLumpedVessel "Lumped volume with a vector of fluid ports and replaceable heat transfer model" extends Buildings.Fluid.Interfaces.PartialLumpedVolume; // Port definitions parameter Integer nPorts=0 "Number of ports";Modelica.Fluid.Vessels.BaseClasses.VesselFluidPorts_b ports[nPorts]( redeclare each package Medium = Medium) "Fluid inlets and outlets"; // Port properties parameter Boolean use_portsData=true "= false to neglect pressure loss and kinetic energy"; parameter Modelica.Fluid.Vessels.BaseClasses.VesselPortsData[nPorts] portsData if use_portsData "Data of inlet/outlet ports"; parameter Modelica.SIunits.MassFlowRate m_flow_small(min=0)=system.m_flow_small "Regularization range at zero mass flow rate"; /* parameter Medium.AbsolutePressure dp_small = system.dp_small "Turbulent flow if |dp| >= dp_small (regularization of zero flow)" annotation(Dialog(tab="Advanced",group="Ports")); */ Medium.EnthalpyFlowRate ports_H_flow[nPorts]; Medium.MassFlowRate ports_mXi_flow[nPorts,Medium.nXi]; Medium.MassFlowRate[Medium.nXi] sum_ports_mXi_flow "Substance mass flows through ports"; Medium.ExtraPropertyFlowRate ports_mC_flow[nPorts,Medium.nC]; Medium.ExtraPropertyFlowRate[Medium.nC] sum_ports_mC_flow "Trace substance mass flows through ports"; // Heat transfer through boundary parameter Boolean use_HeatTransfer = false "= true to use the HeatTransfer model"; replaceable model HeatTransfer = Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer constrainedby Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.PartialVesselHeatTransfer "Wall heat transfer";HeatTransfer heatTransfer( redeclare final package Medium = Medium, final n=1, final states = {medium.state}, final use_k = use_HeatTransfer); Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort if use_HeatTransfer; // Conservation of kinetic energy Medium.Density[nPorts] portDensities "densites of the fluid at the device boudary"; Modelica.SIunits.Velocity[nPorts] portVelocities "velocities of fluid flow at device boundary"; Modelica.SIunits.EnergyFlowRate[nPorts] ports_E_flow "flow of kinetic and potential energy at device boundary"; // Note: should use fluidLevel_start - portsData.height Real[nPorts] s(each start = fluidLevel_max) "curve parameters for port flows vs. port pressures; for further details see, Modelica Tutorial: Ideal switching devices"; Real[nPorts] ports_penetration "penetration of port with fluid, depending on fluid level and port diameter"; // treatment of pressure losses at ports Modelica.SIunits.Area[nPorts] portAreas={Modelica.Constants.pi/4* portsData_diameter[i]^2 for i in 1:nPorts}; Medium.AbsolutePressure[nPorts] vessel_ps_static "static pressures inside the vessel at the height of the corresponding ports, zero flow velocity"; protected input Modelica.SIunits.Height fluidLevel=0 "level of fluid in the vessel for treating heights of ports"; parameter Modelica.SIunits.Height fluidLevel_max=1 "maximum level of fluid in the vessel"; parameter Modelica.SIunits.Area vesselArea=Modelica.Constants.inf "Area of the vessel used to relate to cross flow area of ports"; // Treatment of use_portsData=false to neglect portsData and to not require its specification either in this case. // Remove portsData conditionally if use_portsData=false. Simplify their use in model equations by always // providing portsData_diameter and portsData_height, independend of the use_portsData setting. // Note: this moreover serves as work-around if a tool does not support a zero sized portsData record. Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_diameter_internal = portsData.diameter if use_portsData and nPorts > 0; Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_height_internal = portsData.height if use_portsData and nPorts > 0; Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_zeta_in_internal = portsData.zeta_in if use_portsData and nPorts > 0; Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_zeta_out_internal = portsData.zeta_out if use_portsData and nPorts > 0; Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_diameter; Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_height; Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_zeta_in; Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_zeta_out; equation mb_flow = sum(ports.m_flow); mbXi_flow = sum_ports_mXi_flow; mbC_flow = sum_ports_mC_flow; Hb_flow = sum(ports_H_flow) + sum(ports_E_flow); Qb_flow = heatTransfer.Q_flows[1]; // Only one connection allowed to a port to avoid unwanted ideal mixing for i in 1:nPorts loop assert(cardinality(ports[i]) <= 1," each ports[i] of volume can at most be connected to one component. If two or more connections are present, ideal mixing takes place with these connections, which is usually not the intention of the modeller. Increase nPorts to add an additional port. "); end for; // Check for correct solution assert(fluidLevel <= fluidLevel_max, "Vessel is overflowing (fluidLevel > fluidLevel_max = " + String(fluidLevel) + ")"); assert(fluidLevel > -1e-6*fluidLevel_max, "Fluid level (= " + String(fluidLevel) + ") is below zero meaning that the solution failed."); // Boundary conditions // treatment of conditional portsData connect(portsData_diameter, portsData_diameter_internal); connect(portsData_height, portsData_height_internal); connect(portsData_zeta_in, portsData_zeta_in_internal); connect(portsData_zeta_out, portsData_zeta_out_internal); if not use_portsData then portsData_diameter = zeros(nPorts); portsData_height = zeros(nPorts); portsData_zeta_in = zeros(nPorts); portsData_zeta_out = zeros(nPorts); end if; // actual definition of port variables for i in 1:nPorts loop if use_portsData then // dp = 0.5*zeta*d*v*|v| // Note: assume vessel_ps_static for portDensities to avoid algebraic loops for ports.p portDensities[i] = noEvent(Medium.density(Medium.setState_phX(vessel_ps_static[i], actualStream(ports[i].h_outflow), actualStream(ports[i].Xi_outflow)))); portVelocities[i] = smooth(0, ports[i].m_flow/portAreas[i]/portDensities[i]); // Note: the penetration should not go too close to zero as this would prevent a vessel from running empty ports_penetration[i] = Modelica.Fluid.Utilities.regStep( fluidLevel - portsData_height[i] - 0.1*portsData_diameter[i], 1, 1e-3, 0.1*portsData_diameter[i]); else // an infinite port diameter is assumed portDensities[i] = medium.d; portVelocities[i] = 0; ports_penetration[i] = 1; end if; // fluid flow through ports if fluidLevel >= portsData_height[i] then // regular operation: fluidLevel is above ports[i] // Note: >= covers default values of zero as well if use_portsData then /* Without regularization ports[i].p = vessel_ps_static[i] + 0.5*ports[i].m_flow^2/portAreas[i]^2 * noEvent(if ports[i].m_flow>0 then zeta_in[i]/portDensities[i] else -zeta_out[i]/medium.d); */ ports[i].p = vessel_ps_static[i] + (0.5/portAreas[i]^2* Modelica.Fluid.Utilities.regSquare2( ports[i].m_flow, m_flow_small, (portsData_zeta_in[i] - 1 + portAreas[i]^2/vesselArea^2)/ portDensities[i]*ports_penetration[i], (portsData_zeta_out[i] + 1 - portAreas[i]^2/vesselArea^2)/medium.d/ ports_penetration[i])); /* // alternative formulation m_flow=f(dp); not allowing the ideal portsData_zeta_in[i]=1 though ports[i].m_flow = smooth(2, portAreas[i]*Utilities.regRoot2(ports[i].p - vessel_ps_static[i], dp_small, 2*portDensities[i]/portsData_zeta_in[i], 2*medium.d/portsData_zeta_out[i])); */ else ports[i].p = vessel_ps_static[i]; end if; s[i] = fluidLevel - portsData_height[i]; elseif s[i] > 0 or portsData_height[i] >= fluidLevel_max then // ports[i] is above fluidLevel and has inflow ports[i].p = vessel_ps_static[i]; s[i] = ports[i].m_flow; else // ports[i] is above fluidLevel, preventing outflow ports[i].m_flow = 0; s[i] = (ports[i].p - vessel_ps_static[i])/Medium.p_default*(portsData_height[i] - fluidLevel); end if; ports[i].h_outflow = medium.h; ports[i].Xi_outflow = medium.Xi; ports[i].C_outflow = C; ports_H_flow[i] = ports[i].m_flow * actualStream(ports[i].h_outflow) "Enthalpy flow"; ports_E_flow[i] = ports[i].m_flow*(0.5*portVelocities[i]*portVelocities[i] + system.g*portsData_height[i]) "Flow of kinetic and potential energy"; ports_mXi_flow[i,:] = ports[i].m_flow * actualStream(ports[i].Xi_outflow) "Component mass flow"; ports_mC_flow[i,:] = ports[i].m_flow * actualStream(ports[i].C_outflow) "Trace substance mass flow"; end for; for i in 1:Medium.nXi loop sum_ports_mXi_flow[i] = sum(ports_mXi_flow[:,i]); end for; for i in 1:Medium.nC loop sum_ports_mC_flow[i] = sum(ports_mC_flow[:,i]); end for;connect(heatPort, heatTransfer.heatPorts[1]); end PartialLumpedVessel;
This model represents the same physics as Modelica.Fluid.Vessels.Volume but in addition, it allows to connect signals for the water exchanged with the volume. The model is partial in order to allow a submodel that can be used with media that contain water as a substance, and a submodel that can be used with dry air. Having separate models is required because calls to the medium property function enthalpyOfLiquid results in a linker error if a medium such as Modelica.Media.Air.SimpleAir is used that does not implement this function.
Extends from Modelica.Fluid.Interfaces.PartialLumpedVolume (Lumped volume with mass and energy balance).
Type | Name | Default | Description |
---|---|---|---|
replaceable package Medium | PartialMedium | Medium in the component | |
Volume | fluidVolume | V | Volume [m3] |
Volume | V | Volume [m3] | |
Assumptions | |||
Dynamics | |||
Dynamics | energyDynamics | system.energyDynamics | Formulation of energy balance |
Dynamics | massDynamics | system.massDynamics | Formulation of mass balance |
Heat transfer | |||
Boolean | use_HeatTransfer | false | = true to use the HeatTransfer model |
Initialization | |||
AbsolutePressure | p_start | system.p_start | Start value of pressure [Pa] |
Boolean | use_T_start | true | = true, use T_start, otherwise h_start |
Temperature | T_start | if use_T_start then system.T... | Start value of temperature [K] |
SpecificEnthalpy | h_start | if use_T_start then Medium.s... | Start value of specific enthalpy [J/kg] |
MassFraction | X_start[Medium.nX] | Medium.X_default | Start value of mass fractions m_i/m [kg/kg] |
ExtraProperty | C_start[Medium.nC] | fill(0, Medium.nC) | Start value of trace substances |
Type | Name | Description |
---|---|---|
FluidPorts_b | ports[nPorts] | Fluid outlets |
HeatPort_a | heatPort | |
input RealInput | mWat_flow | Water flow rate added into the medium [kg/s] |
input RealInput | TWat | Temperature of liquid that is drained from or injected into volume [K] |
output RealOutput | XWat | Species composition of medium |
partial model PartialMixingVolumeWaterPort "Partial mixing volume that allows adding or subtracting water vapor" extends Modelica.Fluid.Interfaces.PartialLumpedVolume(fluidVolume = V, m(start=V*rho_nominal, fixed=false));// declarations similar than in PartialLumpedVolumePorts from Modelica.Fluid // Port definitions parameter Integer nPorts(min=1)=1 "Number of ports"; Modelica.Fluid.Interfaces.FluidPorts_b ports[nPorts]( redeclare each package Medium = Medium) "Fluid outlets"; Medium.AbsolutePressure ports_p_static "static pressure at the ports, inside the volume"; Medium.EnthalpyFlowRate ports_H_flow[nPorts]; Medium.MassFlowRate ports_mXi_flow[nPorts,Medium.nXi]; Medium.MassFlowRate[Medium.nXi] sum_ports_mXi_flow "Substance mass flows through ports"; Medium.ExtraPropertyFlowRate ports_mC_flow[nPorts,Medium.nC]; Medium.ExtraPropertyFlowRate[Medium.nC] sum_ports_mC_flow "Trace substance mass flows through ports"; // Heat transfer through boundary parameter Boolean use_HeatTransfer = false "= true to use the HeatTransfer model"; replaceable model HeatTransfer = Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer ( surfaceAreas={4*Modelica.Constants.pi*(3/4*V/Modelica.Constants.pi)^(2/3)}) constrainedby Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.PartialVesselHeatTransfer "Wall heat transfer";HeatTransfer heatTransfer( redeclare final package Medium = Medium, final n=1, final states = {medium.state}, final use_k = use_HeatTransfer); Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort if use_HeatTransfer; // additional declarationsModelica.Blocks.Interfaces.RealInput mWat_flow(final quantity="MassFlowRate", final unit = "kg/s") "Water flow rate added into the medium"; Modelica.Blocks.Interfaces.RealInput TWat(final quantity="ThermodynamicTemperature", final unit = "K", displayUnit = "degC", min=260) "Temperature of liquid that is drained from or injected into volume"; Modelica.Blocks.Interfaces.RealOutput XWat "Species composition of medium"; Medium.MassFlowRate mXi_flow[Medium.nXi] "Mass flow rates of independent substances added to the medium"; Modelica.SIunits.HeatFlowRate HWat_flow "Enthalpy flow rate of extracted water"; parameter Modelica.SIunits.Volume V "Volume"; protected parameter Medium.ThermodynamicState sta0 = Medium.setState_pTX(T=T_start, p=p_start, X=X_start[1:Medium.nXi]); parameter Modelica.SIunits.Density rho_nominal=Medium.density(sta0) "Density, used to compute fluid mass"; equation assert(not (energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState and massDynamics==Modelica.Fluid.Types.Dynamics.SteadyState) or Medium.singleState, "Bad combination of dynamics options and Medium not conserving mass if fluidVolume is fixed."); ports_p_static = medium.p;connect(heatPort, heatTransfer.heatPorts[1]); Wb_flow = 0; mb_flow = sum(ports.m_flow) + mWat_flow "eqn. differs from Modelica.Fluid implementation"; mbXi_flow = sum_ports_mXi_flow + mXi_flow "eqn. differs from Modelica.Fluid implementation"; mbC_flow = sum_ports_mC_flow; Hb_flow = sum(ports_H_flow) + HWat_flow "eqn. differs from Modelica.Fluid implementation"; Qb_flow = heatTransfer.Q_flows[1]; // Only one connection allowed to a port to avoid unwanted ideal mixing for i in 1:nPorts loop assert(cardinality(ports[i]) <= 1," each ports[i] of volume can at most be connected to one component. If two or more connections are present, ideal mixing takes place with these connections, which is usually not the intention of the modeller. Increase nPorts to add an additional port. "); end for; // Boundary conditions for i in 1:nPorts loop ports[i].p = ports_p_static; end for; ports.h_outflow = fill(medium.h, nPorts); ports.Xi_outflow = fill(medium.Xi, nPorts); ports.C_outflow = fill(C, nPorts); for i in 1:nPorts loop ports_H_flow[i] = ports[i].m_flow * actualStream(ports[i].h_outflow) "Enthalpy flow"; ports_mXi_flow[i,:] = ports[i].m_flow * actualStream(ports[i].Xi_outflow) "Component mass flow"; ports_mC_flow[i,:] = ports[i].m_flow * actualStream(ports[i].C_outflow) "Trace substance mass flow"; end for; for i in 1:Medium.nXi loop sum_ports_mXi_flow[i] = sum(ports_mXi_flow[:,i]); end for; for i in 1:Medium.nC loop sum_ports_mC_flow[i] = sum(ports_mC_flow[:,i]); end for; end PartialMixingVolumeWaterPort;
Type | Name | Default | Description |
---|---|---|---|
Ambient | |||
CoefficientOfHeatTransfer | k | 0 | Heat transfer coefficient to ambient [W/(m2.K)] |
Temperature | T_ambient | system.T_ambient | Ambient temperature [K] |
Internal Interface | |||
replaceable package Medium | PartialMedium | Medium in the component | |
Integer | n | 1 | Number of heat transfer segments |
Boolean | use_k | false | = true to use k value for thermal isolation |
Type | Name | Description |
---|---|---|
HeatPorts_a | heatPorts[n] | Heat port to component boundary |
replaceable model HeatTransfer = Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer constrainedby Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.PartialVesselHeatTransfer "Wall heat transfer";
Type | Name | Default | Description |
---|---|---|---|
Area | surfaceAreas[n] | {4*Modelica.Constants.pi*(3/... | Heat transfer areas [m2] |
Ambient | |||
CoefficientOfHeatTransfer | k | 0 | Heat transfer coefficient to ambient [W/(m2.K)] |
Temperature | T_ambient | system.T_ambient | Ambient temperature [K] |
Internal Interface | |||
replaceable package Medium | PartialMedium | Medium in the component | |
Integer | n | 1 | Number of heat transfer segments |
Boolean | use_k | false | = true to use k value for thermal isolation |
Type | Name | Description |
---|---|---|
HeatPorts_a | heatPorts[n] | Heat port to component boundary |
replaceable model HeatTransfer = Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer ( surfaceAreas={4*Modelica.Constants.pi*(3/4*V/Modelica.Constants.pi)^(2/3)}) constrainedby Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.PartialVesselHeatTransfer "Wall heat transfer";