DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs

314 lines
14 KiB
C#
Raw Normal View History

2022-12-27 14:30:52 +05:00
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMap;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
2022-12-27 14:30:52 +05:00
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore;
2022-12-27 14:30:52 +05:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.ProcessMap
{
#nullable enable
public partial class ProcessMapService : IProcessMapService
2022-12-27 14:30:52 +05:00
{
private readonly IAsbCloudDbContext db;
private readonly IWellOperationRepository wellOperationRepository;
2022-12-27 14:30:52 +05:00
private readonly IProcessMapRepository processMapRepository;
private readonly ITelemetryService telemetryService;
2022-12-27 14:30:52 +05:00
public ProcessMapService(
IAsbCloudDbContext db,
IWellOperationRepository wellOperationService,
IProcessMapRepository processMapRepository,
ITelemetryService telemetryService)
{
this.db = db;
this.wellOperationRepository = wellOperationService;
2022-12-27 14:30:52 +05:00
this.processMapRepository = processMapRepository;
this.telemetryService = telemetryService;
2022-12-27 14:30:52 +05:00
}
public async Task<IEnumerable<ProcessMapReportDto>> GetProcessMapAsync(int idWell, CancellationToken token)
{
var operationsRequest = new WellOperationRequest
{
IdWell = idWell,
OperationCategoryIds = WellOperationCategory.MechanicalDrillingSubIds,
OperationType = WellOperation.IdOperationTypeFact,
SortFields = new[]{ nameof(WellOperation.DateStart) }
};
var allFactDrillingOperations = (await wellOperationRepository.GetAsync(operationsRequest, token))
.Where(o => o.DepthEnd > o.DepthStart);
var processMapDtos = (await processMapRepository.GetByIdWellAsync(idWell, token))!;
var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell)!.Value;
2023-01-10 12:31:01 +05:00
IEnumerable<ProcessTelemetrySaubStat> telemetryDataStat = await GetTelemetryDataAsync(idTelemetry, token);
var result = allFactDrillingOperations
.GroupBy(o => o.IdWellSectionType)
.SelectMany(sectionOperations =>
{
var sectionProcessMap = processMapDtos.Where(p => p.IdWellSectionType == sectionOperations.Key);
2023-01-10 12:31:01 +05:00
return HandleSections(sectionOperations, sectionProcessMap, telemetryDataStat);
})
.ToList();
2022-12-27 14:30:52 +05:00
return result;
}
private async Task<IEnumerable<ProcessTelemetrySaubStat>> GetTelemetryDataAsync(int idTelemetry, CancellationToken token)
{
var timezone = telemetryService.GetTimezone(idTelemetry);
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
var query = db.Set<TelemetryDataSaub>()
.Where(t => t.IdTelemetry == idTelemetry)
.Where(t => t.BlockPosition > 0.0001)
.Where(t => t.WellDepth > 0.0001)
.Where(t => t.WellDepth - t.BitDepth < 0.01)
.GroupBy(t => new { H = t.DateTime.Hour, W = Math.Truncate(t.WellDepth!.Value) })
.Select(g => new ProcessTelemetrySaubStat
{
Count = g.Count(),
DateMin = g.Min(t => t.DateTime.UtcDateTime),
DateMax = g.Max(t => t.DateTime.UtcDateTime),
WellDepthMin = g.Min(t => t.WellDepth!.Value),
WellDepthMax = g.Max(t => t.WellDepth!.Value),
Pressure = g.Average(t => t.Pressure!.Value),
PressureSp = g.Average(t => t.PressureSp!.Value),
PressureSpRotor = g.Average(t => t.PressureSpRotor!.Value),
PressureSpSlide = g.Average(t => t.PressureSpSlide!.Value),
PressureIdle = g.Average(t => t.PressureIdle!.Value),
PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
AxialLoad = g.Average(t => t.AxialLoad!.Value),
AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value),
AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value),
RotorTorque = g.Average(t => t.RotorTorque!.Value),
RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value),
RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value),
BlockSpeed = g.Average(t => t.BlockSpeed!.Value),
BlockSpeedSp = g.Average(t => t.BlockSpeedSp!.Value),
BlockSpeedSpRotor = g.Average(t => t.BlockSpeedSpRotor!.Value),
BlockSpeedSpSlide = g.Average(t => t.BlockSpeedSpSlide!.Value),
})
.Where(s => s.WellDepthMin != s.WellDepthMax)
.Where(s => s.Count > 3)
.OrderBy(t => t.DateMin);
var data = await query.ToArrayAsync(token);
return data;
2022-12-27 14:30:52 +05:00
}
private static IEnumerable<ProcessMapReportDto> HandleSections(
IEnumerable<WellOperationDto> sectionOperations,
2023-01-10 12:31:01 +05:00
IEnumerable<ProcessMapDto> sectionProcessMap,
IEnumerable<ProcessTelemetrySaubStat> telemetryDataStat)
2022-12-27 14:30:52 +05:00
{
var minDepth = sectionOperations.Min(o => o.DepthStart);
var maxDepth = sectionOperations.Max(o => o.DepthEnd);
2022-12-27 14:30:52 +05:00
var depthIntervals = SplitByIntervals(minDepth, maxDepth).ToArray();
var result = new ProcessMapReportDto[depthIntervals.Length];
2022-12-27 14:30:52 +05:00
for (var i = 0; i < depthIntervals.Length; i++ )
2023-01-10 12:31:01 +05:00
result[i] = MakeProcessMapReportDto(depthIntervals[i], sectionOperations, sectionProcessMap, telemetryDataStat);
return result;
}
2022-12-27 14:30:52 +05:00
private static ProcessMapReportDto MakeProcessMapReportDto(
(double min, double max) depthInterval,
IEnumerable<WellOperationDto> sectionOperations,
2023-01-10 12:31:01 +05:00
IEnumerable<ProcessMapDto> sectionProcessMap,
IEnumerable<ProcessTelemetrySaubStat> telemetryDataStat)
{
var dto = new ProcessMapReportDto{
DepthStart = depthInterval.min
};
2022-12-27 14:30:52 +05:00
var intervalOperations = sectionOperations.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max);
var intervalProcessMap = sectionProcessMap.Where(map => map.DepthEnd >= depthInterval.min && map.DepthStart <= depthInterval.max);
2023-01-10 12:31:01 +05:00
var intervalTelemetryDataStat = CalcIntervalTelemetryDataStat(depthInterval, telemetryDataStat);
if (intervalOperations.Any())
{
var firstIntervalOperation = intervalOperations.First();
var slideOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdSlide);
var rotorOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdRotor);
dto.DepthStart = depthInterval.min;
dto.DateStart = GetInterpolatedDate(firstIntervalOperation, depthInterval.min);
dto.IdWell = firstIntervalOperation.IdWell;
dto.IdWellSectionType = firstIntervalOperation.IdWellSectionType;
dto.WellSectionTypeName = firstIntervalOperation.WellSectionTypeName;
dto.MechDrillingHours = CalcHours(depthInterval, sectionOperations);
2023-01-10 12:31:01 +05:00
dto.Slide = CalcDrillModeStat(depthInterval, slideOperations, intervalProcessMap, intervalTelemetryDataStat);
dto.Rotor = CalcDrillModeStat(depthInterval, rotorOperations, intervalProcessMap, intervalTelemetryDataStat);
}
return dto;
2022-12-27 14:30:52 +05:00
}
2023-01-10 12:31:01 +05:00
private static ProcessTelemetrySaubStat? CalcIntervalTelemetryDataStat((double min, double max) depthInterval, IEnumerable<ProcessTelemetrySaubStat> telemetryDataStat)
{
ProcessTelemetrySaubStat[] data = telemetryDataStat
.Where(d => d.WellDepthMin <= depthInterval.max && d.WellDepthMax >= depthInterval.min)
.ToArray();
if (!data.Any())
return null;
if (data.Length == 1)
return data.First();
var result = new ProcessTelemetrySaubStat
{
WellDepthMin = data.Min(d => d.WellDepthMin),
WellDepthMax = data.Max(d => d.WellDepthMax),
DateMin = data.Min(d => d.DateMin),
DateMax = data.Max(d => d.DateMax),
};
var intervalDeltaDepth = result.WellDepthMax - result.WellDepthMin;
foreach (var item in data)
{
var itemWeight = (item.WellDepthMax - item.WellDepthMin) / intervalDeltaDepth;
result.Pressure += item.Pressure * itemWeight;
result.PressureSp += item.PressureSp * itemWeight;
result.PressureSpRotor += item.PressureSpSlide * itemWeight;
result.PressureIdle += item.PressureIdle * itemWeight;
result.AxialLoad += item.AxialLoad * itemWeight;
result.AxialLoadSp += item.AxialLoadSp * itemWeight;
result.AxialLoadLimitMax += item.AxialLoadLimitMax * itemWeight;
result.RotorTorque += item.RotorTorque * itemWeight;
result.RotorTorqueSp += item.RotorTorqueSp * itemWeight;
result.RotorTorqueLimitMax += item.RotorTorqueLimitMax * itemWeight;
result.BlockSpeed += item.BlockSpeed * itemWeight;
result.BlockSpeedSp += item.BlockSpeedSp * itemWeight;
result.BlockSpeedSpRotor += item.BlockSpeedSpRotor * itemWeight;
result.BlockSpeedSpSlide += item.BlockSpeedSpSlide * itemWeight;
}
return result;
}
private static ProcessMapReportRowDto CalcDrillModeStat(
(double min, double max) depthInterval,
IEnumerable<WellOperationDto> intervalModeOperations,
2023-01-10 12:31:01 +05:00
IEnumerable<ProcessMapDto> intervalProcessMap,
ProcessTelemetrySaubStat? telemetryDataStat)
{
var dto = new ProcessMapReportRowDto();
2023-01-10 12:31:01 +05:00
if (intervalModeOperations.Any())
2022-12-27 14:30:52 +05:00
{
var deltaDepth = CalcDeltaDepth(depthInterval, intervalModeOperations);
dto.DeltaDepth = deltaDepth;
dto.Rop = deltaDepth / CalcHours(depthInterval, intervalModeOperations);
2023-01-10 12:31:01 +05:00
var processMapFirst = intervalProcessMap.First();
2022-12-27 14:30:52 +05:00
2023-01-10 12:31:01 +05:00
dto.PressureDiff.SetpointPlan = processMapFirst.Pressure.Plan;
dto.AxialLoad.SetpointPlan = processMapFirst.AxialLoad.Plan;
dto.TopDriveTorque.SetpointPlan = processMapFirst.TopDriveTorque.Plan;
dto.SpeedLimit.SetpointPlan = double.NaN;
};
2022-12-27 14:30:52 +05:00
2023-01-10 12:31:01 +05:00
if (telemetryDataStat is not null)
{
2023-01-10 12:31:01 +05:00
dto.PressureDiff.SetpointFact = telemetryDataStat.PressureSp;
dto.PressureDiff.Fact = telemetryDataStat.Pressure;
dto.PressureDiff.Limit = telemetryDataStat.PressureDeltaLimitMax;
dto.AxialLoad.SetpointFact = telemetryDataStat.AxialLoadSp;
dto.AxialLoad.Fact = telemetryDataStat.AxialLoad;
dto.AxialLoad.Limit = telemetryDataStat.AxialLoadLimitMax;
dto.TopDriveTorque.SetpointFact = telemetryDataStat.RotorTorqueSp;
dto.TopDriveTorque.Fact = telemetryDataStat.RotorTorque;
dto.TopDriveTorque.Limit = telemetryDataStat.RotorTorqueLimitMax;
}
2023-01-10 12:31:01 +05:00
return dto;
}
2022-12-27 14:30:52 +05:00
private static double CalcDeltaDepth((double min, double max) depthInterval, IEnumerable<WellOperationDto> intervalOperations)
{
var ddepth = 0d;
foreach (var operation in intervalOperations)
2022-12-27 14:30:52 +05:00
{
var depthStart = operation.DepthStart > depthInterval.min
? operation.DepthStart
: depthInterval.min;
2022-12-27 14:30:52 +05:00
var depthEnd = operation.DepthEnd < depthInterval.max
? operation.DepthEnd
: depthInterval.max;
ddepth += (depthEnd - depthEnd);
2022-12-27 14:30:52 +05:00
}
return ddepth;
}
2022-12-27 14:30:52 +05:00
private static double CalcHours((double min, double max) depthInterval, IEnumerable<WellOperationDto> intervalOperations)
{
var hours = 0d;
foreach (var operation in intervalOperations)
{
var dateStart = operation.DepthStart > depthInterval.min
? operation.DateStart
: GetInterpolatedDate(operation, depthInterval.min);
var dateEnd = operation.DepthEnd < depthInterval.max
? operation.DateStart + TimeSpan.FromHours(operation.DurationHours)
: GetInterpolatedDate(operation, depthInterval.max);
hours += (dateEnd - dateStart).TotalHours;
}
return hours;
2022-12-27 14:30:52 +05:00
}
private static DateTime GetInterpolatedDate(WellOperationDto operation, double depth)
2022-12-27 14:30:52 +05:00
{
if (operation.DepthStart > depth)
throw new ArgumentOutOfRangeException(nameof(depth));
var ratio = (depth - operation.DepthStart) / (operation.DepthEnd - operation.DepthStart);
var deltaHours = operation.DurationHours * ratio;
var interpolatedDate = operation.DateStart + TimeSpan.FromHours(deltaHours);
return interpolatedDate;
2022-12-27 14:30:52 +05:00
}
private static IEnumerable<(double min, double max)> SplitByIntervals(double min, double max)
2022-12-27 14:30:52 +05:00
{
const double step = 100;
var iMin = min;
var iMax = (1 + (int)(min / step)) * step;
for (; iMax < max; iMax += step)
{
yield return (iMin, iMax);
iMin = iMax;
}
yield return (iMin, max);
2022-12-27 14:30:52 +05:00
}
}
#nullable disable
}