From d7e9c4f893b4e18ee88c11738f5e46fe4049b978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 24 Jul 2024 13:19:13 +0300 Subject: [PATCH 1/9] =?UTF-8?q?=D0=90=D0=B2=D1=82=D0=BE=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IDetectedOperationRepository.cs | 10 +- .../Services/IDetectedOperationService.cs | 8 +- .../Services/ITelemetryDataSaubService.cs | 8 ++ .../Repository/DetectedOperationRepository.cs | 36 ++++-- .../DetectedOperationService.cs | 114 +++++++++--------- .../Detectors/DetectorAbstract.cs | 2 + .../WorkOperationDetection.cs | 105 +++++++++++----- .../Services/SAUB/TelemetryDataBaseService.cs | 4 +- .../Services/SAUB/TelemetryDataSaubService.cs | 31 +++++ 9 files changed, 205 insertions(+), 113 deletions(-) diff --git a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs index c588a168..cda3379a 100644 --- a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs +++ b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs @@ -1,11 +1,9 @@ -using System; using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Requests; using System.Collections.Generic; using System.Threading.Tasks; using System.Threading; using AsbCloudApp.Data; -using AsbCloudApp.Data.WellOperation; namespace AsbCloudApp.Repositories; @@ -53,14 +51,14 @@ public interface IDetectedOperationRepository /// /// Task> GetPageAsync(DetectedOperationByTelemetryRequest request, CancellationToken token); - + /// - /// Получение дат последних определённых операций + /// Получение последних автоопределённых операций /// /// /// - Task> GetLastDetectedDatesAsync(CancellationToken token); - + Task> GetLastDetectedOperationsAsync(CancellationToken token); + /// /// Удалить операции /// diff --git a/AsbCloudApp/Services/IDetectedOperationService.cs b/AsbCloudApp/Services/IDetectedOperationService.cs index ac7d650c..3b555f37 100644 --- a/AsbCloudApp/Services/IDetectedOperationService.cs +++ b/AsbCloudApp/Services/IDetectedOperationService.cs @@ -79,9 +79,13 @@ namespace AsbCloudApp.Services /// Определение операций /// /// - /// + /// + /// /// /// - Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, CancellationToken token); + Task<(DateTimeOffset LastDate, IEnumerable Items)> DetectOperationsAsync(int idTelemetry, + TelemetryDataRequest request, + DetectedOperationDto? lastDetectedOperation, + CancellationToken token); } } diff --git a/AsbCloudApp/Services/ITelemetryDataSaubService.cs b/AsbCloudApp/Services/ITelemetryDataSaubService.cs index e9f2d1ac..f684b3d6 100644 --- a/AsbCloudApp/Services/ITelemetryDataSaubService.cs +++ b/AsbCloudApp/Services/ITelemetryDataSaubService.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; +using AsbCloudApp.Data; namespace AsbCloudApp.Services { @@ -44,5 +45,12 @@ namespace AsbCloudApp.Services /// /// Task GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token); + + /// + /// Получение диапозона дат телеметрий + /// + /// + /// + Task> GetDateRangesAsync(CancellationToken token); } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs b/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs index b788dbda..a9123bda 100644 --- a/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs @@ -25,7 +25,29 @@ public class DetectedOperationRepository : CrudRepositoryBase> GetLastDetectedOperationsAsync(CancellationToken token) + { + var entities = await dbContext.Set() + .GroupBy(o => o.IdTelemetry) + .Select(g => new + { + IdTelemetry = g.Key, + LastDetectedOperation = g.OrderBy(o => o.DateEnd).Last() + }) + .ToDictionaryAsync(x => x.IdTelemetry, x => x.LastDetectedOperation, token); + + var dtos = entities.ToDictionary(x => x.Key, x => + { + if (x.Value == null) + throw new ArgumentNullException(nameof(x.Value), "The value of the last detected operation cannot be null"); + + return Convert(x.Value); + }); + + return dtos; + } + public async Task DeleteAsync(DetectedOperationByTelemetryRequest request, CancellationToken token) { var query = BuildQuery(request); @@ -57,17 +79,7 @@ public class DetectedOperationRepository : CrudRepositoryBase> GetLastDetectedDatesAsync(CancellationToken token) => - await dbContext.Set() - .GroupBy(o => o.IdTelemetry) - .Select(g => new - { - IdTelemetry = g.Key, - LastDate = g.Max(o => o.DateEnd) - }) - .ToDictionaryAsync(x => x.IdTelemetry, x => x.LastDate, token); - + public async Task> Get(DetectedOperationByTelemetryRequest request, CancellationToken token) { var query = BuildQuery(request) diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs index 299db028..db2ca4ea 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs @@ -32,7 +32,7 @@ public class DetectedOperationService : IDetectedOperationService new DetectorFlashing(), new DetectorConditioning(), }; - + public DetectedOperationService( IDetectedOperationRepository operationRepository, IWellOperationCategoryRepository wellOperationCategoryRepository, @@ -177,72 +177,70 @@ public class DetectedOperationService : IDetectedOperationService return dtos; } - public async Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, CancellationToken token) + public async Task<(DateTimeOffset LastDate, IEnumerable Items)> DetectOperationsAsync(int idTelemetry, + TelemetryDataRequest request, + DetectedOperationDto? lastDetectedOperation, + CancellationToken token) { - const int take = 4 * 86_400; - - var detectedOperations = new List(); - DetectedOperationDto? lastDetectedOperation = null; const int minOperationLength = 5; const int maxDetectorsInterpolationFrameLength = 30; const int gap = maxDetectorsInterpolationFrameLength + minOperationLength; + + var telemetries = await telemetryDataSaubService.GetByTelemetryAsync(idTelemetry, request, token); + + var count = telemetries.Count(); + + if (count == 0) + throw new InvalidOperationException("InvalidOperation_EmptyTelemetries"); + var timezone = telemetryService.GetTimezone(idTelemetry); - while (true) + if (telemetries.Count() <= gap) { - var request = new TelemetryDataRequest - { - GeDate = beginDate, - Take = take, - Order = 0 - }; - - var dtos = await telemetryDataSaubService.GetByTelemetryAsync(idTelemetry, request, token); - var detectableTelemetries = dtos - .Where(t => t.BlockPosition >= 0) - .Select(t => new DetectableTelemetry - { - DateTime = new DateTimeOffset(t.DateTime, timezone.Offset), - IdUser = t.IdUser, - Mode = t.Mode, - WellDepth = t.WellDepth, - Pressure = t.Pressure, - HookWeight = t.HookWeight, - BlockPosition = t.BlockPosition, - BitDepth = t.BitDepth, - RotorSpeed = t.RotorSpeed, - AxialLoad = t.AxialLoad, - }).ToArray(); - - if (detectableTelemetries.Length <= gap) - break; - - var isDetected = false; - var positionBegin = 0; - var positionEnd = detectableTelemetries.Length - gap; - while (positionEnd > positionBegin) - { - foreach (var detector in detectors) - { - if (!detector.TryDetect(idTelemetry, detectableTelemetries, positionBegin, positionEnd, lastDetectedOperation, out var result)) - continue; - - detectedOperations.Add(result!.Operation); - lastDetectedOperation = result.Operation; - isDetected = true; - positionBegin = result.TelemetryEnd; - break; - } - - positionBegin += 1; - } - - beginDate = isDetected - ? lastDetectedOperation!.DateEnd - : detectableTelemetries[positionEnd].DateTime; + var lastTelemetry = telemetries.Last(); + var lastDateTelemetry = new DateTimeOffset(lastTelemetry.DateTime, timezone.Offset); + return (lastDateTelemetry, Enumerable.Empty()); } - return detectedOperations; + var detectedOperations = new List(); + + var detectableTelemetries = telemetries.Select(t => new DetectableTelemetry + { + DateTime = new DateTimeOffset(t.DateTime, timezone.Offset), + IdUser = t.IdUser, + Mode = t.Mode, + WellDepth = t.WellDepth, + Pressure = t.Pressure, + HookWeight = t.HookWeight, + BlockPosition = t.BlockPosition, + BitDepth = t.BitDepth, + RotorSpeed = t.RotorSpeed, + AxialLoad = t.AxialLoad, + }).ToArray(); + + var positionBegin = 0; + var positionEnd = detectableTelemetries.Length - gap; + + while (positionEnd > positionBegin) + { + foreach (var detector in detectors) + { + if (!detector.TryDetect(idTelemetry, detectableTelemetries, positionBegin, positionEnd, lastDetectedOperation, + out var result)) + continue; + + detectedOperations.Add(result!.Operation); + lastDetectedOperation = result.Operation; + positionBegin = result.TelemetryEnd; + break; + } + + positionBegin += 1; + } + + var lastDate = lastDetectedOperation?.DateEnd ?? detectableTelemetries[positionEnd].DateTime; + + return (lastDate, detectedOperations); } public async Task DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token) diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs index c751dfd5..a0adec19 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs @@ -48,6 +48,8 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors while (positionEnd < end) { + //TODO: поиск провалов телеметрии + positionEnd += 1; if (positionEnd > end) break; diff --git a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs index 9b50f67d..6ad52f4b 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs @@ -1,54 +1,93 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudInfrastructure.Background; using Microsoft.Extensions.DependencyInjection; namespace AsbCloudInfrastructure.Services.DetectOperations; -public class WorkOperationDetection: Work +public class WorkOperationDetection : Work { + private static readonly IDictionary CacheOfStartDatesByTelemetryId = new Dictionary(); - public WorkOperationDetection() - :base("Operation detection") - { - Timeout = TimeSpan.FromMinutes(20); - OnErrorAsync = (id, exception, token) => - { - var text = $"work {id}, when {CurrentState?.State}, throw error:{exception.Message}"; - Trace.TraceWarning(text); - return Task.CompletedTask; - }; - } + public WorkOperationDetection() + : base("Operation detection") + { + Timeout = TimeSpan.FromMinutes(20); + OnErrorAsync = (id, exception, _) => + { + var text = $"work {id}, when {CurrentState?.State}, throw error:{exception.Message}"; + Trace.TraceWarning(text); + return Task.CompletedTask; + }; + } - protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) - { - var telemetryRepository = services.GetRequiredService>(); - var detectedOperationRepository = services.GetRequiredService(); - var detectedOperationService = services.GetRequiredService(); + protected override async Task Action(string id, + IServiceProvider services, + Action onProgressCallback, + CancellationToken token) + { + var telemetryRepository = services.GetRequiredService>(); + var detectedOperationRepository = services.GetRequiredService(); + var detectedOperationService = services.GetRequiredService(); + var telemetryDataSaubService = services.GetRequiredService(); - var telemetryIds = (await telemetryRepository.GetAllAsync(token)) - .Select(t => t.Id) - .ToArray(); + var idsTelemetry = (await telemetryRepository.GetAllAsync(token)) + .Select(t => t.Id) + .ToArray(); - var lastDetectedDates = await detectedOperationRepository.GetLastDetectedDatesAsync(token); + var telemetriesDateRanges = await telemetryDataSaubService.GetDateRangesAsync(token); - for (var i = 0; i < telemetryIds.Length; i++) - { - var telemetryId = telemetryIds[i]; - - var beginDate = lastDetectedDates.TryGetValue(telemetryId, out var date) ? date : (DateTimeOffset?)null; + var lastDetectedOperations = await detectedOperationRepository.GetLastDetectedOperationsAsync(token); - onProgressCallback($"Start detecting telemetry: {telemetryId} from {beginDate}", i / telemetryIds.Length); - var detectedOperations = await detectedOperationService.DetectOperationsAsync(telemetryId, beginDate, token); + for (int i = 0; i < idsTelemetry.Length; i++) + { + var idTelemetry = idsTelemetry[i]; + + if (!telemetriesDateRanges.TryGetValue(idTelemetry, out var telemetryDateRange)) + continue; - if (detectedOperations.Any()) - await detectedOperationRepository.InsertRangeAsync(detectedOperations, token); - } - } -} + var dateBegin = telemetryDateRange.From.DateTime; + var dateEnd = telemetryDateRange.To.DateTime; + + if (lastDetectedOperations.TryGetValue(idTelemetry, out var lastDetectedOperation)) + dateBegin = lastDetectedOperation.DateEnd.UtcDateTime; + + if (CacheOfStartDatesByTelemetryId.TryGetValue(idTelemetry, out var dateBeginFromCahce)) + dateBegin = dateBeginFromCahce; + + onProgressCallback.Invoke($"Start detecting telemetry: {idTelemetry} from {dateBegin}", i / idsTelemetry.Length); + + const int pointsCount = 4 * 86_400; + + while (dateBegin < dateEnd) + { + var request = new TelemetryDataRequest + { + GeDate = dateBegin, + Take = pointsCount, + Order = 0, + GeBlockPosition = 0 + }; + + var detectedOperations = + await detectedOperationService.DetectOperationsAsync(idTelemetry, request, lastDetectedOperation, token); + + await detectedOperationRepository.InsertRangeAsync(detectedOperations.Items, token); + + dateBegin = detectedOperations.LastDate.UtcDateTime; + + CacheOfStartDatesByTelemetryId[idTelemetry] = dateBegin; + + await detectedOperationRepository.InsertRangeAsync(detectedOperations.Items, token); + } + } + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index 88b11941..ea2b7912 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -177,7 +177,7 @@ namespace AsbCloudInfrastructure.Services.SAUB return dtos; } - private IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request) + protected virtual IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request) { var dbSet = db.Set(); @@ -268,7 +268,7 @@ namespace AsbCloudInfrastructure.Services.SAUB }; return range; } - + public DatesRangeDto? GetRange(int idWell) { var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index 78a63b2c..c66cd984 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -13,6 +13,8 @@ using System.Linq; using System.Text.Csv; using System.Threading; using System.Threading.Tasks; +using AsbCloudApp.Data; +using AsbCloudApp.Requests; namespace AsbCloudInfrastructure.Services.SAUB; @@ -174,4 +176,33 @@ public class TelemetryDataSaubService : TelemetryDataBaseService> GetDateRangesAsync(CancellationToken token) + { + return await db.Set().GroupBy(x => x.IdTelemetry) + .Select(g => new + { + IdTelemetry = g.Key, + From = g.Min(x => x.DateTime), + To = g.Max(x => x.DateTime) + }) + .ToDictionaryAsync(x => x.IdTelemetry, x => new DatesRangeDto + { + From = x.From, + To = x.To + }, token); + } + + protected override IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request) + { + var query = base.BuildQuery(idTelemetry, request); + + if (request.GeBlockPosition.HasValue) + query = query.Where(e => e.BlockPosition >= request.GeBlockPosition); + + if (request.LeBlockPosition.HasValue) + query = query.Where(e => e.BlockPosition <= request.LeBlockPosition); + + return query; + } } From e29f21c29197ade852585e1e360429137fba81cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Thu, 25 Jul 2024 11:50:56 +0300 Subject: [PATCH 2/9] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D0=B1=D0=B5?= =?UTF-8?q?=D0=BA=D0=B3=D1=80=D0=B0=D1=84=D0=BD=D1=83=D0=B4=20=D1=81=D0=B5?= =?UTF-8?q?=D1=80=D0=B2=D0=B8=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/DetectOperations/WorkOperationDetection.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs index 6ad52f4b..cb569515 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs @@ -50,7 +50,7 @@ public class WorkOperationDetection : Work for (int i = 0; i < idsTelemetry.Length; i++) { var idTelemetry = idsTelemetry[i]; - + if (!telemetriesDateRanges.TryGetValue(idTelemetry, out var telemetryDateRange)) continue; @@ -80,8 +80,6 @@ public class WorkOperationDetection : Work var detectedOperations = await detectedOperationService.DetectOperationsAsync(idTelemetry, request, lastDetectedOperation, token); - await detectedOperationRepository.InsertRangeAsync(detectedOperations.Items, token); - dateBegin = detectedOperations.LastDate.UtcDateTime; CacheOfStartDatesByTelemetryId[idTelemetry] = dateBegin; From ccffb5e8e523eea8de0bde040cccb902d40c0eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Thu, 25 Jul 2024 12:49:18 +0300 Subject: [PATCH 3/9] =?UTF-8?q?=D0=98=D0=B7=20=D1=81=D0=B5=D1=80=D0=B2?= =?UTF-8?q?=D0=B8=D1=81=D0=B0=20=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D0=B8=20=D1=83=D0=B4=D0=B0=D0=BB=D1=91=D0=BD=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=B0=D1=82=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D0=B8,=20=D0=B4?= =?UTF-8?q?=D0=B0=D1=82=D1=8B=20=D0=B2=20=D0=B1=D0=B5=D0=BA=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D1=83=D0=BD=D0=B4=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B0=D1=8E=D1=82=D1=81?= =?UTF-8?q?=D1=8F=20=D0=B8=D0=B7=20=D0=BA=D1=8D=D1=88=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Requests/TelemetryRequest.cs | 9 ++++++++ .../Services/ITelemetryDataSaubService.cs | 7 ------- .../WorkOperationDetection.cs | 21 ++++++++++--------- .../Services/SAUB/TelemetryDataCache.cs | 6 +++--- .../Services/SAUB/TelemetryDataSaubService.cs | 16 -------------- 5 files changed, 23 insertions(+), 36 deletions(-) diff --git a/AsbCloudApp/Requests/TelemetryRequest.cs b/AsbCloudApp/Requests/TelemetryRequest.cs index 732d8075..e8f88a90 100644 --- a/AsbCloudApp/Requests/TelemetryRequest.cs +++ b/AsbCloudApp/Requests/TelemetryRequest.cs @@ -56,4 +56,13 @@ public class TelemetryDataRequest [Range(1, MaxTake)] public int Take { get; set; } = 1024; + /// + /// Больше или равно высоте талевого блока + /// + public double? GeBlockPosition { get; set; } + + /// + /// Меньше или равно высоте талевого блока + /// + public double? LeBlockPosition { get; set; } } diff --git a/AsbCloudApp/Services/ITelemetryDataSaubService.cs b/AsbCloudApp/Services/ITelemetryDataSaubService.cs index f684b3d6..da32ef50 100644 --- a/AsbCloudApp/Services/ITelemetryDataSaubService.cs +++ b/AsbCloudApp/Services/ITelemetryDataSaubService.cs @@ -45,12 +45,5 @@ namespace AsbCloudApp.Services /// /// Task GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token); - - /// - /// Получение диапозона дат телеметрий - /// - /// - /// - Task> GetDateRangesAsync(CancellationToken token); } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs index cb569515..d00be734 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; +using AsbCloudApp.Data.SAUB; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; @@ -15,7 +16,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations; public class WorkOperationDetection : Work { - private static readonly IDictionary CacheOfStartDatesByTelemetryId = new Dictionary(); + private static readonly IDictionary CacheOfStartDatesByTelemetryId = new Dictionary(); public WorkOperationDetection() : base("Operation detection") @@ -37,28 +38,28 @@ public class WorkOperationDetection : Work var telemetryRepository = services.GetRequiredService>(); var detectedOperationRepository = services.GetRequiredService(); var detectedOperationService = services.GetRequiredService(); - var telemetryDataSaubService = services.GetRequiredService(); + var telemetryDataCache = services.GetRequiredService>(); var idsTelemetry = (await telemetryRepository.GetAllAsync(token)) .Select(t => t.Id) .ToArray(); - var telemetriesDateRanges = await telemetryDataSaubService.GetDateRangesAsync(token); - var lastDetectedOperations = await detectedOperationRepository.GetLastDetectedOperationsAsync(token); for (int i = 0; i < idsTelemetry.Length; i++) { var idTelemetry = idsTelemetry[i]; - if (!telemetriesDateRanges.TryGetValue(idTelemetry, out var telemetryDateRange)) + var telemetryDateRange = telemetryDataCache.GetOrDefaultWellDataDateRange(idTelemetry); + + if(telemetryDateRange == null) continue; - var dateBegin = telemetryDateRange.From.DateTime; - var dateEnd = telemetryDateRange.To.DateTime; - + var dateBegin = telemetryDateRange.From; + var dateEnd = telemetryDateRange.To; + if (lastDetectedOperations.TryGetValue(idTelemetry, out var lastDetectedOperation)) - dateBegin = lastDetectedOperation.DateEnd.UtcDateTime; + dateBegin = lastDetectedOperation.DateEnd; if (CacheOfStartDatesByTelemetryId.TryGetValue(idTelemetry, out var dateBeginFromCahce)) dateBegin = dateBeginFromCahce; @@ -80,7 +81,7 @@ public class WorkOperationDetection : Work var detectedOperations = await detectedOperationService.DetectOperationsAsync(idTelemetry, request, lastDetectedOperation, token); - dateBegin = detectedOperations.LastDate.UtcDateTime; + dateBegin = detectedOperations.LastDate; CacheOfStartDatesByTelemetryId[idTelemetry] = dateBegin; diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index f80ccaa7..da0a9486 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -152,9 +152,9 @@ public class TelemetryDataCache : ITelemetryDataCache where TDto : A if (cacheItem.LastData.Count == 0) return null; - - var to = FromDate(cacheItem.FirstByDate.DateTime, cacheItem.TimezoneOffset); - var from = FromDate(cacheItem.LastData[^1].DateTime, cacheItem.TimezoneOffset); + + var to = FromDate(cacheItem.LastData[^1].DateTime, cacheItem.TimezoneOffset); + var from = FromDate(cacheItem.FirstByDate.DateTime, cacheItem.TimezoneOffset); return new DatesRangeDto { From = from, To = to }; } diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index c66cd984..8541caee 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -177,22 +177,6 @@ public class TelemetryDataSaubService : TelemetryDataBaseService> GetDateRangesAsync(CancellationToken token) - { - return await db.Set().GroupBy(x => x.IdTelemetry) - .Select(g => new - { - IdTelemetry = g.Key, - From = g.Min(x => x.DateTime), - To = g.Max(x => x.DateTime) - }) - .ToDictionaryAsync(x => x.IdTelemetry, x => new DatesRangeDto - { - From = x.From, - To = x.To - }, token); - } - protected override IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request) { var query = base.BuildQuery(idTelemetry, request); From acfe9ab0001c2f7fbc59a19e46085fb7993c4941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Thu, 25 Jul 2024 12:49:53 +0300 Subject: [PATCH 4/9] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D0=BB=D0=B5=D0=B4=D0=BD=D0=B5=D0=B9=20=D0=B4=D0=B0=D1=82=D1=8B?= =?UTF-8?q?=20=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D1=91=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/DetectOperations/DetectedOperationService.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs index db2ca4ea..d583bbf7 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs @@ -238,9 +238,7 @@ public class DetectedOperationService : IDetectedOperationService positionBegin += 1; } - var lastDate = lastDetectedOperation?.DateEnd ?? detectableTelemetries[positionEnd].DateTime; - - return (lastDate, detectedOperations); + return (detectableTelemetries[positionBegin].DateTime, detectedOperations); } public async Task DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token) From ae79426973cb22abf098b81b6a119414d2d19898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Thu, 25 Jul 2024 16:53:48 +0300 Subject: [PATCH 5/9] =?UTF-8?q?=D0=AD=D0=BA=D1=81=D0=BF=D0=BE=D1=80=D1=82?= =?UTF-8?q?=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D1=91=D0=BD=D0=BD=D1=8B=D1=85=20=D0=BE=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DetectedOperationExportService.cs | 333 +++++++++--------- .../SAUB/DetectedOperationController.cs | 6 +- 2 files changed, 174 insertions(+), 165 deletions(-) diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs index bc8869b4..98a9f298 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs @@ -14,210 +14,219 @@ using AsbCloudApp.Exceptions; using AsbCloudApp.Services; using AsbCloudApp.Data; using AsbCloudApp.Data.WellOperation; +using AsbCloudApp.Requests; using AsbCloudInfrastructure.Services.DetectOperations.Detectors; namespace AsbCloudInfrastructure.Services.DetectOperations; public class DetectedOperationExportService { - private readonly IWellService wellService; - private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; - private readonly IDetectedOperationService detectedOperationService; - private const int headerRowsCount = 1; + private readonly IWellService wellService; + private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; + private readonly IDetectedOperationRepository detectedOperationRepository; + private const int headerRowsCount = 1; - private const string cellDepositName = "B1"; - private const string cellClusterName = "B2"; - private const string cellWellName = "B3"; - private const string cellDeltaDate = "H2"; + private const string cellDepositName = "B1"; + private const string cellClusterName = "B2"; + private const string cellWellName = "B3"; + private const string cellDeltaDate = "H2"; - private const int columnOperationName = 1; - private const int columnDateStart = 2; - private const int columnDateEnd = 3; - private const int columnDuration = 4; - private const int columnDepthStart = 5; - private const int columnDepthEnd = 6; - private const int columnDeltaDepth = 7; - private const int columnDepth = 8; - private const int columnIdReasonOfEnd = 9; - private const int columnComment = 10; + private const int columnOperationName = 1; + private const int columnDateStart = 2; + private const int columnDateEnd = 3; + private const int columnDuration = 4; + private const int columnDepthStart = 5; + private const int columnDepthEnd = 6; + private const int columnDeltaDepth = 7; + private const int columnDepth = 8; + private const int columnIdReasonOfEnd = 9; + private const int columnComment = 10; - public DetectedOperationExportService(IWellService wellService, - IWellOperationCategoryRepository wellOperationCategoryRepository, - IDetectedOperationService detectedOperationService) - { - this.wellService = wellService; - this.wellOperationCategoryRepository = wellOperationCategoryRepository; - this.detectedOperationService = detectedOperationService; - } + public DetectedOperationExportService(IWellService wellService, + IWellOperationCategoryRepository wellOperationCategoryRepository, + IDetectedOperationRepository detectedOperationRepository) + { + this.wellService = wellService; + this.wellOperationCategoryRepository = wellOperationCategoryRepository; + this.detectedOperationRepository = detectedOperationRepository; + } - /// - /// Экспорт excel файла с операциями по скважине - /// - /// ключ скважины - /// хост - /// - /// - /// - public async Task ExportAsync(int idWell, string host, CancellationToken token) - { - var well = await wellService.GetOrDefaultAsync(idWell, token); + /// + /// Экспорт excel файла с операциями по скважине + /// + /// ключ скважины + /// хост + /// + /// + /// + public async Task ExportAsync(int idWell, string host, CancellationToken token) + { + var well = await wellService.GetOrDefaultAsync(idWell, token); - if (well is null) - throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} does not exist"); + if (well is null) + throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} does not exist"); - if (!well.IdTelemetry.HasValue) - throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} has no telemetry"); + if (!well.IdTelemetry.HasValue) + throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} has no telemetry"); - var operations = await detectedOperationService.DetectOperationsAsync(well.IdTelemetry.Value, DateTime.UnixEpoch, token); + var request = new DetectedOperationByTelemetryRequest + { + IdTelemetry = well.IdTelemetry.Value + }; - return await GenerateExcelFileStreamAsync(well, host, operations, token); - } + var operations = await detectedOperationRepository.Get(request, token); - private async Task GenerateExcelFileStreamAsync(WellDto well, string host, IEnumerable operationDetectorResults, - CancellationToken cancellationToken) - { - using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken); + return await GenerateExcelFileStreamAsync(well, host, operations, token); + } - using var workbook = new XLWorkbook(excelTemplateStream); + private async Task GenerateExcelFileStreamAsync(WellDto well, + string host, + IEnumerable operationDetectorResults, + CancellationToken cancellationToken) + { + using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken); - AddToWorkbook(workbook, well, host, operationDetectorResults); + using var workbook = new XLWorkbook(excelTemplateStream); - MemoryStream memoryStream = new MemoryStream(); - workbook.SaveAs(memoryStream, new SaveOptions { }); - memoryStream.Seek(0, SeekOrigin.Begin); - return memoryStream; - } + AddToWorkbook(workbook, well, host, operationDetectorResults); - private void AddToWorkbook(XLWorkbook workbook, WellDto well, string host, IEnumerable operations) - { - const string sheetName = "Операции"; + MemoryStream memoryStream = new MemoryStream(); + workbook.SaveAs(memoryStream, new SaveOptions { }); + memoryStream.Seek(0, SeekOrigin.Begin); + return memoryStream; + } - if (!operations.Any()) - return; + private void AddToWorkbook(XLWorkbook workbook, WellDto well, string host, IEnumerable operations) + { + const string sheetName = "Операции"; - var sheet = workbook.GetWorksheet(sheetName); + if (!operations.Any()) + return; - var orderedOperations = operations - .OrderBy(x => x.DateStart) - .ThenBy(x => x.DepthStart).ToArray(); + var sheet = workbook.GetWorksheet(sheetName); - AddToSheet(sheet, well, host, orderedOperations); - } + var orderedOperations = operations + .OrderBy(x => x.DateStart) + .ThenBy(x => x.DepthStart).ToArray(); - private void AddToSheet(IXLWorksheet sheet, WellDto well, string host, IList operations) - { - var wellOperationCategories = wellOperationCategoryRepository.Get(true); + AddToSheet(sheet, well, host, orderedOperations); + } - sheet.Cell(cellDepositName).SetCellValue(well.Deposit); - sheet.Cell(cellClusterName).SetCellValue(well.Cluster); - sheet.Cell(cellWellName).SetCellValue(well.Caption); + private void AddToSheet(IXLWorksheet sheet, WellDto well, string host, IList operations) + { + var wellOperationCategories = wellOperationCategoryRepository.Get(true); - var deltaDate = operations.Max(o => o.DateEnd - o.DateStart); - - sheet.Cell(cellDeltaDate).SetCellValue(deltaDate); + sheet.Cell(cellDepositName).SetCellValue(well.Deposit); + sheet.Cell(cellClusterName).SetCellValue(well.Cluster); + sheet.Cell(cellWellName).SetCellValue(well.Caption); - for (int i = 0; i < operations.Count; i++) - { - var current = operations[i]; - var dateStart = current.DateStart.DateTime; - var dateEnd = current.DateEnd.DateTime; + var deltaDate = operations.Max(o => o.DateEnd - o.DateStart); - var row = sheet.Row(5 + i + headerRowsCount); + sheet.Cell(cellDeltaDate).SetCellValue(deltaDate); - var categoryName = GetCategoryName(wellOperationCategories, current); - - row.Cell(columnDateStart).SetCellValue(dateStart); - row.Cell(columnOperationName).SetCellValue(categoryName); - row.Cell(columnDateEnd).SetCellValue(dateEnd); - row.Cell(columnDuration).SetCellValue((dateEnd - dateStart).TotalMinutes); - row.Cell(columnDepthStart).SetCellValue(current.DepthStart); - row.Cell(columnDepthEnd).SetCellValue(current.DepthEnd); - row.Cell(columnDepth).SetCellValue(current.DepthEnd - current.DepthStart); + for (int i = 0; i < operations.Count; i++) + { + var current = operations[i]; + var dateStart = current.DateStart.DateTime; + var dateEnd = current.DateEnd.DateTime; - if (current.ExtraData.TryGetValue("IdReasonOfEnd", out object? idReasonOfEndObject) - && idReasonOfEndObject is int idReasonOfEnd) - { - var reasonOfEnd = GetIdReasonOfEnd(idReasonOfEnd); - row.Cell(columnIdReasonOfEnd).SetCellValue(reasonOfEnd); - } + var row = sheet.Row(5 + i + headerRowsCount); - var query = new QueryBuilder(); - query.Add("end", dateStart.AddSeconds(1800 * 0.9).ToString("yyyy-MM-ddTHH:mm:ss.fff")); - query.Add("range", "1800"); + var categoryName = GetCategoryName(wellOperationCategories, current); - var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}"; - row.Cell(columnDateStart).SetHyperlink(link); - - var deltaDepth = i > 0 && i + 1 < operations.Count - ? current.DepthStart - operations[i - 1].DepthEnd - : 0; + row.Cell(columnDateStart).SetCellValue(dateStart); + row.Cell(columnOperationName).SetCellValue(categoryName); + row.Cell(columnDateEnd).SetCellValue(dateEnd); + row.Cell(columnDuration).SetCellValue((dateEnd - dateStart).TotalMinutes); + row.Cell(columnDepthStart).SetCellValue(current.DepthStart); + row.Cell(columnDepthEnd).SetCellValue(current.DepthEnd); + row.Cell(columnDepth).SetCellValue(current.DepthEnd - current.DepthStart); - row.Cell(columnDeltaDepth).SetCellValue(deltaDepth); + if (current.ExtraData.TryGetValue("IdReasonOfEnd", out object? idReasonOfEndObject) + && idReasonOfEndObject is int idReasonOfEnd) + { + var reasonOfEnd = GetIdReasonOfEnd(idReasonOfEnd); + row.Cell(columnIdReasonOfEnd).SetCellValue(reasonOfEnd); + } - var comment = CreateComment(operations[i]); - row.Cell(columnComment).SetCellValue(comment); - } - } + var query = new QueryBuilder(); + query.Add("end", dateStart.AddSeconds(1800 * 0.9).ToString("yyyy-MM-ddTHH:mm:ss.fff")); + query.Add("range", "1800"); - private static string GetCategoryName(IEnumerable wellOperationCategories, DetectedOperationDto current) - { - var idCategory = current.IdCategory; - if (idCategory == WellOperationCategory.IdSlide && current.EnabledSubsystems.IsAutoOscillation) - return "Бурение в слайде с осцилляцией"; + var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}"; + row.Cell(columnDateStart).SetHyperlink(link); - var category = wellOperationCategories.FirstOrDefault(o => o.Id == current.IdCategory); - - if(category is not null) - return category.Name; + var deltaDepth = i > 0 && i + 1 < operations.Count + ? current.DepthStart - operations[i - 1].DepthEnd + : 0; - return $"Операция №{idCategory}"; - } + row.Cell(columnDeltaDepth).SetCellValue(deltaDepth); - private static string GetIdReasonOfEnd(int idReasonOfEnd) - => idReasonOfEnd switch { - 0 => "Не определена", - 1 => "Не определено начало операции", - 101 => "Разница глубин забоя и положением долота", - 300 => "Низкое давление", - 301 => "Высокое давление", - 700 => "Изменение глубины долота и осевая нагрузка < веса на крюке", - _ => idReasonOfEnd.ToString($"Причина № {idReasonOfEnd}"), + var comment = CreateComment(operations[i]); + row.Cell(columnComment).SetCellValue(comment); + } + } - }; + private static string GetCategoryName(IEnumerable wellOperationCategories, DetectedOperationDto current) + { + var idCategory = current.IdCategory; + if (idCategory == WellOperationCategory.IdSlide && current.EnabledSubsystems.IsAutoOscillation) + return "Бурение в слайде с осцилляцией"; - private async Task GetExcelTemplateStreamAsync(CancellationToken cancellationToken) - { - string resourceName = Assembly.GetExecutingAssembly() - .GetManifestResourceNames() - .FirstOrDefault(n => n.EndsWith("DetectOperations.xlsx"))!; + var category = wellOperationCategories.FirstOrDefault(o => o.Id == current.IdCategory); - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream(resourceName)!; + if (category is not null) + return category.Name; - var memoryStream = new MemoryStream(); - await stream.CopyToAsync(memoryStream, cancellationToken); - memoryStream.Position = 0; + return $"Операция №{idCategory}"; + } - return memoryStream; - } - - private static string CreateComment(DetectedOperationDto operation) - { - switch (operation.IdCategory) - { - case WellOperationCategory.IdRotor: - case WellOperationCategory.IdSlide: - var comment = ""; - if (operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyAvgRotorSpeed, out object? oAvgRotorSpeed)) - comment += $"Средняя скорость оборотов ротора: {oAvgRotorSpeed}\r\n"; + private static string GetIdReasonOfEnd(int idReasonOfEnd) + => idReasonOfEnd switch + { + 0 => "Не определена", + 1 => "Не определено начало операции", + 101 => "Разница глубин забоя и положением долота", + 300 => "Низкое давление", + 301 => "Высокое давление", + 700 => "Изменение глубины долота и осевая нагрузка < веса на крюке", + _ => idReasonOfEnd.ToString($"Причина № {idReasonOfEnd}"), + }; - if (operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyDispersionOfNormalizedRotorSpeed, out object? oDispersionOfNormalizedRotorSpeed)) - comment += $"Дисперсия нормированных оборотов ротора: {oDispersionOfNormalizedRotorSpeed}"; - - return comment; - - default: - return string.Empty; - } - } + private async Task GetExcelTemplateStreamAsync(CancellationToken cancellationToken) + { + string resourceName = Assembly.GetExecutingAssembly() + .GetManifestResourceNames() + .FirstOrDefault(n => n.EndsWith("DetectOperations.xlsx"))!; + + using var stream = Assembly.GetExecutingAssembly() + .GetManifestResourceStream(resourceName)!; + + var memoryStream = new MemoryStream(); + await stream.CopyToAsync(memoryStream, cancellationToken); + memoryStream.Position = 0; + + return memoryStream; + } + + private static string CreateComment(DetectedOperationDto operation) + { + switch (operation.IdCategory) + { + case WellOperationCategory.IdRotor: + case WellOperationCategory.IdSlide: + var comment = ""; + if (operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyAvgRotorSpeed, out object? oAvgRotorSpeed)) + comment += $"Средняя скорость оборотов ротора: {oAvgRotorSpeed}\r\n"; + + if (operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyDispersionOfNormalizedRotorSpeed, + out object? oDispersionOfNormalizedRotorSpeed)) + comment += $"Дисперсия нормированных оборотов ротора: {oDispersionOfNormalizedRotorSpeed}"; + + return comment; + + default: + return string.Empty; + } + } } \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs b/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs index c593c4d6..5011c8d3 100644 --- a/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs @@ -167,13 +167,13 @@ namespace AsbCloudWebApi.Controllers.SAUB public async Task ExportAsync(int idWell, CancellationToken token) { var idCompany = User.GetCompanyId(); - + if (idCompany is null) return Forbid(); - + var host = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}"; var stream = await detectedOperationExportService.ExportAsync(idWell, host, token); - + return File(stream, "application/octet-stream", "operations.xlsx"); } From 315c259a255539ac1a7e028a0304adeddeb1a934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Thu, 25 Jul 2024 16:58:26 +0300 Subject: [PATCH 6/9] fix merge --- AsbCloudApp/Repositories/IDetectedOperationRepository.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs index 765761be..6b6e43f4 100644 --- a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs +++ b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs @@ -4,6 +4,7 @@ using AsbCloudApp.Requests; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using AsbCloudApp.Services; namespace AsbCloudApp.Repositories; From 0c7aac40ff7332a62b149d93f99cd670e07ee582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Fri, 26 Jul 2024 13:11:03 +0300 Subject: [PATCH 7/9] =?UTF-8?q?Skip=20=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DetectedOperationService.cs | 22 ++++++++++++++++++- .../Detectors/DetectorAbstract.cs | 4 ++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs index d583bbf7..30d83ecd 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs @@ -235,7 +235,12 @@ public class DetectedOperationService : IDetectedOperationService break; } - positionBegin += 1; + var skip = 1; + + while (IsChangingTelemetryInterval(detectableTelemetries[positionBegin], detectableTelemetries[positionBegin + skip])) + skip++; + + positionBegin += skip; } return (detectableTelemetries[positionBegin].DateTime, detectedOperations); @@ -252,6 +257,21 @@ public class DetectedOperationService : IDetectedOperationService return result; } + private static bool IsChangingTelemetryInterval(DetectableTelemetry telemetryBegin, DetectableTelemetry telemetryEnd) + { + return telemetryBegin.Mode == telemetryEnd.Mode && + EqualParameter(telemetryBegin.WellDepth, telemetryEnd.WellDepth, 0.01f) && + EqualParameter(telemetryBegin.Pressure, telemetryEnd.Pressure, 0.1f) && + EqualParameter(telemetryBegin.HookWeight, telemetryEnd.HookWeight, 0.1f) && + EqualParameter(telemetryBegin.BlockPosition, telemetryEnd.BlockPosition, 0.01f) && + EqualParameter(telemetryBegin.BitDepth, telemetryEnd.BitDepth, 0.01f) && + EqualParameter(telemetryBegin.RotorSpeed, telemetryEnd.RotorSpeed, 0.01f) && + EqualParameter(telemetryBegin.AxialLoad, telemetryEnd.AxialLoad, 0.1f); + + bool EqualParameter(float value, float origin, float tolerance) => + value <= origin + tolerance && value >= origin - tolerance; + } + private static IEnumerable GetOperationsDrillersStat(IEnumerable operations) { var groups = operations.GroupBy(o => o.Driller); diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs index a0adec19..623608d8 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs @@ -48,11 +48,11 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors while (positionEnd < end) { - //TODO: поиск провалов телеметрии - positionEnd += 1; if (positionEnd > end) break; + + //TODO: поиск провалов телеметрий. Следует обсудить, так как алгоритмы теряют в точности. idReasonOfEnd = DetectEnd(telemetry, positionEnd, previousOperation); From b6b1220561422e897e61298e780e27d98819816b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Fri, 26 Jul 2024 14:20:46 +0300 Subject: [PATCH 8/9] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D1=80=D0=B5?= =?UTF-8?q?=D0=BF=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D0=B5=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Requests/TelemetryRequest.cs | 10 ------- .../Repository/DetectedOperationRepository.cs | 11 ++------ .../DetectedOperationService.cs | 28 ++++++++++--------- .../WorkOperationDetection.cs | 3 +- .../Services/SAUB/TelemetryDataBaseService.cs | 2 +- .../Services/SAUB/TelemetryDataSaubService.cs | 15 +--------- 6 files changed, 21 insertions(+), 48 deletions(-) diff --git a/AsbCloudApp/Requests/TelemetryRequest.cs b/AsbCloudApp/Requests/TelemetryRequest.cs index e8f88a90..04d4ffb4 100644 --- a/AsbCloudApp/Requests/TelemetryRequest.cs +++ b/AsbCloudApp/Requests/TelemetryRequest.cs @@ -55,14 +55,4 @@ public class TelemetryDataRequest /// [Range(1, MaxTake)] public int Take { get; set; } = 1024; - - /// - /// Больше или равно высоте талевого блока - /// - public double? GeBlockPosition { get; set; } - - /// - /// Меньше или равно высоте талевого блока - /// - public double? LeBlockPosition { get; set; } } diff --git a/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs b/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs index 2dfd0eac..7d664066 100644 --- a/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs @@ -36,15 +36,10 @@ public class DetectedOperationRepository IdTelemetry = g.Key, LastDetectedOperation = g.OrderBy(o => o.DateEnd).Last() }) - .ToDictionaryAsync(x => x.IdTelemetry, x => x.LastDetectedOperation, token); + .ToArrayAsync(token); - var dtos = entities.ToDictionary(x => x.Key, x => - { - if (x.Value == null) - throw new ArgumentNullException(nameof(x.Value), "The value of the last detected operation cannot be null"); - - return Convert(x.Value); - }); + var dtos = entities.ToDictionary(x => x.IdTelemetry, + x => Convert(x.LastDetectedOperation)); return dtos; } diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs index 30d83ecd..4b21ca96 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs @@ -204,19 +204,21 @@ public class DetectedOperationService : IDetectedOperationService var detectedOperations = new List(); - var detectableTelemetries = telemetries.Select(t => new DetectableTelemetry - { - DateTime = new DateTimeOffset(t.DateTime, timezone.Offset), - IdUser = t.IdUser, - Mode = t.Mode, - WellDepth = t.WellDepth, - Pressure = t.Pressure, - HookWeight = t.HookWeight, - BlockPosition = t.BlockPosition, - BitDepth = t.BitDepth, - RotorSpeed = t.RotorSpeed, - AxialLoad = t.AxialLoad, - }).ToArray(); + var detectableTelemetries = telemetries + .Where(t => t.BlockPosition >= 0) + .Select(t => new DetectableTelemetry + { + DateTime = new DateTimeOffset(t.DateTime, timezone.Offset), + IdUser = t.IdUser, + Mode = t.Mode, + WellDepth = t.WellDepth, + Pressure = t.Pressure, + HookWeight = t.HookWeight, + BlockPosition = t.BlockPosition, + BitDepth = t.BitDepth, + RotorSpeed = t.RotorSpeed, + AxialLoad = t.AxialLoad, + }).ToArray(); var positionBegin = 0; var positionEnd = detectableTelemetries.Length - gap; diff --git a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs index d00be734..e4ae3eb4 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs @@ -74,8 +74,7 @@ public class WorkOperationDetection : Work { GeDate = dateBegin, Take = pointsCount, - Order = 0, - GeBlockPosition = 0 + Order = 0 }; var detectedOperations = diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index 8d2b369c..3dbb2e58 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -176,7 +176,7 @@ namespace AsbCloudInfrastructure.Services.SAUB return dtos; } - protected virtual IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request) + private IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request) { var dbSet = db.Set(); diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index 8541caee..2516bd65 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -176,17 +176,4 @@ public class TelemetryDataSaubService : TelemetryDataBaseService BuildQuery(int idTelemetry, TelemetryDataRequest request) - { - var query = base.BuildQuery(idTelemetry, request); - - if (request.GeBlockPosition.HasValue) - query = query.Where(e => e.BlockPosition >= request.GeBlockPosition); - - if (request.LeBlockPosition.HasValue) - query = query.Where(e => e.BlockPosition <= request.LeBlockPosition); - - return query; - } -} +} \ No newline at end of file From fad36886406dc46674b094e9a5cc1092370aecf7 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Fri, 26 Jul 2024 16:56:36 +0500 Subject: [PATCH 9/9] spelling --- .../IDetectedOperationRepository.cs | 2 +- .../Services/IDetectedOperationService.cs | 145 ++-- .../Services/ITelemetryDataSaubService.cs | 70 +- .../DetectedOperationExportService.cs | 1 - .../DetectedOperationService.cs | 15 +- .../Detectors/DetectorAbstract.cs | 762 +++++++++--------- .../Detectors/DetectorConditioning.cs | 4 +- .../Detectors/DetectorFlashing.cs | 4 +- .../Detectors/DetectorSlipsTime.cs | 2 +- .../WorkOperationDetection.cs | 4 +- .../Services/SAUB/TelemetryDataBaseService.cs | 565 +++++++------ .../SAUB/DetectedOperationController.cs | 4 +- 12 files changed, 786 insertions(+), 792 deletions(-) diff --git a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs index 6b6e43f4..6e4eadaf 100644 --- a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs +++ b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs @@ -54,7 +54,7 @@ public interface IDetectedOperationRepository : ITelemetryDataEditorService Task> GetPageAsync(DetectedOperationByTelemetryRequest request, CancellationToken token); /// - /// Получение последних автоопределённых операций + /// Получение последних авто определённых операций /// /// /// diff --git a/AsbCloudApp/Services/IDetectedOperationService.cs b/AsbCloudApp/Services/IDetectedOperationService.cs index 3b555f37..631046c5 100644 --- a/AsbCloudApp/Services/IDetectedOperationService.cs +++ b/AsbCloudApp/Services/IDetectedOperationService.cs @@ -6,86 +6,85 @@ using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data.WellOperation; -namespace AsbCloudApp.Services +namespace AsbCloudApp.Services; + +/// +/// Сервис автоматически определенных по телеметрии операций +/// +public interface IDetectedOperationService { /// - /// Сервис автоматически определенных по телеметрии операций + /// Добавление операций /// - public interface IDetectedOperationService - { - /// - /// Добавление операций - /// - /// - /// - /// - /// - /// - Task InsertRangeManualAsync(int idEditor, int idWell, IEnumerable dtos, CancellationToken token); + /// + /// + /// + /// + /// + Task InsertRangeManualAsync(int idEditor, int idWell, IEnumerable dtos, CancellationToken token); - /// - /// Редактирование операций - /// - /// - /// - /// - /// - /// - Task UpdateRangeManualAsync(int idEditor, int idWell, IEnumerable dtos, CancellationToken token); + /// + /// Редактирование операций + /// + /// + /// + /// + /// + /// + Task UpdateRangeManualAsync(int idEditor, int idWell, IEnumerable dtos, CancellationToken token); - /// - /// Список названий операций. - /// Если указан idWell, то возвращается список названий операций найденных на указанной скважине. - /// - /// - /// - /// - Task> GetCategoriesAsync(int? idWell, CancellationToken token); + /// + /// Список названий операций. + /// Если указан idWell, то возвращается список названий операций найденных на указанной скважине. + /// + /// + /// + /// + Task> GetCategoriesAsync(int? idWell, CancellationToken token); - /// - /// Получить автоматически определенные по телеметрии операции с анализом по бурильщикам - /// - /// - /// - /// - Task GetAsync(DetectedOperationByWellRequest request, CancellationToken token); - - /// - /// Получить автоматически определенные по телеметрии операции - /// - /// - /// - /// - Task> GetOperationsAsync(DetectedOperationByWellRequest request, CancellationToken token); + /// + /// Получить автоматически определенные по телеметрии операции с анализом по бурильщикам + /// + /// + /// + /// + Task GetAsync(DetectedOperationByWellRequest request, CancellationToken token); + + /// + /// Получить автоматически определенные по телеметрии операции + /// + /// + /// + /// + Task> GetOperationsAsync(DetectedOperationByWellRequest request, CancellationToken token); - /// - /// Удалить операции - /// - /// - /// - /// - Task DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token); + /// + /// Удалить операции + /// + /// + /// + /// + Task DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token); - /// - /// Статистика по операциям - /// - /// - /// - /// - [Obsolete] - Task> GetOperationsStatAsync(DetectedOperationByWellRequest request, CancellationToken token); + /// + /// Статистика по операциям + /// + /// + /// + /// + [Obsolete] + Task> GetOperationsStatAsync(DetectedOperationByWellRequest request, CancellationToken token); - /// - /// Определение операций - /// - /// - /// - /// - /// - /// - Task<(DateTimeOffset LastDate, IEnumerable Items)> DetectOperationsAsync(int idTelemetry, - TelemetryDataRequest request, - DetectedOperationDto? lastDetectedOperation, - CancellationToken token); - } + /// + /// Определение операций + /// + /// + /// + /// + /// + /// + Task<(DateTimeOffset LastDate, IEnumerable Items)> DetectOperationsAsync(int idTelemetry, + TelemetryDataRequest request, + DetectedOperationDto? lastDetectedOperation, + CancellationToken token); } diff --git a/AsbCloudApp/Services/ITelemetryDataSaubService.cs b/AsbCloudApp/Services/ITelemetryDataSaubService.cs index da32ef50..3823788a 100644 --- a/AsbCloudApp/Services/ITelemetryDataSaubService.cs +++ b/AsbCloudApp/Services/ITelemetryDataSaubService.cs @@ -4,46 +4,44 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; -using AsbCloudApp.Data; -namespace AsbCloudApp.Services +namespace AsbCloudApp.Services; + +/// +/// Телеметрия САУБ +/// +public interface ITelemetryDataSaubService : ITelemetryDataService { /// - /// Телеметрия САУБ + /// Получение телеметрии для РТК статистики /// - public interface ITelemetryDataSaubService : ITelemetryDataService - { - /// - /// Получение телеметрии для РТК статистики - /// - /// - /// - /// - /// - /// - /// - /// - Task> Get(int idTelemetry, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token); + /// + /// + /// + /// + /// + /// + /// + Task> Get(int idTelemetry, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token); - /// - /// усредненная статистика по 1м за весь период - /// - /// МЕДЛЕННЫЙ ЗАПРОС - /// - /// - /// - /// - /// - Task> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token); + /// + /// усредненная статистика по 1м за весь период + /// + /// МЕДЛЕННЫЙ ЗАПРОС + /// + /// + /// + /// + /// + Task> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token); - /// - /// Получить упакованый csv файл - /// - /// - /// - /// - /// - /// - Task GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token); - } + /// + /// Получить упакованный csv файл + /// + /// + /// + /// + /// + /// + Task GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token); } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs index 98a9f298..daffc4e3 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs @@ -1,6 +1,5 @@ using AsbCloudDb.Model; using ClosedXML.Excel; -using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs index 4b21ca96..aacfe853 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs @@ -110,7 +110,7 @@ public class DetectedOperationService : IDetectedOperationService private async Task GetIdTelemetryByWell(int idWell, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(idWell, token) ?? - throw new ArgumentInvalidException(nameof(idWell), "Well doesn`t exist"); + throw new ArgumentInvalidException(nameof(idWell), "Well doesn't exist"); var idTelemetry = well.IdTelemetry ?? throw new ArgumentInvalidException(nameof(idWell), "У скважины отсутствует телеметрия"); @@ -193,12 +193,12 @@ public class DetectedOperationService : IDetectedOperationService if (count == 0) throw new InvalidOperationException("InvalidOperation_EmptyTelemetries"); - var timezone = telemetryService.GetTimezone(idTelemetry); + var timeZone = telemetryService.GetTimezone(idTelemetry); if (telemetries.Count() <= gap) { var lastTelemetry = telemetries.Last(); - var lastDateTelemetry = new DateTimeOffset(lastTelemetry.DateTime, timezone.Offset); + var lastDateTelemetry = new DateTimeOffset(lastTelemetry.DateTime, timeZone.Offset); return (lastDateTelemetry, Enumerable.Empty()); } @@ -208,7 +208,7 @@ public class DetectedOperationService : IDetectedOperationService .Where(t => t.BlockPosition >= 0) .Select(t => new DetectableTelemetry { - DateTime = new DateTimeOffset(t.DateTime, timezone.Offset), + DateTime = new DateTimeOffset(t.DateTime, timeZone.Offset), IdUser = t.IdUser, Mode = t.Mode, WellDepth = t.WellDepth, @@ -270,8 +270,10 @@ public class DetectedOperationService : IDetectedOperationService EqualParameter(telemetryBegin.RotorSpeed, telemetryEnd.RotorSpeed, 0.01f) && EqualParameter(telemetryBegin.AxialLoad, telemetryEnd.AxialLoad, 0.1f); - bool EqualParameter(float value, float origin, float tolerance) => - value <= origin + tolerance && value >= origin - tolerance; + static bool EqualParameter(float value, float origin, float tolerance) + { + return value <= origin + tolerance && value >= origin - tolerance; + } } private static IEnumerable GetOperationsDrillersStat(IEnumerable operations) @@ -323,7 +325,6 @@ public class DetectedOperationService : IDetectedOperationService }; } - private static DetectedOperationWithDrillerDto Convert(DetectedOperationDto operation, IEnumerable operationValues, IEnumerable schedules) { var dto = operation.Adapt(); diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs index 623608d8..5f17a248 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs @@ -2,412 +2,410 @@ using System; using System.Collections.Generic; using AsbCloudApp.Data.DetectedOperation; -namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors +namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors; + +public abstract class DetectorAbstract { - public abstract class DetectorAbstract + protected const int IdReasonOfEnd_NotDetected = 0; + protected const int IdReasonOfEnd_NotDetectBegin = 1; + + protected const int IdReasonOfEnd_DeltaDepthIsLo = 100; + protected const int IdReasonOfEnd_DeltaDepthIsHi = 101; + protected const int IdReasonOfEnd_DeltaDepthOutOfRange = 102; + protected const int IdReasonOfEnd_WellDepthDeviates = 200; + + protected const int IdReasonOfEnd_PressureIsLo = 300; + protected const int IdReasonOfEnd_PressureIsHi = 301; + protected const int IdReasonOfEnd_PressureOutOfRange = 302; + protected const int IdReasonOfEnd_PressureIsRising = 303; + + protected const int IdReasonOfEnd_RotorSpeedIsLo = 400; + protected const int IdReasonOfEnd_RotorSpeedIsHi = 401; + protected const int IdReasonOfEnd_AvgRotorSpeedIsHi = 402; + protected const int IdReasonOfEnd_AvgRotorSpeedIsLo = 403; + + protected const int IdReasonOfEnd_BlockPositionIsLo = 500; + protected const int IdReasonOfEnd_BlockPositionIsHi = 501; + protected const int IdReasonOfEnd_BlockPositionDeviates = 502; + + protected const int IdReasonOfEnd_Drilling = 600; + + protected const int IdReasonOfEnd_ChangeBitDepthAndAxiLoadLessHookWeight = 700; + + protected const int IdReasonOfEnd_DeltaWellDepthAndBitDepthIsLo = 800; + + protected const int IdReasonOfEnd_BitDepthIsLo = 900; + + public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperationDto? previousOperation, + out OperationDetectorResult? result) { - protected const int IdReasonOfEnd_NotDetected = 0; - protected const int IdReasonOfEnd_NotDetectBegin = 1; - - protected const int IdReasonOfEnd_DeltaDepthIsLo = 100; - protected const int IdReasonOfEnd_DeltaDepthIsHi = 101; - protected const int IdReasonOfEnd_DeltaDepthOutOfRange = 102; - protected const int IdReasonOfEnd_WellDepthDeviates = 200; - - protected const int IdReasonOfEnd_PressureIsLo = 300; - protected const int IdReasonOfEnd_PressureIsHi = 301; - protected const int IdReasonOfEnd_PressureOutOfRange = 302; - protected const int IdReasonOfEnd_PressureIsRising = 303; - - protected const int IdReasonOfEnd_RotorSpeedIsLo = 400; - protected const int IdReasonOfEnd_RotorSpeedIsHi = 401; - protected const int IdReasonOfEnd_AvgRotorSpeedIsHi = 402; - protected const int IdReasonOfEnd_AvgRotorSpeedIsLo = 403; - - protected const int IdReasonOfEnd_BlockPositionIsLo = 500; - protected const int IdReasonOfEnd_BlockPositionIsHi = 501; - protected const int IdReasonOfEnd_BlockPositionDeviates = 502; - - protected const int IdReasonOfEnd_Drilling = 600; - - protected const int IdReasonOfEnd_ChangeBithDepthAndAxiloadLessHookWeight = 700; - - protected const int IdReasonOfEnd_DeltaWellDepthAndBithDepthIsLo = 800; - - protected const int IdReasonOfEnd_BithDepthIsLo = 900; - - public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperationDto? previousOperation, - out OperationDetectorResult? result) + // Проверка соответствия критерию начала операции + if (DetectBegin(telemetry, begin, previousOperation)) { - // Проверка соответствия критерию начала операции - if (DetectBegin(telemetry, begin, previousOperation)) - { - // Поиск окончания соответствия критерию - int idReasonOfEnd = 0; - var positionEnd = begin; - - while (positionEnd < end) - { - positionEnd += 1; - if (positionEnd > end) - break; - - //TODO: поиск провалов телеметрий. Следует обсудить, так как алгоритмы теряют в точности. - - idReasonOfEnd = DetectEnd(telemetry, positionEnd, previousOperation); - - if (idReasonOfEnd != IdReasonOfEnd_NotDetected) - break; - } - - var (Begin, End) = RefineEdges(telemetry, begin, positionEnd); - - result = MakeOperationDetectorResult(idTelemetry, telemetry, Begin, End, idReasonOfEnd); - - return IsValidOperationDetectorResult(result); - } - - result = null; - return false; - } - - protected virtual (int Begin, int End) RefineEdges(DetectableTelemetry[] telemetry, int begin, int end) - => (begin, end); - - protected virtual bool IsValidOperationDetectorResult(OperationDetectorResult operationDetectorResult) - => operationDetectorResult.Operation.DateEnd - operationDetectorResult.Operation.DateStart > TimeSpan.FromSeconds(3); - - protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation); - - protected virtual int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation) - => DetectBegin(telemetry, position, previousOperation) - ? IdReasonOfEnd_NotDetected - : IdReasonOfEnd_NotDetectBegin; - - private OperationDetectorResult MakeOperationDetectorResult( - int idTelemetry, - DetectableTelemetry[] telemetry, - int begin, - int end, - int idReasonOfEnd) - { - var operation = MakeDetectedOperation(idTelemetry, telemetry, begin, end); - - operation.ExtraData["IdReasonOfEnd"] = idReasonOfEnd; - - var result = new OperationDetectorResult - { - TelemetryBegin = begin, - TelemetryEnd = end, - Operation = operation, - }; - - return result; - } - - private DetectedOperationDto MakeDetectedOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end) - { - var pBegin = telemetry[begin]; - var pEnd = telemetry[end]; - var (IdCategory, ExtraData) = GetSpecificInformation(telemetry, begin, end); - var operation = new DetectedOperationDto - { - IdCategory = IdCategory, - IdTelemetry = idTelemetry, - IdUserAtStart = pBegin.IdUser ?? -1, - DateStart = pBegin.DateTime, - DateEnd = pEnd.DateTime, - DepthStart = (double)pBegin.WellDepth, - DepthEnd = (double)pEnd.WellDepth, - ExtraData = ExtraData, - Value = CalcValue(telemetry, begin, end), - EnabledSubsystems = DetectEnabledSubsystems(telemetry, begin, end, ExtraData) - }; - - return operation; - } - - /// - /// Получение информации специфичной для конкретного детектора - /// IdCategory - одна из констант WellOperationCategory - /// ExtraData - дополнительная информация для отладки алгоритмов авто определения - /// - /// - protected abstract (int IdCategory, IDictionary ExtraData) GetSpecificInformation(DetectableTelemetry[] telemetry, int begin, int end); - - /// - /// Расчет ключевого параметра операции - /// - /// - /// - /// - /// - protected abstract double CalcValue(DetectableTelemetry[] telemetry, int begin, int end); - - /// - /// Определение включенных подсистем во время выполнения операции - /// - /// - /// - /// - /// - /// - private static int DetectEnabledSubsystems(DetectableTelemetry[] telemetry, int begin, int end, IDictionary extraData) - { - var enabledSubsystems = 0; - - if (extraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out var hasOscillation) - && hasOscillation is true) - enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoOscillation; + // Поиск окончания соответствия критерию + int idReasonOfEnd = 0; + var positionEnd = begin; - for (var i = begin; i < end; i += 2) + while (positionEnd < end) { - var mode = telemetry[i].Mode; + positionEnd += 1; + if (positionEnd > end) + break; + + //TODO: поиск провалов телеметрий. Следует обсудить, так как алгоритмы теряют в точности. - if(mode == 1) - enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoRotor; + idReasonOfEnd = DetectEnd(telemetry, positionEnd, previousOperation); - if (mode == 3) - enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSlide; - - if (mode == 2) - enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoConditionig; - - if (mode == 4) - enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSinking; - - if (mode == 5) - enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLifting; - - if (mode == 6) - enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLiftingWithConditionig; - - if (mode == 10) - enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoBlocknig; + if (idReasonOfEnd != IdReasonOfEnd_NotDetected) + break; } + + var (Begin, End) = RefineEdges(telemetry, begin, positionEnd); + + result = MakeOperationDetectorResult(idTelemetry, telemetry, Begin, End, idReasonOfEnd); - return enabledSubsystems; + return IsValidOperationDetectorResult(result); } - /// - /// расчет продолжительности операции - /// - /// - /// - /// - /// - protected static double CalcDeltaMinutes(DetectableTelemetry[] telemetry, int begin, int end) + result = null; + return false; + } + + protected virtual (int Begin, int End) RefineEdges(DetectableTelemetry[] telemetry, int begin, int end) + => (begin, end); + + protected virtual bool IsValidOperationDetectorResult(OperationDetectorResult operationDetectorResult) + => operationDetectorResult.Operation.DateEnd - operationDetectorResult.Operation.DateStart > TimeSpan.FromSeconds(3); + + protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation); + + protected virtual int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation) + => DetectBegin(telemetry, position, previousOperation) + ? IdReasonOfEnd_NotDetected + : IdReasonOfEnd_NotDetectBegin; + + private OperationDetectorResult MakeOperationDetectorResult( + int idTelemetry, + DetectableTelemetry[] telemetry, + int begin, + int end, + int idReasonOfEnd) + { + var operation = MakeDetectedOperation(idTelemetry, telemetry, begin, end); + + operation.ExtraData["IdReasonOfEnd"] = idReasonOfEnd; + + var result = new OperationDetectorResult { - var pBegin = telemetry[begin]; - var pEnd = telemetry[end]; - var result = (pEnd.DateTime - pBegin.DateTime).TotalMinutes; - return result; + TelemetryBegin = begin, + TelemetryEnd = end, + Operation = operation, + }; + + return result; + } + + private DetectedOperationDto MakeDetectedOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end) + { + var pBegin = telemetry[begin]; + var pEnd = telemetry[end]; + var (IdCategory, ExtraData) = GetSpecificInformation(telemetry, begin, end); + var operation = new DetectedOperationDto + { + IdCategory = IdCategory, + IdTelemetry = idTelemetry, + IdUserAtStart = pBegin.IdUser ?? -1, + DateStart = pBegin.DateTime, + DateEnd = pEnd.DateTime, + DepthStart = (double)pBegin.WellDepth, + DepthEnd = (double)pEnd.WellDepth, + ExtraData = ExtraData, + Value = CalcValue(telemetry, begin, end), + EnabledSubsystems = DetectEnabledSubsystems(telemetry, begin, end, ExtraData) + }; + + return operation; + } + + /// + /// Получение информации специфичной для конкретного детектора + /// IdCategory - одна из констант WellOperationCategory + /// ExtraData - дополнительная информация для отладки алгоритмов авто определения + /// + /// + protected abstract (int IdCategory, IDictionary ExtraData) GetSpecificInformation(DetectableTelemetry[] telemetry, int begin, int end); + + /// + /// Расчет ключевого параметра операции + /// + /// + /// + /// + /// + protected abstract double CalcValue(DetectableTelemetry[] telemetry, int begin, int end); + + /// + /// Определение включенных подсистем во время выполнения операции + /// + /// + /// + /// + /// + /// + private static int DetectEnabledSubsystems(DetectableTelemetry[] telemetry, int begin, int end, IDictionary extraData) + { + var enabledSubsystems = 0; + + if (extraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out var hasOscillation) + && hasOscillation is true) + enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoOscillation; + + for (var i = begin; i < end; i += 2) + { + var mode = telemetry[i].Mode; + + if(mode == 1) + enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoRotor; + + if (mode == 3) + enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSlide; + + if (mode == 2) + enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoConditionig; + + if (mode == 4) + enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSinking; + + if (mode == 5) + enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLifting; + + if (mode == 6) + enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLiftingWithConditionig; + + if (mode == 10) + enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoBlocknig; } - /// - /// часто используемый предикат для определения отсутствия изменения глубины ствола скважины - /// - /// - /// - /// - /// - protected static bool IsValidByWellDepthDoesNotChange(DetectableTelemetry[] telemetry, int begin, int end) - { - var pBegin = telemetry[begin]; - var pEnd = telemetry[end]; - if (Math.Abs((double)(pBegin.WellDepth - pEnd.WellDepth)) > 0.01) - return false; - return true; - } + return enabledSubsystems; + } - protected static bool IsValidByWellDepthIncreasing(DetectableTelemetry[] telemetry, int begin, int end) - { - var pBegin = telemetry[begin]; - var pEnd = telemetry[end]; - if (pBegin.WellDepth >= pEnd.WellDepth) - return false; - return true; - } - - protected static double CalcRop(DetectableTelemetry[] telemetry, int begin, int end) - { - var pBegin = telemetry[begin]; - var pEnd = telemetry[end]; - var result = (double)(pEnd.WellDepth - pBegin.WellDepth) / (pEnd.DateTime - pBegin.DateTime).TotalHours; - return result; - } - - /// - /// Расчет статистики по массиву данных за интервал - /// - /// - /// - /// - /// - /// - protected static (double min, double max, double sum, int count) CalcStat( - DetectableTelemetry[] telemetry, - Func getter, - int begin, - int count) - { - var sum = 0d; - var min = double.MaxValue; - var max = double.MinValue; - var end = begin + count; - end = end < telemetry.Length ? end : telemetry.Length; - - for (var i = begin; i < end; i++) - { - var item = telemetry[i]; - var itemValue = getter(item); - if (min > itemValue) - min = itemValue; - if (max < itemValue) - max = itemValue; - sum += itemValue; - } - - return (min, max, sum, end - begin); - } - - /// - /// Максимальное отклонение от среднего за интервал - /// - /// - /// - /// - /// - /// - protected static double CalcMaxDeviation( - DetectableTelemetry[] telemetry, - Func getter, - int begin, - int count) - { - var stat = CalcStat(telemetry, getter, begin, count); - var avg = stat.sum / stat.count; - var dev1 = avg - stat.min; - var dev2 = stat.max - avg; - var dev = dev1 > dev2 ? dev1 : dev2; - return dev; - } - - /// - /// Определяет наличие разброса значений в интервале большего указанного значения. - /// - /// - /// - /// - /// - /// - /// - protected static bool ContainsDeviation( - DetectableTelemetry[] telemetry, - Func getter, - int begin, - int count, - double deviation) - { - var min = double.MaxValue; - var max = double.MinValue; - var end = begin + count; - end = end < telemetry.Length ? end : telemetry.Length; - - for (var i = begin; i < end; i++) - { - var item = telemetry[i]; - var itemValue = getter(item); - if (min > itemValue) - min = itemValue; - if (max < itemValue) - max = itemValue; - if (max - min > deviation) - return true; - } + /// + /// расчет продолжительности операции + /// + /// + /// + /// + /// + protected static double CalcDeltaMinutes(DetectableTelemetry[] telemetry, int begin, int end) + { + var pBegin = telemetry[begin]; + var pEnd = telemetry[end]; + var result = (pEnd.DateTime - pBegin.DateTime).TotalMinutes; + return result; + } + /// + /// часто используемый предикат для определения отсутствия изменения глубины ствола скважины + /// + /// + /// + /// + /// + protected static bool IsValidByWellDepthDoesNotChange(DetectableTelemetry[] telemetry, int begin, int end) + { + var pBegin = telemetry[begin]; + var pEnd = telemetry[end]; + if (Math.Abs((double)(pBegin.WellDepth - pEnd.WellDepth)) > 0.01) return false; - } - - /// - /// Определяет наличие разброса значений в интервале большего указанного значения. По нескольким значениям из интервала. - /// - /// - /// - /// - /// - /// - /// - protected static bool ContainsDeviationApprox( - DetectableTelemetry[] telemetry, - Func getter, - int begin, - int count, - double deviation) - { - var min = double.MaxValue; - var max = double.MinValue; - var end = begin + count; - end = end < telemetry.Length ? end : telemetry.Length; - var step = count > 15 ? count / 5 : count > 3 ? 3 : 1; - for (var i = begin; i < end; i += step) - { - var item = telemetry[i]; - var itemValue = getter(item); - if (min > itemValue) - min = itemValue; - if (max < itemValue) - max = itemValue; - if (max - min > deviation) - return true; - } + return true; + } + protected static bool IsValidByWellDepthIncreasing(DetectableTelemetry[] telemetry, int begin, int end) + { + var pBegin = telemetry[begin]; + var pEnd = telemetry[end]; + if (pBegin.WellDepth >= pEnd.WellDepth) return false; - } + return true; + } - protected static bool DeviatesFromBegin( - DetectableTelemetry[] telemetry, - Func getter, - int begin, - int count, - double deviation) + protected static double CalcRop(DetectableTelemetry[] telemetry, int begin, int end) + { + var pBegin = telemetry[begin]; + var pEnd = telemetry[end]; + var result = (double)(pEnd.WellDepth - pBegin.WellDepth) / (pEnd.DateTime - pBegin.DateTime).TotalHours; + return result; + } + + /// + /// Расчет статистики по массиву данных за интервал + /// + /// + /// + /// + /// + /// + protected static (double min, double max, double sum, int count) CalcStat( + DetectableTelemetry[] telemetry, + Func getter, + int begin, + int count) + { + var sum = 0d; + var min = double.MaxValue; + var max = double.MinValue; + var end = begin + count; + end = end < telemetry.Length ? end : telemetry.Length; + + for (var i = begin; i < end; i++) { - var beginPointValue = getter(telemetry[begin]); - var end = begin + count; - end = end < telemetry.Length ? end : telemetry.Length; - var step = count > 15 ? count / 5 : count > 3 ? 3 : 1; - for (var i = begin; i < end; i += step) - { - var item = telemetry[i]; - var itemValue = getter(item); - if (Math.Abs(beginPointValue - itemValue) > deviation) - return true; - } - - return false; + var item = telemetry[i]; + var itemValue = getter(item); + if (min > itemValue) + min = itemValue; + if (max < itemValue) + max = itemValue; + sum += itemValue; } - protected static bool RisesFromBegin( - DetectableTelemetry[] telemetry, - Func getter, - int begin, - int count, - double deviation) + return (min, max, sum, end - begin); + } + + /// + /// Максимальное отклонение от среднего за интервал + /// + /// + /// + /// + /// + /// + protected static double CalcMaxDeviation( + DetectableTelemetry[] telemetry, + Func getter, + int begin, + int count) + { + var stat = CalcStat(telemetry, getter, begin, count); + var avg = stat.sum / stat.count; + var dev1 = avg - stat.min; + var dev2 = stat.max - avg; + var dev = dev1 > dev2 ? dev1 : dev2; + return dev; + } + + /// + /// Определяет наличие разброса значений в интервале большего указанного значения. + /// + /// + /// + /// + /// + /// + /// + protected static bool ContainsDeviation( + DetectableTelemetry[] telemetry, + Func getter, + int begin, + int count, + double deviation) + { + var min = double.MaxValue; + var max = double.MinValue; + var end = begin + count; + end = end < telemetry.Length ? end : telemetry.Length; + + for (var i = begin; i < end; i++) { - var beginPointValue = getter(telemetry[begin]); - var end = begin + count; - end = end < telemetry.Length ? end : telemetry.Length; - var step = count > 15 ? count / 5 : count > 3 ? 3 : 1; - for (var i = begin; i < end; i += step) - { - var item = telemetry[i]; - var itemValue = getter(item); - if (itemValue - beginPointValue > deviation) - return true; - } - - return false; + var item = telemetry[i]; + var itemValue = getter(item); + if (min > itemValue) + min = itemValue; + if (max < itemValue) + max = itemValue; + if (max - min > deviation) + return true; } + + return false; + } + + /// + /// Определяет наличие разброса значений в интервале большего указанного значения. По нескольким значениям из интервала. + /// + /// + /// + /// + /// + /// + /// + protected static bool ContainsDeviationApprox( + DetectableTelemetry[] telemetry, + Func getter, + int begin, + int count, + double deviation) + { + var min = double.MaxValue; + var max = double.MinValue; + var end = begin + count; + end = end < telemetry.Length ? end : telemetry.Length; + var step = count > 15 ? count / 5 : count > 3 ? 3 : 1; + for (var i = begin; i < end; i += step) + { + var item = telemetry[i]; + var itemValue = getter(item); + if (min > itemValue) + min = itemValue; + if (max < itemValue) + max = itemValue; + if (max - min > deviation) + return true; + } + + return false; + } + + protected static bool DeviatesFromBegin( + DetectableTelemetry[] telemetry, + Func getter, + int begin, + int count, + double deviation) + { + var beginPointValue = getter(telemetry[begin]); + var end = begin + count; + end = end < telemetry.Length ? end : telemetry.Length; + var step = count > 15 ? count / 5 : count > 3 ? 3 : 1; + for (var i = begin; i < end; i += step) + { + var item = telemetry[i]; + var itemValue = getter(item); + if (Math.Abs(beginPointValue - itemValue) > deviation) + return true; + } + + return false; + } + + protected static bool RisesFromBegin( + DetectableTelemetry[] telemetry, + Func getter, + int begin, + int count, + double deviation) + { + var beginPointValue = getter(telemetry[begin]); + var end = begin + count; + end = end < telemetry.Length ? end : telemetry.Length; + var step = count > 15 ? count / 5 : count > 3 ? 3 : 1; + for (var i = begin; i < end; i += step) + { + var item = telemetry[i]; + var itemValue = getter(item); + if (itemValue - beginPointValue > deviation) + return true; + } + + return false; } } - diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorConditioning.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorConditioning.cs index 1a5142e3..6ef413ef 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorConditioning.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorConditioning.cs @@ -41,9 +41,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors if (currentPoint.RotorSpeed <=8) return IdReasonOfEnd_RotorSpeedIsHi; if ((currentPoint.WellDepth - currentPoint.BitDepth) < 0.03d) - return IdReasonOfEnd_DeltaWellDepthAndBithDepthIsLo; + return IdReasonOfEnd_DeltaWellDepthAndBitDepthIsLo; if (currentPoint.BitDepth < 150) - return IdReasonOfEnd_BithDepthIsLo; + return IdReasonOfEnd_BitDepthIsLo; return IdReasonOfEnd_NotDetected; } diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs index 24b69219..f300f1c5 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs @@ -48,11 +48,11 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors if (currentPoint.Pressure < 10) return IdReasonOfEnd_PressureIsLo; if ((currentPoint.WellDepth - currentPoint.BitDepth) < 0.01d) - return IdReasonOfEnd_DeltaWellDepthAndBithDepthIsLo; + return IdReasonOfEnd_DeltaWellDepthAndBitDepthIsLo; if (currentPoint.RotorSpeed > 8) return IdReasonOfEnd_RotorSpeedIsHi; if (currentPoint.BitDepth < 150) - return IdReasonOfEnd_BithDepthIsLo; + return IdReasonOfEnd_BitDepthIsLo; return IdReasonOfEnd_NotDetected; } diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs index 47208183..af2e3db0 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs @@ -50,7 +50,7 @@ public class DetectorSlipsTime : DetectorAbstract var deltaBitDepth = Math.Abs(currentPoint.BitDepth - prevPoint.BitDepth); if (deltaBitDepth > 0.001d && currentPoint.AxialLoad < currentPoint.HookWeight) - return IdReasonOfEnd_ChangeBithDepthAndAxiloadLessHookWeight; + return IdReasonOfEnd_ChangeBitDepthAndAxiLoadLessHookWeight; return IdReasonOfEnd_NotDetected; } diff --git a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs index e4ae3eb4..93a8b9c3 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs @@ -61,8 +61,8 @@ public class WorkOperationDetection : Work if (lastDetectedOperations.TryGetValue(idTelemetry, out var lastDetectedOperation)) dateBegin = lastDetectedOperation.DateEnd; - if (CacheOfStartDatesByTelemetryId.TryGetValue(idTelemetry, out var dateBeginFromCahce)) - dateBegin = dateBeginFromCahce; + if (CacheOfStartDatesByTelemetryId.TryGetValue(idTelemetry, out var dateBeginFromCache)) + dateBegin = dateBeginFromCache; onProgressCallback.Invoke($"Start detecting telemetry: {idTelemetry} from {dateBegin}", i / idsTelemetry.Length); diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index 3dbb2e58..31bf9a3f 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -13,299 +13,298 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace AsbCloudInfrastructure.Services.SAUB +namespace AsbCloudInfrastructure.Services.SAUB; + +public abstract class TelemetryDataBaseService : ITelemetryDataService + where TDto : AsbCloudApp.Data.ITelemetryData + where TEntity : class, AsbCloudDb.Model.ITelemetryData { - public abstract class TelemetryDataBaseService : ITelemetryDataService - where TDto : AsbCloudApp.Data.ITelemetryData - where TEntity : class, AsbCloudDb.Model.ITelemetryData + protected readonly IAsbCloudDbContext db; + protected readonly ITelemetryService telemetryService; + protected readonly ITelemetryDataCache telemetryDataCache; + + protected TelemetryDataBaseService( + IAsbCloudDbContext db, + ITelemetryService telemetryService, + ITelemetryDataCache telemetryDataCache) { - protected readonly IAsbCloudDbContext db; - protected readonly ITelemetryService telemetryService; - protected readonly ITelemetryDataCache telemetryDataCache; + this.db = db; + this.telemetryService = telemetryService; + this.telemetryDataCache = telemetryDataCache; + } - protected TelemetryDataBaseService( - IAsbCloudDbContext db, - ITelemetryService telemetryService, - ITelemetryDataCache telemetryDataCache) + /// + public virtual async Task UpdateDataAsync(string uid, IEnumerable dtos, CancellationToken token = default) + { + if (dtos == default || !dtos.Any()) + return 0; + + var dtosList = dtos.OrderBy(d => d.DateTime).ToList(); + + var dtoMinDate = dtosList.First().DateTime; + var dtoMaxDate = dtosList.Last().DateTime; + + if (dtosList.Count > 1) { - this.db = db; - this.telemetryService = telemetryService; - this.telemetryDataCache = telemetryDataCache; + var duplicates = new List(8); + for (int i = 1; i < dtosList.Count; i++) + if (dtosList[i].DateTime - dtosList[i - 1].DateTime < TimeSpan.FromMilliseconds(100)) + duplicates.Add(dtosList[i - 1]); + foreach (var duplicate in duplicates) + dtosList.Remove(duplicate); } - /// - public virtual async Task UpdateDataAsync(string uid, IEnumerable dtos, CancellationToken token = default) + var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid); + var timeZone = telemetryService.GetTimezone(telemetry.Id); + + telemetryDataCache.AddRange(telemetry.Id, dtos); + + var entities = dtosList.Select(dto => { - if (dtos == default || !dtos.Any()) - return 0; + var entity = Convert(dto, timeZone.Hours); + entity.IdTelemetry = telemetry.Id; + return entity; + }); - var dtosList = dtos.OrderBy(d => d.DateTime).ToList(); - - var dtoMinDate = dtosList.First().DateTime; - var dtoMaxDate = dtosList.Last().DateTime; - - if (dtosList.Count > 1) - { - var duplicates = new List(8); - for (int i = 1; i < dtosList.Count; i++) - if (dtosList[i].DateTime - dtosList[i - 1].DateTime < TimeSpan.FromMilliseconds(100)) - duplicates.Add(dtosList[i - 1]); - foreach (var duplicate in duplicates) - dtosList.Remove(duplicate); - } - - var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid); - var timezone = telemetryService.GetTimezone(telemetry.Id); - - telemetryDataCache.AddRange(telemetry.Id, dtos); - - var entities = dtosList.Select(dto => - { - var entity = Convert(dto, timezone.Hours); - entity.IdTelemetry = telemetry.Id; - return entity; - }); - - var stopwatch = Stopwatch.StartNew(); - var dbSet = db.Set(); - try - { - return await db.Database.ExecInsertOrUpdateAsync(dbSet, entities, token).ConfigureAwait(false); - } - catch (Exception ex) - { - stopwatch.Stop(); - Trace.WriteLine($"Fail to save data telemetry " + - $"uid: {uid}, " + - $"idTelemetry {telemetry.Id}, " + - $"count: {entities.Count()}, " + - $"dataDate: {entities.FirstOrDefault()?.DateTime}, " + - $"dbSaveDurationTime:{stopwatch.ElapsedMilliseconds}ms. " + - $"Message: {ex.Message}"); - return 0; - } + var stopwatch = Stopwatch.StartNew(); + var dbSet = db.Set(); + try + { + return await db.Database.ExecInsertOrUpdateAsync(dbSet, entities, token).ConfigureAwait(false); } - - /// - public virtual async Task> GetByWellAsync(int idWell, - DateTime dateBegin = default, double intervalSec = 600d, - int approxPointsCount = 1024, CancellationToken token = default) + catch (Exception ex) { - var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); - if (telemetry is null) - return Enumerable.Empty(); - - var timezone = telemetryService.GetTimezone(telemetry.Id); - - var filterByDateEnd = dateBegin != default; - DateTimeOffset dateBeginUtc; - if (dateBegin == default) - { - var dateRange = telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id); - dateBeginUtc = (dateRange?.To.ToUniversalTime() ?? DateTimeOffset.UtcNow) - .AddSeconds(-intervalSec); - } - else - { - dateBeginUtc = dateBegin.ToUtcDateTimeOffset(timezone.Hours); - } - - var cacheData = telemetryDataCache.GetOrDefault(telemetry.Id, dateBeginUtc.ToRemoteDateTime(timezone.Hours), intervalSec, approxPointsCount); - if (cacheData is not null) - return cacheData; - - var dateEnd = dateBeginUtc.AddSeconds(intervalSec); - var dbSet = db.Set(); - - var query = dbSet - .Where(d => d.IdTelemetry == telemetry.Id - && d.DateTime >= dateBeginUtc); - - if (filterByDateEnd) - query = query.Where(d => d.DateTime <= dateEnd); - - var fullDataCount = await query.CountAsync(token) - .ConfigureAwait(false); - - if (fullDataCount == 0) - return Enumerable.Empty(); - - if (fullDataCount > 1.75 * approxPointsCount) - { - var m = (int)Math.Round(1d * fullDataCount / approxPointsCount); - if (m > 1) - query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0); - } - - var entities = await query - .AsNoTracking() - .ToArrayAsync(token); - - var dtos = entities.Select(e => Convert(e, timezone.Hours)); - - return dtos; - } - - /// - public virtual async Task> GetByWellAsync(int idWell, TelemetryDataRequest request, CancellationToken token) - { - var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); - if (telemetry is null) - return Enumerable.Empty(); - - return await GetByTelemetryAsync(telemetry.Id, request, token); - } - - public async Task> GetByTelemetryAsync(int idTelemetry, TelemetryDataRequest request, CancellationToken token) - { - var timezone = telemetryService.GetTimezone(idTelemetry); - - var cache = telemetryDataCache.GetOrDefault(idTelemetry, request); - - if (cache is not null) - return cache; - - var query = BuildQuery(idTelemetry, request); - - var entities = await query - .AsNoTracking() - .ToArrayAsync(token); - - var dtos = entities.Select(e => Convert(e, timezone.Hours)); - - return dtos; - } - - private IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request) - { - var dbSet = db.Set(); - - var query = dbSet - .Where(d => d.IdTelemetry == idTelemetry); - - if (request.GeDate.HasValue) - { - var geDate = request.GeDate.Value.UtcDateTime; - query = query.Where(d => d.DateTime >= geDate); - } - - if (request.LeDate.HasValue) - { - var leDate = request.LeDate.Value.UtcDateTime; - query = query.Where(d => d.DateTime <= leDate); - } - - if (request.Divider > 1) - query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0); - - switch (request.Order) - { - case 1:// Поздние вперед - query = query - .OrderByDescending(d => d.DateTime) - .Skip(request.Skip) - .Take(request.Take) - .OrderBy(d => d.DateTime); - break; - default:// Ранние вперед - query = query - .OrderBy(d => d.DateTime) - .Skip(request.Skip) - .Take(request.Take); - break; - } - - return query; - } - - private IQueryable BuildQuery(TelemetryPartDeleteRequest request) - { - var query = db.Set() - .Where(o => o.IdTelemetry == request.IdTelemetry); - - if (request.GeDate is not null) - { - var geDate = request.GeDate.Value.ToUniversalTime(); - query = query.Where(o => o.DateTime <= geDate); - } - - if (request.LeDate is not null) - { - var leDate = request.LeDate.Value.ToUniversalTime(); - query = query.Where(o => o.DateTime >= leDate); - } - - return query; - } - - /// - public async Task GetRangeAsync(int idWell, DateTimeOffset geDate, DateTimeOffset? leDate, CancellationToken token) - { - var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell) - ?? throw new ArgumentInvalidException(nameof(idWell), $"По скважине id:{idWell} нет телеметрии"); - - if ((DateTimeOffset.UtcNow - geDate) < TimeSpan.FromHours(12)) - { - // пробуем обойтись кэшем - var cachedRange = telemetryDataCache.GetOrDefaultCachedDataDateRange(telemetry.Id); - if (cachedRange is not null) - { - var datesRange = new DatesRangeDto { From = cachedRange.From, To = cachedRange.To }; - if (geDate >= cachedRange.From) - datesRange.From = geDate.ToOffset(cachedRange.From.Offset); - - if (leDate.HasValue && leDate <= cachedRange.To) - datesRange.To = leDate.Value.ToOffset(cachedRange.To.Offset); - - return datesRange; - } - } - - var query = db.Set() - .Where(entity => entity.IdTelemetry == telemetry.Id) - .Where(entity => entity.DateTime >= geDate.ToUniversalTime()); - - if (leDate.HasValue) - query = query.Where(entity => entity.DateTime <= leDate.Value.ToUniversalTime()); - - var groupQuery = query - .GroupBy(entity => entity.IdTelemetry) - .Select(group => new - { - MinDate = group.Min(entity => entity.DateTime), - MaxDate = group.Max(entity => entity.DateTime), - }); - - var result = await groupQuery.FirstOrDefaultAsync(token); - if (result is null) - return null; - - var range = new DatesRangeDto - { - From = result.MinDate.ToOffset(telemetry.TimeZone!.Offset), - To = result.MaxDate.ToOffset(telemetry.TimeZone!.Offset), - }; - return range; - } - - public DatesRangeDto? GetRange(int idWell) - { - var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); - if (telemetry is null) - return default; - - return telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id); - } - - protected abstract TDto Convert(TEntity src, double timezoneOffset); - - protected abstract TEntity Convert(TDto src, double timezoneOffset); - - public async Task DeleteAsync(TelemetryPartDeleteRequest request, CancellationToken token) - { - var query = BuildQuery(request); - db.Set().RemoveRange(query); - return await db.SaveChangesAsync(token); + stopwatch.Stop(); + Trace.WriteLine($"Fail to save data telemetry " + + $"uid: {uid}, " + + $"idTelemetry {telemetry.Id}, " + + $"count: {entities.Count()}, " + + $"dataDate: {entities.FirstOrDefault()?.DateTime}, " + + $"dbSaveDurationTime:{stopwatch.ElapsedMilliseconds}ms. " + + $"Message: {ex.Message}"); + return 0; } } + + /// + public virtual async Task> GetByWellAsync(int idWell, + DateTime dateBegin = default, double intervalSec = 600d, + int approxPointsCount = 1024, CancellationToken token = default) + { + var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); + if (telemetry is null) + return Enumerable.Empty(); + + var timezone = telemetryService.GetTimezone(telemetry.Id); + + var filterByDateEnd = dateBegin != default; + DateTimeOffset dateBeginUtc; + if (dateBegin == default) + { + var dateRange = telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id); + dateBeginUtc = (dateRange?.To.ToUniversalTime() ?? DateTimeOffset.UtcNow) + .AddSeconds(-intervalSec); + } + else + { + dateBeginUtc = dateBegin.ToUtcDateTimeOffset(timezone.Hours); + } + + var cacheData = telemetryDataCache.GetOrDefault(telemetry.Id, dateBeginUtc.ToRemoteDateTime(timezone.Hours), intervalSec, approxPointsCount); + if (cacheData is not null) + return cacheData; + + var dateEnd = dateBeginUtc.AddSeconds(intervalSec); + var dbSet = db.Set(); + + var query = dbSet + .Where(d => d.IdTelemetry == telemetry.Id + && d.DateTime >= dateBeginUtc); + + if (filterByDateEnd) + query = query.Where(d => d.DateTime <= dateEnd); + + var fullDataCount = await query.CountAsync(token) + .ConfigureAwait(false); + + if (fullDataCount == 0) + return Enumerable.Empty(); + + if (fullDataCount > 1.75 * approxPointsCount) + { + var m = (int)Math.Round(1d * fullDataCount / approxPointsCount); + if (m > 1) + query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0); + } + + var entities = await query + .AsNoTracking() + .ToArrayAsync(token); + + var dtos = entities.Select(e => Convert(e, timezone.Hours)); + + return dtos; + } + + /// + public virtual async Task> GetByWellAsync(int idWell, TelemetryDataRequest request, CancellationToken token) + { + var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); + if (telemetry is null) + return Enumerable.Empty(); + + return await GetByTelemetryAsync(telemetry.Id, request, token); + } + + public async Task> GetByTelemetryAsync(int idTelemetry, TelemetryDataRequest request, CancellationToken token) + { + var timeZone = telemetryService.GetTimezone(idTelemetry); + + var cache = telemetryDataCache.GetOrDefault(idTelemetry, request); + + if (cache is not null) + return cache; + + var query = BuildQuery(idTelemetry, request); + + var entities = await query + .AsNoTracking() + .ToArrayAsync(token); + + var dtos = entities.Select(e => Convert(e, timeZone.Hours)); + + return dtos; + } + + private IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request) + { + var dbSet = db.Set(); + + var query = dbSet + .Where(d => d.IdTelemetry == idTelemetry); + + if (request.GeDate.HasValue) + { + var geDate = request.GeDate.Value.UtcDateTime; + query = query.Where(d => d.DateTime >= geDate); + } + + if (request.LeDate.HasValue) + { + var leDate = request.LeDate.Value.UtcDateTime; + query = query.Where(d => d.DateTime <= leDate); + } + + if (request.Divider > 1) + query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0); + + switch (request.Order) + { + case 1:// Поздние вперед + query = query + .OrderByDescending(d => d.DateTime) + .Skip(request.Skip) + .Take(request.Take) + .OrderBy(d => d.DateTime); + break; + default:// Ранние вперед + query = query + .OrderBy(d => d.DateTime) + .Skip(request.Skip) + .Take(request.Take); + break; + } + + return query; + } + + private IQueryable BuildQuery(TelemetryPartDeleteRequest request) + { + var query = db.Set() + .Where(o => o.IdTelemetry == request.IdTelemetry); + + if (request.GeDate is not null) + { + var geDate = request.GeDate.Value.ToUniversalTime(); + query = query.Where(o => o.DateTime <= geDate); + } + + if (request.LeDate is not null) + { + var leDate = request.LeDate.Value.ToUniversalTime(); + query = query.Where(o => o.DateTime >= leDate); + } + + return query; + } + + /// + public async Task GetRangeAsync(int idWell, DateTimeOffset geDate, DateTimeOffset? leDate, CancellationToken token) + { + var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell) + ?? throw new ArgumentInvalidException(nameof(idWell), $"По скважине id:{idWell} нет телеметрии"); + + if ((DateTimeOffset.UtcNow - geDate) < TimeSpan.FromHours(12)) + { + // пробуем обойтись кэшем + var cachedRange = telemetryDataCache.GetOrDefaultCachedDataDateRange(telemetry.Id); + if (cachedRange is not null) + { + var datesRange = new DatesRangeDto { From = cachedRange.From, To = cachedRange.To }; + if (geDate >= cachedRange.From) + datesRange.From = geDate.ToOffset(cachedRange.From.Offset); + + if (leDate.HasValue && leDate <= cachedRange.To) + datesRange.To = leDate.Value.ToOffset(cachedRange.To.Offset); + + return datesRange; + } + } + + var query = db.Set() + .Where(entity => entity.IdTelemetry == telemetry.Id) + .Where(entity => entity.DateTime >= geDate.ToUniversalTime()); + + if (leDate.HasValue) + query = query.Where(entity => entity.DateTime <= leDate.Value.ToUniversalTime()); + + var groupQuery = query + .GroupBy(entity => entity.IdTelemetry) + .Select(group => new + { + MinDate = group.Min(entity => entity.DateTime), + MaxDate = group.Max(entity => entity.DateTime), + }); + + var result = await groupQuery.FirstOrDefaultAsync(token); + if (result is null) + return null; + + var range = new DatesRangeDto + { + From = result.MinDate.ToOffset(telemetry.TimeZone!.Offset), + To = result.MaxDate.ToOffset(telemetry.TimeZone!.Offset), + }; + return range; + } + + public DatesRangeDto? GetRange(int idWell) + { + var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); + if (telemetry is null) + return default; + + return telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id); + } + + protected abstract TDto Convert(TEntity src, double timeZoneOffset); + + protected abstract TEntity Convert(TDto src, double timeZoneOffset); + + public async Task DeleteAsync(TelemetryPartDeleteRequest request, CancellationToken token) + { + var query = BuildQuery(request); + db.Set().RemoveRange(query); + return await db.SaveChangesAsync(token); + } } diff --git a/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs b/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs index 5011c8d3..d4171f25 100644 --- a/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs @@ -111,7 +111,7 @@ namespace AsbCloudWebApi.Controllers.SAUB } /// - /// Получить список автоопределенных операций для редактирования + /// Получить список авто определенных операций для редактирования /// /// /// @@ -136,7 +136,7 @@ namespace AsbCloudWebApi.Controllers.SAUB } /// - /// Получить статистику по автоопределенным операциям + /// Получить статистику по авто определенным операциям /// /// ///