Summary
Remove/Extract Flagged Features hangs indefinitely when Fill-in Removed Features is enabled and
any vacated cell fails to acquire a fill source. There is no error and no progress — the dilation
loop spins forever and the pipeline must be killed.
Root cause
IdentifyNeighbors() in src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/RemoveFlaggedFeatures.cpp
tallies the most common feature among a bad cell's six face neighbors, but only records a fill source
inside the found branch (line 97):
bool found = false;
for(usize featIndex = 0; featIndex < discoveredFeatures.size(); featIndex++)
{
if(discoveredFeatures[featIndex] == feature)
{
found = true;
numHits[featIndex]++;
current = numHits[featIndex];
if(current > most)
{
most = current;
storageArray[voxelIndex] = static_cast<int32>(neighborPoint); // line 97
}
break;
}
}
if(!found)
{
discoveredFeatures.push_back(feature); // line 104: no numHits increment, no source recorded
}
On the first sighting of a feature the entry is pushed to discoveredFeatures but numHits is
never incremented, so it stays 0. A source is therefore only ever recorded on the second or
later sighting of the same feature.
Consequently a bad cell whose valid face neighbors all belong to distinct features, or which has
only a single valid neighbor, never receives a storageArray entry. FindVoxelArrays() copies
nothing into it, so it remains at -1. The next pass sees featureName <= 0, sets
shouldLoop = true again, and the do { ... } while(shouldLoop) loop in RemoveFlaggedFeatures::operator()
never terminates.
Reproduction
A 5x2x1 ImageGeom, FeatureIds = 1 1 1 2 3 / 1 4 4 4 3, feature sizes 4/1/2/3. Remove features 2
and 3 with Fill-in Removed Features enabled. FeatureIds becomes 1 1 1 -1 -1 / 1 4 4 4 -1 and
none of the three vacated cells can be filled:
| Cell |
Valid neighbors |
Source recorded? |
| 3 |
features {1, 4} — both first sightings |
no |
| 4 |
both neighbors are -1 |
no |
| 9 |
feature {4} — single sighting |
no |
The filter hangs.
Why this was never caught
The fill path has no execution test coverage. RemoveFlaggedFeaturesTest.cpp passes
FillRemovedFeatures = false at both of its execute sites (lines 144 and 218); line 279 is only a
SIMPL-conversion argument assertion and never runs the algorithm.
On large 3D volumes a bad cell almost always has two or more face neighbors belonging to the same
feature, which satisfies the second-sighting condition and lets the loop terminate. The defect
surfaces on thin geometries (single-slice or single-voxel-deep volumes) and on small or isolated bad
regions.
Proposed fix
Count the first sighting as a hit, which also makes numHits a true tally rather than a count of
repeat sightings:
if(!found)
{
discoveredFeatures.push_back(feature);
numHits[discoveredFeatures.size() - 1] = 1;
if(1 > most)
{
most = 1;
storageArray[voxelIndex] = static_cast<int32>(neighborPoint);
}
}
Any cell with at least one valid neighbor then acquires a source. Cells with no valid neighbor on the
first pass are filled on a later pass once their neighbors are resolved, so the loop terminates as
long as at least one feature survives — which FlagFeatures() already guarantees by erroring when
every feature is flagged.
This changes behavior: previously such cells were left unfilled and the filter never returned; now
they are filled from the first-seen neighboring feature, ties going to the first encountered.
Requested work
Beyond the fix, this filter should have the entire V&V suite performed:
- Oracle classification and independent expected output
- SIMPLNX vs. oracle reconciliation
- Comparison against legacy DREAM3D 6.5.171, written up as structured deviation entries
- Full test-coverage inventory, with every enumerated code path mapped to a named test
The fill-by-dilation path in particular needs real assertions on which surviving feature each
vacated cell is assigned to, not merely that no cell is left at zero. An infinite loop reachable from
a checkbox in the GUI, in a code path with no execution coverage, is exactly the class of defect the
V&V process exists to surface.
For context, the neighboring filters in this family — FillBadData and
ReplaceElementAttributesWithNeighborValues — are already V&V'ed;
Remove/Extract Flagged Features is not.
Summary
Remove/Extract Flagged Featureshangs indefinitely when Fill-in Removed Features is enabled andany vacated cell fails to acquire a fill source. There is no error and no progress — the dilation
loop spins forever and the pipeline must be killed.
Root cause
IdentifyNeighbors()insrc/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/RemoveFlaggedFeatures.cpptallies the most common feature among a bad cell's six face neighbors, but only records a fill source
inside the
foundbranch (line 97):On the first sighting of a feature the entry is pushed to
discoveredFeaturesbutnumHitsisnever incremented, so it stays
0. A source is therefore only ever recorded on the second orlater sighting of the same feature.
Consequently a bad cell whose valid face neighbors all belong to distinct features, or which has
only a single valid neighbor, never receives a
storageArrayentry.FindVoxelArrays()copiesnothing into it, so it remains at
-1. The next pass seesfeatureName <= 0, setsshouldLoop = trueagain, and thedo { ... } while(shouldLoop)loop inRemoveFlaggedFeatures::operator()never terminates.
Reproduction
A 5x2x1
ImageGeom,FeatureIds=1 1 1 2 3 / 1 4 4 4 3, feature sizes 4/1/2/3. Remove features 2and 3 with Fill-in Removed Features enabled.
FeatureIdsbecomes1 1 1 -1 -1 / 1 4 4 4 -1andnone of the three vacated cells can be filled:
-1The filter hangs.
Why this was never caught
The fill path has no execution test coverage.
RemoveFlaggedFeaturesTest.cpppassesFillRemovedFeatures = falseat both of its execute sites (lines 144 and 218); line 279 is only aSIMPL-conversion argument assertion and never runs the algorithm.
On large 3D volumes a bad cell almost always has two or more face neighbors belonging to the same
feature, which satisfies the second-sighting condition and lets the loop terminate. The defect
surfaces on thin geometries (single-slice or single-voxel-deep volumes) and on small or isolated bad
regions.
Proposed fix
Count the first sighting as a hit, which also makes
numHitsa true tally rather than a count ofrepeat sightings:
Any cell with at least one valid neighbor then acquires a source. Cells with no valid neighbor on the
first pass are filled on a later pass once their neighbors are resolved, so the loop terminates as
long as at least one feature survives — which
FlagFeatures()already guarantees by erroring whenevery feature is flagged.
This changes behavior: previously such cells were left unfilled and the filter never returned; now
they are filled from the first-seen neighboring feature, ties going to the first encountered.
Requested work
Beyond the fix, this filter should have the entire V&V suite performed:
The fill-by-dilation path in particular needs real assertions on which surviving feature each
vacated cell is assigned to, not merely that no cell is left at zero. An infinite loop reachable from
a checkbox in the GUI, in a code path with no execution coverage, is exactly the class of defect the
V&V process exists to surface.
For context, the neighboring filters in this family —
FillBadDataandReplaceElementAttributesWithNeighborValues— are already V&V'ed;Remove/Extract Flagged Featuresis not.