DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/ProcessMaps/WellDrillingProcessMap/Report/WellDrillingProcessMapReportService.cs

229 lines
9.6 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps.WellDrillingProcessMap;
using AsbCloudInfrastructure.Services.ProcessMaps.WellDrillingProcessMap.Report.Data;
namespace AsbCloudInfrastructure.Services.ProcessMaps.WellDrillingProcessMap.Report;
public class WellDrillingProcessMapReportService : IProcessMapReportWellDrillingService
{
private readonly IWellService wellService;
private readonly IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository;
private readonly ITelemetryDataSaubService telemetryDataSaubService;
private readonly IWellOperationRepository wellOperationRepository;
public WellDrillingProcessMapReportService(IWellService wellService,
IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository,
ITelemetryDataSaubService telemetryDataSaubService,
IWellOperationRepository wellOperationRepository)
{
this.wellService = wellService;
this.processMapPlanWellDrillingRepository = processMapPlanWellDrillingRepository;
this.telemetryDataSaubService = telemetryDataSaubService;
this.wellOperationRepository = wellOperationRepository;
}
public async Task<IEnumerable<ProcessMapReportWellDrillingDto>> GetAsync(int idWell,
CancellationToken token)
{
var well = await wellService.GetOrDefaultAsync(idWell, token)
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважина с Id: {idWell} не найдена");
if (!well.IdTelemetry.HasValue)
throw new ArgumentInvalidException(nameof(idWell), $"Скважина с Id: {idWell} не имеет телеметрии");
var processMapPlanWellDrillings = await processMapPlanWellDrillingRepository.GetByIdWellAsync(idWell, token);
if (!processMapPlanWellDrillings.Any())
return Enumerable.Empty<ProcessMapReportWellDrillingDto>();
var telemetryDataStat =
(await telemetryDataSaubService.GetTelemetryDataStatAsync(well.IdTelemetry.Value, token)).ToArray();
if (!telemetryDataStat.Any())
return Enumerable.Empty<ProcessMapReportWellDrillingDto>();
var result = CalcByIntervals(processMapPlanWellDrillings, telemetryDataStat);
return result;
}
private IEnumerable<ProcessMapReportWellDrillingDto> CalcByIntervals(
IEnumerable<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillings,
TelemetryDataSaubStatDto[] telemetryDataStat)
{
var processMapIntervals = CalcDepthIntervals(processMapPlanWellDrillings);
var result = new List<ProcessMapReportWellDrillingDto>(processMapIntervals.Count() * 4);
var telemetryIndexStart =
Array.FindIndex(telemetryDataStat, t => t.WellDepthMin >= processMapIntervals.First().DepthStart);
if (telemetryIndexStart < 0)
return Enumerable.Empty<ProcessMapReportWellDrillingDto>();
IDictionary<int, string> sectionTypes = wellOperationRepository
.GetSectionTypes()
.ToDictionary(s => s.Id, s => s.Caption);
foreach (var interval in processMapIntervals)
{
var processMapPlanWellDrillingInterval = processMapPlanWellDrillings
.Where(p => p.DepthStart <= interval.DepthEnd && p.DepthEnd >= interval.DepthStart);
if (!processMapPlanWellDrillingInterval.Any())
continue;
var telemetryIndexEnd = Array.FindIndex(telemetryDataStat, telemetryIndexStart,
t => t.WellDepthMin >= interval.DepthEnd);
if (telemetryIndexEnd < 0)
telemetryIndexEnd = telemetryDataStat.Length - 1;
var telemetryDataInterval =
telemetryDataStat.AsSpan(telemetryIndexStart, telemetryIndexEnd - telemetryIndexStart);
IEnumerable<ProcessMapReportWellDrillingDto> subIntervalsResult =
CalcSubIntervals(interval, processMapPlanWellDrillingInterval, telemetryDataInterval, sectionTypes);
result.AddRange(subIntervalsResult);
telemetryIndexStart = telemetryIndexEnd;
}
return result;
}
private static IEnumerable<(double DepthStart, double DepthEnd)> CalcDepthIntervals(
IEnumerable<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillings)
{
if (!processMapPlanWellDrillings.Any())
yield break;
var intervalStarts = processMapPlanWellDrillings
.OrderBy(i => i.DepthStart)
.Select(p => p.DepthStart)
.Distinct()
.ToArray();
for (var i = 1; i < intervalStarts.Length; i++)
yield return (intervalStarts[i - 1], intervalStarts[i]);
yield return (intervalStarts[^1], processMapPlanWellDrillings.Max(p => p.DepthEnd));
}
private static IEnumerable<ProcessMapReportWellDrillingDto> CalcSubIntervals(
(double DepthStart, double DepthEnd) interval,
IEnumerable<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingInterval,
Span<TelemetryDataSaubStatDto> telemetryDataInterval,
IDictionary<int, string> sectionTypes)
{
var telemetryDataIntervalLength = telemetryDataInterval.Length;
if (telemetryDataInterval.Length == 0)
return Enumerable.Empty<ProcessMapReportWellDrillingDto>();
var result = new List<ProcessMapReportWellDrillingDto>();
var telemetryIndexStart = 0;
var subInterval = interval;
for (var i = telemetryIndexStart + 1; i < telemetryDataIntervalLength; i++)
{
if (IsDifferent(telemetryDataInterval[telemetryIndexStart], telemetryDataInterval[i]))
{
subInterval.DepthEnd = telemetryDataInterval[i - 1].WellDepthMax;
var telemetryRowSpan = telemetryDataInterval[telemetryIndexStart..(i - 1)];
if (!telemetryRowSpan.IsEmpty)
{
var intervalReportRow = CalcSubIntervalReportRow(subInterval, processMapPlanWellDrillingInterval,
telemetryRowSpan, sectionTypes);
result.Add(intervalReportRow);
}
telemetryIndexStart = i;
subInterval.DepthStart = subInterval.DepthEnd;
}
}
subInterval.DepthEnd = interval.DepthEnd;
var intervalReportRowLast = CalcSubIntervalReportRow(subInterval, processMapPlanWellDrillingInterval,
telemetryDataInterval[telemetryIndexStart..telemetryDataIntervalLength], sectionTypes);
result.Add(intervalReportRowLast);
return result;
}
private static ProcessMapReportWellDrillingDto CalcSubIntervalReportRow(
(double DepthStart, double DepthEnd) subInterval,
IEnumerable<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillings,
Span<TelemetryDataSaubStatDto> telemetryRowSpan,
IDictionary<int, string> sectionTypes)
{
var telemetryStat = new TelemetryStat(telemetryRowSpan);
var processMapByMode = processMapPlanWellDrillings.FirstOrDefault(p => p.IdMode == telemetryStat.IdMode);
var processMapFirst = processMapPlanWellDrillings.First();
var idWellSectionType = processMapByMode?.IdWellSectionType ?? processMapFirst.IdWellSectionType;
var result = new ProcessMapReportWellDrillingDto
{
IdWell = processMapByMode?.IdWell ?? processMapFirst.IdWell,
IdWellSectionType = idWellSectionType,
WellSectionTypeName = sectionTypes[idWellSectionType],
DepthStart = subInterval.DepthStart,
DepthEnd = subInterval.DepthEnd,
DateStart = telemetryStat.DateStart,
MechDrillingHours = telemetryStat.MechDrillingHours,
DrillingMode = telemetryStat.ModeName,
DeltaDepth = telemetryStat.DeltaDepth,
PressureDiff = telemetryStat.Pressure.MakeParams(processMapByMode?.Pressure.Plan),
AxialLoad = telemetryStat.AxialLoad.MakeParams(processMapByMode?.AxialLoad.Plan),
TopDriveTorque = telemetryStat.RotorTorque.MakeParams(processMapByMode?.TopDriveTorque.Plan),
SpeedLimit = telemetryStat.BlockSpeed.MakeParams(processMapByMode?.RopPlan),
Rop = telemetryStat.Rop,
UsagePlan = processMapByMode?.UsageSaub ?? telemetryStat.UsagePredictPlan,
UsageFact = telemetryStat.UsageSaub,
};
return result;
}
private static bool IsDifferent(TelemetryDataSaubStatDto intervalStart, TelemetryDataSaubStatDto current)
{
if (intervalStart.WellDepthMin > current.WellDepthMin)
return true;
if (intervalStart.IdMode != current.IdMode)
return true;
if (Math.Abs(intervalStart.PressureSp - current.PressureSp) > 5d)
return true;
if (Math.Abs(intervalStart.AxialLoadSp - current.AxialLoadSp) > 1d)
return true;
if (Math.Abs(intervalStart.RotorTorqueSp - current.RotorTorqueSp) > 5d)
return true;
var blockSpeedSpDiff = Math.Abs(intervalStart.BlockSpeedSp - current.BlockSpeedSp);
if (!(blockSpeedSpDiff > 5d))
return false;
switch (intervalStart.BlockSpeedSp)
{
case <= 30:
case > 30 when blockSpeedSpDiff > 15d:
case > 80 when blockSpeedSpDiff > 20d:
return true;
}
return false;
}
}