public void BuildLiftsForSinglePassCell_CMVPercentChange(float[] heights, short[] cmvs) { var siteModel = DITAGFileAndSubGridRequestsWithIgniteFixture.NewEmptyModel(); var baseTime = DateTime.UtcNow; var cellPasses = new[] { new CellPass { Time = baseTime, Height = heights[0], CCV = cmvs[0] }, new CellPass { Time = baseTime.AddHours(1), Height = heights[1], CCV = cmvs[1] }, new CellPass { Time = baseTime.AddHours(2), Height = heights[2], CCV = cmvs[2] }, new CellPass { Time = baseTime.AddHours(3), Height = heights[3], CCV = cmvs[3] } }; DITAGFileAndSubGridRequestsFixture.AddSingleCellWithPasses (siteModel, SubGridTreeConsts.DefaultIndexOriginOffset, SubGridTreeConsts.DefaultIndexOriginOffset, cellPasses); IClientLeafSubGrid clientGrid = ClientLeafSubGridFactoryFactory.CreateClientSubGridFactory().GetSubGrid(GridDataType.CCVPercentChange) as ClientCMVLeafSubGrid; var serverGrid = TRex.SubGridTrees.Server.Utilities.SubGridUtilities.LocateSubGridContaining( siteModel.PrimaryStorageProxy, siteModel.Grid, SubGridTreeConsts.DefaultIndexOriginOffset, SubGridTreeConsts.DefaultIndexOriginOffset, siteModel.Grid.NumLevels, false, false) as IServerLeafSubGrid; var builder = new CellLiftBuilder(siteModel, GridDataType.CCVPercentChange, new FilteredValuePopulationControl(), new FilterSet(new CombinedFilter()), new CellPassFastEventLookerUpper(siteModel)); var cell = new ProfileCell(); var segmentIterator = new SubGridSegmentIterator(serverGrid, serverGrid.Directory, siteModel.PrimaryStorageProxy); var cellPassIterator = new SubGridSegmentCellPassIterator_NonStatic(segmentIterator); var filteredValueAssignmentContext = new FilteredValueAssignmentContext(); builder.Build(cell, new LiftParameters(), clientGrid, filteredValueAssignmentContext, cellPassIterator, true).Should().BeTrue(); cell.Layers.Count().Should().Be(1); cell.Layers[0].PassCount.Should().Be(4); filteredValueAssignmentContext.FilteredValue.FilteredPassData.FilteredPass.CCV.Should().Be(cmvs[cmvs.Length - 1]); filteredValueAssignmentContext.PreviousFilteredValue.FilteredPassData.FilteredPass.CCV.Should().Be(cmvs[cmvs.Length - 2]); }
/// <summary> /// Cleaves all dirty segments requiring cleaving within the given sub grid /// </summary> public void PerformSegmentCleaving(IStorageProxy storageProxyForSubGridSegments, IServerLeafSubGrid subGrid, int subGridSegmentPassCountLimit = 0) { var iterator = new SubGridSegmentIterator(subGrid, storageProxyForSubGridSegments) { IterationDirection = IterationDirection.Forwards, ReturnDirtyOnly = true, RetrieveAllPasses = true }; var origin = new SubGridCellAddress(subGrid.OriginX, subGrid.OriginY); if (!iterator.MoveToFirstSubGridSegment()) { return; } do { var segment = iterator.CurrentSubGridSegment; var cleavedTimeRangeStart = segment.SegmentInfo.StartTime; var cleavedTimeRangeEnd = segment.SegmentInfo.EndTime; if (!segment.RequiresCleaving(out var totalPassCount, out var maximumPassCount)) { continue; } if (subGrid.Cells.CleaveSegment(segment, NewSegmentsFromCleaving, PersistedClovenSegments, subGridSegmentPassCountLimit)) { iterator.SegmentListExtended(); if (_segmentCleavingOperationsToLog) { _log.LogInformation( $"Info: Performed cleave on segment ({cleavedTimeRangeStart}-{cleavedTimeRangeEnd}) of sub grid {ServerSubGridTree.GetLeafSubGridFullFileName(origin)}. TotalPassCount = {totalPassCount} MaximumPassCount = {maximumPassCount}"); } } else { // The segment cleave failed. While this is not a serious problem (as the sub grid will be // cleaved at some point in the future when it is modified again via tag file processing etc) // it will be noted in the log. _log.LogWarning( $"Cleave on segment ({cleavedTimeRangeStart}-{cleavedTimeRangeEnd}) of sub grid {ServerSubGridTree.GetLeafSubGridFullFileName(origin)} failed. TotalPassCount = {totalPassCount} MaximumPassCount = {maximumPassCount}"); } if (_segmentCleavingOperationsToLog) { if (segment.RequiresCleaving(out totalPassCount, out maximumPassCount)) { _log.LogWarning( $"Cleave on segment ({cleavedTimeRangeStart}-{cleavedTimeRangeEnd}) of sub grid {subGrid.Moniker()} failed to reduce cell pass count below maximums (max passes = {totalPassCount}/{subGridSegmentPassCountLimit}, per cell = {maximumPassCount}/{_subGridMaxSegmentCellPassesLimit})"); } } } while (iterator.MoveToNextSubGridSegment()); }
public void Test_SubGridSegmentIterator_SubGridSegmentIterator() { ServerSubGridTree tree = new ServerSubGridTree(SubGridTreeConsts.SubGridTreeLevels, 1.0, new SubGridFactory <NodeSubGrid, ServerSubGridTreeLeaf>(), StorageMutability.Mutable); IServerLeafSubGrid leaf = new ServerSubGridTreeLeaf(tree, null, SubGridTreeConsts.SubGridTreeLevels, StorageMutability.Mutable); SubGridSegmentIterator iterator = new SubGridSegmentIterator(leaf, leaf.Directory, StorageProxy.Instance(StorageMutability.Mutable)); Assert.True(iterator.Directory == leaf.Directory && iterator.SubGrid == leaf, "SubGrid segment iterator not correctly initialised"); }
public void BuildLiftsForMultiplePassCell(float height1, float height2, float height3, float first, float last, float lowest, float heighest) { var siteModel = DITAGFileAndSubGridRequestsWithIgniteFixture.NewEmptyModel(); var baseTime = DateTime.UtcNow; var cellPasses = new[] { new CellPass { Time = baseTime, Height = height1 }, new CellPass { Time = baseTime.AddHours(1), Height = height2 }, new CellPass { Time = baseTime.AddHours(2), Height = height3 } }; DITAGFileAndSubGridRequestsFixture.AddSingleCellWithPasses (siteModel, SubGridTreeConsts.DefaultIndexOriginOffset, SubGridTreeConsts.DefaultIndexOriginOffset, cellPasses); IClientLeafSubGrid clientGrid = ClientLeafSubGridFactoryFactory.CreateClientSubGridFactory().GetSubGrid(GridDataType.Height) as ClientHeightLeafSubGrid; var serverGrid = TRex.SubGridTrees.Server.Utilities.SubGridUtilities.LocateSubGridContaining( siteModel.PrimaryStorageProxy, siteModel.Grid, SubGridTreeConsts.DefaultIndexOriginOffset, SubGridTreeConsts.DefaultIndexOriginOffset, siteModel.Grid.NumLevels, false, false) as IServerLeafSubGrid; var builder = new CellLiftBuilder(siteModel, GridDataType.Height, new FilteredValuePopulationControl(), new FilterSet(new CombinedFilter()), new CellPassFastEventLookerUpper(siteModel)); var cell = new ProfileCell(); var segmentIterator = new SubGridSegmentIterator(serverGrid, serverGrid.Directory, siteModel.PrimaryStorageProxy); var cellPassIterator = new SubGridSegmentCellPassIterator_NonStatic(segmentIterator); builder.Build(cell, new LiftParameters(), clientGrid, new FilteredValueAssignmentContext(), cellPassIterator, false).Should().BeTrue(); cell.Layers.Count().Should().Be(1); cell.Layers[0].PassCount.Should().Be(3); cell.Layers[0].MinimumPassHeight.Should().Be(lowest); cell.Layers[0].MaximumPassHeight.Should().Be(heighest); cell.Layers[0].FirstPassHeight.Should().Be(first); cell.Layers[0].LastPassHeight.Should().Be(last); }
public void Test_SubGridSegmentIterator_SetIteratorElevationRange() { ServerSubGridTree tree = new ServerSubGridTree(SubGridTreeConsts.SubGridTreeLevels, 1.0, new SubGridFactory <NodeSubGrid, ServerSubGridTreeLeaf>(), StorageMutability.Mutable); IServerLeafSubGrid leaf = new ServerSubGridTreeLeaf(tree, null, SubGridTreeConsts.SubGridTreeLevels, StorageMutability.Mutable); SubGridSegmentIterator iterator = new SubGridSegmentIterator(leaf, leaf.Directory, StorageProxy.Instance(StorageMutability.Mutable)); const double lowerElevation = 9.0; const double upperElevation = 19.0; iterator.SetIteratorElevationRange(lowerElevation, upperElevation); Assert.True(iterator.IterationState.MinIterationElevation == lowerElevation && iterator.IterationState.MaxIterationElevation == upperElevation, "Elevation lower and upper bounds not set correctly"); }
public void Test_SubGridSegmentIterator_SetTimeRange() { ServerSubGridTree tree = new ServerSubGridTree(SubGridTreeConsts.SubGridTreeLevels, 1.0, new SubGridFactory <NodeSubGrid, ServerSubGridTreeLeaf>(), StorageMutability.Mutable); IServerLeafSubGrid leaf = new ServerSubGridTreeLeaf(tree, null, SubGridTreeConsts.SubGridTreeLevels, StorageMutability.Mutable); SubGridSegmentIterator iterator = new SubGridSegmentIterator(leaf, leaf.Directory, StorageProxy.Instance(StorageMutability.Mutable)); DateTime start = DateTime.SpecifyKind(new DateTime(2000, 1, 1, 1, 1, 1), DateTimeKind.Utc); DateTime end = DateTime.SpecifyKind(new DateTime(2000, 1, 2, 1, 1, 1), DateTimeKind.Utc); iterator.SetTimeRange(start, end); Assert.True(iterator.IterationState.StartSegmentTime == start && iterator.IterationState.EndSegmentTime == end, "Start and end time not set correctly"); }
public void Test_SubGridSegmentIterator_InitialiseIterator() { ServerSubGridTree tree = new ServerSubGridTree(SubGridTreeConsts.SubGridTreeLevels, 1.0, new SubGridFactory <NodeSubGrid, ServerSubGridTreeLeaf>(), StorageMutability.Mutable); IServerLeafSubGrid leaf = new ServerSubGridTreeLeaf(tree, null, SubGridTreeConsts.SubGridTreeLevels, StorageMutability.Mutable); SubGridSegmentIterator iterator = new SubGridSegmentIterator(leaf, leaf.Directory, StorageProxy.Instance(StorageMutability.Mutable)) { IterationDirection = IterationDirection.Forwards }; iterator.InitialiseIterator(); Assert.Equal(-1, iterator.IterationState.Idx); iterator.IterationDirection = IterationDirection.Backwards; iterator.InitialiseIterator(); Assert.Equal(iterator.IterationState.Idx, leaf.Directory.SegmentDirectory.Count); }
public void Test_SegmentIterator_MoveToFirstSegment() { var subGrid = MakeSubgridWith10240CellPassesAtOneSecondIntervals(); var Iterator = new SubGridSegmentIterator(subGrid, StorageProxy.Instance(StorageMutability.Mutable)) { IterationDirection = IterationDirection.Forwards, ReturnDirtyOnly = true, RetrieveAllPasses = true }; Assert.True(Iterator.MoveToFirstSubGridSegment(), "Was not able to move to first segment (forwards) when requesting only dirty segments"); Iterator = new SubGridSegmentIterator(subGrid, StorageProxy.Instance(StorageMutability.Mutable)) { IterationDirection = IterationDirection.Backwards, ReturnDirtyOnly = true, RetrieveAllPasses = true }; Assert.True(Iterator.MoveToFirstSubGridSegment(), "Was not able to move to first segment (backwards) when requesting only dirty segments"); Iterator = new SubGridSegmentIterator(subGrid, StorageProxy.Instance(StorageMutability.Mutable)) { IterationDirection = IterationDirection.Forwards, ReturnDirtyOnly = false, RetrieveAllPasses = true }; Assert.True(Iterator.MoveToFirstSubGridSegment(), "Was not able to move to first segment (forwards) when requesting all segments"); Iterator = new SubGridSegmentIterator(subGrid, StorageProxy.Instance(StorageMutability.Mutable)) { IterationDirection = IterationDirection.Backwards, ReturnDirtyOnly = false, RetrieveAllPasses = true }; Assert.True(Iterator.MoveToFirstSubGridSegment(), "Was not able to move to first segment (backwards) when requesting all segments"); }
public bool IntegrateSubGridTree(SubGridTreeIntegrationMode integrationMode, Action <int, int> subGridChangeNotifier) { // Iterate over the sub grids in source and merge the cell passes from source // into the sub grids in this sub grid tree; var iterator = new SubGridTreeIterator(_storageProxySubGrids, false) { Grid = _source }; var segmentIterator = new SubGridSegmentIterator(null, _storageProxySubGridSegments) { IterationDirection = IterationDirection.Forwards }; while (iterator.MoveToNextSubGrid()) { var sourceSubGrid = iterator.CurrentSubGrid as IServerLeafSubGrid; /* * // TODO: Terminated check for integration processing * if (Terminated) * { * // Service has been shutdown. Abort integration of changes and flag the * // operation as failed. The TAG file will be reprocessed when the service restarts * return false; * } */ IntegrateSubGrid(sourceSubGrid, integrationMode, subGridChangeNotifier, segmentIterator); // Release the resources used by SourceSubGrid as this is the last point it is needed sourceSubGrid?.DeAllocateLeafFullPassStacks(); sourceSubGrid?.DeAllocateLeafLatestPassGrid(); } return(true); }
/// <summary> /// Orchestrates all the activities relating to saving the state of a created or modified sub grid, including /// cleaving, saving updated elements, creating new elements and arranging for the retirement of /// elements that have been replaced in the persistent store as a result of this activity. /// </summary> public bool SaveLeafSubGrid(IServerLeafSubGrid subGrid, IStorageProxy storageProxyForSubGrids, IStorageProxy storageProxyForSubGridSegments, List <ISubGridSpatialAffinityKey> invalidatedSpatialStreams) { //Log.LogInformation($"Saving {subGrid.Moniker()} to persistent store"); try { // Perform segment cleaving as the first activity in the action of saving a leaf sub grid // to disk. This reduces the number of segment cleaving actions that would otherwise // be performed in the context of the aggregated integrator. if (_segmentCleavingOperationsToLog) { _log.LogDebug($"About to perform segment cleaving on {subGrid.Moniker()}"); } var cleaver = new SubGridSegmentCleaver(); cleaver.PerformSegmentCleaving(storageProxyForSubGridSegments, subGrid); // Calculate the cell last pass information here, immediately before it is // committed to the persistent store. The reason for this is to remove this // compute intensive operation from the critical path in TAG file processing // (which is the only writer of this information in the Raptor system). // The computer is instructed to do a partial recompute, which will recompute // all segments from the first segment marked as dirty. subGrid.ComputeLatestPassInformation(false, storageProxyForSubGridSegments); if (_segmentCleavingOperationsToLog) { _log.LogInformation($"SaveLeafSubGrid: {subGrid.Moniker()} ({subGrid.Cells.PassesData.Count} segments)"); } var modifiedOriginalSegments = new List <ISubGridCellPassesDataSegment>(100); var originAddress = new SubGridCellAddress(subGrid.OriginX, subGrid.OriginY); // The following used to be an assert/exception. However, this is may readily // happen if there are no modified segments resulting from processing a // process TAG file where the Dirty flag for the sub grid is set but no cell // passes are added to segments in that sub grid. As this is not an integrity // issue the persistence of the modified sub grid is allowed, but noted in // the log for posterity. if (subGrid.Cells.PassesData.Count == 0) { _log.LogInformation( $"Note: Saving a sub grid, {subGrid.Moniker()}, (Segments = {subGrid.Cells.PassesData.Count}, Dirty = {subGrid.Dirty}) with no cached sub grid segments to the persistent store in SaveLeafSubGrid (possible reprocessing of TAG file with no cell pass changes). " + $"SubGrid.Directory.PersistedClovenSegments.Count={cleaver.PersistedClovenSegments?.Count}, ModifiedOriginalFiles.Count={modifiedOriginalSegments.Count}, NewSegmentsFromCleaving.Count={cleaver.NewSegmentsFromCleaving.Count}"); } var iterator = new SubGridSegmentIterator(subGrid, storageProxyForSubGridSegments) { IterationDirection = IterationDirection.Forwards, ReturnDirtyOnly = true, }; //********************************************************************** //***Construct list of original segment files that have been modified*** //*** These files may be updated in-situ with no sub grid/segment *** //*** integrity issues wrt the segment directory in the sub grid *** //********************************************************************** iterator.MoveToFirstSubGridSegment(); while (iterator.CurrentSubGridSegment != null) { if (iterator.CurrentSubGridSegment.SegmentInfo.ExistsInPersistentStore && iterator.CurrentSubGridSegment.Dirty) { modifiedOriginalSegments.Add(iterator.CurrentSubGridSegment); } iterator.MoveToNextSubGridSegment(); } //********************************************************************** //*** Construct list of spatial streams that will be deleted or replaced //*** in the FS file. These will be passed to the call that saves the //*** sub grid directory file as an instruction to place them into the //*** deferred deletion list //********************************************************************** lock (invalidatedSpatialStreams) { if (cleaver.PersistedClovenSegments != null) { invalidatedSpatialStreams.AddRange(cleaver.PersistedClovenSegments); } invalidatedSpatialStreams.AddRange(modifiedOriginalSegments.Select(x => x.SegmentInfo.AffinityKey(ID))); } if (cleaver.NewSegmentsFromCleaving.Count > 0) { //********************************************************************** //*** Write new segment files generated by cleaving *** //*** File system integrity failures here will have no effect on the *** //*** sub grid/segment directory as they are not referenced by it. *** //*** At worst they become orphans they may be cleaned by in the FS *** //*** recovery phase *** //********************************************************************** if (_segmentCleavingOperationsToLog) { _log.LogInformation($"Sub grid has {cleaver.NewSegmentsFromCleaving.Count} new segments from cleaving"); } foreach (var segment in cleaver.NewSegmentsFromCleaving) { // Update the version of the segment as it is about to be written segment.SegmentInfo.Touch(); segment.SaveToFile(storageProxyForSubGridSegments, GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo), out var fsError); segment.Dirty = false; if (fsError == FileSystemErrorStatus.OK) { if (_segmentCleavingOperationsToLog) { _log.LogInformation($"Saved new cloven grid segment file: {GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo)}"); } } else { _log.LogWarning($"Failed to save cloven grid segment {GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo)}: Error:{fsError}"); return(false); } } } if (modifiedOriginalSegments.Count > 0) { //********************************************************************** //*** Write modified segment files *** //*** File system integrity failures here will have no effect on the *** //*** sub grid/segment directory as the previous version of the *** //*** modified file being written will be recovered. *** //********************************************************************** if (_log.IsTraceEnabled()) { _log.LogTrace($"Sub grid has {modifiedOriginalSegments.Count} modified segments"); } foreach (var segment in modifiedOriginalSegments) { // Update the version of the segment as it is about to be written segment.SegmentInfo.Touch(); segment.Dirty = false; if (segment.SaveToFile(storageProxyForSubGridSegments, GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo), out var fsError)) { segment.Dirty = false; if (_log.IsTraceEnabled()) { _log.LogTrace($"Saved modified grid segment file: {segment}"); } } else { _log.LogError($"Failed to save modified original grid segment {GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo)}: Error:{fsError}"); return(false); } } } // Any remaining dirty segments in the sub grid will be due to previously empty sub grids with newly // created segments from ingest processing that have not required cleaving. These segments do not require any // special treatment are jsut saved to persistent store foreach (var segment in subGrid.Directory.SegmentDirectory.Select(x => x.Segment).Where(x => (x?.Dirty ?? false))) { if (segment.SaveToFile(storageProxyForSubGridSegments, GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo), out var fsError)) { segment.Dirty = false; if (_log.IsTraceEnabled()) { _log.LogTrace($"Saved new sub grid segment file: {segment}"); } } else { _log.LogError($"Failed to save new sub grid segment {GetLeafSubGridSegmentFullFileName(originAddress, segment.SegmentInfo)}: Error:{fsError}"); return(false); } } //********************************************************************** //*** Write the sub grid directory file *** //********************************************************************** /* * There is no need to add the sub grid directory stream to the segment retirement * queue as this will be automatically replaced when the new version of the * sub grid directory is written to persistent store. * * // Add the stream representing the sub grid directory file to the list of * // invalidated streams as this stream will be replaced with the stream * // containing the updated directory information. Note: This only needs to * // be done if the sub grid has previously been read from the FS file (if not * // it has been created and not yet persisted to the store. * * if (subGrid.Directory.ExistsInPersistentStore) * { * // Include an additional invalidated spatial stream for the sub grid directory stream * lock (invalidatedSpatialStreams) * { * invalidatedSpatialStreams.Add(subGrid.AffinityKey()); * } * } */ if (subGrid.SaveDirectoryToFile(storageProxyForSubGrids, GetLeafSubGridFullFileName(originAddress))) { if (_log.IsTraceEnabled()) { _log.LogTrace($"Saved grid directory file: {GetLeafSubGridFullFileName(originAddress)}"); } } else { if (_log.IsTraceEnabled()) { _log.LogTrace($"Failed to save grid: {GetLeafSubGridFullFileName(originAddress)}"); } return(false); } //********************************************************************** //*** Reset segment dirty flags *** //********************************************************************** iterator.MoveToFirstSubGridSegment(); while (iterator.CurrentSubGridSegment != null) { iterator.CurrentSubGridSegment.Dirty = false; iterator.CurrentSubGridSegment.SegmentInfo.ExistsInPersistentStore = true; iterator.MoveToNextSubGridSegment(); } //Log.LogInformation($"Completed saving {subGrid.Moniker()} to persistent store"); return(true); } catch (Exception e) { _log.LogError(e, "Exception raised in SaveLeafSubGrid"); } return(false); }
private void CompareSiteModels(ISiteModel sm1, ISiteModel sm2, int expectedExistanceMapSubGridCount, int expectedCallPassCount, int expectedNonNullCelCount) { var bitCount1 = sm1.ExistenceMap.CountBits(); var bitCount2 = sm2.ExistenceMap.CountBits(); // Check both site models have the same number of sub grids in their existence maps bitCount1.Should().Be(bitCount2); bitCount1.Should().Be(expectedExistanceMapSubGridCount); // Check the content of the existence maps is identical var testMap = new SubGridTreeSubGridExistenceBitMask(); testMap.SetOp_OR(sm1.ExistenceMap); testMap.SetOp_XOR(sm2.ExistenceMap); testMap.CountBits().Should().Be(0); // The expected distribution of cell pass counts long[] expectedCounts = { 93, 687, 68, 385, 57, 598, 65, 986, 52, 63, 0, 0, 0, 0, 0 }; // Scan the leaves in each model and count cell passes int sm1Count = 0; int sm1LeafCount = 0; long[] actualCounts1 = new long[15]; int segmentCount1 = 0; int nonNullCellCount1 = 0; sm1.ExistenceMap.ScanAllSetBitsAsSubGridAddresses(address => { sm1LeafCount++; var leaf = SubGridUtilities.LocateSubGridContaining(sm1.PrimaryStorageProxy, sm1.Grid, address.X, address.Y, sm1.Grid.NumLevels, false, false) as IServerLeafSubGrid; var iterator = new SubGridSegmentIterator(leaf, sm1.PrimaryStorageProxy); while (iterator.MoveNext()) { segmentCount1++; TRex.SubGridTrees.Core.Utilities.SubGridUtilities.SubGridDimensionalIterator((x, y) => { var passCount = iterator.CurrentSubGridSegment.PassesData.PassCount(x, y); sm1Count += passCount; if (passCount > 0) { nonNullCellCount1++; actualCounts1[passCount - 1]++; } }); } }); int sm2Count = 0; int sm2LeafCount = 0; long[] actualCounts2 = new long[15]; int segmentCount2 = 0; int nonNullCellCount2 = 0; sm2.ExistenceMap.ScanAllSetBitsAsSubGridAddresses(address => { sm2LeafCount++; var leaf = SubGridUtilities.LocateSubGridContaining(sm2.PrimaryStorageProxy, sm2.Grid, address.X, address.Y, sm2.Grid.NumLevels, false, false) as IServerLeafSubGrid; var iterator = new SubGridSegmentIterator(leaf, sm2.PrimaryStorageProxy); while (iterator.MoveNext()) { segmentCount2++; TRex.SubGridTrees.Core.Utilities.SubGridUtilities.SubGridDimensionalIterator((x, y) => { var passCount = iterator.CurrentSubGridSegment.PassesData.PassCount(x, y); sm2Count += passCount; if (passCount > 0) { nonNullCellCount2++; actualCounts2[passCount - 1]++; } }); } }); segmentCount1.Should().Be(segmentCount2); segmentCount1.Should().Be(sm1LeafCount); sm1LeafCount.Should().Be(expectedExistanceMapSubGridCount); sm1Count.Should().Be(sm2Count); sm2LeafCount.Should().Be(expectedExistanceMapSubGridCount); sm1Count.Should().Be(expectedCallPassCount); actualCounts1.Should().BeEquivalentTo(actualCounts2); actualCounts1.Should().BeEquivalentTo(expectedCounts); nonNullCellCount1.Should().Be(nonNullCellCount2); nonNullCellCount1.Should().Be(expectedNonNullCelCount); }