using System; using FluidSim.Interfaces; namespace FluidSim.Components { public class Orifice { public Port PortA { get; } public Port PortB { get; } public double Area { get; set; } public double DischargeCoeff { get; set; } = 0.62; public double Gamma { get; set; } = 1.4; public Orifice(double area) { Area = area; PortA = new Port(); PortB = new Port(); } public void Simulate() { double pA = PortA.Pressure, pB = PortB.Pressure; double dp = pA - pB; double rho = dp >= 0 ? PortA.Density : PortB.Density; if (rho <= 0) rho = 1.225; double massFlow; double absDp = Math.Abs(dp); double critical = 1e-3 * pA; // blend threshold if (absDp < critical) { // Linearised region for numerical stability massFlow = Area * DischargeCoeff * Math.Sqrt(2 * rho * critical) * dp / critical; } else { double sign = Math.Sign(dp); double pratio = Math.Min(pA, pB) / Math.Max(pA, pB); double choked = Math.Pow(2.0 / (Gamma + 1.0), Gamma / (Gamma - 1.0)); if (pratio < choked) { double term = Math.Sqrt(Gamma * Math.Pow(2.0 / (Gamma + 1.0), (Gamma + 1.0) / (Gamma - 1.0))); massFlow = DischargeCoeff * Area * Math.Sqrt(rho * Math.Max(pA, pB)) * term; } else { double exp = 1.0 - Math.Pow(pratio, (Gamma - 1.0) / Gamma); massFlow = DischargeCoeff * Area * Math.Sqrt(2.0 * rho * Math.Max(pA, pB) * (Gamma / (Gamma - 1.0)) * pratio * pratio * exp); } massFlow *= sign; } PortA.MassFlowRate = -massFlow; // outflow from A PortB.MassFlowRate = massFlow; // inflow to B if (massFlow > 0) // A->B { PortA.SpecificEnthalpy = PortA.SpecificEnthalpy; PortB.SpecificEnthalpy = PortA.SpecificEnthalpy; } else { PortA.SpecificEnthalpy = PortB.SpecificEnthalpy; PortB.SpecificEnthalpy = PortB.SpecificEnthalpy; } } } }