using AsbCloudApp.Data.SAUB; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.DetectOperations.Detectors; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Background.PeriodicWorks { /// /// задача по добавлению данных в таблицу DataSaubStat, которая используется дл построения РТК-отчета /// internal class WorkDataSaubStat : Work { private int MechanicalDrillingCategoryId = 4001; private int Gap = 60; public WorkDataSaubStat() : base("Generate DataSaubStat entries and save them into Db") { Timeout = TimeSpan.FromMinutes(10); } protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) { using var db = services.GetRequiredService(); var telemetryDataCache = services.GetRequiredService>(); var cacheRequest = new TelemetryDataRequest() { GeDate = DateTime.UtcNow.AddDays(-Gap) }; var idTelemetries = telemetryDataCache.GetIds(cacheRequest); if (!idTelemetries.Any()) return; var statsQuery = await db.Set() .Where(s => idTelemetries.Contains(s.IdTelemetry)) .ToArrayAsync(token); var stats = statsQuery .GroupBy(s => s.IdTelemetry) .ToDictionary( g => g.Key, g => g.OrderByDescending(s => s.DateEnd).First() ); foreach ( var idTelemetry in idTelemetries) { var lastDate = stats.GetValueOrDefault(idTelemetry)?.DateEnd ?? DateTimeOffset.UnixEpoch; await CreateStatForTelemetryFromDate(db, idTelemetry, lastDate, token); } } private async Task CreateStatForTelemetryFromDate(IAsbCloudDbContext db, int idTelemetry, DateTimeOffset begin, CancellationToken token) { var detectedOperations = await db.Set() .Where(o => o.IdTelemetry == idTelemetry) .Where(o => o.DateStart > begin) .Where(o => o.OperationCategory.IdParent == MechanicalDrillingCategoryId) .OrderBy(o => o.DateStart) .Take(500) .ToArrayAsync(token); if (!detectedOperations.Any()) return; var minDate = detectedOperations.First().DateStart; var maxDate = detectedOperations.OrderByDescending(d => d.DateEnd).First().DateEnd; var telemetryDataSaub = await db.Set() .Where(t => t.IdTelemetry == idTelemetry) .Where(t => t.DateTime >= minDate) .Where(t => t.DateTime <= maxDate) .Where(t => Math.Abs(t.BitDepth - t.WellDepth) < 0.0001) .ToArrayAsync(token); if (!telemetryDataSaub.Any()) return; var dataSaubStats = CreateDataSaubStat(detectedOperations, telemetryDataSaub); db.Set().AddRange(dataSaubStats); await db.SaveChangesAsync(token); } private static IEnumerable CreateDataSaubStat(IEnumerable detectedOperations, TelemetryDataSaub[] telemetryDataSaub) { var indexStart = 0; var indexEnd = 0; var result = new List(); foreach (var operation in detectedOperations) { indexStart = Array.FindIndex(telemetryDataSaub, indexEnd, t => t.DateTime >= operation.DateStart); indexEnd = Array.FindIndex(telemetryDataSaub, indexStart, t => t.DateTime > operation.DateEnd) - 1; if (indexStart >= 0 && indexEnd >= indexStart) { var length = indexEnd - indexStart; var subset = telemetryDataSaub.AsSpan(indexStart, length + 1); var stats = CalcStats(operation, subset); result.AddRange(stats); } else { indexStart = 0; indexEnd = 0; } } return result; } private static IEnumerable CalcStats(DetectedOperation operation, Span telemetryDataSaub) { var result = new List(); var indexStart = 0; for (var i = 1; i < telemetryDataSaub.Length; i++) { var previous = telemetryDataSaub[i - 1]; var current = telemetryDataSaub[i]; if (IsNewCacheItem(previous, current) || i == telemetryDataSaub.Length - 1) { var length = i - indexStart; var span = telemetryDataSaub.Slice(indexStart, length); indexStart = i; var stat = CalcStat(operation, span); result.Add(stat); } } return result; } private static DataSaubStat CalcStat(DetectedOperation operation, Span span) { var hasOscillation = operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out object? hasOscillationObject) && hasOscillationObject is true; var aggregatedValues = CalcAggregate(span); var processMapDrillingCacheItem = new DataSaubStat { DateStart = operation.DateStart, DateEnd = operation.DateEnd, DepthStart = operation.DepthStart, DepthEnd = operation.DepthEnd, Speed = (operation.DepthEnd - operation.DepthStart) / ((operation.DateEnd - operation.DateStart).TotalHours), BlockSpeedSp = span[0].BlockSpeedSp, Pressure = aggregatedValues.Pressure, PressureIdle = span[0].PressureIdle, PressureSp = span[0].PressureSp, AxialLoad = aggregatedValues.AxialLoad, AxialLoadSp = span[0].AxialLoadSp, AxialLoadLimitMax = span[0].AxialLoadLimitMax, RotorTorque = aggregatedValues.RotorTorque, RotorTorqueSp = span[0].RotorTorqueSp, RotorTorqueLimitMax = span[0].RotorTorqueLimitMax, IdFeedRegulator = span[0].IdFeedRegulator, RotorSpeed = aggregatedValues.RotorSpeed, IdCategory = operation.IdCategory, EnabledSubsystems = operation.EnabledSubsystems, HasOscillation = hasOscillation, IdTelemetry = operation.IdTelemetry, Flow = aggregatedValues.Flow }; return processMapDrillingCacheItem; } private static ( double Pressure, double AxialLoad, double RotorTorque, double RotorSpeed, double Flow ) CalcAggregate(Span span) { var sumPressure = 0.0; var sumAxialLoad = 0.0; var sumRotorTorque = 0.0; var sumRotorSpeed = 0.0; var flow = span[0].Flow ?? 0.0; var diffDepthTotal = span[^1].WellDepth - span[0].WellDepth; for (var i = 0; i < span.Length - 1; i++) { var diffDepth = span[i + 1].WellDepth - span[i].WellDepth; sumPressure += diffDepth * span[i].Pressure; sumAxialLoad += diffDepth * span[i].AxialLoad; sumRotorTorque += diffDepth * span[i].RotorTorque; sumRotorSpeed += diffDepth * span[i].RotorSpeed; flow = span[i + 1].Flow > flow ? span[i + 1].Flow ?? 0.0 : flow; } return ( Pressure: sumPressure / diffDepthTotal, AxialLoad: sumAxialLoad / diffDepthTotal, RotorTorque: sumRotorTorque / diffDepthTotal, RotorSpeed: sumRotorSpeed / diffDepthTotal, Flow: flow ); } private static bool IsNewCacheItem(TelemetryDataSaub previous, TelemetryDataSaub current) { return !(current.Mode == previous.Mode) || !(current.BlockSpeedSp == previous.BlockSpeedSp) || !(current.PressureIdle == previous.PressureIdle) || !(current.PressureSp == previous.PressureSp) || !(current.AxialLoadSp == previous.AxialLoadSp) || !(current.AxialLoadLimitMax == previous.AxialLoadLimitMax) || !(current.HookWeightIdle == previous.HookWeightIdle) || !(current.RotorTorqueIdle == previous.RotorTorqueIdle) || !(current.RotorTorqueSp == previous.RotorTorqueSp) || !(current.RotorTorqueLimitMax == previous.RotorTorqueLimitMax) || !(current.IdFeedRegulator == previous.IdFeedRegulator); } } }