using FluidSim.Components; using FluidSim.Core; using FluidSim.Interfaces; using SFML.Graphics; using SFML.System; using System; namespace FluidSim.Tests { public class HelmholtzScenario : Scenario { private Volume0D cavity; private Port cavityPort; private PipeSystem pipeSystem; private int[] pipeStart = { 0 }; private int[] pipeEnd; private BoundarySystem boundaries; private int cavityOrificeIdx = 0; private int openEndIdx = 0; private Solver solver; private double dt; private int stepCount; private SoundProcessor soundProcessor; public override void Initialize(int sampleRate) { dt = 1.0 / sampleRate; // --- Realistic Helmholtz resonator dimensions --- float cavityVolume = 1e-3f; // 1 liter float neckLength = 0.05f; // 5 cm float neckDiameter = 0.02f; // 2 cm diameter float neckArea = MathF.PI * 0.25f * neckDiameter * neckDiameter; int neckCells = 20; // --- Volume (cavity) --- float initialPressure = 1.1f * 101325f; // slight overpressure float initialTemperature = 300f; cavity = new Volume0D(cavityVolume, initialPressure, initialTemperature); cavityPort = cavity.CreatePort(); // --- Pipe (neck) --- float[] areas = new float[neckCells]; float[] dxs = new float[neckCells]; float dx = neckLength / neckCells; for (int i = 0; i < neckCells; i++) { areas[i] = neckArea; dxs[i] = dx; } pipeEnd = new[] { neckCells }; float rho0 = 101325f / (287f * 300f); pipeSystem = new PipeSystem(neckCells, pipeStart, pipeEnd, areas, dxs, rho0, 0f, 101325f); // --- Boundary system --- boundaries = new BoundarySystem(pipeSystem, maxOrifices: 1, maxOpenEnds: 1); // Standard orifice with built‑in minor loss (K = 0.5) – no inertance needed boundaries.AddOrificeWithInertance( cavityPort, pipeIndex: 0, isLeftEnd: true, areaIndex: cavityOrificeIdx, dischargeCoeff: 0.9f, effectiveLength: neckLength // physical neck length ); // Open end at right side of pipe boundaries.AddOpenEnd(pipeIndex: 0, isLeftEnd: false, 101325f, neckArea); float[] orificeAreas = new float[1] { neckArea }; boundaries.SetOrificeAreas(orificeAreas); // --- Solver --- solver = new Solver { SubStepCount = 8, EnableProfiling = false }; solver.SetTimeStep(dt); solver.SetPipeSystem(pipeSystem); solver.SetBoundarySystem(boundaries); solver.AddComponent(cavity); // --- Sound --- soundProcessor = new SoundProcessor(sampleRate, 1f) { Gain = 2f }; Console.WriteLine("Helmholtz resonator ready."); stepCount = 0; } public override float Process() { solver.Step(); stepCount++; float flow = boundaries.GetOpenEndMassFlow(openEndIdx); float sample = soundProcessor.Process(flow); return sample; } public override void Draw(RenderWindow target) { float winW = target.GetView().Size.X; float winH = target.GetView().Size.Y; float cavityCenterX = 100f; float cavityWidth = 80f, cavityHeight = 100f; float cavityTopY = winH / 2f - cavityHeight / 2f; DrawVolume(target, cavity, cavityCenterX, cavityTopY - 40f, cavityWidth, cavityHeight); float pipeStartX = cavityCenterX + cavityWidth / 2f + 10f; float pipeEndX = winW - 50f; float pipeCenterY = winH / 2f; DrawPipe(target, pipeSystem, 0, pipeCenterY, pipeStartX, pipeEndX); } } }