using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.DetectOperations.Detectors; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Background.PeriodicWorks { internal class WorkProcessMapDrillingCache : Work { private int MechanicalDrillingCategoryId = 4001; public WorkProcessMapDrillingCache() : base("Generate process map drilling cache table") { Timeout = TimeSpan.FromMinutes(10); } protected override Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) { //1 найти последнюю запись в кеш-таблице (по полям "Дата до") //2 определяем дату с которой начинаем анализ //3 находим автоопределнные операции по скважине, начиная с начальной даты из пункта 2 // 3.1 только те, которые связанные с бурением (idParent = 4001) // 3.2 выбираем 500 операций // 3.3. выбираем минимальную дату начала и максимальную дату окончания //4 по полученным в пункте выше данным выбираем записи из telemetry_data_saub // 4.1.выбираем те у которых (bit_depth == well_depth) //5. для каждой операции из 3.2 находим соответствующий ей кусок телеметрии (по дате начала и окончания) // и храним индексы этого куска в виде span //6. кусок телеметрии, полученный в пункте 5 (span) и соответствующая ей операция направляется на разбивку диапазонов //7/ разбивка диапазонов: // параметры метода: массив из using var db = services.GetRequiredService(); var dateFrom = db.ProcessMapDrillingCache .OrderByDescending(c => c.DateTo) .FirstOrDefault()?.DateTo ?? DateTimeOffset.MinValue; //а остальные операции, которые не вошли в 500 первых? var detectedOperations = db.DetectedOperations .Where(o => o.DateStart > dateFrom) .Where(o => o.OperationCategory.IdParent == MechanicalDrillingCategoryId) .OrderBy(o => o.DateStart) .Take(500) .ToArray(); var minDate = detectedOperations.FirstOrDefault()?.DateStart; var maxDate = detectedOperations.OrderByDescending(d =>d.DateEnd).FirstOrDefault()?.DateEnd; var telemetryDataSaub = db.TelemetryDataSaub .Where(t => t.DateTime >= minDate) .Where(t => t.DateTime <= maxDate) .Where(t => Math.Abs(t.BitDepth - t.WellDepth) < 0.0001) .OrderBy(t => t.DateTime) .ToArray(); var indexStart = 0; var indexEnd = 0; 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 result = CalcStats(operation, subset); } } return Task.CompletedTask; } private object CalcStats(DetectedOperation operation, Span telemetryDataSaub) { 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) { var length = i - indexStart; var span = telemetryDataSaub.Slice(indexStart, length); indexStart = i; var processMapDrillingCacheItem = CalcStat(operation, span); } } return null; } private ProcessMapDrillingCache CalcStat(DetectedOperation operation, Span span) { var depthStart = span[0].WellDepth; var depthEnd = span[^1].WellDepth; var hasOscillation = false; if (operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out object? HasOscillation)) hasOscillation = Convert.ToBoolean(HasOscillation); var processMapDrillingCacheItem = new ProcessMapDrillingCache { DateDrillingStart = operation.DateStart, DateDrillingEnd = operation.DateEnd, DepthStart = depthStart, DepthEnd = depthEnd, Speed = (depthEnd - depthStart) / ((operation.DateEnd - operation.DateStart).TotalHours), BlockSpeedSp = span[0].BlockSpeedSp, Pressure = CalcValue(span, depthEnd - depthStart).Pressure, PressureIdle = span[0].PressureIdle, PressureSp = span[0].PressureSp, AxialLoad = CalcValue(span, depthEnd - depthStart).AxialLoad, AxialLoadSp = span[0].AxialLoadSp, AxialLoadLimitMax = span[0].AxialLoadLimitMax, RotorTorque = CalcValue(span, depthEnd - depthStart).RotorTorque, RotorTorqueSp = span[0].RotorTorqueSp, RotorTorqueLimitMax = span[0].RotorTorqueLimitMax, //Значение столбца id_feed_regulator из таблицы “Фильтрованная телеметрия” //в границах временного интервала (диапазоне). IdFeedRegulator = span[0].IdFeedRegulator, RotorSpeed = CalcValue(span, depthEnd - depthStart).RotorSpeed, //? DetectedOperationCategoryId = operation.IdCategory, EnabledSubsystems = operation.EnabledSubsystems, HasOscillation = hasOscillation }; return processMapDrillingCacheItem; } private ( double Pressure, double AxialLoad, double RotorTorque, double RotorSpeed ) CalcValue(Span span) { var sumPressure = 0.0; var sumAxialLoad = 0.0; var sumRotorTorque = 0.0; var sumRotorSpeed = 0.0; var diffDepthTotal = span[^1].WellDepth - span[0].WellDepth; for (var i = 0; i < span.Length - 1; i++) { var weigth = span[i + 1].WellDepth - span[i].WellDepth; sumPressure += () * span[i].Pressure; sumAxialLoad += (span[i + 1].WellDepth - span[i].WellDepth) * span[i].AxialLoad; sumRotorTorque += (span[i + 1].WellDepth - span[i].WellDepth) * span[i].RotorTorque; sumRotorSpeed += (span[i + 1].WellDepth - span[i].WellDepth) * span[i].RotorSpeed; } return ( Pressure: sumPressure / diffDepthTotal, AxialLoad: sumAxialLoad / diffDepthTotal, RotorTorque: sumRotorTorque / diffDepthTotal, RotorSpeed: sumRotorSpeed / diffDepthTotal ); } private 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); } } }