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 dataSaubStatDrillingQualityRepository; private ITelemetryDataSaubService dataSaubService; private ITelemetryDataCache telemetryDataCache; public Dictionary> QualitySettingsForFeedRegulators { get; } public DataSaubStatDrillingQualityService( IDataSaubStatRepository dataSaubStatDrillingQualityRepository, ITelemetryDataCache telemetryDataCache, ITelemetryDataSaubService dataSaubService) { this.dataSaubStatDrillingQualityRepository = dataSaubStatDrillingQualityRepository; this.dataSaubService = dataSaubService; this.telemetryDataCache = telemetryDataCache; Predicate hasQualityWithIdFeedRegulator1 = (TelemetryDataSaubDto spanItem) => (spanItem.BlockSpeed >= spanItem.BlockSpeedSp * 0.95 && spanItem.BlockSpeed <= spanItem.BlockSpeedSp * 1.05); Predicate hasQualityWithIdFeedRegulator2 = (TelemetryDataSaubDto spanItem) => (spanItem.Pressure >= (spanItem.PressureSp - spanItem.PressureIdle) - 5 && spanItem.Pressure <= (spanItem.PressureSp - spanItem.PressureIdle) + 5); Predicate hasQualityWithIdFeedRegulator3 = (TelemetryDataSaubDto spanItem) => (spanItem.AxialLoad >= (spanItem.AxialLoadSp - 0.5) && spanItem.AxialLoad <= (spanItem.AxialLoadSp + 0.5)); Predicate hasQualityWithIdFeedRegulator4 = (TelemetryDataSaubDto spanItem) => (spanItem.RotorTorque >= (spanItem.RotorTorqueSp - 0.5) && spanItem.RotorTorque <= (spanItem.RotorTorqueSp + 0.5)); QualitySettingsForFeedRegulators = new Dictionary>() { { 1, hasQualityWithIdFeedRegulator1 }, { 2, hasQualityWithIdFeedRegulator2 }, { 3, hasQualityWithIdFeedRegulator3 }, { 4, hasQualityWithIdFeedRegulator4 }, }; } public async Task CreateStatAsync(int lastDaysFilter, Action 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 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(); 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 CreateDataSaubStatDrillingQuality( int idFeedRegulator, Predicate checkQuality, TelemetryDataSaubDto[] dataSaub) { var result = new List(); 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 = indexStart + 1; for (var i = indexStart + 1; i < dataSaub.Count(); i++) { if (dataSaub[i].WellDepth >= dataSaub[i - 1].WellDepth) indexEnd = i; else if (dataSaub[i].IdFeedRegulator != idFeedRegulator) break; else break; } 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 dataSaub, Predicate 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; } }