forked from ddrilling/AsbCloudServer
231 lines
9.2 KiB
C#
231 lines
9.2 KiB
C#
using AsbCloudApp.Data;
|
|
using AsbCloudApp.Data.SAUB;
|
|
using AsbCloudApp.Repositories;
|
|
using AsbCloudApp.Requests;
|
|
using AsbCloudApp.Services;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AsbCloudInfrastructure.Services;
|
|
|
|
|
|
public class DataSaubStatDrillingQualityService : IDataSaubStatDrillingQualityService
|
|
{
|
|
private IDataSaubStatRepository<DataSaubStatDrillingQualityDto> dataSaubStatDrillingQualityRepository;
|
|
private ITelemetryDataSaubService dataSaubService;
|
|
private ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
|
|
private ITelemetryService telemetryService;
|
|
|
|
private static int IdFeedRegulatorRop = 1;
|
|
private static int IdFeedRegulatorPressureDelta = 2;
|
|
private static int IdFeedRegulatorAxialLoad = 3;
|
|
private static int IdFeedRegulatorTorque = 4;
|
|
|
|
public Dictionary<int, Predicate<TelemetryDataSaubDto>> QualitySettingsForFeedRegulators { get; }
|
|
|
|
public DataSaubStatDrillingQualityService(
|
|
IDataSaubStatRepository<DataSaubStatDrillingQualityDto> dataSaubStatDrillingQualityRepository,
|
|
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache,
|
|
ITelemetryDataSaubService dataSaubService,
|
|
ITelemetryService telemetryService)
|
|
{
|
|
this.dataSaubStatDrillingQualityRepository = dataSaubStatDrillingQualityRepository;
|
|
this.dataSaubService = dataSaubService;
|
|
this.telemetryDataCache = telemetryDataCache;
|
|
this.telemetryService = telemetryService;
|
|
|
|
Predicate<TelemetryDataSaubDto> hasQualityWithIdFeedRegulator1 = (TelemetryDataSaubDto spanItem)
|
|
=> (spanItem.BlockSpeed >= spanItem.BlockSpeedSp * 0.95
|
|
&& spanItem.BlockSpeed <= spanItem.BlockSpeedSp * 1.05);
|
|
|
|
Predicate<TelemetryDataSaubDto> hasQualityWithIdFeedRegulator2 = (TelemetryDataSaubDto spanItem)
|
|
=> (spanItem.Pressure >= (spanItem.PressureSp) - 5
|
|
&& spanItem.Pressure <= (spanItem.PressureSp) + 5);
|
|
|
|
Predicate<TelemetryDataSaubDto> hasQualityWithIdFeedRegulator3 = (TelemetryDataSaubDto spanItem)
|
|
=> (spanItem.AxialLoad >= (spanItem.AxialLoadSp - 0.5)
|
|
&& spanItem.AxialLoad <= (spanItem.AxialLoadSp + 0.5));
|
|
|
|
Predicate<TelemetryDataSaubDto> hasQualityWithIdFeedRegulator4 = (TelemetryDataSaubDto spanItem)
|
|
=> (spanItem.RotorTorque >= (spanItem.RotorTorqueSp - 0.5)
|
|
&& spanItem.RotorTorque <= (spanItem.RotorTorqueSp + 0.5));
|
|
|
|
QualitySettingsForFeedRegulators = new Dictionary<int, Predicate<TelemetryDataSaubDto>>() {
|
|
{ IdFeedRegulatorRop, hasQualityWithIdFeedRegulator1 },
|
|
{ IdFeedRegulatorPressureDelta, hasQualityWithIdFeedRegulator2 },
|
|
{ IdFeedRegulatorAxialLoad, hasQualityWithIdFeedRegulator3 },
|
|
{ IdFeedRegulatorTorque, hasQualityWithIdFeedRegulator4 },
|
|
};
|
|
}
|
|
|
|
public async Task CreateStatAsync(int lastDaysFilter, Action<string, double?> onProgressCallback, CancellationToken token)
|
|
{
|
|
var cacheRequest = new TelemetryDataRequest()
|
|
{
|
|
GeDate = DateTime.UtcNow.AddDays(-lastDaysFilter)
|
|
};
|
|
var idTelemetries = telemetryDataCache.GetIds(cacheRequest).ToArray();
|
|
|
|
if (!idTelemetries.Any())
|
|
return;
|
|
|
|
var stats = await dataSaubStatDrillingQualityRepository.GetLastsAsync(idTelemetries, token);
|
|
|
|
for (var i = 0; i < idTelemetries.Length; i++)
|
|
{
|
|
var idTelemetry = idTelemetries[i];
|
|
var lastDate = stats.FirstOrDefault(s => s.IdTelemetry == idTelemetry)?.DateEnd.ToUniversalTime() ?? DateTimeOffset.UnixEpoch;
|
|
var result = await CreateStatDrillingQualityForTelemetry(idTelemetry, lastDate, token);
|
|
|
|
var statsCount = result.Count();
|
|
if (result.Any())
|
|
statsCount = await dataSaubStatDrillingQualityRepository.InsertRangeAsync(result, token);
|
|
|
|
if (onProgressCallback != null)
|
|
onProgressCallback($"Calculate stat for telemetry: {idTelemetry}; from {lastDate}; results count: {statsCount};", 1d * i / idTelemetries.Length);
|
|
}
|
|
}
|
|
|
|
public async Task<IEnumerable<DataSaubStatDrillingQualityDto>> CreateStatDrillingQualityForTelemetry(
|
|
int idTelemetry,
|
|
DateTimeOffset geDate,
|
|
CancellationToken token)
|
|
{
|
|
var leDate = DateTimeOffset.UtcNow;
|
|
var result = new List<DataSaubStatDrillingQualityDto>();
|
|
|
|
var dataSaub = await dataSaubService.Get(idTelemetry, true, geDate, leDate, 100_000, token);
|
|
|
|
if (!dataSaub.Any())
|
|
return result;
|
|
|
|
if (dataSaub is not TelemetryDataSaubDto[] dataSaubArray)
|
|
dataSaubArray = dataSaub.ToArray();
|
|
|
|
foreach (var item in QualitySettingsForFeedRegulators)
|
|
{
|
|
var data = CreateDataSaubStatDrillingQuality(item.Key, item.Value, dataSaubArray);
|
|
result.AddRange(data);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static IEnumerable<DataSaubStatDrillingQualityDto> CreateDataSaubStatDrillingQuality(
|
|
int idFeedRegulator,
|
|
Predicate<TelemetryDataSaubDto> checkQuality,
|
|
TelemetryDataSaubDto[] dataSaub)
|
|
{
|
|
var result = new List<DataSaubStatDrillingQualityDto>();
|
|
|
|
var indexStart = 0;
|
|
var indexEnd = 0;
|
|
|
|
while (indexEnd < dataSaub.Count() - 1)
|
|
{
|
|
indexStart = Array.FindIndex(dataSaub, indexEnd, t => t.IdFeedRegulator == idFeedRegulator);
|
|
if (indexStart < 0)
|
|
break;
|
|
|
|
indexEnd = FindIndexEnd(indexStart, idFeedRegulator, dataSaub);
|
|
|
|
var length = indexEnd - indexStart + 1;
|
|
var subset = dataSaub.AsSpan(indexStart, length);
|
|
|
|
if ((subset[^1].WellDepth - subset[0].WellDepth) < 0.15)
|
|
continue; // мелкие выборки не учитываем.
|
|
|
|
var stats = CalcStatsDrillingQuality(idFeedRegulator, subset, checkQuality);
|
|
result.Add(stats);
|
|
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static int FindIndexEnd(int indexStart, int idFeedRegulator, TelemetryDataSaubDto[] dataSaub)
|
|
{
|
|
var indexEnd = indexStart + 1;
|
|
for (var i = indexStart + 1; i < dataSaub.Count(); i++)
|
|
{
|
|
if (dataSaub[i].WellDepth >= dataSaub[i - 1].WellDepth)
|
|
{
|
|
indexEnd = i;
|
|
}
|
|
if (dataSaub[i].IdFeedRegulator != idFeedRegulator)
|
|
break;
|
|
}
|
|
return indexEnd;
|
|
}
|
|
|
|
private static DataSaubStatDrillingQualityDto CalcStatsDrillingQuality(
|
|
int idFeedRegulator,
|
|
Span<TelemetryDataSaubDto> dataSaub,
|
|
Predicate<TelemetryDataSaubDto> predicate
|
|
)
|
|
{
|
|
var result = new DataSaubStatDrillingQualityDto();
|
|
result.IdTelemetry = dataSaub[0].IdTelemetry;
|
|
result.IdFeedRegulator = idFeedRegulator;
|
|
result.DepthStart = dataSaub[0].WellDepth;
|
|
result.DepthEnd = dataSaub[^1].WellDepth;
|
|
result.DateStart = dataSaub[0].DateTime;
|
|
result.DateEnd = dataSaub[^1].DateTime;
|
|
|
|
var depthDrillingQuality = 0.0;
|
|
for (var i = 0; i < dataSaub.Length - 1; i++)
|
|
{
|
|
if (predicate(dataSaub[i]))
|
|
{
|
|
depthDrillingQuality += dataSaub[i + 1].WellDepth - dataSaub[i].WellDepth;
|
|
}
|
|
}
|
|
result.DepthDrillingQuality = depthDrillingQuality;
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<IEnumerable<DrillingQualityDto>> GetStatAsync(DrillingQualityRequest request, CancellationToken token)
|
|
{
|
|
var telemetries = telemetryService.GetOrDefaultTelemetriesByIdsWells(request.IdsWell);
|
|
var idsTelemetriesWithIdWell = telemetries
|
|
.Where(t => t.IdWell.HasValue)
|
|
.ToDictionary(t => t.Id, t => t.IdWell!.Value);
|
|
|
|
var dataSaubStatDrillingQuality = await dataSaubStatDrillingQualityRepository.GetAsync(idsTelemetriesWithIdWell.Keys, request.GeDate, request.LeDate, token);
|
|
|
|
var dtosGroupedByIdTelemetries = dataSaubStatDrillingQuality
|
|
.GroupBy(s => new { s.IdTelemetry, s.IdFeedRegulator })
|
|
.Select(stat => new
|
|
{
|
|
IdFeedRegulator = stat.Key.IdFeedRegulator,
|
|
IdTelemetry = stat.Key.IdTelemetry,
|
|
Kpd = (stat.Sum(s => s.DepthDrillingQuality) / stat.Sum(s => s.DepthEnd - s.DepthStart)) * 100,
|
|
})
|
|
.GroupBy(stat => stat.IdTelemetry);
|
|
|
|
var result = new List<DrillingQualityDto>();
|
|
foreach (var dtos in dtosGroupedByIdTelemetries)
|
|
{
|
|
var kpdValuesByIdFeedRegulator = dtos
|
|
.GroupBy(d => d.IdFeedRegulator)
|
|
.ToDictionary(d => d.Key, d => d.FirstOrDefault()!.Kpd);
|
|
|
|
var item = new DrillingQualityDto()
|
|
{
|
|
IdWell = idsTelemetriesWithIdWell[dtos.Key],
|
|
KpdAxialLoad = kpdValuesByIdFeedRegulator.GetValueOrDefault(IdFeedRegulatorAxialLoad),
|
|
KpdPressureDelta = kpdValuesByIdFeedRegulator.GetValueOrDefault(IdFeedRegulatorPressureDelta),
|
|
KpdRop = kpdValuesByIdFeedRegulator.GetValueOrDefault(IdFeedRegulatorRop),
|
|
KpdTorque = kpdValuesByIdFeedRegulator.GetValueOrDefault(IdFeedRegulatorTorque)
|
|
};
|
|
|
|
result.Add(item);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|