Helmholtz testing (no decay bug)

This commit is contained in:
max
2026-05-09 01:44:35 +02:00
parent 9c9e23147a
commit 77ef4753a3
23 changed files with 1811 additions and 2118 deletions

View File

@@ -1,72 +1,60 @@
using System;
using SFML.Graphics;
using SFML.Graphics;
using SFML.System;
using FluidSim.Core;
using FluidSim.Components;
namespace FluidSim.Tests
{
public abstract class Scenario
{
protected const float AmbientPressure = 101325f;
protected const float AmbientTemperature = 300f;
public float Throttle { get; set; }
public abstract void Initialize(int sampleRate);
public abstract float Process();
public abstract void Draw(RenderWindow target);
protected const double AmbientPressure = 101325.0;
protected const double AmbientTemperature = 300.0;
public double Throttle { get; set; } = 0.0;
// ---------- Color from pressure (volumes) ----------
protected Color PressureColor(double pressurePa)
protected Color PressureColor(float pressurePa)
{
double bar = pressurePa / 1e5; // convert to bar for easier mapping
float bar = pressurePa / 1e5f;
byte r, g, b;
if (bar < 1.0) // vacuum → blue to green
if (bar < 1f)
{
double factor = Math.Clamp(bar, 0.0, 1.0);
r = 0;
g = (byte)(255 * factor);
b = (byte)(255 * (1.0 - factor));
}
else // above ambient → green to red
{
double factor = Math.Min((bar - 1.0) / 9.0, 1.0); // 1→10 bar maps to 0→1
r = (byte)(255 * factor);
g = (byte)(255 * (1.0 - factor));
b = 0;
}
return new Color(r, g, b);
}
// ---------- Color from temperature (pipes) ----------
protected Color TemperatureColor(double temperature)
{
double t = Math.Clamp(temperature, 0.0, 2000.0);
byte r, g, b;
if (t < AmbientTemperature)
{
double factor = t / AmbientTemperature;
r = 0;
g = (byte)(255 * factor);
b = (byte)(255 * (1.0 - factor));
float f = Math.Clamp(bar, 0f, 1f);
r = 0; g = (byte)(255 * f); b = (byte)(255 * (1 - f));
}
else
{
double factor = (t - AmbientTemperature) / (2000.0 - AmbientTemperature);
r = (byte)(255 * factor);
g = (byte)(255 * (1.0 - factor));
b = 0;
float f = Math.Min((bar - 1f) / 9f, 1f);
r = (byte)(255 * f); g = (byte)(255 * (1 - f)); b = 0;
}
return new Color(r, g, b);
}
protected Color TemperatureColor(float t)
{
t = Math.Clamp(t, 0f, 2000f);
byte r, g, b;
if (t < AmbientTemperature)
{
float f = t / AmbientTemperature;
r = 0; g = (byte)(255 * f); b = (byte)(255 * (1 - f));
}
else
{
float f = (t - AmbientTemperature) / (2000f - AmbientTemperature);
r = (byte)(255 * f); g = (byte)(255 * (1 - f)); b = 0;
}
return new Color(r, g, b);
}
// ---------- Draw a generic volume (e.g. plenum) ----------
protected void DrawVolume(RenderWindow target, Volume0D volume,
float centerX, float topY, float width, float height)
{
var rect = new RectangleShape(new Vector2f(width, height))
{
FillColor = PressureColor(volume.Pressure), // ← pressurebased
FillColor = PressureColor(volume.Pressure),
Position = new Vector2f(centerX - width / 2f, topY)
};
target.Draw(rect);
@@ -75,122 +63,99 @@ namespace FluidSim.Tests
FillColor = Color.Transparent,
OutlineColor = Color.White,
OutlineThickness = 1f,
Position = new Vector2f(centerX - width / 2f, topY)
Position = rect.Position
};
target.Draw(border);
}
// ---------- Draw an engine cylinder ----------
protected void DrawCylinder(RenderWindow target, Cylinder cylinder,
float centerX, float topY, float width, float maxHeight)
{
double fraction = cylinder.PistonFraction;
float currentHeight = (float)(maxHeight * fraction);
// Walls
var wall = new RectangleShape(new Vector2f(width, maxHeight));
wall.FillColor = new Color(60, 60, 60);
wall.Position = new Vector2f(centerX - width / 2f, topY);
float fraction = cylinder.PistonFraction;
float currentHeight = maxHeight * fraction;
var wall = new RectangleShape(new Vector2f(width, maxHeight))
{
FillColor = new Color(60, 60, 60),
Position = new Vector2f(centerX - width / 2f, topY)
};
target.Draw(wall);
// Gas colored by pressure now
float gasTop = topY;
var gasRect = new RectangleShape(new Vector2f(width, currentHeight));
gasRect.FillColor = PressureColor(cylinder.Pressure); // ← pressurebased
gasRect.Position = new Vector2f(centerX - width / 2f, gasTop);
target.Draw(gasRect);
// Piston line
var pistonLine = new RectangleShape(new Vector2f(width, 4f));
pistonLine.FillColor = Color.White;
pistonLine.Position = new Vector2f(centerX - width / 2f, topY + currentHeight);
target.Draw(pistonLine);
// Valve indicators
var gas = new RectangleShape(new Vector2f(width, currentHeight))
{
FillColor = PressureColor(cylinder.Pressure),
Position = new Vector2f(centerX - width / 2f, topY)
};
target.Draw(gas);
var piston = new RectangleShape(new Vector2f(width, 4f))
{
FillColor = Color.White,
Position = new Vector2f(centerX - width / 2f, topY + currentHeight)
};
target.Draw(piston);
float valveW = 6f, valveH = 10f, valveY = topY + 4f;
var intakeValve = new RectangleShape(new Vector2f(valveW, valveH));
intakeValve.FillColor = cylinder.IntakeValveArea > 0 ? Color.Green : Color.Red;
intakeValve.Position = new Vector2f(centerX - width / 2f - valveW - 2f, valveY);
target.Draw(intakeValve);
var exhaustValve = new RectangleShape(new Vector2f(valveW, valveH));
exhaustValve.FillColor = cylinder.ExhaustValveArea > 0 ? Color.Green : Color.Red;
exhaustValve.Position = new Vector2f(centerX + width / 2f + 2f, valveY);
target.Draw(exhaustValve);
var iv = new RectangleShape(new Vector2f(valveW, valveH))
{
FillColor = cylinder.IntakeValveArea > 0f ? Color.Green : Color.Red,
Position = new Vector2f(centerX - width / 2f - valveW - 2f, valveY)
};
target.Draw(iv);
var ev = new RectangleShape(new Vector2f(valveW, valveH))
{
FillColor = cylinder.ExhaustValveArea > 0f ? Color.Green : Color.Red,
Position = new Vector2f(centerX + width / 2f + 2f, valveY)
};
target.Draw(ev);
}
// ---------- Draw a pipe (unchanged) ----------
protected void DrawPipe(RenderWindow target, Pipe1D pipe, float pipeCenterY, float pipeStartX, float pipeEndX)
protected void DrawPipe(RenderWindow target, PipeSystem pipeSystem, int pipeIndex,
float pipeCenterY, float pipeStartX, float pipeEndX)
{
int n = pipe.CellCount;
int start = pipeSystem.GetPipeStart(pipeIndex);
int end = pipeSystem.GetPipeEnd(pipeIndex);
int n = end - start;
if (n < 2) return;
float pipeLengthPx = pipeEndX - pipeStartX;
float dx = pipeLengthPx / (n - 1);
float pipeLen = pipeEndX - pipeStartX;
float dx = pipeLen / (n - 1);
float baseRadius = 25f;
float rangeFactor = 2f;
float scaleFactor = 2f;
static float SmoothStep(float edge0, float edge1, float x)
{
float t = Math.Clamp((x - edge0) / (edge1 - edge0), 0f, 1f);
return t * t * (3f - 2f * t);
}
var centers = new float[n];
var radii = new float[n];
var temperatures = new double[n];
double R_gas = 287.0;
var temps = new float[n];
for (int i = 0; i < n; i++)
{
double p = pipe.GetCellPressure(i);
double rho = pipe.GetCellDensity(i);
double T = p / Math.Max(rho * R_gas, 1e-12);
temperatures[i] = T;
float deviation = (float)Math.Tanh((p - AmbientPressure) / AmbientPressure / rangeFactor);
radii[i] = baseRadius * (1f + deviation * scaleFactor);
int cell = start + i;
float p = pipeSystem.GetCellPressure(cell);
float rho = pipeSystem.GetCellDensity(cell);
temps[i] = p / MathF.Max(rho * 287f, 1e-12f);
float dev = MathF.Tanh((p - AmbientPressure) / AmbientPressure * 0.5f);
radii[i] = baseRadius * (1f + dev * 2f);
if (radii[i] < 2f) radii[i] = 2f;
centers[i] = pipeStartX + i * dx;
}
int segmentsPerCell = 8;
int totalPoints = n + (n - 1) * segmentsPerCell;
Vertex[] stripVertices = new Vertex[totalPoints * 2];
int idx = 0;
int segments = 8;
var va = new VertexArray(PrimitiveType.TriangleStrip);
for (int i = 0; i < n; i++)
{
float x = centers[i];
float r = radii[i];
Color col = TemperatureColor(temperatures[i]); // pipes still use temperature
stripVertices[idx++] = new Vertex(new Vector2f(x, pipeCenterY - r), col);
stripVertices[idx++] = new Vertex(new Vector2f(x, pipeCenterY + r), col);
float x = centers[i], r = radii[i];
Color col = TemperatureColor(temps[i]);
va.Append(new Vertex(new Vector2f(x, pipeCenterY - r), col));
va.Append(new Vertex(new Vector2f(x, pipeCenterY + r), col));
if (i < n - 1)
{
for (int s = 1; s <= segmentsPerCell; s++)
for (int s = 1; s <= segments; s++)
{
float t = s / (float)segmentsPerCell;
float st = SmoothStep(0f, 1f, t);
float t = s / (float)segments;
float xi = centers[i] + (centers[i + 1] - centers[i]) * t;
float ri = radii[i] + (radii[i + 1] - radii[i]) * st;
double Ti = temperatures[i] + (temperatures[i + 1] - temperatures[i]) * st;
Color coli = TemperatureColor(Ti);
stripVertices[idx++] = new Vertex(new Vector2f(xi, pipeCenterY - ri), coli);
stripVertices[idx++] = new Vertex(new Vector2f(xi, pipeCenterY + ri), coli);
float ri = radii[i] + (radii[i + 1] - radii[i]) * t;
float Ti = temps[i] + (temps[i + 1] - temps[i]) * t;
Color colS = TemperatureColor(Ti);
va.Append(new Vertex(new Vector2f(xi, pipeCenterY - ri), colS));
va.Append(new Vertex(new Vector2f(xi, pipeCenterY + ri), colS));
}
}
}
var pipeMesh = new VertexArray(PrimitiveType.TriangleStrip, (uint)stripVertices.Length);
for (int i = 0; i < stripVertices.Length; i++)
pipeMesh[(uint)i] = stripVertices[i];
target.Draw(pipeMesh);
target.Draw(va);
}
}
}