using System; using FluidSim.Components; namespace FluidSim.Core { public class OpenEndLink { public Pipe1D Pipe { get; } public bool IsLeftEnd { get; } public double AmbientPressure { get; set; } = 101325.0; public double Gamma { get; set; } = 1.4; public double GasConstant { get; set; } = 287.0; public double AmbientTemperature { get; set; } = 300.0; public double LastMassFlowRate { get; private set; } public double LastFaceDensity { get; private set; } public double LastFaceVelocity { get; private set; } public double LastFacePressure { get; private set; } public OpenEndLink(Pipe1D pipe, bool isLeftEnd) { Pipe = pipe ?? throw new ArgumentNullException(nameof(pipe)); IsLeftEnd = isLeftEnd; } public void Resolve(double dtSub) { (double rhoInt, double uInt, double pInt) = IsLeftEnd ? Pipe.GetInteriorStateLeft() : Pipe.GetInteriorStateRight(); double gamma = Gamma; double gm1 = gamma - 1.0; double cInt = Math.Sqrt(gamma * pInt / Math.Max(rhoInt, 1e-12)); double pAmb = AmbientPressure; double rhoAmb = pAmb / (GasConstant * AmbientTemperature); double aAmb = Math.Sqrt(gamma * pAmb / rhoAmb); double rhoGhost, uGhost, pGhost; // ----- Supersonic outflow: extrapolate interior ----- bool supersonicOut = IsLeftEnd ? (uInt <= -cInt) : (uInt >= cInt); if (supersonicOut) { rhoGhost = rhoInt; uGhost = uInt; pGhost = pInt; } else { // Riemann invariants double J_plus = uInt + 2.0 * cInt / gm1; double J_minus = uInt - 2.0 * cInt / gm1; // Trial subsonic outflow ghost state double s = pInt / Math.Pow(rhoInt, gamma); double rhoOut = Math.Pow(pAmb / s, 1.0 / gamma); double cOut = Math.Sqrt(gamma * pAmb / rhoOut); double uOut = IsLeftEnd ? (J_minus + 2.0 * cOut / gm1) : (J_plus - 2.0 * cOut / gm1); bool outflowPossible = IsLeftEnd ? (uOut <= 0) : (uOut >= 0); if (outflowPossible) { // Subsonic outflow pGhost = pAmb; rhoGhost = rhoOut; uGhost = uOut; } else { // Subsonic inflow (ambient reservoir model) pGhost = pAmb; rhoGhost = rhoAmb; uGhost = IsLeftEnd ? (J_minus + 2.0 * aAmb / gm1) : (J_plus - 2.0 * aAmb / gm1); } } if (IsLeftEnd) Pipe.SetGhostLeft(rhoGhost, uGhost, pGhost); else Pipe.SetGhostRight(rhoGhost, uGhost, pGhost); double area = Pipe.Area; double mdot = rhoGhost * uGhost * area; if (IsLeftEnd) mdot = -mdot; LastMassFlowRate = mdot; LastFaceDensity = rhoGhost; LastFaceVelocity = uGhost; LastFacePressure = pGhost; } } }