120 lines
4.3 KiB
C#
120 lines
4.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using FluidSim.Interfaces;
|
|
|
|
namespace FluidSim.Components
|
|
{
|
|
public class Volume0D : IComponent
|
|
{
|
|
public List<Port> Ports { get; } = new List<Port>();
|
|
|
|
private double _airMass;
|
|
private double _exhaustMass;
|
|
public double InternalEnergy { get; 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 AmbientPressure { get; set; } = 101325.0;
|
|
|
|
// Derived quantities
|
|
public double Mass => _airMass + _exhaustMass;
|
|
public double AirFraction => _airMass / Math.Max(Mass, 1e-12);
|
|
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 Volume0D(double initialVolume, double initialPressure,
|
|
double initialTemperature, double gasConstant = 287.0, double gamma = 1.4)
|
|
{
|
|
GasConstant = gasConstant;
|
|
Gamma = gamma;
|
|
Volume = initialVolume;
|
|
Dvdt = 0.0;
|
|
|
|
double rho0 = initialPressure / (GasConstant * initialTemperature);
|
|
_airMass = rho0 * Volume; // starts with all air
|
|
_exhaustMass = 0.0;
|
|
InternalEnergy = (initialPressure * Volume) / (Gamma - 1.0);
|
|
}
|
|
|
|
public Port CreatePort()
|
|
{
|
|
var port = new Port { Owner = this };
|
|
port.Pressure = Pressure;
|
|
port.Density = Density;
|
|
port.Temperature = Temperature;
|
|
port.SpecificEnthalpy = SpecificEnthalpy;
|
|
port.AirFraction = AirFraction;
|
|
Ports.Add(port);
|
|
return port;
|
|
}
|
|
|
|
public void SetPressure(double pressure, double? temperature = null)
|
|
{
|
|
double V = Math.Max(Volume, 1e-12);
|
|
double T = temperature ?? Temperature;
|
|
double rho = pressure / (GasConstant * T);
|
|
double totalMass = rho * V;
|
|
// Keep current air fraction when setting pressure?
|
|
double af = AirFraction;
|
|
_airMass = totalMass * af;
|
|
_exhaustMass = totalMass * (1.0 - af);
|
|
InternalEnergy = pressure * V / (Gamma - 1.0);
|
|
}
|
|
|
|
public void UpdateState(double dt)
|
|
{
|
|
double totalMdotAir = 0.0;
|
|
double totalMdotExhaust = 0.0;
|
|
double totalEdot = 0.0;
|
|
|
|
foreach (var port in Ports)
|
|
{
|
|
double mdot = port.MassFlowRate; // positive INTO volume
|
|
double af = mdot >= 0 ? port.AirFraction : AirFraction; // inflow: use port's fraction; outflow: well-mixed
|
|
totalMdotAir += mdot * af;
|
|
totalMdotExhaust += mdot * (1.0 - af);
|
|
totalEdot += mdot * port.SpecificEnthalpy;
|
|
}
|
|
|
|
double dAir = totalMdotAir * dt;
|
|
double dExhaust = totalMdotExhaust * dt;
|
|
double dE = totalEdot * dt - Pressure * Dvdt * dt;
|
|
|
|
_airMass += dAir;
|
|
_exhaustMass += dExhaust;
|
|
InternalEnergy += dE;
|
|
|
|
double V = Math.Max(Volume, 1e-12);
|
|
double totalMass = _airMass + _exhaustMass;
|
|
if (totalMass < 1e-9)
|
|
{
|
|
_airMass = 1e-9;
|
|
_exhaustMass = 0.0;
|
|
InternalEnergy = AmbientPressure * V / (Gamma - 1.0);
|
|
}
|
|
else if (InternalEnergy < 0.0)
|
|
{
|
|
InternalEnergy = AmbientPressure * V / (Gamma - 1.0);
|
|
}
|
|
|
|
if (_airMass < 0.0) _airMass = 0.0;
|
|
if (_exhaustMass < 0.0) _exhaustMass = 0.0;
|
|
|
|
double p = Pressure, rho = Density, T = Temperature, h = SpecificEnthalpy, afrac = AirFraction;
|
|
foreach (var port in Ports)
|
|
{
|
|
port.Pressure = p;
|
|
port.Density = rho;
|
|
port.Temperature = T;
|
|
port.SpecificEnthalpy = h;
|
|
port.AirFraction = afrac;
|
|
}
|
|
}
|
|
|
|
IReadOnlyList<Port> IComponent.Ports => Ports;
|
|
}
|
|
} |