DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs
Степанов Дмитрий 72e6c8931b Удаление метода из API подсистем
Удалён метод получения статистики наработки по активным скважинам. /api/Subsystem/statByActiveWell
2024-01-23 09:14:09 +05:00

246 lines
8.7 KiB
C#

using AsbCloudApp.Data;
using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudInfrastructure.Services.DetectOperations;
namespace AsbCloudInfrastructure.Services.Subsystems;
internal class SubsystemService : ISubsystemService
{
private const int IdSubsystemAPD = 1;
private const int IdSubsystemAPDRotor = 11;
private const int IdSubsystemAPDSlide = 12;
private const int IdSubsystemOscillation = 65536;
private readonly ICrudRepository<SubsystemDto> subsystemRepository;
private readonly IWellService wellService;
private readonly IDetectedOperationService detectedOperationService;
private IDictionary<int, SubsystemDto> subsystems = new Dictionary<int, SubsystemDto>();
public SubsystemService(ICrudRepository<SubsystemDto> subsystemRepository,
IWellService wellService,
IDetectedOperationService detectedOperationService)
{
this.wellService = wellService;
this.subsystemRepository = subsystemRepository;
this.detectedOperationService = detectedOperationService;
}
public async Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemRequest request, CancellationToken token)
{
var well = await wellService.GetOrDefaultAsync(request.IdWell, token)
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist");
if(!well.IdTelemetry.HasValue)
return Enumerable.Empty<SubsystemStatDto>();
var detectedOperationSummaryRequest = new DetectedOperationRequest
{
IdWell = request.IdWell,
IdsTelemetries = new[] { well.IdTelemetry.Value },
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
GeDateStart = request.GeDate,
LeDateEnd = request.LeDate,
GeDepth = request.GeDepth,
LeDepth = request.LeDepth,
};
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<SubsystemStatDto>();
var stat = await CalcStatAsync(operations, token);
return stat;
}
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token)
{
var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token);
var result = await GetStatAsync(activeWells, null, null, token);
return result;
}
private async Task<IEnumerable<SubsystemStatDto>> CalcStatAsync(IEnumerable<DetectedOperationDto> operations, CancellationToken token)
{
if (!subsystems.Any())
subsystems = (await subsystemRepository.GetAllAsync(token)).ToDictionary(s => s.Id, s => s);
var oscillationStat = CalcOscillationStat(operations);
var apdStat = CalcApdStat(operations);
var stat = new List<SubsystemStatDto> { oscillationStat };
stat.AddRange(apdStat);
return stat;
}
private SubsystemStatDto CalcOscillationStat(IEnumerable<DetectedOperationDto> operations)
{
operations = operations.Where(o => o.IdCategory == WellOperationCategory.IdSlide);
var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(IdSubsystemOscillation, operations);
var oscillationStat = new SubsystemStatDto
{
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<SubsystemStatDto> CalcApdStat(IEnumerable<DetectedOperationDto> operations)
{
var apdRotorAndSlide = operations
.Where(o => WellOperationCategory.MechanicalDrillingSubIds.Contains(o.IdCategory))
.GroupBy(o => o.IdCategory)
.Select(group =>
{
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))
};
var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(idSubsystem, group);
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,
};
subsystemStat.KUsage = subsystemStat.SumDepthInterval / subsystemStat.SumOperationDepthInterval;
return subsystemStat;
});
if (!apdRotorAndSlide.Any())
return Enumerable.Empty<SubsystemStatDto>();
var apdSum = new SubsystemStatDto
{
IdSubsystem = IdSubsystemAPD,
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;
var apdStat = new List<SubsystemStatDto> { apdSum };
apdStat.AddRange(apdRotorAndSlide);
return apdStat;
}
private static (double SumDepthInterval, double UsedTimeHours, int Count) AggregateOperations(int idSubsystem,
IEnumerable<DetectedOperationDto> 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<DetectedOperationDto> 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<IEnumerable<SubsystemActiveWellStatDto>> GetStatAsync(IEnumerable<WellDto> wells,
DateTime? geDate,
DateTime? leDate,
CancellationToken token)
{
if (!wells.Any())
return Enumerable.Empty<SubsystemActiveWellStatDto>();
var idsTelemetries = wells
.Where(w => w.IdTelemetry is not null)
.Select(w => w.IdTelemetry!.Value)
.Distinct();
var wellsStat = new List<SubsystemActiveWellStatDto>();
foreach (var well in wells)
{
var hoursOffset = well.Timezone.Hours;
var geDateStartUtc = geDate?.ToUtcDateTimeOffset(hoursOffset);
var leDateUtc = leDate?.ToUtcDateTimeOffset(hoursOffset);
var request = new DetectedOperationRequest
{
IdWell = well.Id,
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
GeDateStart = geDateStartUtc,
LeDateEnd = leDateUtc,
};
var telemetryOperations = await detectedOperationService
.GetOperationsAsync(request, token);
var wellStat = new SubsystemActiveWellStatDto { Well = well };
if (!telemetryOperations.Any())
continue;
var subsystemStat = await CalcStatAsync(telemetryOperations, token);
if (!subsystemStat.Any())
continue;
wellStat.SubsystemAPD = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPD);
wellStat.SubsystemOscillation = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemOscillation);
wellsStat.Add(wellStat);
}
return wellsStat;
}
}