Apply boundary sink free-outflow on ghost cells

This commit is contained in:
2026-02-11 00:00:33 +01:00
parent 9aa9daee79
commit 736f310118
4 changed files with 170 additions and 8 deletions

View File

@@ -65,6 +65,7 @@ namespace FloodSWE.Networking
private HashSet<int> activeSourceIds = new HashSet<int>();
private HashSet<int> activeSinkIds = new HashSet<int>();
private readonly Dictionary<int, int[]> activeBoundaryInflowGhostCells = new Dictionary<int, int[]>();
private readonly Dictionary<int, int[]> activeBoundarySinkGhostCells = new Dictionary<int, int[]>();
private readonly Dictionary<int, int[]> activeSourceAreaCells = new Dictionary<int, int[]>();
private readonly Dictionary<int, int[]> activeSinkCells = new Dictionary<int, int[]>();
private bool activeTileHasBoundaryCellGroups;
@@ -692,6 +693,7 @@ namespace FloodSWE.Networking
activeSourceIds = new HashSet<int>();
activeSinkIds = new HashSet<int>();
activeBoundaryInflowGhostCells.Clear();
activeBoundarySinkGhostCells.Clear();
activeSourceAreaCells.Clear();
activeSinkCells.Clear();
activeTileHasBoundaryCellGroups = false;
@@ -714,18 +716,20 @@ namespace FloodSWE.Networking
CollectIdsFromRefs(tile.boundary_inflow_ids, activeSourceIds);
CollectCellGroups(tile.boundary_cells, activeBoundaryInflowGhostCells, activeSourceIds);
CollectCellGroups(tile.boundary_sink_cells, activeBoundarySinkGhostCells, activeSinkIds);
CollectCellGroups(tile.source_area_cells, activeSourceAreaCells, activeSourceIds);
CollectCellGroups(tile.sink_cells, activeSinkCells, activeSinkIds);
activeTileHasBoundaryCellGroups =
activeBoundaryInflowGhostCells.Count > 0 ||
activeBoundarySinkGhostCells.Count > 0 ||
activeSourceAreaCells.Count > 0 ||
activeSinkCells.Count > 0;
Debug.Log(
$"SweServerRuntime: active tile inflowIds={activeSourceIds.Count}, sinkIds={activeSinkIds.Count}, " +
$"boundaryGhostGroups={activeBoundaryInflowGhostCells.Count}, sourceAreaGroups={activeSourceAreaCells.Count}, " +
$"sinkGroups={activeSinkCells.Count}");
$"boundaryInGhostGroups={activeBoundaryInflowGhostCells.Count}, boundaryOutGhostGroups={activeBoundarySinkGhostCells.Count}, " +
$"sourceAreaGroups={activeSourceAreaCells.Count}, sinkGroups={activeSinkCells.Count}");
}
private void RecomputeExternalDepthRate()
@@ -749,6 +753,8 @@ namespace FloodSWE.Networking
var ghostIndices = new List<int>(128);
var ghostLevels = new List<float>(128);
var ghostVelocities = new List<Vector2>(128);
var ghostOutflowCells = new HashSet<int>();
var boundarySinkIdsWithGhostOutflow = new HashSet<int>();
foreach (var pair in activeBoundaryInflowGhostCells)
{
@@ -786,6 +792,39 @@ namespace FloodSWE.Networking
simulator.ClearGhostBoundaryOverrides();
}
foreach (var pair in activeBoundarySinkGhostCells)
{
int boundaryId = pair.Key;
if (boundaryId <= 0)
{
continue;
}
boundarySinkIdsWithGhostOutflow.Add(boundaryId);
int[] cells = pair.Value;
if (cells == null || cells.Length == 0)
{
continue;
}
for (int i = 0; i < cells.Length; i++)
{
int idx = cells[i];
if (idx >= 0)
{
ghostOutflowCells.Add(idx);
}
}
}
bool hasGhostOutflow =
ghostOutflowCells.Count > 0 &&
simulator.SetGhostFreeOutflowCells(new List<int>(ghostOutflowCells).ToArray());
if (!hasGhostOutflow)
{
simulator.ClearGhostFreeOutflowCells();
}
int totalCells = simulator.gridRes * simulator.gridRes;
float[] perCell = new float[totalCells];
bool hasDepthForcing = false;
@@ -834,6 +873,11 @@ namespace FloodSWE.Networking
foreach (var pair in activeSinkCells)
{
int boundaryId = pair.Key;
if (boundarySinkIdsWithGhostOutflow.Contains(boundaryId))
{
continue;
}
float rate = 0.0f;
if (TryResolveBoundaryProfile("sink", boundaryId, out SweBoundaryProfile profile) && profile != null && profile.enabled)
{
@@ -897,22 +941,38 @@ namespace FloodSWE.Networking
forcedDepthCells = 0;
}
if (!hasGhostForcing && !hasDepthForcing)
if (!hasGhostForcing && !hasDepthForcing && !hasGhostOutflow)
{
lastForcedCellCount = 0;
lastForcingStatus = "disabled:no_active_boundary_profiles";
return;
}
lastForcedCellCount = ghostIndices.Count + forcedDepthCells;
if (hasGhostForcing && hasDepthForcing)
lastForcedCellCount = ghostIndices.Count + forcedDepthCells + (hasGhostOutflow ? ghostOutflowCells.Count : 0);
if (hasGhostForcing && hasDepthForcing && hasGhostOutflow)
{
lastForcingStatus = "ghost+localized+free_outflow";
}
else if (hasGhostForcing && hasDepthForcing)
{
lastForcingStatus = "ghost+localized";
}
else if (hasGhostForcing && hasGhostOutflow)
{
lastForcingStatus = "ghost+free_outflow";
}
else if (hasDepthForcing && hasGhostOutflow)
{
lastForcingStatus = "localized+free_outflow";
}
else if (hasGhostForcing)
{
lastForcingStatus = "ghost_only";
}
else if (hasGhostOutflow)
{
lastForcingStatus = "free_outflow_only";
}
else
{
lastForcingStatus = "localized";
@@ -921,13 +981,14 @@ namespace FloodSWE.Networking
if (verboseDiagnostics)
{
Debug.Log(
$"SweServerRuntime: forcing applied status={lastForcingStatus} ghost={ghostIndices.Count} depth={forcedDepthCells}");
$"SweServerRuntime: forcing applied status={lastForcingStatus} ghost={ghostIndices.Count} depth={forcedDepthCells} freeOutflow={ghostOutflowCells.Count}");
}
}
private void RecomputeLegacyBoundaryDepthRate()
{
simulator.ClearGhostBoundaryOverrides();
simulator.ClearGhostFreeOutflowCells();
var sourceRates = new Dictionary<int, float>();
foreach (int sourceId in activeSourceIds)