Open end working

This commit is contained in:
2026-05-07 12:55:57 +02:00
parent bc0df51ddb
commit 685b48b577
7 changed files with 355 additions and 330 deletions

View File

@@ -3,19 +3,15 @@ using FluidSim.Components;
namespace FluidSim.Core
{
/// <summary>
/// Characteristic openend boundary condition.
/// For subsonic outflow the outgoing Riemann invariant is conserved,
/// and the ghost pressure is set to the prescribed ambient value.
/// </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;
// Last resolved state (for audio / monitoring)
public double LastMassFlowRate { get; private set; }
public double LastFaceDensity { get; private set; }
public double LastFaceVelocity { get; private set; }
@@ -27,9 +23,6 @@ namespace FluidSim.Core
IsLeftEnd = isLeftEnd;
}
/// <summary>
/// Compute the ghost state and mass flow for one substep.
/// </summary>
public void Resolve(double dtSub)
{
(double rhoInt, double uInt, double pInt) = IsLeftEnd
@@ -40,80 +33,61 @@ 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);
double rhoGhost, uGhost, pGhost;
double mdot;
if (IsLeftEnd)
// ----- Supersonic outflow: extrapolate interior -----
bool supersonicOut = IsLeftEnd ? (uInt <= -cInt) : (uInt >= cInt);
if (supersonicOut)
{
// Left end: outgoing invariant is J- = u - 2c/(γ-1)
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;
if (uInt <= -cInt) // supersonic inflow (all info from outside)
{
// Simple reservoir model use ambient density and temperature 300 K
rhoGhost = pAmb / (287.0 * 300.0);
uGhost = uInt; // keep interior velocity (should be supersonic inward)
pGhost = pAmb;
}
else if (uInt < 0) // subsonic inflow
{
double rhoAmb = pAmb / (287.0 * 300.0);
double cAmb = Math.Sqrt(gamma * pAmb / rhoAmb);
uGhost = J_minus + 2.0 * cAmb / gm1;
rhoGhost = rhoAmb;
pGhost = pAmb;
}
else // subsonic outflow (uInt >= 0)
{
double s = pInt / Math.Pow(rhoInt, gamma);
rhoGhost = Math.Pow(pAmb / s, 1.0 / gamma);
double cGhost = Math.Sqrt(gamma * pAmb / rhoGhost);
uGhost = J_minus + 2.0 * cGhost / gm1;
if (uGhost < 0) uGhost = 0;
pGhost = pAmb;
}
}
else // Right end
{
// Right end: outgoing invariant is J+ = u + 2c/(γ-1)
double J_plus = 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);
if (uInt >= cInt) // supersonic outflow
bool outflowPossible = IsLeftEnd ? (uOut <= 0) : (uOut >= 0);
if (outflowPossible)
{
rhoGhost = rhoInt;
uGhost = uInt;
pGhost = pInt;
}
else if (uInt >= 0) // subsonic outflow
{
double s = pInt / Math.Pow(rhoInt, gamma);
rhoGhost = Math.Pow(pAmb / s, 1.0 / gamma);
double cGhost = Math.Sqrt(gamma * pAmb / rhoGhost);
uGhost = J_plus - 2.0 * cGhost / gm1;
if (uGhost < 0) uGhost = 0;
// Subsonic outflow
pGhost = pAmb;
rhoGhost = rhoOut;
uGhost = uOut;
}
else // subsonic inflow (uInt < 0)
else
{
double rhoAmb = pAmb / (287.0 * 300.0);
double cAmb = Math.Sqrt(gamma * pAmb / rhoAmb);
uGhost = J_plus - 2.0 * cAmb / gm1;
// Subsonic inflow (ambient reservoir model)
pGhost = pAmb;
rhoGhost = rhoAmb;
pGhost = pAmb;
uGhost = IsLeftEnd
? (J_minus + 2.0 * aAmb / gm1)
: (J_plus - 2.0 * aAmb / gm1);
}
}
// Apply ghost to pipe
if (IsLeftEnd)
Pipe.SetGhostLeft(rhoGhost, uGhost, pGhost);
else
Pipe.SetGhostRight(rhoGhost, uGhost, pGhost);
// Mass flow (positive = out of pipe)
double area = Pipe.Area;
mdot = rhoGhost * uGhost * area;
if (IsLeftEnd) mdot = -mdot; // positive u into pipe, so out of pipe is negative u
double mdot = rhoGhost * uGhost * area;
if (IsLeftEnd) mdot = -mdot;
LastMassFlowRate = mdot;
LastFaceDensity = rhoGhost;
LastFaceVelocity = uGhost;