refactoring (broken right now)
This commit is contained in:
@@ -1,69 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FluidSim.Interfaces;
|
||||
|
||||
namespace FluidSim.Components
|
||||
{
|
||||
public class Volume0D
|
||||
/// <summary>
|
||||
/// Zero‑dimensional control volume with arbitrary number of ports.
|
||||
/// Integrates mass and energy fluxes from all ports.
|
||||
/// Safeguards keep a tiny amount of gas to avoid negative states.
|
||||
/// </summary>
|
||||
public class Volume0D : IComponent
|
||||
{
|
||||
public double Mass { get; set; }
|
||||
public double InternalEnergy { get; set; }
|
||||
public List<Port> Ports { get; } = new List<Port>();
|
||||
|
||||
public double Mass { get; private set; }
|
||||
public double InternalEnergy { get; private set; }
|
||||
public double Volume { get; set; }
|
||||
public double Dvdt { get; set; }
|
||||
public double Gamma { get; set; } = 1.4;
|
||||
public double GasConstant { get; set; } = 287.0;
|
||||
|
||||
public double Volume { get; set; }
|
||||
public double Dvdt { get; set; }
|
||||
|
||||
private double _dt;
|
||||
// Ambient pressure used for emergency refill – default 101325 Pa
|
||||
public double AmbientPressure { get; set; } = 101325.0;
|
||||
|
||||
// Derived quantities
|
||||
public double Density => Mass / Math.Max(Volume, 1e-12);
|
||||
public double Pressure => (Gamma - 1.0) * InternalEnergy / Math.Max(Volume, 1e-12);
|
||||
public double Temperature => Pressure / Math.Max(Density * GasConstant, 1e-12);
|
||||
public double SpecificEnthalpy => Gamma / (Gamma - 1.0) * Pressure / Math.Max(Density, 1e-12);
|
||||
|
||||
public double MassFlowRateIn { get; set; }
|
||||
public double SpecificEnthalpyIn { get; set; }
|
||||
|
||||
public Volume0D(double initialVolume, double initialPressure,
|
||||
double initialTemperature, int sampleRate,
|
||||
double gasConstant = 287.0, double gamma = 1.4)
|
||||
double initialTemperature, double gasConstant = 287.0, double gamma = 1.4)
|
||||
{
|
||||
GasConstant = gasConstant;
|
||||
Gamma = gamma;
|
||||
Volume = initialVolume;
|
||||
Dvdt = 0.0;
|
||||
_dt = 1.0 / sampleRate;
|
||||
|
||||
double rho0 = initialPressure / (GasConstant * initialTemperature);
|
||||
Mass = rho0 * Volume;
|
||||
InternalEnergy = (initialPressure * Volume) / (Gamma - 1.0);
|
||||
}
|
||||
|
||||
public void Integrate(double dtOverride)
|
||||
/// <summary>Add a new port and initialise it to the volume's current state.</summary>
|
||||
public Port CreatePort()
|
||||
{
|
||||
double dm = MassFlowRateIn * dtOverride;
|
||||
double dE = (MassFlowRateIn * SpecificEnthalpyIn) * dtOverride - Pressure * Dvdt * dtOverride;
|
||||
var port = new Port { Owner = this };
|
||||
// Set the port state immediately to avoid a mismatch before the first integration
|
||||
port.Pressure = Pressure;
|
||||
port.Density = Density;
|
||||
port.Temperature = Temperature;
|
||||
port.SpecificEnthalpy = SpecificEnthalpy;
|
||||
Ports.Add(port);
|
||||
return port;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Integrate over dt using the MassFlowRate and SpecificEnthalpy
|
||||
/// that have been set on each port during the coupling resolution phase.
|
||||
/// </summary>
|
||||
public void UpdateState(double dt)
|
||||
{
|
||||
double totalMdot = 0.0;
|
||||
double totalEdot = 0.0;
|
||||
|
||||
foreach (var port in Ports)
|
||||
{
|
||||
totalMdot += port.MassFlowRate;
|
||||
// mdot * h gives energy flow: positive mdot = inflow, negative = outflow
|
||||
totalEdot += port.MassFlowRate * port.SpecificEnthalpy;
|
||||
}
|
||||
|
||||
double dm = totalMdot * dt;
|
||||
double dE = totalEdot * dt - Pressure * Dvdt * dt; // piston work
|
||||
|
||||
Mass += dm;
|
||||
InternalEnergy += dE;
|
||||
|
||||
// ---- ABSOLUTE SAFEGUARD: keep at least 1 µg of gas at ambient pressure ----
|
||||
double minMass = 1e-9;
|
||||
// Safeguards: keep at least 1 µg of gas at a small pressure
|
||||
double V = Math.Max(Volume, 1e-12);
|
||||
if (Mass < minMass)
|
||||
if (Mass < 1e-9)
|
||||
{
|
||||
Mass = minMass;
|
||||
InternalEnergy = 5000.0 * V / (Gamma - 1.0); // 0.05 bar, not ambient
|
||||
Mass = 1e-9;
|
||||
InternalEnergy = AmbientPressure * V / (Gamma - 1.0);
|
||||
}
|
||||
else if (InternalEnergy < 0.0)
|
||||
{
|
||||
InternalEnergy = 101325.0 * V / (Gamma - 1.0);
|
||||
InternalEnergy = AmbientPressure * V / (Gamma - 1.0);
|
||||
}
|
||||
|
||||
// Final non‑negative clamp
|
||||
if (Mass < 0.0) Mass = 0.0;
|
||||
if (InternalEnergy < 0.0) InternalEnergy = 0.0;
|
||||
// Final non‑negative clamps (should not be needed after above)
|
||||
if (Mass < 0.0) Mass = 1e-9;
|
||||
if (InternalEnergy < 0.0) InternalEnergy = AmbientPressure * V / (Gamma - 1.0);
|
||||
|
||||
// Push updated state back to all ports
|
||||
double p = Pressure, rho = Density, T = Temperature, h = SpecificEnthalpy;
|
||||
foreach (var port in Ports)
|
||||
{
|
||||
port.Pressure = p;
|
||||
port.Density = rho;
|
||||
port.Temperature = T;
|
||||
port.SpecificEnthalpy = h; // will be overwritten by couplings for inflow, but this is the default
|
||||
}
|
||||
}
|
||||
|
||||
public void Integrate() => Integrate(_dt);
|
||||
IReadOnlyList<Port> IComponent.Ports => Ports;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user