DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/DataSaubStatDrillingQualityService.cs

173 lines
6.6 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 : IDataSaubStatService
{
private IDataSaubStatRepository<DataSaubStatDrillingQualityDto> dataSaubStatDrillingQualityRepository;
private ITelemetryDataSaubService dataSaubService;
private ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
public Dictionary<int, Predicate<TelemetryDataSaubDto>> QualitySettingsForFeedRegulators { get; }
public DataSaubStatDrillingQualityService(
IDataSaubStatRepository<DataSaubStatDrillingQualityDto> dataSaubStatDrillingQualityRepository,
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache,
ITelemetryDataSaubService dataSaubService)
{
this.dataSaubStatDrillingQualityRepository = dataSaubStatDrillingQualityRepository;
this.dataSaubService = dataSaubService;
this.telemetryDataCache = telemetryDataCache;
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 - spanItem.PressureIdle) - 5
&& spanItem.Pressure <= (spanItem.PressureSp - spanItem.PressureIdle) + 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>>() {
{ 1, hasQualityWithIdFeedRegulator1 },
{ 2, hasQualityWithIdFeedRegulator2 },
{ 3, hasQualityWithIdFeedRegulator3 },
{ 4, 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 statsCount = await CreateStatDrillingQualityForTelemetry(idTelemetry, lastDate, token);
if (onProgressCallback != null)
onProgressCallback($"Calculate stat for telemetry: {idTelemetry}; from {lastDate}; results count: {statsCount};", 1d * i / idTelemetries.Length);
}
}
private async Task<int> CreateStatDrillingQualityForTelemetry(
int idTelemetry,
DateTimeOffset geDate,
CancellationToken token)
{
var leDate = DateTimeOffset.UtcNow;
var dataSaub = await dataSaubService.Get(idTelemetry, true, geDate, leDate, 100_000, token);
if (!dataSaub.Any())
return 0;
if (dataSaub is not TelemetryDataSaubDto[] dataSaubArray)
dataSaubArray = dataSaub.ToArray();
var result = new List<DataSaubStatDrillingQualityDto>();
foreach (var item in QualitySettingsForFeedRegulators)
{
var data = CreateDataSaubStatDrillingQuality(item.Key, item.Value, dataSaubArray);
result.AddRange(data);
}
if (result.Any())
return await dataSaubStatDrillingQualityRepository.InsertRangeAsync(result, token);
return 0;
}
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 = Array.FindIndex(dataSaub, indexStart, t => t.IdFeedRegulator != idFeedRegulator);
if (indexEnd < 0)
indexEnd = dataSaub.Length - 1;
if (indexEnd == indexStart)
continue;
var length = indexEnd - indexStart + 1;
var subset = dataSaub.AsSpan(indexStart, length);
if (length <= 2 || (subset[^1].WellDepth - subset[0].WellDepth) < 0.15)
continue; // мелкие выборки не учитываем.
var stats = CalcStatsDrillingQuality(idFeedRegulator, subset, checkQuality);
result.Add(stats);
}
return result;
}
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;
}
}