From c19d8263743ebb35cce57dc3e368a912c5a9e7f8 Mon Sep 17 00:00:00 2001 From: Mohcine Chraibi Date: Tue, 11 Aug 2026 11:45:37 +0200 Subject: [PATCH] Fix false 'incomplete entity data' warning on time-varying populations RunHdf5SimDataGatheringLoop compared the peak per-timestep entity count against MaxAgents and reported missing data when it was lower: Incomplete entity data: HDF5: peak entity count 386 < MaxAgents 493. Some entities may be missing. Those two numbers measure different things. MaxAgents comes from ConvertJuelichToMobiusFormat as the count of distinct entity IDs across the whole run, while the peak is the busiest single timestep. They are only equal when every agent is present for the entire simulation, so the check fires on any dataset where agents enter and leave. For the file above all 493 entities are present in the data; the busiest frame simply holds 386 of them, and no agent spans the full run. Replace the comparison with one that measures the intended property: count the distinct entity indices that actually have samples and report how many have none. That still catches genuinely truncated data without misfiring on normal pedestrian flow. --- .../MassAI/SubSystems/AgentDataSubsystem.cpp | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/UnrealFolder/ProjectMobius/Source/ProjectMobius/Private/MassAI/SubSystems/AgentDataSubsystem.cpp b/UnrealFolder/ProjectMobius/Source/ProjectMobius/Private/MassAI/SubSystems/AgentDataSubsystem.cpp index 7c4922a3..b76f2241 100644 --- a/UnrealFolder/ProjectMobius/Source/ProjectMobius/Private/MassAI/SubSystems/AgentDataSubsystem.cpp +++ b/UnrealFolder/ProjectMobius/Source/ProjectMobius/Private/MassAI/SubSystems/AgentDataSubsystem.cpp @@ -1298,11 +1298,6 @@ void FProcessSimulationDataRunnable::RunHdf5SimDataGatheringLoop(bool bCalculate // --- Incomplete data detection --- int32 ActualTimestepCount = MaxTimestepIndex + 1; - int32 PeakEntityCount = 0; - for (int32 Count : NumOfAgentsPerTimeStep) - { - PeakEntityCount = FMath::Max(PeakEntityCount, Count); - } // Timestep mismatch: metadata says more timesteps than we actually loaded if (Hdf5Data.Meta.Duration > 0 && Hdf5Data.Meta.SamplingRate > 0) @@ -1318,14 +1313,31 @@ void FProcessSimulationDataRunnable::RunHdf5SimDataGatheringLoop(bool bCalculate } } - // Entity count mismatch: fewer entities observed than metadata declares - if (MaxAgents > 0 && PeakEntityCount > 0 && PeakEntityCount < MaxAgents) + // Entity coverage: every entity the metadata declares should appear in at least one + // timestep. This deliberately does not compare against the busiest timestep, because + // agents enter and leave over the course of a simulation, so the peak concurrent count + // is legitimately lower than the total number of distinct entities. + if (MaxAgents > 0) { - ReportAgentDataErrorAnyThread(OwnerSubsystem.Get(), - TEXT("Incomplete entity data"), - FString::Printf(TEXT("HDF5: peak entity count %d < MaxAgents %d. Some entities may be missing."), - PeakEntityCount, MaxAgents), - TEXT("AgentDataSubsystem - RunHdf5SimDataGatheringLoop")); + TBitArray<> ObservedEntities(false, MaxAgents); + int32 ObservedEntityCount = 0; + for (const FHdf5SampleData& Sample : Hdf5Data.Samples) + { + if (ObservedEntities.IsValidIndex(Sample.EntityId) && !ObservedEntities[Sample.EntityId]) + { + ObservedEntities[Sample.EntityId] = true; + ++ObservedEntityCount; + } + } + + if (ObservedEntityCount < MaxAgents) + { + ReportAgentDataErrorAnyThread(OwnerSubsystem.Get(), + TEXT("Incomplete entity data"), + FString::Printf(TEXT("HDF5: %d of %d entities have no samples. Data may be incomplete."), + MaxAgents - ObservedEntityCount, MaxAgents), + TEXT("AgentDataSubsystem - RunHdf5SimDataGatheringLoop")); + } } }