using System; using SFML.Graphics; using SFML.System; using FluidSim.Components; using FluidSim.Core; namespace FluidSim.Tests { public class TestScenario : Scenario { private Solver solver; private Pipe1D pipe; private OrificeLink closedEnd; // left end – closed wall private OpenEndLink openEndLink; // right end – atmosphere private SoundProcessor soundProcessor; private OutdoorExhaustReverb reverb; private int stepCount; private double simTime; // elapsed simulation time (seconds) private double pulseInterval = 0.1; // seconds between pulses private double nextPulseTime; private double dt; public override void Initialize(int sampleRate) { dt = 1.0 / sampleRate; soundProcessor = new SoundProcessor(sampleRate, 1); soundProcessor.Gain = 10; reverb = new OutdoorExhaustReverb(sampleRate); solver = new Solver(); solver.SetTimeStep(dt); // Pipe: 2 m long, 1 cm² area, 200 cells pipe = new Pipe1D(length: 2, area: 1e-4, cellCount: 100); solver.AddComponent(pipe); // Initially pipe at ambient conditions pipe.SetUniformState(1.225, 0.0, 101325.0); // Left end: closed wall (area = 0 → reflective) closedEnd = new OrificeLink(null, pipe, isPipeLeftEnd: true, areaProvider: () => 0.0); solver.AddOrificeLink(closedEnd); // Right end: open to atmosphere openEndLink = new OpenEndLink(pipe, isLeftEnd: false) { AmbientPressure = 101325.0, Gamma = 1.4 }; solver.AddOpenEndLink(openEndLink); stepCount = 0; simTime = 0.0; nextPulseTime = pulseInterval; // first pulse at 100 ms Console.WriteLine("Pulse reflection test – closed left, open right"); Console.WriteLine("Pulse injected every 100 ms at left end (cell 0)"); } public override float Process() { solver.Step(); stepCount++; simTime += dt; // ---- Inject a pressure pulse at the closed end every 100 ms ---- if (simTime >= nextPulseTime) { // Apply a Gaussian pulse to the first few cells double ambientPressure = 101325.0; double pulseAmplitude = 20 * ambientPressure; // 0.5 atm overpressure double pulseWidth = 0.05; // m (spread over a few cells) int n = pipe.CellCount; double dx = 2.0 / n; // Only modify cells within 2*pulseWidth from the left end int maxCell = Math.Min(5, n - 1); // at most the first 5 cells for (int i = 0; i <= maxCell; i++) { double x = (i + 0.5) * dx; double P = pulseAmplitude * Math.Exp(-x * x / (pulseWidth * pulseWidth)); double currentP = pipe.GetCellPressure(i); double newP = P; // Update pressure, keeping density and velocity unchanged // We recompute total energy accordingly double rho = pipe.GetCellDensity(i); double u = pipe.GetCellVelocity(i); double e = newP / ((1.4 - 1.0) * rho); double E = rho * e + 0.5 * rho * u * u; pipe.SetCellState(i, rho, u, newP); } Console.WriteLine($"Pulse injected at t = {simTime:F3} s"); nextPulseTime += pulseInterval; } // Audio from open‑end mass flow float sample = soundProcessor.Process(openEndLink); // Log every 200 steps if (stepCount % 1000 == 0) { int leftIdx = 0; int midIdx = pipe.CellCount / 2; int rightIdx = pipe.CellCount - 1; double pL = pipe.GetCellPressure(leftIdx); double pM = pipe.GetCellPressure(midIdx); double pR = pipe.GetCellPressure(rightIdx); Console.WriteLine($"Step {stepCount}: P_left={pL:F1} Pa, P_mid={pM:F1} Pa, P_right={pR:F1} Pa"); } if (double.IsNaN(pipe.GetCellPressure(0))) { Console.WriteLine("NaN detected – stopping simulation."); return 0f; } return reverb.Process(sample); } public override void Draw(RenderWindow target) { float winWidth = target.GetView().Size.X; float winHeight = target.GetView().Size.Y; float pipeCenterY = winHeight / 2f; float margin = 60f; float pipeStartX = margin; float pipeEndX = winWidth - margin; DrawPipe(target, pipe, pipeCenterY, pipeStartX, pipeEndX); } } }