Files
FluidSim/Core/Solver.cs

116 lines
4.4 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.Collections.Generic;
using FluidSim.Components;
using FluidSim.Interfaces;
namespace FluidSim.Core
{
public class Solver
{
private readonly List<Volume0D> _volumes = new();
private readonly List<Pipe1D> _pipes = new();
private readonly List<Connection> _connections = new();
public void AddVolume(Volume0D v) => _volumes.Add(v);
public void AddPipe(Pipe1D p) => _pipes.Add(p);
public void AddConnection(Connection c) => _connections.Add(c);
public void Step()
{
// 1. Volumes publish state
foreach (var v in _volumes)
v.PushStateToPort();
// 2. Compute boundary fluxes (orifice model)
foreach (var conn in _connections)
{
if (IsPipePort(conn.PortA) && IsVolumePort(conn.PortB))
ApplyOrifice(conn, conn.PortA, conn.PortB);
else if (IsVolumePort(conn.PortA) && IsPipePort(conn.PortB))
ApplyOrifice(conn, conn.PortB, conn.PortA);
else if (IsVolumePort(conn.PortA) && IsVolumePort(conn.PortB))
VolumeToVolume(conn);
}
// 3. Pipe simulation step
foreach (var p in _pipes)
p.Simulate();
// 4. Transfer pipeport data to volumes
foreach (var conn in _connections)
{
if (IsPipePort(conn.PortA) && IsVolumePort(conn.PortB))
TransferPipeToVolume(conn.PortA, conn.PortB);
else if (IsVolumePort(conn.PortA) && IsPipePort(conn.PortB))
TransferPipeToVolume(conn.PortB, conn.PortA);
}
// 5. Integrate volumes
foreach (var v in _volumes)
v.Integrate();
}
bool IsVolumePort(Port p) => _volumes.Exists(v => v.Port == p);
bool IsPipePort(Port p) => _pipes.Exists(pp => pp.PortA == p || pp.PortB == p);
Pipe1D GetPipe(Port p) => _pipes.Find(pp => pp.PortA == p || pp.PortB == p);
void ApplyOrifice(Connection conn, Port pipePort, Port volPort)
{
Pipe1D pipe = GetPipe(pipePort);
if (pipe == null) return;
bool isLeft = pipe.PortA == pipePort;
double pP = isLeft ? pipe.GetLeftPressure() : pipe.GetRightPressure();
double rhoP = isLeft ? pipe.GetLeftDensity() : pipe.GetRightDensity();
double uP = isLeft ? pipe.GetCellVelocity(0)
: pipe.GetCellVelocity(pipe.GetCellCount() - 1);
double pV = volPort.Pressure;
double rhoV = volPort.Density;
double uV = 0.0; // volume has zero organized velocity
OrificeBoundary.PipeVolumeFlux(
pP, rhoP, uP,
pV, rhoV, uV,
conn, pipe.Area, isLeft,
out double massFlux, out double momFlux, out double energyFlux);
if (isLeft)
pipe.SetLeftBoundaryFlux(massFlux, momFlux, energyFlux);
else
pipe.SetRightBoundaryFlux(massFlux, momFlux, energyFlux);
}
void VolumeToVolume(Connection conn)
{
double mdot = OrificeBoundary.MassFlow(
conn.PortA.Pressure, conn.PortA.Density,
conn.PortB.Pressure, conn.PortB.Density, conn);
conn.PortA.MassFlowRate = -mdot;
conn.PortB.MassFlowRate = mdot;
if (mdot > 0)
conn.PortB.SpecificEnthalpy = conn.PortA.SpecificEnthalpy;
else if (mdot < 0)
conn.PortA.SpecificEnthalpy = conn.PortB.SpecificEnthalpy;
}
void TransferPipeToVolume(Port pipePort, Port volPort)
{
double mdot = pipePort.MassFlowRate;
// mdot > 0 → fluid enters pipe from volume
// mdot < 0 → fluid leaves pipe and enters volume
// Volume mass flow sign is opposite (positive into volume)
volPort.MassFlowRate = -mdot;
if (mdot < 0) // pipe → volume
{
// ★ pipePort.SpecificEnthalpy now contains TOTAL enthalpy
volPort.SpecificEnthalpy = pipePort.SpecificEnthalpy;
}
// else: fluid goes volume → pipe → volume owns its own (static) enthalpy,
// which is already correct.
}
}
}