Files
FluidSim/Components/Pipe1D.cs
2026-05-02 18:05:14 +02:00

203 lines
7.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using FluidSim.Interfaces;
namespace FluidSim.Components
{
public class Pipe1D
{
public Port PortA { get; }
public Port PortB { get; }
public double Area => _area;
private int _n;
private double _dx, _dt, _gamma = 1.4, _area;
private double[] _rho, _rhou, _E;
// Volume states at boundaries
private double _rhoLeft, _pLeft, _rhoRight, _pRight;
private bool _leftBCSet, _rightBCSet;
public double FrictionFactor { get; set; } = 0.02;
public int GetCellCount() => _n;
public double GetCellDensity(int i) => _rho[i];
public double GetCellPressure(int i) => Pressure(i);
public double GetCellVelocity(int i) => _rhou[i] / Math.Max(_rho[i], 1e-12);
public Pipe1D(double length, double area, int nCells, int sampleRate)
{
_n = nCells;
_dx = length / nCells;
_dt = 1.0 / sampleRate;
_area = area;
_rho = new double[_n];
_rhou = new double[_n];
_E = new double[_n];
PortA = new Port();
PortB = new Port();
}
public void SetUniformState(double rho, double u, double p)
{
double e = p / ((_gamma - 1) * rho);
double Etot = rho * e + 0.5 * rho * u * u;
for (int i = 0; i < _n; i++)
{
_rho[i] = rho;
_rhou[i] = rho * u;
_E[i] = Etot;
}
}
public double GetLeftPressure() => Pressure(0);
public double GetRightPressure() => Pressure(_n - 1);
public double GetLeftDensity() => _rho[0];
public double GetRightDensity() => _rho[_n - 1];
// ★ New: pass both density and pressure from the volume
public void SetLeftVolumeState(double rhoVol, double pVol)
{
_rhoLeft = rhoVol;
_pLeft = pVol;
_leftBCSet = true;
}
public void SetRightVolumeState(double rhoVol, double pVol)
{
_rhoRight = rhoVol;
_pRight = pVol;
_rightBCSet = true;
}
private double GetCellTotalSpecificEnthalpy(int i)
{
double rho = Math.Max(_rho[i], 1e-12);
double u = _rhou[i] / rho;
double p = Pressure(i);
double h = _gamma / (_gamma - 1.0) * p / rho;
return h + 0.5 * u * u;
}
public void Simulate()
{
int n = _n;
double[] Fm = new double[n + 1], Fp = new double[n + 1], Fe = new double[n + 1];
// --- Left boundary (face 0) ---
if (_leftBCSet)
{
// Ghost = actual volume state (ρ_vol, u=0, p_vol)
double rhoL = _rhoLeft;
double uL = 0.0;
double pL = _pLeft;
double rhoR = _rho[0];
double uR = _rhou[0] / Math.Max(rhoR, 1e-12);
double pR = Pressure(0);
HLLCFlux(rhoL, uL, pL, rhoR, uR, pR, out Fm[0], out Fp[0], out Fe[0]);
}
else
{
Fm[0] = 0;
Fp[0] = Pressure(0);
Fe[0] = 0;
}
// --- Internal faces ---
for (int i = 0; i < n - 1; i++)
{
double uL = _rhou[i] / Math.Max(_rho[i], 1e-12);
double uR = _rhou[i + 1] / Math.Max(_rho[i + 1], 1e-12);
HLLCFlux(_rho[i], uL, Pressure(i), _rho[i + 1], uR, Pressure(i + 1),
out Fm[i + 1], out Fp[i + 1], out Fe[i + 1]);
}
// --- Right boundary (face n) ---
if (_rightBCSet)
{
double rhoL = _rho[n - 1];
double uL = _rhou[n - 1] / Math.Max(rhoL, 1e-12);
double pL = Pressure(n - 1);
// Ghost = actual volume state (ρ_vol, u=0, p_vol)
double rhoR = _rhoRight;
double uR = 0.0;
double pR = _pRight;
HLLCFlux(rhoL, uL, pL, rhoR, uR, pR, out Fm[n], out Fp[n], out Fe[n]);
}
else
{
Fm[n] = 0;
Fp[n] = Pressure(n - 1);
Fe[n] = 0;
}
// --- Cell update ---
for (int i = 0; i < n; i++)
{
double dM = (Fm[i + 1] - Fm[i]) / _dx;
double dP = (Fp[i + 1] - Fp[i]) / _dx;
double dE = (Fe[i + 1] - Fe[i]) / _dx;
_rho[i] -= _dt * dM;
_rhou[i] -= _dt * dP;
_E[i] -= _dt * dE;
if (_rho[i] < 1e-12) _rho[i] = 1e-12;
double kinetic = 0.5 * _rhou[i] * _rhou[i] / _rho[i];
if (_E[i] < kinetic) _E[i] = kinetic;
}
// --- Friction disabled ---
// if (FrictionFactor > 0) { … }
// --- Port flows ---
PortA.MassFlowRate = _leftBCSet ? Fm[0] * _area : 0.0;
PortB.MassFlowRate = _rightBCSet ? -Fm[n] * _area : 0.0;
PortA.SpecificEnthalpy = GetCellTotalSpecificEnthalpy(0);
PortB.SpecificEnthalpy = GetCellTotalSpecificEnthalpy(_n - 1);
_leftBCSet = _rightBCSet = false;
}
double Pressure(int i) =>
(_gamma - 1.0) * (_E[i] - 0.5 * _rhou[i] * _rhou[i] / Math.Max(_rho[i], 1e-12));
void HLLCFlux(double rL, double uL, double pL, double rR, double uR, double pR,
out double fm, out double fp, out double fe)
{
double cL = Math.Sqrt(_gamma * pL / Math.Max(rL, 1e-12));
double cR = Math.Sqrt(_gamma * pR / Math.Max(rR, 1e-12));
double EL = pL / ((_gamma - 1) * rL) + 0.5 * uL * uL;
double ER = pR / ((_gamma - 1) * rR) + 0.5 * uR * uR;
double SL = Math.Min(uL - cL, uR - cR);
double SR = Math.Max(uL + cL, uR + cR);
double Ss = (pR - pL + rL * uL * (SL - uL) - rR * uR * (SR - uR))
/ (rL * (SL - uL) - rR * (SR - uR));
double FrL_m = rL * uL, FrL_p = rL * uL * uL + pL, FrL_e = (rL * EL + pL) * uL;
double FrR_m = rR * uR, FrR_p = rR * uR * uR + pR, FrR_e = (rR * ER + pR) * uR;
if (SL >= 0) { fm = FrL_m; fp = FrL_p; fe = FrL_e; }
else if (SR <= 0) { fm = FrR_m; fp = FrR_p; fe = FrR_e; }
else if (Ss >= 0)
{
double rsL = rL * (SL - uL) / (SL - Ss);
double ps = pL + rL * (SL - uL) * (Ss - uL);
double EsL = EL + (Ss - uL) * (Ss + pL / (rL * (SL - uL)));
fm = rsL * Ss; fp = rsL * Ss * Ss + ps; fe = (rsL * EsL + ps) * Ss;
}
else
{
double rsR = rR * (SR - uR) / (SR - Ss);
double ps = pL + rL * (SL - uL) * (Ss - uL);
double EsR = ER + (Ss - uR) * (Ss + pR / (rR * (SR - uR)));
fm = rsR * Ss; fp = rsR * Ss * Ss + ps; fe = (rsR * EsR + ps) * Ss;
}
}
}
}