orifice confirmed working

This commit is contained in:
2026-05-07 13:28:41 +02:00
parent 685b48b577
commit f79cf6b7eb
5 changed files with 143 additions and 150 deletions

View File

@@ -3,14 +3,19 @@ using FluidSim.Components;
namespace FluidSim.Core
{
/// <summary>
/// Characteristic openend boundary condition after Jones (1978).
/// For all subsonic flow (outflow and inflow), the ghost state is derived
/// from the isentropic expansion to ambient pressure, using the pipe's entropy,
/// and the outgoing Riemann invariant. This avoids a density jump at flow reversal.
/// Supersonic outflow extrapolates the interior state.
/// </summary>
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; }
@@ -33,61 +38,63 @@ namespace FluidSim.Core
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);
// Riemann invariants
double J_plus = uInt + 2.0 * cInt / gm1;
double J_minus = uInt - 2.0 * cInt / gm1;
double rhoGhost, uGhost, pGhost;
// ----- Supersonic outflow: extrapolate interior -----
bool supersonicOut = IsLeftEnd ? (uInt <= -cInt) : (uInt >= cInt);
if (supersonicOut)
// ---- Subsonic branch (used for both outflow and inflow) ----
// Isentropic expansion to ambient pressure using pipe's entropy
double s = pInt / Math.Pow(rhoInt, gamma); // entropy constant
double rhoIso = Math.Pow(pAmb / s, 1.0 / gamma);
double cIso = Math.Sqrt(gamma * pAmb / Math.Max(rhoIso, 1e-12));
double uIso = IsLeftEnd
? (J_minus + 2.0 * cIso / gm1)
: (J_plus - 2.0 * cIso / gm1);
// Check for supersonic outflow: if the isentropic velocity exceeds the speed of sound,
// the flow is supersonic and we extrapolate the interior state.
bool supersonic = IsLeftEnd
? (uInt <= -cInt) // left end: outflow is when u < -c
: (uInt >= cInt); // right end: outflow is when u > c
// Extra check: if the isentropic velocity is supersonic in the outflow direction,
// also treat as supersonic (this can happen when the interior pressure is very high).
if (!supersonic)
{
if (IsLeftEnd)
supersonic = uIso <= -cIso;
else
supersonic = uIso >= cIso;
}
if (supersonic)
{
// Supersonic outflow extrapolate interior
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);
}
// Subsonic flow use the isentropic state
rhoGhost = rhoIso;
uGhost = uIso;
pGhost = pAmb;
}
// Apply ghost to pipe
if (IsLeftEnd)
Pipe.SetGhostLeft(rhoGhost, uGhost, pGhost);
else
Pipe.SetGhostRight(rhoGhost, uGhost, pGhost);
// Mass flow out of the pipe (positive = leaving)
double area = Pipe.Area;
double mdot = rhoGhost * uGhost * area;
if (IsLeftEnd) mdot = -mdot;
if (IsLeftEnd) mdot = -mdot; // left end: positive u is into pipe, so out is -u
LastMassFlowRate = mdot;
LastFaceDensity = rhoGhost;
LastFaceVelocity = uGhost;