102 lines
4.0 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
} |