/// <summary> /// Performs functional initialization of ComputeVolumes state that is dependent on the initial state /// set via the constructor /// </summary> /// <param name="computeVolumes"></param> private void InitialiseVolumesCalculator(ProgressiveVolumesCalculator computeVolumes) { // Set up the volumes calc parameters VolumesUtilities.SetProdReportSelectionType(VolumeType, out var fromSelectionType, out var toSelectionType); computeVolumes.FromSelectionType = fromSelectionType; computeVolumes.ToSelectionType = toSelectionType; computeVolumes.RefOriginal = _baseDesign == null || _baseDesign.DesignID == Guid.Empty ? null : _siteModel.Designs.Locate(_baseDesign.DesignID); computeVolumes.RefDesign = _topDesign == null || _topDesign.DesignID == Guid.Empty ? null : _siteModel.Designs.Locate(_topDesign.DesignID); if (computeVolumes.FromSelectionType == ProdReportSelectionType.Surface) { computeVolumes.ActiveDesign = computeVolumes.RefOriginal != null ? new DesignWrapper(_baseDesign, computeVolumes.RefOriginal) : null; } else { computeVolumes.ActiveDesign = computeVolumes.ToSelectionType == ProdReportSelectionType.Surface && computeVolumes.RefDesign != null ? new DesignWrapper(_topDesign, computeVolumes.RefDesign) : null; } // Assign the active design into the aggregator for use Aggregator.ActiveDesign = computeVolumes.ActiveDesign; }
/// <summary> /// Executes the progressive volumes computation returning a ProgressiveVolumesResponse with the results /// </summary> public async Task <ProgressiveVolumesResponse> ExecuteAsync() { var volumesResult = new ProgressiveVolumesResponse(); var resultBoundingExtents = BoundingWorldExtent3D.Null(); var requestDescriptor = Guid.NewGuid(); // TODO ASNodeImplInstance.NextDescriptor; _log.LogInformation($"#In# Performing {nameof(ComputeProgressiveVolumes_Coordinator)}.Execute for DataModel:{SiteModelID}"); try { try { ApplicationServiceRequestStatistics.Instance.NumProgressiveVolumeRequests.Increment(); // Prepare filter for use in the request var resultStatus = FilterUtilities.PrepareFiltersForUse(new[] { Filter, AdditionalSpatialFilter }, SiteModelID); if (resultStatus != RequestErrorStatus.OK) { return(volumesResult); } // Obtain the site model context for the request _siteModel = DIContext.Obtain <ISiteModels>().GetSiteModel(SiteModelID); if (_siteModel == null) { return(volumesResult); } // Determine the number of progressions that are required and establish the required aggregation states in the aggregator var numProgressions = (int)((EndDate.Ticks - StartDate.Ticks) / Interval.Ticks); if ((EndDate.Ticks - StartDate.Ticks) % Interval.Ticks == 0) { numProgressions++; } if (VolumeType == VolumeComputationType.Between2Filters) { // One fewer progressions will be calculated as each volume in the progression is computed across the interval of two // surfaces derived from production data. numProgressions--; } if (numProgressions > ClientProgressiveHeightsLeafSubGrid.MaxNumberOfHeightLayers) { throw new ArgumentException($"No more than {ClientProgressiveHeightsLeafSubGrid.MaxNumberOfHeightLayers} height layers may be requested at one time"); } // Create and configure the aggregator that contains the business logic for the underlying volume calculation Aggregator = new ProgressiveVolumesCalculationsAggregator { SiteModel = _siteModel, LiftParams = _liftParams, CellSize = _siteModel.CellSize, VolumeType = VolumeType, CutTolerance = CutTolerance, FillTolerance = FillTolerance, AggregationStates = Enumerable .Range(VolumeType == VolumeComputationType.Between2Filters ? 1 : 0, numProgressions) .Select(x => StartDate + x * Interval) .Select(d => new ProgressiveVolumeAggregationState(_siteModel.CellSize) { Date = d, CutTolerance = CutTolerance, FillTolerance = FillTolerance }).ToArray() }; // Create and configure the volumes calculation engine var computeVolumes = new ProgressiveVolumesCalculator { RequestDescriptor = requestDescriptor, SiteModel = _siteModel, Aggregator = Aggregator, Filter = Filter, VolumeType = VolumeType, LiftParams = _liftParams, StartDate = StartDate, EndDate = EndDate, Interval = Interval }; InitialiseVolumesCalculator(computeVolumes); // Perform the volume computation if (computeVolumes.ComputeVolumeInformation()) { resultStatus = RequestErrorStatus.OK; } else { resultStatus = computeVolumes.AbortedDueToTimeout ? RequestErrorStatus.AbortedDueToPipelineTimeout : RequestErrorStatus.Unknown; } if (resultStatus != RequestErrorStatus.OK) { _log.LogInformation($"Progressive volume result: Failure, error = {resultStatus}"); // Send the (empty) results back to the caller return(volumesResult); } // Instruct the Aggregator to perform any finalization logic before reading out the results Aggregator.Finalise(); var noProductionDataCount = 0; var invalidPlanExtentsCount = 0; foreach (var state in Aggregator.AggregationStates) { _log.LogInformation($"#Result# Progressive volume result: Cut={state.CutFillVolume.CutVolume:F3}, Fill={state.CutFillVolume.FillVolume:F3}, Area={state.CoverageArea:F3}"); if (!state.BoundingExtents.IsValidPlanExtent) { if (state.CoverageArea == 0 && state.CutFillVolume.CutVolume == 0 && state.CutFillVolume.FillVolume == 0) { noProductionDataCount++; } else { invalidPlanExtentsCount++; } } } if (noProductionDataCount == Aggregator.AggregationStates.Length) { resultStatus = RequestErrorStatus.NoProductionDataFound; } else if (invalidPlanExtentsCount == Aggregator.AggregationStates.Length) { resultStatus = RequestErrorStatus.InvalidPlanExtents; } if (resultStatus == RequestErrorStatus.NoProductionDataFound || resultStatus == RequestErrorStatus.InvalidPlanExtents) { _log.LogInformation($"Progressive volume invalid plan extents or no data found: {resultStatus}"); } volumesResult.ResultStatus = resultStatus; if (resultStatus == RequestErrorStatus.OK) { volumesResult.Volumes = Aggregator.AggregationStates.Select(aggregator => new ProgressiveVolumeResponseItem { Date = aggregator.Date, Volume = new SimpleVolumesResponse { Cut = aggregator.CutFillVolume.CutVolume, Fill = aggregator.CutFillVolume.FillVolume, TotalCoverageArea = aggregator.CoverageArea, CutArea = aggregator.CutArea, FillArea = aggregator.FillArea, BoundingExtentGrid = aggregator.BoundingExtents, BoundingExtentLLH = resultBoundingExtents } }).ToArray(); } } finally { ApplicationServiceRequestStatistics.Instance.NumProgressiveVolumeRequestsCompleted.Increment(); if (volumesResult.ResultStatus != RequestErrorStatus.OK) { ApplicationServiceRequestStatistics.Instance.NumProgressiveVolumeRequestsFailed.Increment(); } } } catch (Exception e) { _log.LogError(e, $"Failed to compute the progressive volumes. Site Model ID: {SiteModelID}"); } return(volumesResult); }