Files
FluidSim/Core/Solver.cs
2026-06-09 17:49:11 +02:00

102 lines
4.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using FluidSim.Components;
using FluidSim.Interfaces;
namespace FluidSim.Core
{
public class Solver
{
private readonly List<IComponent> _components = new();
private PipeSystem _pipeSystem;
private BoundarySystem _boundarySystem;
private double _dt;
public int SubStepCount { get; set; } = 4;
public bool EnableProfiling { get; set; } = false;
private long _stepCount;
private long _ticksOrifice, _ticksOpenEnd, _ticksPipe, _ticksUpdate;
public void SetTimeStep(double dt) => _dt = dt;
public void AddComponent(IComponent component) => _components.Add(component);
public void SetPipeSystem(PipeSystem pipeSystem)
{
_pipeSystem = pipeSystem;
}
public void SetBoundarySystem(BoundarySystem boundarySystem)
{
_boundarySystem = boundarySystem;
}
public void Step()
{
if (_pipeSystem == null || _boundarySystem == null) return;
int nSub = _pipeSystem.GetRequiredSubSteps((float)_dt, 0.8f);
nSub = Math.Max(nSub, SubStepCount); // never go below fixed minimum
float dtSub = (float)(_dt / nSub);
for (int sub = 0; sub < nSub; sub++)
{
long t0;
t0 = Stopwatch.GetTimestamp();
_boundarySystem.ResolveOrifices(dtSub);
_ticksOrifice += Stopwatch.GetTimestamp() - t0;
t0 = Stopwatch.GetTimestamp();
_boundarySystem.ResolveOpenEnds(dtSub);
_ticksOpenEnd += Stopwatch.GetTimestamp() - t0;
t0 = Stopwatch.GetTimestamp();
_pipeSystem.SimulateStep(dtSub);
_ticksPipe += Stopwatch.GetTimestamp() - t0;
}
long tUS = Stopwatch.GetTimestamp();
foreach (var comp in _components)
comp.UpdateState((float)_dt);
_ticksUpdate += Stopwatch.GetTimestamp() - tUS;
_stepCount++;
if (_stepCount % 5000 == 0 && EnableProfiling)
{
double freq = Stopwatch.Frequency;
double total = _ticksOrifice + _ticksOpenEnd + _ticksPipe + _ticksUpdate;
double avgStepUs = (total / freq) * 1e6 / 5000.0;
int orificeCalls = 5000 * nSub;
int updateCalls = 5000;
double orificeMs = _ticksOrifice * 1000.0 / freq;
double openEndMs = _ticksOpenEnd * 1000.0 / freq;
double pipeMs = _ticksPipe * 1000.0 / freq;
double updateMs = _ticksUpdate * 1000.0 / freq;
double orificeAvgUs = orificeMs * 1000.0 / orificeCalls;
double openEndAvgUs = openEndMs * 1000.0 / orificeCalls;
double pipeAvgUs = pipeMs * 1000.0 / orificeCalls;
double updateAvgUs = updateMs * 1000.0 / updateCalls;
Console.WriteLine($"--- Solver ({5000} steps, nSub={nSub}) ---");
Console.WriteLine($" Average step: {avgStepUs:F2} µs");
Console.WriteLine($" Orifice: {orificeMs:F2} ms ({(double)_ticksOrifice / total * 100:F1}%), avg {orificeAvgUs:F2} µs/call");
Console.WriteLine($" OpenEnd: {openEndMs:F2} ms ({(double)_ticksOpenEnd / total * 100:F1}%), avg {openEndAvgUs:F2} µs/call");
Console.WriteLine($" Pipe: {pipeMs:F2} ms ({(double)_ticksPipe / total * 100:F1}%), avg {pipeAvgUs:F2} µs/call");
Console.WriteLine($" Update: {updateMs:F2} ms ({(double)_ticksUpdate / total * 100:F1}%), avg {updateAvgUs:F2} µs/call");
// Pipe internal breakdown (with per-phase averages)
if (_pipeSystem.EnableProfiling)
{
Console.WriteLine(_pipeSystem.GetProfileReport());
}
_ticksOrifice = _ticksOpenEnd = _ticksPipe = _ticksUpdate = 0;
}
}
}
}