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]); }
public override bool PerformHeightAnnotation(SubGridTreeBitmapSubGridBits processingMap, IList filteredSurveyedSurfaces, bool returnEarliestFilteredCellPass, IClientLeafSubGrid surfaceElevationsSource, Func <int, int, float, bool> elevationRangeFilterLambda) { if (!(surfaceElevationsSource is ClientHeightAndTimeLeafSubGrid surfaceElevations)) { _log.LogError($"{nameof(ClientHeightAndTimeLeafSubGrid)}.{nameof(PerformHeightAnnotation)} not supplied a ClientHeightAndTimeLeafSubGrid instance, but an instance of {surfaceElevationsSource?.GetType().FullName}"); return(false); } // For all cells we wanted to request a surveyed surface elevation for, // update the cell elevation if a non null surveyed surface of appropriate time was computed // Note: The surveyed surface will return all cells in the requested sub grid, not just the ones indicated in the processing map // IE: It is unsafe to test for null top indicate not-filtered, use the processing map iterators to cover only those cells required processingMap.ForEachSetBit((x, y) => { var surveyedSurfaceCellHeight = surfaceElevations.Cells[x, y]; // ReSharper disable once CompareOfFloatsByEqualityOperator if (surveyedSurfaceCellHeight == Consts.NullHeight) { return; } // If we got back a surveyed surface elevation... var surveyedSurfaceCellTime = surfaceElevations.Times[x, y]; var prodHeight = Cells[x, y]; var prodTime = Times[x, y]; // Determine if the elevation from the surveyed surface data is required based on the production data elevation being null, and // the relative age of the measured surveyed surface elevation compared with a non-null production data height // ReSharper disable once CompareOfFloatsByEqualityOperator if (!(prodHeight == Consts.NullHeight || (returnEarliestFilteredCellPass ? surveyedSurfaceCellTime <prodTime : surveyedSurfaceCellTime> prodTime))) { // We didn't get a surveyed surface elevation, so clear the bit in the processing map to indicate there is no surveyed surface information present for it processingMap.ClearBit(x, y); return; } // Check if there is an elevation range filter in effect and whether the surveyed surface elevation data matches it if (elevationRangeFilterLambda != null) { if (!elevationRangeFilterLambda(x, y, surveyedSurfaceCellHeight)) { // We didn't get a surveyed surface elevation, so clear the bit in the processing map to indicate there is no surveyed surface information present for it processingMap.ClearBit(x, y); return; } } Cells[x, y] = surveyedSurfaceCellHeight; Times[x, y] = surveyedSurfaceCellTime; }); // if (ClientGrid_is_TICClientSubGridTreeLeaf_HeightAndTime) // ClientGridAsHeightAndTime.SurveyedSurfaceMap.Assign(ProcessingMap); return(true); }
/// <summary> /// Determines if the leaf content of this subgrid is equal to 'other' /// </summary> /// <param name="other"></param> /// <returns></returns> public override bool LeafContentEquals(IClientLeafSubGrid other) { bool result = true; IGenericClientLeafSubGrid <MachineSpeedExtendedRecord> _other = (IGenericClientLeafSubGrid <MachineSpeedExtendedRecord>)other; ForEach((x, y) => result &= Cells[x, y].Equals(_other.Cells[x, y])); return(result); }
public IClientLeafSubGrid ExtractFromCachedItem(IClientLeafSubGrid cachedItem, SubGridTreeBitmapSubGridBits map, SurveyedSurfacePatchType patchType) { var resultItem = _clientLeafSubGridFactory.GetSubGridEx (patchType == SurveyedSurfacePatchType.CompositeElevations ? GridDataType.CompositeHeights : GridDataType.HeightAndTime, cachedItem.CellSize, cachedItem.Level, cachedItem.OriginX, cachedItem.OriginY); resultItem.AssignFromCachedPreProcessedClientSubGrid(cachedItem, map); return(resultItem); }
/// <summary> /// Determines if the leaf content of this sub grid is equal to 'other' /// </summary> /// <param name="other"></param> /// <returns></returns> public override bool LeafContentEquals(IClientLeafSubGrid other) { bool result = true; IGenericClientLeafSubGrid <ushort> _other = (IGenericClientLeafSubGrid <ushort>)other; ForEach((x, y) => result &= Cells[x, y] == _other.Cells[x, y]); return(result); }
/// <summary> /// Determines if the leaf content of this subgrid is equal to 'other' /// </summary> /// <param name="other"></param> /// <returns></returns> public override bool LeafContentEquals(IClientLeafSubGrid other) { bool result = true; IGenericClientLeafSubGrid <SubGridCellPassDataMDPEntryRecord> _other = (IGenericClientLeafSubGrid <SubGridCellPassDataMDPEntryRecord>)other; ForEach((x, y) => result &= Cells[x, y].Equals(_other.Cells[x, y])); return(result); }
public override bool LeafContentEquals(IClientLeafSubGrid other) { bool result = true; IGenericClientLeafSubGrid <ClientCellProfileAllPassesLeafSubgridRecord> _other = (IGenericClientLeafSubGrid <ClientCellProfileAllPassesLeafSubgridRecord>)other; ForEach((x, y) => result &= Cells[x, y].Equals(_other.Cells[x, y])); return(result); }
public override bool LeafContentEquals(IClientLeafSubGrid other) { var result = true; // ReSharper disable once InconsistentNaming var _other = (IGenericClientLeafSubGrid <ClientCellProfileLeafSubgridRecord>)other; ForEach((x, y) => result &= Cells[x, y].Equals(_other.Cells[x, y])); return(result); }
/// <summary> /// Assigns the state of one client leaf sub grid to this client leaf sub grid /// Note: The cell values are explicitly NOT copied in this operation /// </summary> public void Assign(IClientLeafSubGrid source) { level = source.Level; originX = source.OriginX; originY = source.OriginY; // Grid data type is never assigned from one client grid to another... //GridDataType = source.GridDataType; CellSize = source.CellSize; IndexOriginOffset = source.IndexOriginOffset; ProdDataMap.Assign(source.ProdDataMap); FilterMap.Assign(source.FilterMap); }
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_SubGridClientLeafFactory_Creation() { IClientLeafSubGridFactory factory = new ClientLeafSubGridFactory(); Assert.NotNull(factory); IClientLeafSubGrid HeightLeaf = factory.GetSubGrid(Types.GridDataType.Height); Assert.NotNull(factory); IClientLeafSubGrid HeightAndTimeLeaf = factory.GetSubGrid(Types.GridDataType.HeightAndTime); Assert.NotNull(factory); }
/// <summary> /// Construct a concrete instance of a sub grid implementing the IClientLeafSubGrid interface based /// on the role it should play according to the grid data type requested. All aspects of leaf ownership /// by a sub grid tree, parentage, level, cell size, index origin offset are delegated responsibilities /// of the caller or a derived factory class /// </summary> /// <returns>An appropriate instance derived from ClientLeafSubGrid</returns> public IClientLeafSubGrid GetSubGrid(GridDataType gridDataType) { IClientLeafSubGrid result = null; //* TODO: Don't use repatriated sub grids for now... // if (!ClientLeaves[(int) gridDataType].TryTake(out IClientLeafSubGrid result)) // { if (_typeMap[(int)gridDataType] != null) { result = _typeMap[(int)gridDataType](); } // } result?.Clear(); return(result); }
public void Test_SubGridClientLeafFactory_Recycling() { IClientLeafSubGridFactory factory = new ClientLeafSubGridFactory(); Assert.NotNull(factory); IClientLeafSubGrid HeightLeaf = factory.GetSubGrid(Types.GridDataType.Height); factory.ReturnClientSubGrid(ref HeightLeaf); Assert.Null(HeightLeaf); IClientLeafSubGrid HeightAndTimeLeaf = factory.GetSubGrid(Types.GridDataType.HeightAndTime); factory.ReturnClientSubGrid(ref HeightAndTimeLeaf); Assert.Null(HeightAndTimeLeaf); }
/// <summary> /// Return a client grid previous obtained from the factory so it may reuse it /// </summary> public void ReturnClientSubGrid(ref IClientLeafSubGrid clientGrid) { // TODO: Don't accept any repatriated sub grids for now /* * if (clientGrid == null) * return; * * // Make sure the type of the client grid being returned matches it's advertised grid type * // if (!typeMap[(int)clientGrid.GridDataType].Equals(clientGrid.GetType())) * // { * // throw new TRexException("Type of client grid being returned does not match advertised grid data type."); * // } * * ClientLeaves[(int) clientGrid.GridDataType].Add(clientGrid); */ clientGrid = null; }
// creates an array of NEE for a sub grid // which is sent to Coordinate service // to resolve into a list of LHH (in same order) // Note: only adds entry where cellPassCount exists, so may not be 1024 entries private XYZ[] SetupLLPositions(string csibName, IClientLeafSubGrid subGrid) { var indexIntoNEECoords = 0; var NEECoords = new XYZ[1024]; var subGridProfile = subGrid as ClientCellProfileLeafSubgrid; subGrid.CalculateWorldOrigin(out double subGridWorldOriginX, out double subGridWorldOriginY); SubGridUtilities.SubGridDimensionalIterator((x, y) => { var cell = subGridProfile.Cells[x, y]; if (cell.PassCount == 0) // Nothing for us to do, as cell is empty { return; } var easting = subGridWorldOriginX + (x + 0.5) * subGridProfile.CellSize; var northing = subGridWorldOriginY + (y + 0.5) * subGridProfile.CellSize; NEECoords[indexIntoNEECoords] = new XYZ(easting, northing, cell.Height); indexIntoNEECoords++; }); return(_convertCoordinates.NEEToLLH(csibName, NEECoords.ToCoreX_XYZ()).ToTRex_XYZ()); }
public void Test_SubGridClientLeafFactory_Reuse() { IClientLeafSubGridFactory factory = ClientLeafSubGridFactoryFactory.CreateClientSubGridFactory(); Assert.NotNull(factory); IClientLeafSubGrid HeightLeaf = factory.GetSubGrid(Types.GridDataType.Height); factory.ReturnClientSubGrid(ref HeightLeaf); IClientLeafSubGrid HeightAndTimeLeaf = factory.GetSubGrid(Types.GridDataType.HeightAndTime); factory.ReturnClientSubGrid(ref HeightAndTimeLeaf); IClientLeafSubGrid HeightLeaf2 = factory.GetSubGrid(Types.GridDataType.Height); Assert.NotNull(HeightLeaf2); Assert.Equal(Types.GridDataType.Height, HeightLeaf2.GridDataType); IClientLeafSubGrid HeightAndTimeLeaf2 = factory.GetSubGrid(Types.GridDataType.HeightAndTime); Assert.NotNull(HeightAndTimeLeaf2); Assert.Equal(Types.GridDataType.HeightAndTime, HeightAndTimeLeaf2.GridDataType); }
/// <summary> /// Decorates the base sub grid request logic with additional requirements for progressive requests /// </summary> public override ServerRequestResult RetrieveSubGrid(IClientLeafSubGrid clientGrid, SubGridTreeBitmapSubGridBits cellOverrideMask, out bool sieveFilterInUse, Func <ServerRequestResult> computeSpatialFilterMaskAndClientProdDataMap) { // Establish the expected number of height layers in the client sub grid if (!(clientGrid is IClientProgressiveHeightsLeafSubGrid subGrid)) { throw new ArgumentException($"Supplied client {clientGrid.Moniker()} is not a {nameof(IClientProgressiveHeightsLeafSubGrid)}"); } _progressiveClientSubGrid = subGrid; var numHeightLayers = (int)((EndDate.Ticks - StartDate.Ticks) / Interval.Ticks); if ((EndDate.Ticks - StartDate.Ticks) % Interval.Ticks == 0) { numHeightLayers++; } _progressiveClientSubGrid.NumberOfHeightLayers = numHeightLayers; return(base.RetrieveSubGrid(clientGrid, cellOverrideMask, out sieveFilterInUse, computeSpatialFilterMaskAndClientProdDataMap)); }
/// <summary> /// Populate requested elevation information into the sub grid result /// </summary> /// <param name="subGrid"></param> public override void Populate(IClientLeafSubGrid subGrid) { //======================================================================================== byte BytesForRangeExcludingNull(uint range) => range < byte.MaxValue ? ONE_BYTE : range < ushort.MaxValue ? TWO_BYTES : FOUR_BYTES; //======================================================================================== base.Populate(subGrid); ClientHeightAndTimeLeafSubGrid elevSubGrid = (ClientHeightAndTimeLeafSubGrid)subGrid; var elevations = elevSubGrid.Cells; var times = elevSubGrid.Times; IsNull = true; subGrid.CalculateWorldOrigin(out var worldOriginX, out var worldOriginY); SubGridOriginX = worldOriginX; SubGridOriginY = worldOriginY; if (elevSubGrid.Cells != null) { // Determine the minimum/maximum non-null elevation/time in the sub grid double minElevation = DOUBLE_VALUE; double maxElevation = -DOUBLE_VALUE; uint minTime = TIME_MAXIMUM_VALUE; uint maxTime = TIME_MINIMUM_VALUE; SubGridUtilities.SubGridDimensionalIterator((x, y) => { var valueHeight = elevations[x, y]; if (Math.Abs(valueHeight - CellPassConsts.NullHeight) > Consts.TOLERANCE_DIMENSION) { if (valueHeight < minElevation) { minElevation = valueHeight; } if (valueHeight > maxElevation) { maxElevation = valueHeight; } long valueTime = times[x, y]; if (valueTime < minTime) { minTime = (uint)valueTime; } if (valueTime > maxTime) { minTime = (uint)valueTime; } } }); if (Math.Abs(minElevation - CellPassConsts.NullHeight) >= Consts.TOLERANCE_DIMENSION) { var minElevationAsMM = (uint)Math.Floor(minElevation * ELEVATION_OFFSET_FACTOR + ELEVATION_OFFSET_TOLERANCE); var maxElevationAsMM = (uint)Math.Floor(maxElevation * ELEVATION_OFFSET_FACTOR + ELEVATION_OFFSET_TOLERANCE); // Set the appropriate values into the result Data = new PatchOffsetsRecord[SubGridTreeConsts.SubGridTreeDimension, SubGridTreeConsts.SubGridTreeDimension]; IsNull = false; ElevationOrigin = (float)minElevation; ElevationOffsetSize = BytesForRangeExcludingNull(maxElevationAsMM - minElevationAsMM); TimeOrigin = minTime; TimeOffsetSize = BytesForRangeExcludingNull(minTime - maxTime); SubGridUtilities.SubGridDimensionalIterator((x, y) => { var valueHeight = elevations[x, y]; var valueTime = (uint)times[x, y]; if (Math.Abs(valueHeight - CellPassConsts.NullHeight) < Consts.TOLERANCE_DIMENSION) { Data[x, y] = new PatchOffsetsRecord(uint.MaxValue, uint.MaxValue); } else { Data[x, y] = new PatchOffsetsRecord((uint)Math.Floor((valueHeight - minElevation) * ELEVATION_OFFSET_FACTOR + ELEVATION_OFFSET_TOLERANCE), valueTime - minTime); } }); } } }
/// <summary> /// Processes a response containing a set of sub grids from the sub grid processor for a request /// </summary> private void ProcessResponse(ISerialisedByteArrayWrapper message) { var sw = Stopwatch.StartNew(); int responseCount = 0; using (var MS = new MemoryStream(message.Bytes)) { using (var reader = new BinaryReader(MS, Encoding.UTF8, true)) { // Read the number of sub grid present in the stream responseCount = reader.ReadInt32(); //Log.LogDebug($"Sub grid listener processing a collection of {responseCount} sub grid results"); // Create a single instance of the client grid. The approach here is that TransferResponse does not move ownership // to the called context (it may clone the passed in client grid if desired) var clientGrids = new IClientLeafSubGrid[responseCount][]; try { for (var i = 0; i < responseCount; i++) { var subGridCount = reader.ReadInt32(); clientGrids[i] = new IClientLeafSubGrid[subGridCount]; for (var j = 0; j < subGridCount; j++) { clientGrids[i][j] = _clientLeafSubGridFactory.GetSubGrid(TRexTask.GridDataType); // Check if the returned sub grid is null if (reader.ReadBoolean()) { clientGrids[i][j].Read(reader); } // else - Remove to reduce unwanted log traffic // Log.LogWarning($"Sub grid at position [{i},{j}] in sub grid response array is null"); } } // Log.InfoFormat("Transferring response#{0} to processor (from thread {1})", thisResponseCount, System.Threading.Thread.CurrentThread.ManagedThreadId); // Send the decoded grid to the PipelinedTask, but ensure sub grids are serialized into the TRexTask // (no assumption of thread safety within the TRexTask itself) try { lock (TRexTask) { for (var i = 0; i < responseCount; i++) { var thisResponseCount = ++responseCounter; if (TRexTask.TransferResponse(clientGrids[i])) { // Log.DebugFormat("Processed response#{0} (from thread {1})", thisResponseCount, System.Threading.Thread.CurrentThread.ManagedThreadId); } else { _log.LogInformation($"Processing response#{thisResponseCount} FAILED (from thread {Thread.CurrentThread.ManagedThreadId})"); } } } } finally { // Tell the pipeline that a set of sub grid have been completely processed TRexTask.PipeLine.SubGridsProcessed(responseCount); } } finally { // Return the client grid to the factory for recycling now its role is complete here... when using SimpleConcurrentBag _clientLeafSubGridFactory.ReturnClientSubGrids(clientGrids, responseCount); } } } _log.LogDebug($"Sub grid listener processed a collection of {responseCount} sub grid results in {sw.Elapsed}"); }
private void ValidateSurveyedSurfaceSuGridResult(ISiteModel siteModel, GridDataType expectedGridType, SurveyedSurfacePatchType patchType, IClientLeafSubGrid result) { result.Should().NotBeNull(); result.CellSize.Should().Be(siteModel.CellSize); result.IndexOriginOffset.Should().Be(SubGridTreeConsts.DefaultIndexOriginOffset); result.Level.Should().Be(SubGridTreeConsts.SubGridTreeLevels); result.WorldExtents().Should().BeEquivalentTo(new BoundingWorldExtent3D(0, 0, SubGridTreeConsts.SubGridTreeDimension * siteModel.CellSize, SubGridTreeConsts.SubGridTreeDimension * siteModel.CellSize)); result.GridDataType.Should().Be(expectedGridType); if (patchType == SurveyedSurfacePatchType.EarliestSingleElevation || patchType == SurveyedSurfacePatchType.LatestSingleElevation) { result.Should().BeOfType <ClientHeightAndTimeLeafSubGrid>(); } else { result.Should().BeOfType <ClientCompositeHeightsLeafSubgrid>(); } result.CountNonNullCells().Should().Be(903); }
/// <summary> /// Populates base class information from the supplied client leaf sub grid /// </summary> /// <param name="subGrid"></param> public virtual void Populate(IClientLeafSubGrid subGrid) { CellOriginX = (int)subGrid.OriginX; CellOriginY = (int)subGrid.OriginY; }
public CacheContextAdditionResult Add(IClientLeafSubGrid clientResult, long subGridInvalidationVersion) { return(_cache.Add(_context, clientResult, subGridInvalidationVersion)); }
public abstract bool LeafContentEquals(IClientLeafSubGrid other);
public virtual bool PerformHeightAnnotation(SubGridTreeBitmapSubGridBits processingMap, IList filteredSurveyedSurfaces, bool returnEarliestFilteredCellPass, IClientLeafSubGrid surfaceElevationsSource, Func <int, int, float, bool> elevationRangeFilter) { return(false); }
/// <summary> /// Orchestrates the mainline work of analyzing cell and cell pass information to create a client sub grid (heights, CMV, MDP etc) /// based on filter and other information established in the class /// </summary> /// <param name="clientGrid"></param> /// <param name="cellOverrideMask"></param> /// <returns></returns> public virtual ServerRequestResult RetrieveSubGrid(IClientLeafSubGrid clientGrid, SubGridTreeBitmapSubGridBits cellOverrideMask, out bool sieveFilterInUse, Func <ServerRequestResult> computeSpatialFilterMaskAndClientProdDataMap) { sieveFilterInUse = false; if (!Utilities.DerivedGridDataTypesAreCompatible(_gridDataType, clientGrid.GridDataType)) { throw new TRexSubGridProcessingException($"Grid data type of client leaf sub grid [{clientGrid.GridDataType}] is not compatible with the grid data type of retriever [{_gridDataType}]"); } var result = ServerRequestResult.UnknownError; // SIGLogMessage.PublishNoODS(Nil, Format('In RetrieveSubGrid: Active pass filters = %s, Active cell filters = %s', [PassFilter.ActiveFiltersText, CellFilter.ActiveFiltersText])); // Set up class local state for other methods to access _clientGrid = clientGrid; _clientGridAsLeaf = clientGrid as ClientLeafSubGrid; _canUseGlobalLatestCells &= !(_gridDataType == GridDataType.CCV || _gridDataType == GridDataType.CCVPercent) && _liftParams.CCVSummaryTypes != CCVSummaryTypes.None && !(_gridDataType == GridDataType.MDP || _gridDataType == GridDataType.MDPPercent) && _liftParams.MDPSummaryTypes != MDPSummaryTypes.None && !(_gridDataType == GridDataType.CCA || _gridDataType == GridDataType.CCAPercent) && !(_gridDataType == GridDataType.CellProfile || _gridDataType == GridDataType.PassCount || _gridDataType == GridDataType.CellPasses || _gridDataType == GridDataType.MachineSpeed || _gridDataType == GridDataType.CCVPercentChange || _gridDataType == GridDataType.MachineSpeedTarget || _gridDataType == GridDataType.CCVPercentChangeIgnoredTopNullValue); // Support for lazy construction of any required profiling infrastructure if (_clientGrid.WantsLiftProcessingResults() && _profiler == null) { // Some display types require lift processing to be able to select the // appropriate cell pass containing the filtered value required. _profiler = DIContext.Obtain <IProfilerBuilder <ProfileCell> >(); //TODO: should referenceDesignWrapper be null here or be passed through from args? _profiler.Configure(ProfileStyle.CellPasses, _siteModel, _pdExistenceMap, _gridDataType, new FilterSet(_filter), null, _populationControl, new CellPassFastEventLookerUpper(_siteModel), VolumeComputationType.None, _overrides, _liftParams); _cellProfile = new ProfileCell(); // Create and configure the assignment context which is used to contain // a filtered pass and its attendant machine events and target values // prior to assignment to the client sub grid. _assignmentContext.CellProfile = _cellProfile; } try { // Ensure pass type filter is set correctly if (_filter.AttributeFilter.HasPassTypeFilter) { if ((_filter.AttributeFilter.PassTypeSet & (PassTypeSet.Front | PassTypeSet.Rear)) == PassTypeSet.Front) { _filter.AttributeFilter.PassTypeSet |= PassTypeSet.Rear; // these two types go together as half passes } } // ... unless we can use the last pass grid to satisfy the query if (_canUseGlobalLatestCells && !_filter.AttributeFilter.HasElevationRangeFilter && !_clientGrid.WantsLiftProcessingResults() && !_filter.AttributeFilter.HasElevationMappingModeFilter && !(_filter.AttributeFilter.HasElevationTypeFilter && (_filter.AttributeFilter.ElevationType == ElevationType.Highest || _filter.AttributeFilter.ElevationType == ElevationType.Lowest)) && !(_gridDataType == GridDataType.PassCount || _gridDataType == GridDataType.Temperature || _gridDataType == GridDataType.CellProfile || _gridDataType == GridDataType.CellPasses || _gridDataType == GridDataType.MachineSpeed)) { _useLastPassGrid = true; } // First get the sub grid we are interested in // SIGLogMessage.PublishNoODS(Nil, Format('Begin LocateSubGridContaining at %dx%d', [clientGrid.OriginX, clientGrid.OriginY])); _subGrid = SubGridTrees.Server.Utilities.SubGridUtilities.LocateSubGridContaining(_storageProxy, _siteModel.Grid, clientGrid.OriginX, clientGrid.OriginY, _siteModel.Grid.NumLevels, false, false); // SIGLogMessage.PublishNoODS(Nil, Format('End LocateSubGridContaining at %dx%d', [clientGrid.OriginX, clientGrid.Origin])); if (_subGrid == null) // This should never really happen, but we'll be polite about it { Log.LogWarning( $"Sub grid address (CellX={clientGrid.OriginX}, CellY={clientGrid.OriginY}) passed to LocateSubGridContaining() from RetrieveSubGrid() did not match an existing sub grid in the data model. Returning SubGridNotFound as response with a null sub grid reference."); return(ServerRequestResult.SubGridNotFound); } // Now process the contents of that sub grid into the sub grid to be returned to the client. if (!_subGrid.IsLeafSubGrid()) { Log.LogInformation("Requests of node sub grids in the server sub grid are not yet supported"); return(result); } if (!(_subGrid is IServerLeafSubGrid)) { Log.LogError($"_SubGrid {_subGrid.Moniker()} is not a server grid leaf node"); return(result); } // SIGLogMessage.PublishNoODS(Nil, Format('Getting sub grid leaf at %dx%d', [clientGrid.OriginX, clientGrid.OriginY])); _subGridAsLeaf = (IServerLeafSubGrid)_subGrid; _globalLatestCells = _subGridAsLeaf.Directory.GlobalLatestCells; if (PruneSubGridRetrievalHere()) { return(ServerRequestResult.NoError); } // SIGLogMessage.PublishNoODS(Nil, Format('Setup for stripe iteration at %dx%d', [clientGrid.OriginX, clientGrid.OriginY])); SetupForCellPassStackExamination(); // Determine if a sieve filter is required for the sub grid where the sieve matches // the X and Y pixel world size (used for WMS tile computation) _subGrid.CalculateWorldOrigin(out var subGridWorldOriginX, out var subGridWorldOriginY); sieveFilterInUse = _areaControlSet.UseIntegerAlgorithm ? GridRotationUtilities.ComputeSieveBitmaskInteger(subGridWorldOriginX, subGridWorldOriginY, _subGrid.Moniker(), _areaControlSet, _siteModel.CellSize, out _sieveBitmask) : GridRotationUtilities.ComputeSieveBitmaskFloat(subGridWorldOriginX, subGridWorldOriginY, _areaControlSet, _siteModel.CellSize, _assignmentContext, out _sieveBitmask); //if (Debug_ExtremeLogSwitchC) Log.LogDebug($"Performing stripe iteration at {clientGrid.OriginX}x{clientGrid.OriginY}"); if (computeSpatialFilterMaskAndClientProdDataMap != null) { _clientGrid.ProdDataMap.Assign(_subGridAsLeaf.Directory.GlobalLatestCells.PassDataExistenceMap); var innerResult = computeSpatialFilterMaskAndClientProdDataMap(); if (innerResult != ServerRequestResult.NoError) { return(innerResult); } } // Before iterating over stripes of this sub grid, compute a scan map detailing to the best of our current // knowledge, which cells need to be visited so that only cells the filter wants and which are actually // present in the data set are requested. If the intent is to store the result in a cache then ensure the // entire content is requested for the sub grid. if (_prepareGridForCacheStorageIfNoSieving) { _aggregatedCellScanMap.Fill(); } else { _aggregatedCellScanMap.OrWith(_globalLatestCells.PassDataExistenceMap); if (sieveFilterInUse) { _aggregatedCellScanMap.AndWith(_sieveBitmask); // ... and which are required by any sieve mask } _aggregatedCellScanMap.AndWith(_clientGridAsLeaf.ProdDataMap); // ... and which are in the required production data map _aggregatedCellScanMap.AndWith(_clientGridAsLeaf.FilterMap); // ... and which are in the required filter map } // Iterate over the stripes in the sub grid processing each one in turn. for (byte i = 0; i < SubGridTreeConsts.SubGridTreeDimension; i++) { RetrieveSubGridStripe(i); } //if Debug_ExtremeLogSwitchC then Log.LogDebug($"Stripe iteration complete at {clientGrid.OriginX}x{clientGrid.OriginY}"); result = ServerRequestResult.NoError; } catch (Exception e) { Log.LogError(e, $"Exception occurred in {nameof(RetrieveSubGrid)}"); throw; } return(result); }
/// <summary> /// Responsible for coordinating the retrieval of production data for a sub grid from a site model and also annotating it with /// surveyed surface information for requests involving height data. /// </summary> public (ServerRequestResult requestResult, IClientLeafSubGrid clientGrid) RequestSubGridInternal( SubGridCellAddress subGridAddress, bool prodDataRequested, bool surveyedSurfaceDataRequested) { (ServerRequestResult requestResult, IClientLeafSubGrid clientGrid)result = (ServerRequestResult.UnknownError, null); if (!(prodDataRequested || surveyedSurfaceDataRequested)) { result.requestResult = ServerRequestResult.MissingInputParameters; return(result); } _prodDataRequested = prodDataRequested; _surveyedSurfaceDataRequested = surveyedSurfaceDataRequested; // if <config>.Debug_ExtremeLogSwitchB then Log.LogDebug("About to call RetrieveSubGrid()"); result.clientGrid = ClientLeafSubGridFactory.GetSubGridEx( Utilities.IntermediaryICGridDataTypeForDataType(_gridDataType, subGridAddress.SurveyedSurfaceDataRequested), _siteModel.CellSize, SubGridTreeConsts.SubGridTreeLevels, subGridAddress.X & ~SubGridTreeConsts.SubGridLocalKeyMask, subGridAddress.Y & ~SubGridTreeConsts.SubGridLocalKeyMask); _clientGrid = result.clientGrid; if (ShouldInitialiseFilterContext() && !InitialiseFilterContext()) { result.requestResult = ServerRequestResult.FilterInitialisationFailure; ClientLeafSubGridFactory.ReturnClientSubGrid(ref _clientGrid); return(result); } _haveComputedSpatialFilterMaskAndClientProdDataMap = false; if (_prodDataRequested) { if (_isTraceLoggingEnabled) { _log.LogTrace("Performing data extraction"); } if ((result.requestResult = PerformDataExtraction()) != ServerRequestResult.NoError) { ClientLeafSubGridFactory.ReturnClientSubGrid(ref _clientGrid); return(result); } } if (_surveyedSurfaceDataRequested) { if (_isTraceLoggingEnabled) { _log.LogTrace("Performing height annotation"); } if ((result.requestResult = PerformHeightAnnotation()) != ServerRequestResult.NoError) { ClientLeafSubGridFactory.ReturnClientSubGrid(ref _clientGrid); return(result); } } // Reassign _clientGrid to result as its reference may have been changed as a result of caching. result.clientGrid = _clientGrid; return(result); }
/// <summary> /// Calculates a cut/fill sub grid from a production data elevation sub grid and an elevation sub grid computed from a referenced design, /// replacing the elevations in the first sub grid with the resulting cut fill values /// </summary> public static (bool executionResult, DesignProfilerRequestResult profilerRequestResult) ComputeCutFillSubGrid(ISiteModel siteModel, IClientLeafSubGrid SubGrid, IDesignWrapper designWrapper) { (bool executionResult, DesignProfilerRequestResult profilerRequestResult)result = (false, DesignProfilerRequestResult.UnknownError); if (designWrapper?.Design == null) { return(result); } var getDesignHeightsResult = designWrapper.Design.GetDesignHeightsViaLocalCompute(siteModel, designWrapper.Offset, SubGrid.OriginAsCellAddress(), SubGrid.CellSize); result.profilerRequestResult = getDesignHeightsResult.errorCode; if (result.profilerRequestResult != DesignProfilerRequestResult.OK && result.profilerRequestResult != DesignProfilerRequestResult.NoElevationsInRequestedPatch) { _log.LogError($"Design profiler sub grid elevation request for {SubGrid.OriginAsCellAddress()} failed with error {result.profilerRequestResult}"); return(result); } ComputeCutFillSubGrid((IClientHeightLeafSubGrid)SubGrid, getDesignHeightsResult.designHeights); result.executionResult = true; return(result); }
/// <summary> /// // Note: There is an assumption you have already checked on a existence map that there is a sub grid for this address /// </summary> private ServerRequestResult PerformDataExtraction() { // If there is a cache context for this sub grid, but the sub grid does not support assignation then complain var assignationSupported = ClientLeafSubGrid.SupportsAssignationFromCachedPreProcessedClientSubGrid[(int)_clientGrid.GridDataType]; var subGridCacheContext = _subGridCacheContexts?.FirstOrDefault(x => x.GridDataType == _clientGrid.GridDataType); if (subGridCacheContext != null && !assignationSupported) { throw new TRexException($"Client sub grid of type {_clientGrid.GridDataType} does not support assignation from cached sub grids but has a cache context enabled for it."); } if (subGridCacheContext != null && assignationSupported) { if (subGridCacheContext != null && _clientGrid.GridDataType != subGridCacheContext.GridDataType) { _log.LogWarning($"Client grid data type {_clientGrid.GridDataType} does not match type of sub grid cache context {subGridCacheContext.GridDataType}"); } // Determine if there is a suitable pre-calculated result present in the general sub grid result cache. // If there is, then apply the filter mask to the cached data and copy it to the client grid var cachedSubGrid = (IClientLeafSubGrid)_subGridCache?.Get(subGridCacheContext, _clientGrid.CacheOriginX, _clientGrid.CacheOriginY); // If there was a cached sub grid located, assign its contents according the client grid mask into the client grid and return it if (cachedSubGrid != null) { // Log.LogInformation($"Acquired sub grid {CachedSubGrid.Moniker()} for client sub grid {ClientGrid.Moniker()} in data model {SiteModel.ID} from result cache"); // Check the cache supplied a tpe of sub grid we can use. If not (due to an issue), ignore the returned item and request the result directly if (_clientGrid.SupportsAssignationFrom(cachedSubGrid.GridDataType)) { _clientGrid.ProdDataMap.Assign(cachedSubGrid.ProdDataMap); var innerResult = ComputeSpatialFilterMaskAndClientProdDataMap(); if (innerResult != ServerRequestResult.NoError) { return(innerResult); } // Use the filter mask to copy the relevant cells from the cache to the client sub grid _clientGrid.AssignFromCachedPreProcessedClientSubGrid(cachedSubGrid, _clientGrid.FilterMap); return(ServerRequestResult.NoError); } _log.LogError($"Sub grid retrieved from cache is not valid for assigning into client grid. Ignoring. Client sub grid = {_clientGrid.Moniker()}/{_clientGrid.GridDataType}. Cache sub grid = {cachedSubGrid.Moniker()}/{cachedSubGrid.GridDataType}"); } } var result = _retriever.RetrieveSubGrid(_clientGrid, CellOverrideMask, out var sieveFilterInUse, ComputeSpatialFilterMaskAndClientProdDataMap); // If a sub grid was retrieved and this is a supported data type in the cache then add it to the cache // If the sub grid does not support assignation from a precomputed sub grid then just return the result with // no reference to the cache. if (result == ServerRequestResult.NoError && assignationSupported) { // Determine if this sub grid is suitable for storage in the cache // Don't add sub grids computed using a non-trivial WMS sieve to the general sub grid cache var shouldBeCached = subGridCacheContext != null && !sieveFilterInUse && (_clientGrid.GridDataType == subGridCacheContext.GridDataType); var subGridInvalidationVersion = shouldBeCached ? subGridCacheContext.InvalidationVersion : 0; var clientGrid2 = ClientLeafSubGridFactory.GetSubGrid(_clientGrid.GridDataType); clientGrid2.Assign(_clientGrid); clientGrid2.AssignFromCachedPreProcessedClientSubGrid(_clientGrid, _clientGrid.FilterMap); if (shouldBeCached) { //Log.LogInformation($"Adding sub grid {ClientGrid.Moniker()} in data model {SiteModel.ID} to result cache"); // Add the newly computed client sub grid to the cache by creating a clone of the client and adding it... if (_subGridCache.Add(subGridCacheContext, _clientGrid, subGridInvalidationVersion) != CacheContextAdditionResult.Added) { _log.LogWarning($"Failed to add sub grid {clientGrid2.Moniker()}, data model {_siteModel.ID} to sub grid result cache context [FingerPrint:{subGridCacheContext.FingerPrint}], returning sub grid to factory as not added to cache"); ClientLeafSubGridFactory.ReturnClientSubGrid(ref _clientGrid); } } _clientGrid = clientGrid2; } //if <config>.Debug_ExtremeLogSwitchB then SIGLogMessage.PublishNoODS(Nil, 'Completed call to RetrieveSubGrid()'); return(result); }