Engine working
This commit is contained in:
@@ -7,10 +7,10 @@ namespace FluidSim.Components
|
||||
/// <summary>
|
||||
/// 1‑D compressible Euler pipe with Lax‑Friedrichs finite‑volume scheme.
|
||||
/// Ghost states are set externally via SetGhostLeft/Right; they are always required.
|
||||
/// Now includes a passive scalar for air mass fraction.
|
||||
/// </summary>
|
||||
public class Pipe1D : IComponent
|
||||
{
|
||||
// ---------- Compile‑time profiling flag ----------
|
||||
public const bool EnableDetailedProfiling = false; // set to false in release builds
|
||||
|
||||
public Port PortA { get; }
|
||||
@@ -36,10 +36,11 @@ namespace FluidSim.Components
|
||||
private readonly double _gamma = 1.4;
|
||||
|
||||
private double[] _rho, _rhou, _E;
|
||||
private double[] _fluxM, _fluxP, _fluxE; // flux at cell faces (0.._n) – kept for possible external use, not used internally anymore
|
||||
private double[] _Y; // air mass fraction
|
||||
private double[] _fluxM, _fluxP, _fluxE;
|
||||
|
||||
private double _rhoGhostL, _uGhostL, _pGhostL;
|
||||
private double _rhoGhostR, _uGhostR, _pGhostR;
|
||||
private double _rhoGhostL, _uGhostL, _pGhostL, _YGhostL;
|
||||
private double _rhoGhostR, _uGhostR, _pGhostR, _YGhostR;
|
||||
private bool _ghostLValid, _ghostRValid;
|
||||
|
||||
private double _laminarCoeff;
|
||||
@@ -65,7 +66,7 @@ namespace FluidSim.Components
|
||||
_rho = new double[_n];
|
||||
_rhou = new double[_n];
|
||||
_E = new double[_n];
|
||||
|
||||
_Y = new double[_n];
|
||||
_fluxM = new double[_n + 1];
|
||||
_fluxP = new double[_n + 1];
|
||||
_fluxE = new double[_n + 1];
|
||||
@@ -87,16 +88,19 @@ namespace FluidSim.Components
|
||||
public void UpdateState(double dt) { }
|
||||
|
||||
// ---------- Ghost interface ----------
|
||||
public void SetGhostLeft(double rho, double u, double p)
|
||||
public void SetGhostLeft(double rho, double u, double p, double airFraction)
|
||||
{
|
||||
_rhoGhostL = rho; _uGhostL = u; _pGhostL = p; _ghostLValid = true;
|
||||
_rhoGhostL = rho; _uGhostL = u; _pGhostL = p; _YGhostL = airFraction; _ghostLValid = true;
|
||||
}
|
||||
public void SetGhostRight(double rho, double u, double p)
|
||||
public void SetGhostRight(double rho, double u, double p, double airFraction)
|
||||
{
|
||||
_rhoGhostR = rho; _uGhostR = u; _pGhostR = p; _ghostRValid = true;
|
||||
_rhoGhostR = rho; _uGhostR = u; _pGhostR = p; _YGhostR = airFraction; _ghostRValid = true;
|
||||
}
|
||||
public void ClearGhostFlags() { _ghostLValid = false; _ghostRValid = false; }
|
||||
|
||||
public double GetInteriorAirFractionLeft() => _Y[0];
|
||||
public double GetInteriorAirFractionRight() => _Y[_n - 1];
|
||||
|
||||
public (double rho, double u, double p) GetInteriorStateLeft()
|
||||
{
|
||||
double rho = Math.Max(_rho[0], 1e-12);
|
||||
@@ -172,6 +176,34 @@ namespace FluidSim.Components
|
||||
t0 = t1;
|
||||
}
|
||||
|
||||
// ---------- Local flux functions ----------
|
||||
void LaxFlux(double rL, double uL, double pL, double cL,
|
||||
double rR, double uR, double pR, double cR,
|
||||
out double fm, out double fp, out double fe)
|
||||
{
|
||||
double EL = pL / (gm1 * rL) + 0.5 * uL * uL;
|
||||
double ER = pR / (gm1 * rR) + 0.5 * uR * uR;
|
||||
double Fm_L = rL * uL;
|
||||
double Fp_L = rL * uL * uL + pL;
|
||||
double Fe_L = (rL * EL + pL) * uL;
|
||||
double Fm_R = rR * uR;
|
||||
double Fp_R = rR * uR * uR + pR;
|
||||
double Fe_R = (rR * ER + pR) * uR;
|
||||
double alpha = Math.Max(Math.Abs(uL) + cL, Math.Abs(uR) + cR);
|
||||
fm = 0.5 * (Fm_L + Fm_R) - 0.5 * alpha * (rR - rL);
|
||||
fp = 0.5 * (Fp_L + Fp_R) - 0.5 * alpha * (rR * uR - rL * uL);
|
||||
fe = 0.5 * (Fe_L + Fe_R) - 0.5 * alpha * (rR * ER - rL * EL);
|
||||
}
|
||||
|
||||
void ScalarFlux(double rL, double uL, double cL, double YL,
|
||||
double rR, double uR, double cR, double YR,
|
||||
double alpha, out double fy)
|
||||
{
|
||||
double Fm_L = rL * uL;
|
||||
double Fm_R = rR * uR;
|
||||
fy = 0.5 * (Fm_L * YL + Fm_R * YR) - 0.5 * alpha * (rR * YR - rL * YL);
|
||||
}
|
||||
|
||||
// ---------- Phase 2: Left face flux (ghostL – cell 0) ----------
|
||||
double rL_ghost = Math.Max(_rhoGhostL, 1e-12);
|
||||
double pL_ghost = _pGhostL;
|
||||
@@ -182,6 +214,12 @@ namespace FluidSim.Components
|
||||
_rho[0], _rhou[0] / Math.Max(_rho[0], 1e-12), p[0], c[0],
|
||||
out double fluxM_left, out double fluxP_left, out double fluxE_left);
|
||||
|
||||
double alphaLeft = Math.Max(Math.Abs(uL_ghost) + cL_ghost,
|
||||
Math.Abs(_rhou[0] / Math.Max(_rho[0], 1e-12)) + c[0]);
|
||||
ScalarFlux(rL_ghost, uL_ghost, cL_ghost, _YGhostL,
|
||||
_rho[0], _rhou[0] / Math.Max(_rho[0], 1e-12), c[0], _Y[0],
|
||||
alphaLeft, out double fluxY_left);
|
||||
|
||||
if (EnableDetailedProfiling)
|
||||
{
|
||||
t1 = Stopwatch.GetTimestamp();
|
||||
@@ -193,6 +231,7 @@ namespace FluidSim.Components
|
||||
double fluxM_prev = fluxM_left;
|
||||
double fluxP_prev = fluxP_left;
|
||||
double fluxE_prev = fluxE_left;
|
||||
double fluxY_prev = fluxY_left;
|
||||
|
||||
for (int i = 0; i < n - 1; i++)
|
||||
{
|
||||
@@ -203,23 +242,31 @@ namespace FluidSim.Components
|
||||
double uL = _rhou[iL] / rL;
|
||||
double pL = p[iL];
|
||||
double cL = c[iL];
|
||||
double YL = _Y[iL];
|
||||
|
||||
double rR = Math.Max(_rho[iR], 1e-12);
|
||||
double uR = _rhou[iR] / rR;
|
||||
double pR = p[iR];
|
||||
double cR = c[iR];
|
||||
double YR = _Y[iR];
|
||||
|
||||
LaxFlux(rL, uL, pL, cL, rR, uR, pR, cR,
|
||||
out double fluxM_right, out double fluxP_right, out double fluxE_right);
|
||||
|
||||
double alpha = Math.Max(Math.Abs(uL) + cL, Math.Abs(uR) + cR);
|
||||
ScalarFlux(rL, uL, cL, YL, rR, uR, cR, YR, alpha, out double fluxY_right);
|
||||
|
||||
// Update cell i
|
||||
double r = _rho[i];
|
||||
double ru = _rhou[i];
|
||||
double E = _E[i];
|
||||
double Y = _Y[i];
|
||||
|
||||
double newR = r - dt_dx * (fluxM_right - fluxM_prev);
|
||||
double newRu = ru - dt_dx * (fluxP_right - fluxP_prev);
|
||||
double newE = E - dt_dx * (fluxE_right - fluxE_prev);
|
||||
double oldRhoY = r * Y;
|
||||
double newRhoY = oldRhoY - dt_dx * (fluxY_right - fluxY_prev);
|
||||
|
||||
double dampingFactor = Math.Exp(-coeff / Math.Max(r, 1e-12) * dt);
|
||||
newRu *= dampingFactor;
|
||||
@@ -234,10 +281,12 @@ namespace FluidSim.Components
|
||||
_rho[i] = newR;
|
||||
_rhou[i] = newRu;
|
||||
_E[i] = newE;
|
||||
_Y[i] = Math.Clamp(newRhoY / newR, 0.0, 1.0);
|
||||
|
||||
fluxM_prev = fluxM_right;
|
||||
fluxP_prev = fluxP_right;
|
||||
fluxE_prev = fluxE_right;
|
||||
fluxY_prev = fluxY_right;
|
||||
}
|
||||
|
||||
if (EnableDetailedProfiling)
|
||||
@@ -253,20 +302,31 @@ namespace FluidSim.Components
|
||||
double uR_ghost = _uGhostR;
|
||||
double cR_ghost = Math.Sqrt(gamma * pR_ghost / rR_ghost);
|
||||
|
||||
LaxFlux(_rho[n - 1], _rhou[n - 1] / Math.Max(_rho[n - 1], 1e-12), p[n - 1], c[n - 1],
|
||||
double rInt = _rho[n - 1];
|
||||
double uInt = _rhou[n - 1] / Math.Max(rInt, 1e-12);
|
||||
|
||||
LaxFlux(rInt, uInt, p[n - 1], c[n - 1],
|
||||
rR_ghost, uR_ghost, pR_ghost, cR_ghost,
|
||||
out double fluxM_right_final, out double fluxP_right_final, out double fluxE_right_final);
|
||||
|
||||
// Update last cell (identical to interior, but with final fluxes)
|
||||
double alphaRight = Math.Max(Math.Abs(uInt) + c[n - 1], Math.Abs(uR_ghost) + cR_ghost);
|
||||
ScalarFlux(rInt, uInt, c[n - 1], _Y[n - 1],
|
||||
rR_ghost, uR_ghost, cR_ghost, _YGhostR,
|
||||
alphaRight, out double fluxY_right_final);
|
||||
|
||||
// Update last cell
|
||||
{
|
||||
int i = n - 1;
|
||||
double r = _rho[i];
|
||||
double ru = _rhou[i];
|
||||
double E = _E[i];
|
||||
double Y = _Y[i];
|
||||
|
||||
double newR = r - dt_dx * (fluxM_right_final - fluxM_prev);
|
||||
double newRu = ru - dt_dx * (fluxP_right_final - fluxP_prev);
|
||||
double newE = E - dt_dx * (fluxE_right_final - fluxE_prev);
|
||||
double oldRhoY = r * Y;
|
||||
double newRhoY = oldRhoY - dt_dx * (fluxY_right_final - fluxY_prev);
|
||||
|
||||
double dampingFactor = Math.Exp(-coeff / Math.Max(r, 1e-12) * dt);
|
||||
newRu *= dampingFactor;
|
||||
@@ -281,6 +341,7 @@ namespace FluidSim.Components
|
||||
_rho[i] = newR;
|
||||
_rhou[i] = newRu;
|
||||
_E[i] = newE;
|
||||
_Y[i] = Math.Clamp(newRhoY / newR, 0.0, 1.0);
|
||||
}
|
||||
|
||||
if (EnableDetailedProfiling)
|
||||
@@ -295,11 +356,13 @@ namespace FluidSim.Components
|
||||
PortA.Pressure = pA; PortA.Density = rhoA;
|
||||
PortA.Temperature = pA / (rhoA * 287.0);
|
||||
PortA.SpecificEnthalpy = gm1 / (gamma - 1.0) * pA / rhoA;
|
||||
PortA.AirFraction = _Y[0];
|
||||
|
||||
(double rhoB, double uB, double pB) = GetInteriorStateRight();
|
||||
PortB.Pressure = pB; PortB.Density = rhoB;
|
||||
PortB.Temperature = pB / (rhoB * 287.0);
|
||||
PortB.SpecificEnthalpy = gm1 / (gamma - 1.0) * pB / rhoB;
|
||||
PortB.AirFraction = _Y[_n - 1];
|
||||
|
||||
if (EnableDetailedProfiling)
|
||||
{
|
||||
@@ -308,48 +371,6 @@ namespace FluidSim.Components
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Local Lax‑Friedrichs flux function ----------
|
||||
private void LaxFlux(double rL, double uL, double pL, double cL,
|
||||
double rR, double uR, double pR, double cR,
|
||||
out double fm, out double fp, out double fe)
|
||||
{
|
||||
double gm1 = _gamma - 1.0;
|
||||
double EL = pL / (gm1 * rL) + 0.5 * uL * uL;
|
||||
double ER = pR / (gm1 * rR) + 0.5 * uR * uR;
|
||||
double Fm_L = rL * uL;
|
||||
double Fp_L = rL * uL * uL + pL;
|
||||
double Fe_L = (rL * EL + pL) * uL;
|
||||
double Fm_R = rR * uR;
|
||||
double Fp_R = rR * uR * uR + pR;
|
||||
double Fe_R = (rR * ER + pR) * uR;
|
||||
double alpha = Math.Max(Math.Abs(uL) + cL, Math.Abs(uR) + cR);
|
||||
fm = 0.5 * (Fm_L + Fm_R) - 0.5 * alpha * (rR - rL);
|
||||
fp = 0.5 * (Fp_L + Fp_R) - 0.5 * alpha * (rR * uR - rL * uL);
|
||||
fe = 0.5 * (Fe_L + Fe_R) - 0.5 * alpha * (rR * ER - rL * EL);
|
||||
}
|
||||
|
||||
// Original LaxFriedrichsFlux (kept for compatibility, can be removed if unused)
|
||||
private void LaxFriedrichsFlux(double rL, double uL, double pL, double eL,
|
||||
double rR, double uR, double pR, double eR,
|
||||
out double fm, out double fp, out double fe)
|
||||
{
|
||||
double rhoL = rL, rhoR = rR;
|
||||
double EL = rhoL * eL;
|
||||
double ER = rhoR * eR;
|
||||
double Fm_L = rhoL * uL;
|
||||
double Fp_L = rhoL * uL * uL + pL;
|
||||
double Fe_L = (EL + pL) * uL;
|
||||
double Fm_R = rhoR * uR;
|
||||
double Fp_R = rhoR * uR * uR + pR;
|
||||
double Fe_R = (ER + pR) * uR;
|
||||
double cL = Math.Sqrt(_gamma * pL / rL);
|
||||
double cR = Math.Sqrt(_gamma * pR / rR);
|
||||
double alpha = Math.Max(Math.Abs(uL) + cL, Math.Abs(uR) + cR);
|
||||
fm = 0.5 * (Fm_L + Fm_R) - 0.5 * alpha * (rhoR - rhoL);
|
||||
fp = 0.5 * (Fp_L + Fp_R) - 0.5 * alpha * (rhoR * uR - rhoL * uL);
|
||||
fe = 0.5 * (Fe_L + Fe_R) - 0.5 * alpha * (ER - EL);
|
||||
}
|
||||
|
||||
private double PressureScalar(int i)
|
||||
{
|
||||
double rho = Math.Max(_rho[i], 1e-12);
|
||||
@@ -365,6 +386,7 @@ namespace FluidSim.Components
|
||||
_rho[i] = rho;
|
||||
_rhou[i] = rho * u;
|
||||
_E[i] = E;
|
||||
_Y[i] = 1.0; // initially pure air
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,6 +398,7 @@ namespace FluidSim.Components
|
||||
_rho[i] = rho;
|
||||
_rhou[i] = rho * u;
|
||||
_E[i] = E;
|
||||
_Y[i] = 1.0;
|
||||
}
|
||||
|
||||
public void SetCellPressure(int i, double p)
|
||||
|
||||
Reference in New Issue
Block a user