diff --git a/AsbCloudApp/Data/DetectedOperation/DetectedOperationDto.cs b/AsbCloudApp/Data/DetectedOperation/DetectedOperationDto.cs index 0b9a2f91..cdc6571b 100644 --- a/AsbCloudApp/Data/DetectedOperation/DetectedOperationDto.cs +++ b/AsbCloudApp/Data/DetectedOperation/DetectedOperationDto.cs @@ -39,9 +39,9 @@ namespace AsbCloudApp.Data.DetectedOperation public DateTime DateEnd { get; set; } /// - /// Продолжительность операции в часах + /// Продолжительность операции в минутах /// - public double DurationHours => (DateEnd - DateStart).TotalHours; + public double DurationMinutes => (DateEnd - DateStart).TotalMinutes; /// /// глубина на начало операции, м diff --git a/AsbCloudApp/Requests/SubsystemRequest.cs b/AsbCloudApp/Requests/SubsystemRequest.cs index 79c88530..23a7e70a 100644 --- a/AsbCloudApp/Requests/SubsystemRequest.cs +++ b/AsbCloudApp/Requests/SubsystemRequest.cs @@ -17,6 +17,11 @@ namespace AsbCloudApp.Requests [Required] public int IdWell { get; set; } + /// + /// Идентификатор бурильщика + /// + public int? IdDriller { get; set; } + /// /// Больше или равно дате /// diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorDrilling.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorDrilling.cs index 3e8b0fa1..68eda39e 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorDrilling.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorDrilling.cs @@ -71,9 +71,7 @@ public class DetectorDrilling : DetectorAbstract private static (double avgRotorSpeed, double dispersionOfNormalizedRotorSpeed) CalcCriteries(DetectableTelemetry[] telemetry, int begin, int end) { - var telemetryRange = telemetry[begin..end] - .OrderBy(t => t.DateTime).ToList(); - + var telemetryRange = telemetry[begin..end]; var avgRotorSpeed = telemetryRange.Average(t => t.RotorSpeed); var dispersion = telemetryRange.Average(t => Math.Pow(t.RotorSpeed / avgRotorSpeed - 1, 2)); return (avgRotorSpeed, dispersion); diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs index 6b5970b9..7ff4076a 100644 --- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs +++ b/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs @@ -27,6 +27,8 @@ internal class SubsystemService : ISubsystemService private readonly IDetectedOperationService detectedOperationService; private readonly ITelemetryDataSaubService telemetryDataSaubService; + private IDictionary subsystems = new Dictionary(); + public SubsystemService(ICrudRepository subsystemRepository, IWellService wellService, IDetectedOperationService detectedOperationService, @@ -43,21 +45,25 @@ internal class SubsystemService : ISubsystemService var well = await wellService.GetOrDefaultAsync(request.IdWell, token) ?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist"); - var detectedOperationSummaryRequest = new DetectedOperationSummaryRequest + var detectedOperationSummaryRequest = new DetectedOperationRequest { + IdWell = request.IdWell, IdsTelemetries = new[] { well.IdTelemetry!.Value }, - IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds, + IdsCategories = WellOperationCategory.MechanicalDrillingSubIds, GeDateStart = request.GeDate, - LeDateStart = request.LeDate, + LeDateEnd = request.LeDate, - GeDepthStart = request.GeDepth, - LeDepthStart = request.LeDepth, + GeDepth = request.GeDepth, + LeDepth = request.LeDepth, }; - var operations = await detectedOperationService.GetOperationSummaryAsync(detectedOperationSummaryRequest, + var operations = await detectedOperationService.GetOperationsAsync(detectedOperationSummaryRequest, token); + if (request.IdDriller.HasValue) + operations = operations.Where(o => o.Driller is not null && o.Driller.Id == request.IdDriller.Value); + if (!operations.Any()) return Enumerable.Empty(); @@ -81,89 +87,119 @@ internal class SubsystemService : ISubsystemService var result = await GetStatAsync(activeWells, null, null, token); return result; } - - private async Task> CalcStatAsync(IEnumerable operations, CancellationToken token) + + private async Task> CalcStatAsync(IEnumerable operations, CancellationToken token) { - var subsystems = await subsystemRepository.GetAllAsync(token); + if (!subsystems.Any()) + subsystems = (await subsystemRepository.GetAllAsync(token)).ToDictionary(s => s.Id, s => s); - var groupedOperations = operations - .GroupBy(o => o.IdCategory); + var oscillationStat = CalcOscillationStat(operations); + var apdStat = CalcApdStat(operations); - var stat = groupedOperations.Select(groupOperations => + var stat = new List { oscillationStat }; + stat.AddRange(apdStat); + + return stat; + } + + private SubsystemStatDto CalcOscillationStat(IEnumerable operations) + { + operations = operations.Where(o => o.IdCategory == WellOperationCategory.IdSlide); + + var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(IdSubsystemOscillation, operations); + + var oscillationStat = new SubsystemStatDto { - var idSubsystem = groupOperations.Key switch + IdSubsystem = IdSubsystemOscillation, + SubsystemName = subsystems.TryGetValue(IdSubsystemOscillation, out var subsystemDto) ? subsystemDto.Name : "unknown", + UsedTimeHours = usedTimeHours, + SumOperationDepthInterval = operations.Sum(o => o.DepthEnd - o.DepthStart), + SumOperationDurationHours = operations.Sum(o => o.DurationMinutes / 60), + SumDepthInterval = sumDepthInterval, + OperationCount = operationCount, + }; + + oscillationStat.KUsage = oscillationStat.SumDepthInterval / oscillationStat.SumOperationDepthInterval; + + return oscillationStat; + } + + private IEnumerable CalcApdStat(IEnumerable operations) + { + var apdRotorAndSlide = operations + .Where(o => WellOperationCategory.MechanicalDrillingSubIds.Contains(o.IdCategory)) + .GroupBy(o => o.IdCategory) + .Select(group => { - WellOperationCategory.IdRotor => IdSubsystemAPDRotor, - WellOperationCategory.IdSlide => IdSubsystemAPDSlide, - _ => throw new ArgumentException($"IdCategory: {groupOperations.Key} does not supported in this method", - nameof(groupOperations.Key)), - }; - - var operationsWithEnableSubsystems = groupOperations.Where(o => - (EnabledSubsystemsFlags.AutoRotor | - EnabledSubsystemsFlags.AutoSlide | - EnabledSubsystemsFlags.AutoOscillation).HasEnabledSubsystems(o.EnabledSubsystems)); - - var subsystemStat = new SubsystemStatDto - { - IdSubsystem = idSubsystem, - SubsystemName = subsystems.FirstOrDefault(s => s.Id == idSubsystem)?.Name ?? "unknown", - UsedTimeHours = operationsWithEnableSubsystems.Sum(o => o.SumDurationHours), - SumOperationDepthInterval = groupOperations.Sum(o => o.SumDepthIntervals), - SumOperationDurationHours = groupOperations.Sum(o => o.SumDurationHours), - SumDepthInterval = operationsWithEnableSubsystems.Sum(o => o.SumDepthIntervals), - OperationCount = operationsWithEnableSubsystems.Sum(o => o.Count), - }; + var idSubsystem = group.Key switch + { + WellOperationCategory.IdRotor => IdSubsystemAPDRotor, + WellOperationCategory.IdSlide => IdSubsystemAPDSlide, + _ => throw new ArgumentException($"IdCategory: {group.Key} does not supported in this method", nameof(group.Key)) + }; - subsystemStat.KUsage = subsystemStat.SumDepthInterval / subsystemStat.SumOperationDepthInterval; - - return subsystemStat; - }); + var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(idSubsystem, group); - var apdSlidePart = stat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPDSlide); + var subsystemStat = new SubsystemStatDto + { + IdSubsystem = idSubsystem, + SubsystemName = subsystems.TryGetValue(idSubsystem, out var subsystemDto) ? subsystemDto.Name : "unknown", + UsedTimeHours = usedTimeHours, + SumOperationDepthInterval = group.Sum(o => o.DepthEnd - o.DepthStart), + SumOperationDurationHours = group.Sum(o => o.DurationMinutes / 60), + SumDepthInterval = sumDepthInterval, + OperationCount = operationCount, + }; - if (apdSlidePart is not null) - { - var operationsWithOscillation = - operations.Where(o => EnabledSubsystemsFlags.AutoOscillation.HasEnabledSubsystems(o.EnabledSubsystems)); + subsystemStat.KUsage = subsystemStat.SumDepthInterval / subsystemStat.SumOperationDepthInterval; - var spinMaster = new SubsystemStatDto - { - IdSubsystem = IdSubsystemOscillation, - SubsystemName = subsystems.FirstOrDefault(s => s.Id == IdSubsystemOscillation)?.Name ?? "unknown", - UsedTimeHours = operationsWithOscillation.Sum(o => o.SumDurationHours), - SumOperationDepthInterval = apdSlidePart.SumOperationDepthInterval, - SumOperationDurationHours = apdSlidePart.SumOperationDurationHours, - SumDepthInterval = operationsWithOscillation.Sum(o => o.SumDepthIntervals), - OperationCount = operationsWithOscillation.Sum(s => s.Count) - }; - - spinMaster.KUsage = spinMaster.SumDepthInterval / spinMaster.SumOperationDepthInterval; - - stat = stat.Append(spinMaster); - } - - var apdParts = stat.Where(s => s.IdSubsystem is IdSubsystemAPDRotor or IdSubsystemAPDSlide); - - if (!apdParts.Any()) - return stat; + return subsystemStat; + }); + + if (!apdRotorAndSlide.Any()) + return Enumerable.Empty(); var apdSum = new SubsystemStatDto { IdSubsystem = IdSubsystemAPD, - SubsystemName = "АПД", - UsedTimeHours = apdParts.Sum(part => part.UsedTimeHours), - SumOperationDepthInterval = apdParts.Sum(part => part.SumOperationDepthInterval), - SumOperationDurationHours = apdParts.Sum(part => part.SumOperationDurationHours), - SumDepthInterval = apdParts.Sum(part => part.SumDepthInterval), - OperationCount = apdParts.Sum(part => part.OperationCount), + SubsystemName = subsystems.TryGetValue(IdSubsystemAPD, out var subsystemDto) ? subsystemDto.Name : "unknown", + UsedTimeHours = apdRotorAndSlide.Sum(part => part.UsedTimeHours), + SumOperationDepthInterval = apdRotorAndSlide.Sum(part => part.SumOperationDepthInterval), + SumOperationDurationHours = apdRotorAndSlide.Sum(part => part.SumOperationDurationHours), + SumDepthInterval = apdRotorAndSlide.Sum(part => part.SumDepthInterval), + OperationCount = apdRotorAndSlide.Sum(part => part.OperationCount), }; apdSum.KUsage = apdSum.SumDepthInterval / apdSum.SumOperationDepthInterval; - - stat = stat.Append(apdSum).OrderBy(m => m.IdSubsystem); - return stat; + var apdStat = new List { apdSum }; + apdStat.AddRange(apdRotorAndSlide); + + return apdStat; + } + + private static (double SumDepthInterval, double UsedTimeHours, int Count) AggregateOperations(int idSubsystem, + IEnumerable operations) => + idSubsystem switch + { + IdSubsystemAPDRotor => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoRotor), + IdSubsystemAPDSlide => CalcOperationsByEnableSubsystems(operations, + EnabledSubsystemsFlags.AutoSlide | EnabledSubsystemsFlags.AutoOscillation), + IdSubsystemOscillation => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoOscillation), + _ => throw new ArgumentException($"IdSubsystem: {idSubsystem} does not supported in this method", nameof(idSubsystem)) + }; + + private static (double SumDepthInterval, double UsedTimeHours, int OperationCount) CalcOperationsByEnableSubsystems( + IEnumerable operations, + EnabledSubsystemsFlags enabledSubsystems) + { + var filtered = operations.Where(o => enabledSubsystems.HasEnabledSubsystems(o.EnabledSubsystems)); + + var sumDepthInterval = filtered.Sum(o => o.DepthEnd - o.DepthStart); + var usedTimeHours = filtered.Sum(o => o.DurationMinutes / 60); + var operationCount = filtered.Count(); + + return (sumDepthInterval, usedTimeHours, operationCount); } private async Task> GetStatAsync(IEnumerable wells, @@ -195,14 +231,16 @@ internal class SubsystemService : ISubsystemService ? ltDate.Value.ToUtcDateTimeOffset(hoursOffset) : dateRange.To.ToUtcDateTimeOffset(hoursOffset); + var request = new DetectedOperationRequest + { + IdsTelemetries = idsTelemetries, + IdsCategories = WellOperationCategory.MechanicalDrillingSubIds, + GeDateStart = beginUTC, + LeDateEnd = endUTC, + }; + var operations = await detectedOperationService - .GetOperationSummaryAsync(new() - { - IdsTelemetries = idsTelemetries, - IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds, - GeDateStart = beginUTC, - LeDateEnd = endUTC, - }, token); + .GetOperationsAsync(request, token); var wellStat = new SubsystemActiveWellStatDto { Well = well };