within TAeZoSysPro.FluidDynamics.Components.Orifices; model Opening import TAeZoSysPro.HeatTransfer.Types.Dynamics ; replaceable package Medium = TAeZoSysPro.Media.MyMedia ; // User defined parameters parameter Real Cd = 0.61 "discharge coefficient"; parameter Modelica.SIunits.CrossSection A = 1 "Opening cross section"; parameter Modelica.SIunits.Height H = 1 "Opening's Height"; parameter Integer N = 5 "Number discrete layer along the height of the opening"; parameter Modelica.SIunits.Length NotionalLength = 1e-4 "Opening's thickness"; parameter Dynamics massDynamics = Dynamics.SteadyStateInitial "Formulation of mass balance"; parameter Modelica.SIunits.Velocity Vel_start = 0.0 "Start value for velocity, if not steady state"; parameter Modelica.SIunits.Length Alt_a = 1.0 "Altitude of port_a"; parameter Modelica.SIunits.Length Alt_b = 1.0 "Altitude of port_b"; parameter Modelica.SIunits.Length Alt_opening = 1.0 "Altitude at the opening center"; // Internal variables Modelica.SIunits.Pressure p_a "Pressure at port_a"; Modelica.SIunits.Pressure p_b "Pressure at port_b"; Modelica.SIunits.PressureDifference dp_i[N]; Modelica.SIunits.PressureDifference dp; Modelica.SIunits.MassFlowRate m_flow_i[N] ; Modelica.SIunits.Velocity Vel[N] ; Modelica.SIunits.MassFlowRate m_flow "Mass flow rate throught the opening"; Modelica.SIunits.Density d[N]; Modelica.SIunits.IsentropicExponent gamma "Isentropic exponent"; Modelica.SIunits.MachNumber M "Mach number at the opening"; Medium.ThermodynamicState state, state_a, state_b; Modelica.SIunits.MassFraction[Medium.nX] X_a,X_b; // Imported modules TAeZoSysPro.FluidDynamics.Interfaces.FlowPort_a port_a(redeclare package Medium = Medium) annotation ( Placement(visible = true, transformation(origin = {-58, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-90, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); TAeZoSysPro.FluidDynamics.Interfaces.FlowPort_b port_b(redeclare package Medium = Medium) annotation ( Placement(visible = true, transformation(origin = {38, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {90, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); protected Modelica.SIunits.MassFlowRate mX_flow_i[N, Medium.nX] ; Modelica.SIunits.SpecificEnthalpy h_a "Specific enthalpy from port_a" ; Modelica.SIunits.SpecificEnthalpy h_b "Specific enthalpy from port_b" ; parameter Modelica.SIunits.Velocity Vel_small = 0.001 ; initial equation if massDynamics == Dynamics.SteadyStateInitial then der(Vel) = fill(0.0, N); elseif massDynamics == Dynamics.FixedInitial then Vel = fill(Vel_start, N) ; end if; equation // state_a = Medium.setState_dTX(d = sum(port_a.d), T = port_a.T, X = port_a.d / sum(port_a.d)); state_b = Medium.setState_dTX(d = sum(port_b.d), T = port_b.T, X = port_b.d / sum(port_b.d)); // pressure reconstruction p_a = Medium.pressure(state_a) + sum(port_a.d) * Modelica.Constants.g_n * (Alt_a-Alt_opening); p_b = Medium.pressure(state_b) + sum(port_b.d) * Modelica.Constants.g_n * (Alt_b-Alt_opening); dp = p_a - p_b; // specific enthalpy reconstruction h_a = Medium.specificEnthalpy(state_a); h_b = Medium.specificEnthalpy(state_b); for i in 1:N loop dp_i[i] = dp + Modelica.Constants.g_n * (H / 2 - H * (i - 1 / 2) / N) * (sum(port_a.d) - sum(port_b.d)); d[i] = TAeZoSysPro.FluidDynamics.Utilities.regStep(x = Vel[i], x_small = 1e-10, y1 = sum(port_a.d), y2 = sum(port_b.d)); if massDynamics == Dynamics.SteadyState then dp_i[i] - 1 / 2 * Modelica.Fluid.Utilities.regSquare2(x = Vel[i], x_small = Vel_small, k1 = sum(port_a.d), k2 = sum(port_b.d)) = 0.0; else /* inertial opening */ dp_i[i] - 1 / 2 * Modelica.Fluid.Utilities.regSquare2(x = Vel[i], x_small = Vel_small, k1 = sum(port_a.d), k2 = sum(port_b.d)) = NotionalLength * d[i] * der(Vel[i]); end if; m_flow_i[i] = Vel[i] * Cd * A / N * d[i]; end for ; /*Ensure compatibility with mono substance medium*/ X_a=port_a.d/sum(port_a.d); X_b=port_b.d/sum(port_b.d); mX_flow_i = {m_flow_i[i] * TAeZoSysPro.FluidDynamics.Utilities.regStep( x = Vel[i], x_small = 1e-14, y1 = port_a.d/sum(port_a.d), y2 = port_b.d/sum(port_b.d) ) for i in 1:N} ; m_flow = sum(m_flow_i) ; // assertion, Mach number has to remain bellow 0.3 to keep the assumption of an uncrompressible flow valid state = Medium.setSmoothState( x = sum(Vel)/N, x_small = Vel_small, state_a = state_a, state_b = state_b); gamma = Medium.isentropicExponent(state) /* gamma is supposed contant along the flow */; // Mach number calculation: The pressure at the orifice is the downstream node pressure M = min(1, (2 / (gamma - 1) * ((min(p_a, p_b) / max(p_a, p_b)) ^ ((1 - gamma) / gamma) - 1)) ^ 0.5); assert(M<=0.3,"Mach number > 0.3, the flow becomes compressible. The assumption of uncrompressible flow is not valid", AssertionLevel.warning) ; // Port handover port_a.m_flow = {sum(mX_flow_i[:, i]) for i in 1:Medium.nX} ; port_a.m_flow + port_b.m_flow = fill(0.0, Medium.nX); // port_a.H_flow = sum( smooth(0, if dp_i[i] >= 0.0 then m_flow_i[i] * h_a else m_flow_i[i] * h_b) for i in 1:N); port_a.H_flow = m_flow_i * TAeZoSysPro.FluidDynamics.Utilities.regStep( x = Vel, x_small = 1e-3, y1 = h_a, y2 = h_b); port_a.H_flow + port_b.H_flow = 0; annotation(defaultComponentName="opening", Documentation(info = "<html> <head> <title>VerticalOpening</title> </head> <body lang=\"en-UK\"> <p> This components allows to model the mass flow rate through from either static boundary pressure difference or buoyancy effect through a vertical orifice in a wall spliting two ambiances. </p> <p> To be considered as an orifice, the depth of the hole in the wall has to remain bellow the hydrodynamic entrance region (Distance between the entrance of the hole and the position where the dynamic boundary layers meet). In that case and due to visquous and inertial forces, the current line is not at right angles to the opening but curved. The flow is constricted in the orifice. Consequently, the cross-section of the fluid is not equal to the geometric section of the orifice. the ratio between the fluid passage section and the geometric section is called the discharge coefficient. It is assumed to be constant and therefore independent of the flow regime. </p> <p> The orifice is split in <b>N</b> number of layers along the vertical axis over an height of the fluid stream. Because of the narrowing of the passage section, the height considered for the fluid stream is not the geometric height but the distance between the lowest and highest current line. For a rectangular opening, the relation derives: </p> <img src=\"modelica://TAeZoSysPro/Information/FluidDynamics/Components/Orifices/EQ_VerticalOpening1.PNG\" /> <p> The pressure difference for the layer <b>i</b> derives (index 1 refers to the top of the opening): </p> <img src=\"modelica://TAeZoSysPro/Information/FluidDynamics/Components/Orifices/EQ_VerticalOpening2.PNG\" /> <p> In the flow, all the boundary pressure difference (from static pressure or buoyancy) is converted in kinetic energy. </p> <img src=\"modelica://TAeZoSysPro/Information/FluidDynamics/Components/Orifices/EQ_VerticalOpening3.PNG\" /> <p> It is equivalent to have a pressure loss factor equation to one. </p> <img src=\"modelica://TAeZoSysPro/Information/FluidDynamics/Components/Orifices/EQ_VerticalOpening4.PNG\" /> <p> The Fundamental principle of the dynamics derives: </p> <p> Therefore, the relation to compute mass flow rate through the orifice derives: </p> <img src=\"modelica://TAeZoSysPro/Information/FluidDynamics/Components/Orifices/EQ_VerticalOpening5.PNG\" /> <p> <b>Where</b>: <ul> <li> <code>H_fluidStream</code> is height between the bottom and the top current lines </li> <li> <code>H</code> is the geometrical height of the orifice </li> <li> <code>dp</code> is the static pressure difference between port_a.p and port_b.p </li> <li> <code>d</code> is the upstream density </li> <li> <code>Vel</code> is fluid velocity </li> <li> <code>m_flow_i</code> is the mass flow rate through the layer index <b>i</b></li> <li> <code>A</code> is cross section of the orifice </li> <li> <code>Cd</code> is the discharge coefficient </li> </ul> </p> <p> To avoid infinite derivative at Vel_i=0, The square is replaced by the function <b>regSquare2</b> of the MSL that replace the square by a polynomial expression to insure a finite derivative. The threshold to switch between the polynom and the square is defined by the parameter <b> Vel_small </b> </p> </body> </html>"), Icon(graphics = {Line(origin = {0, 50}, points = {{0, 30}, {0, -20}}, thickness = 2), Line(origin = {0, -50}, points = {{0, 20}, {0, -30}}, thickness = 2), Text(origin = {16, -113}, extent = {{-116, 33}, {84, 13}}, textString = "A=%A"), Text(origin = {-43, 88}, extent = {{-57, 12}, {143, -8}}, textString = "%name"), Line(points = {{0, 24}, {0, -24}}, color = {255, 0, 0}, arrow = {Arrow.Filled, Arrow.Filled}, arrowSize = 5), Text(origin = {120, 39}, extent = {{-116, 33}, {-20, 13}}, textString = "H=%H"), Line(points = {{-40, 0}, {40, 0}}, pattern = LinePattern.Dash, arrow = {Arrow.Filled, Arrow.Filled}), Line(origin = {-1, 27.24}, points = {{-39, 12.7571}, {-19, -7.24287}, {1, -15.2429}, {21, -7.24287}, {41, 12.7571}}, pattern = LinePattern.Dash, arrow = {Arrow.Filled, Arrow.Filled}, smooth = Smooth.Bezier), Line(origin = {1.02, -27.23}, rotation = 180, points = {{-39, 12.7571}, {-19, -7.24287}, {1, -15.2429}, {21, -7.24287}, {41, 12.7571}}, pattern = LinePattern.Dash, arrow = {Arrow.Filled, Arrow.Filled}, smooth = Smooth.Bezier), Line(origin = {6, 32}, points = {{-6, -8}, {44, 22}}, color = {255, 0, 0})}, coordinateSystem(initialScale = 0.1))); end Opening;