diff --git a/AsbCloudApp/Data/DataSaubStatDto.cs b/AsbCloudApp/Data/DataSaubStatDto.cs deleted file mode 100644 index 3bb46d6d..00000000 --- a/AsbCloudApp/Data/DataSaubStatDto.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using AsbCloudApp.Data.WellOperation; - -namespace AsbCloudApp.Data; - -/// -/// dto для хранения данных статистики сауб -/// -public class DataSaubStatDto:IId -{ - /// - /// - /// - public int Id { get; set; } - - /// - /// Дата и время начала - /// - public DateTimeOffset DateStart { get; set; } - - /// - /// Дата и время окончания - /// - public DateTimeOffset DateEnd { get; set; } - - /// - /// Глубина забоя по стволу начальная - /// - public double DepthStart { get; set; } - - /// - /// Глубина забоя по стволу конечная - /// - public double DepthEnd { get; set; } - - /// - /// Скорость бурения - /// - public double Speed { get; set; } - - /// - /// Ограничение скорости блока - /// - public double? BlockSpeedSp { get; set; } - - /// - /// Давление - /// - public double Pressure { get; set; } - - /// - /// Давление холостого хода - /// - public double? PressureIdle { get; set; } - - /// - /// Ограничение фактического давления - /// - public double? PressureSp { get; set; } - - /// - /// Фактическая нагрузка - /// - public double AxialLoad { get; set; } - - /// - /// Ограничение факт. нагрузки - /// - public double? AxialLoadSp { get; set; } - - /// - /// Максимально допустимая нагрузка - /// - public double? AxialLoadLimitMax { get; set; } - - /// - /// Фактический момент - /// - public double RotorTorque { get; set; } - - /// - /// Ограничение факт. момента - /// - public double? RotorTorqueSp { get; set; } - - /// - /// Максимально допустимый момент - /// - public double? RotorTorqueLimitMax { get; set; } - - /// - /// Работа при достижении ограничения - /// - public short? IdFeedRegulator { get; set; } - - /// - /// Фактическая скорость оборотов ВСП - /// - public double RotorSpeed { get; set; } - - /// - /// Название автоопределённой операции - /// - public int IdCategory { get; set; } - - /// - /// Флаги подсистем - /// - public int EnabledSubsystems { get; set; } - - /// - /// Наличие или отсутствие осцилляции - /// - public bool HasOscillation { get; set; } - - /// - /// Фактический расход - /// - public double Flow { get; set; } - - /// - /// Ключ телеметрии - /// - public int IdTelemetry { get; set; } - - /// - /// Телеметрия - /// - public TelemetryDto Telemetry { get; set; } = null!; - - /// - /// Категория автоопределенной операции - /// - public WellOperationCategoryDto OperationCategory { get; set; } = null!; -} diff --git a/AsbCloudApp/Repositories/IDataSaubStatRepository.cs b/AsbCloudApp/Repositories/IDataSaubStatRepository.cs index d419ad82..628276bc 100644 --- a/AsbCloudApp/Repositories/IDataSaubStatRepository.cs +++ b/AsbCloudApp/Repositories/IDataSaubStatRepository.cs @@ -1,4 +1,4 @@ -using AsbCloudApp.Data; +using AsbCloudApp.Data.DataSaubStat; using AsbCloudApp.Services; using System; using System.Collections.Generic; diff --git a/AsbCloudApp/Services/ITelemetryDataSaubService.cs b/AsbCloudApp/Services/ITelemetryDataSaubService.cs index 4a23ee87..fc4bbda8 100644 --- a/AsbCloudApp/Services/ITelemetryDataSaubService.cs +++ b/AsbCloudApp/Services/ITelemetryDataSaubService.cs @@ -21,8 +21,9 @@ public interface ITelemetryDataSaubService : ITelemetryDataService /// /// + /// /// - Task> Get(IEnumerable idsTelemetries, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token); + Task> Get(IEnumerable idsTelemetries, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token, IEnumerable? idsFeedRegulators = null); /// /// усредненная статистика по 1м за весь период diff --git a/AsbCloudInfrastructure.Tests/Services/DataSaubStatServiceTest.cs b/AsbCloudInfrastructure.Tests/Services/DataSaubStatServiceTest.cs index 80783c73..1e507f6f 100644 --- a/AsbCloudInfrastructure.Tests/Services/DataSaubStatServiceTest.cs +++ b/AsbCloudInfrastructure.Tests/Services/DataSaubStatServiceTest.cs @@ -1,4 +1,4 @@ -using AsbCloudApp.Data; +using AsbCloudApp.Data.DataSaubStat; using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Data.SAUB; using AsbCloudApp.Repositories; diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 859cfba5..86e4df64 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -319,7 +319,8 @@ public static class DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); + //services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient< diff --git a/AsbCloudInfrastructure/Repository/DataSaubStatRepository.cs b/AsbCloudInfrastructure/Repository/DataSaubStatRepository.cs index d8932b28..cb986215 100644 --- a/AsbCloudInfrastructure/Repository/DataSaubStatRepository.cs +++ b/AsbCloudInfrastructure/Repository/DataSaubStatRepository.cs @@ -1,4 +1,4 @@ -using AsbCloudApp.Data; +using AsbCloudApp.Data.DataSaubStat; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; diff --git a/AsbCloudInfrastructure/Services/DataSaubStatDrillingQualityService.cs b/AsbCloudInfrastructure/Services/DataSaubStatDrillingQualityService.cs new file mode 100644 index 00000000..1726af5c --- /dev/null +++ b/AsbCloudInfrastructure/Services/DataSaubStatDrillingQualityService.cs @@ -0,0 +1,239 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.DataSaubStat; +using AsbCloudApp.Data.DetectedOperation; +using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudDb.Model; +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 dataSaubStatRepository; + private ITelemetryDataCache telemetryDataCache; + private ITelemetryDataSaubService dataSaubService; + private IDetectedOperationRepository detectedOperationRepository; + + public DataSaubStatDrillingQualityService( + IDataSaubStatRepository dataSaubStatRepository, + ITelemetryDataCache telemetryDataCache, + ITelemetryDataSaubService dataSaubService, + IDetectedOperationRepository detectedOperationRepository) + { + this.dataSaubStatRepository = dataSaubStatRepository; + this.telemetryDataCache = telemetryDataCache; + this.dataSaubService = dataSaubService; + this.detectedOperationRepository = detectedOperationRepository; + } + + public async Task CreateStatAsync(int lastDaysFilter, Action onProgressCallback, CancellationToken token) + { + //to do + var cacheRequest = new TelemetryDataRequest() + { + GeDate = DateTime.UtcNow.AddDays(-5000) + }; + var idTelemetries = telemetryDataCache.GetIds(cacheRequest).ToArray(); + + if (!idTelemetries.Any()) + return; + + var stats = new List(); + //await dataSaubStatRepository.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 CreateStatForTelemetryFromDate(idTelemetry, lastDate, token); + // if(onProgressCallback != null) + // onProgressCallback($"Calculate stat for telemetry: {idTelemetry}; from {lastDate}; results count: {statsCount};", 1d * i / idTelemetries.Length); + //} + } + + private async Task CreateStatForTelemetryFromDate( + 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 dataSaubStats = CreateDataSaubStat(dataSaubArray); + + return 0; + + //return await dataSaubStatRepository.InsertRangeAsync(dataSaubStats, token); + } + + private static IEnumerable CreateDataSaubStat2(int idFeedRegulator, TelemetryDataSaubDto[] dataSaub) + { + var result = new List(); + + var indexStart = 0; + var indexEnd = 0; + + while (indexEnd < dataSaub.Count()) + { + 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.001) + continue; // мелкие выборки не учитываем. + + var stats = CalcStats(subset); + result.Add(stats); + + } + return result; + } + + private static Dictionary> CreateDataSaubStat(TelemetryDataSaubDto[] dataSaub) + { + + var dict = new Dictionary>() { + { 1, new List() }, + { 2, new List() }, + { 3, new List() }, + { 4, new List() }, + }; + + foreach (var item in dict) + { + var data = CreateDataSaubStat2(item.Key, dataSaub); + item.Value.AddRange(data); + } + + return dict; + } + + private static DataSaubStatDrillingQualityDto CalcStats(Span dataSaub) + { + var depthDrillingQuality = CalcAggregate(dataSaub); + + var result = new DataSaubStatDrillingQualityDto(); + result.DepthStart = dataSaub[0].WellDepth; + result.DepthEnd = dataSaub[^1].WellDepth; + result.DateStart = dataSaub[0].DateTime; + result.DateEnd = dataSaub[^1].DateTime; + result.DepthDrillingQuality = depthDrillingQuality; + + return result; + } + + private static DataSaubStatDto CalcStat(DetectedOperationDto operation, Span span) + { + var aggregatedValues = CalcAggregate(span); + var dateStart = span[0].DateTime; + var dateEnd = span[^1].DateTime; + var depthStart = span[0].WellDepth; + var depthEnd = span[^1].WellDepth; + var speed = ((depthEnd - depthStart) / (dateEnd - dateStart).TotalHours); + + var processMapDrillingCacheItem = new DataSaubStatDto + { + DateStart = dateStart, + DateEnd = dateEnd, + DepthStart = depthStart, + DepthEnd = depthEnd, + Speed = speed, + 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 = operation.EnabledSubsystems.IsAutoOscillation, + 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(TelemetryDataSaubDto previous, TelemetryDataSaubDto current) + { + return !(current.Mode == previous.Mode) + || !(current.WellDepth >= previous.WellDepth) + || !(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); + } +} diff --git a/AsbCloudInfrastructure/Services/DataSaubStatService.cs b/AsbCloudInfrastructure/Services/DataSaubStatService.cs index 82ee0416..f1722ba5 100644 --- a/AsbCloudInfrastructure/Services/DataSaubStatService.cs +++ b/AsbCloudInfrastructure/Services/DataSaubStatService.cs @@ -1,4 +1,4 @@ -using AsbCloudApp.Data; +using AsbCloudApp.Data.DataSaubStat; using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Data.SAUB; using AsbCloudApp.Repositories; diff --git a/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDrillingService.cs b/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDrillingService.cs index cae5bdce..574a320e 100644 --- a/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDrillingService.cs +++ b/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDrillingService.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Data.DataSaubStat; using AsbCloudApp.Data.ProcessMaps; using AsbCloudApp.Data.ProcessMaps.Operations; using AsbCloudApp.Data.ProcessMaps.Report; diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index 0abd8fdf..c864eb7d 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -37,7 +37,14 @@ public class TelemetryDataSaubService : TelemetryDataBaseService> Get(IEnumerable idsTelemetries, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token) + public async Task> Get( + IEnumerable idsTelemetries, + bool isBitOnBottom, + DateTimeOffset geDate, + DateTimeOffset leDate, + int take, + CancellationToken token, + IEnumerable? idsFeedRegulators) { var offsetDict = new Dictionary(); foreach (var idTelemetry in idsTelemetries) @@ -56,6 +63,11 @@ public class TelemetryDataSaubService : TelemetryDataBaseService Math.Abs(t.BitDepth - t.WellDepth) < 0.0001); + if (idsFeedRegulators != null && idsFeedRegulators.Any()) + query = query + .Where(t => t.IdFeedRegulator.HasValue) + .Where(t => idsFeedRegulators.Contains(t.IdFeedRegulator!.Value)); + query = query .OrderBy(t => t.DateTime) .Take(take); diff --git a/AsbCloudWebApi.IntegrationTests/Repository/DataSaubStatRepositoryTest.cs b/AsbCloudWebApi.IntegrationTests/Repository/DataSaubStatRepositoryTest.cs index e69cc692..7919a445 100644 --- a/AsbCloudWebApi.IntegrationTests/Repository/DataSaubStatRepositoryTest.cs +++ b/AsbCloudWebApi.IntegrationTests/Repository/DataSaubStatRepositoryTest.cs @@ -1,4 +1,4 @@ -using AsbCloudApp.Data; +using AsbCloudApp.Data.DataSaubStat; using AsbCloudApp.Repositories; using AsbCloudDb.Model; using Mapster; diff --git a/AsbCloudWebApi/appsettings.json b/AsbCloudWebApi/appsettings.json index 72d50f57..ae879099 100644 --- a/AsbCloudWebApi/appsettings.json +++ b/AsbCloudWebApi/appsettings.json @@ -7,10 +7,10 @@ } }, "ConnectionStrings": { - "DefaultConnection": "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True", - "DebugConnection": "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True;Include Error Detail=True", - "TestConnection": "Host=localhost;Database=test;Username=postgres;Password=q;Persist Security Info=True;Include Error Detail=True", - "LocalConnection": "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True" + "DefaultConnection": "Host=192.168.0.10;Database=postgres;Username=postgres;Password=q;Persist Security Info=True", + "DebugConnection": "Host=192.168.0.10;Database=postgres;Username=postgres;Password=q;Persist Security Info=True;Include Error Detail=True", + "TestConnection": "Host=192.168.0.10;Database=test;Username=postgres;Password=q;Persist Security Info=True;Include Error Detail=True", + "LocalConnection": "Host=192.168.0.10;Database=postgres;Username=postgres;Password=q;Persist Security Info=True" }, "AllowedHosts": "*", "ContentPath": "../data", @@ -26,5 +26,5 @@ }, "DirectoryNameHelpPageFiles": "helpPages", "DirectoryManualFiles": "manuals", - "Urls": "http://0.0.0.0:5000" + "Urls": "http://0.0.0.0:5010" }