diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index bcde8237..1139dd3a 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -180,7 +180,7 @@ namespace AsbCloudInfrastructure services.AddTransient< IChangeLogRepository, - ProcessMapPlanBaseRepository>(); + ProcessMapPlanBaseRepository>(); services.AddTransient(); diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectableTelemetry.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectableTelemetry.cs index aeb18fe2..50d6dd14 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectableTelemetry.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectableTelemetry.cs @@ -4,14 +4,53 @@ namespace AsbCloudInfrastructure.Services.DetectOperations; public class DetectableTelemetry { + /// + /// Дата начала + /// public DateTimeOffset DateTime { get; set; } + + /// + /// Режим + /// public int Mode { get; set; } + + /// + /// Ключ пользователя + /// public int? IdUser { get; set; } + + /// + /// Глубина забоя + /// public float WellDepth { get; set; } + + /// + /// Давление + /// public float Pressure { get; set; } + + /// + /// Вес на крюке + /// public float HookWeight { get; set; } + + /// + /// Положение талевого блока + /// public float BlockPosition { get; set; } + + /// + /// Глубина долота + /// public float BitDepth { get; set; } + + /// + /// Обороты ротора + /// public float RotorSpeed { get; set; } + + /// + /// Осевая нагрузка + /// public float AxialLoad { get; set; } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs index 9059d6bb..31f2c821 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs @@ -26,14 +26,15 @@ public class DetectedOperationService : IDetectedOperationService private static readonly DetectorAbstract[] detectors = { new DetectorDrilling(), - new DetectorSlipsTime() + new DetectorSlipsTime(), + new DetectorFlashing(), }; - + public DetectedOperationService( IDetectedOperationRepository operationRepository, IWellOperationCategoryRepository wellOperationCategoryRepository, IWellService wellService, - IRepositoryWellRelated operationValueRepository, + IRepositoryWellRelated operationValueRepository, IScheduleRepository scheduleRepository, ITelemetryDataSaubService telemetryDataSaubService) { @@ -87,9 +88,9 @@ public class DetectedOperationService : IDetectedOperationService if (well?.IdTelemetry is null) return Enumerable.Empty(); - var request = new DetectedOperationByTelemetryRequest() - { - IdTelemetry = well.IdTelemetry.Value + var request = new DetectedOperationByTelemetryRequest() + { + IdTelemetry = well.IdTelemetry.Value }; var operations = await operationRepository.Get(request, token); @@ -112,7 +113,7 @@ public class DetectedOperationService : IDetectedOperationService if (!operations.Any()) return Enumerable.Empty(); - + var dtos = operations .GroupBy(o => (o.IdCategory, o.OperationCategory.Name)) .OrderBy(g => g.Key) @@ -136,39 +137,39 @@ public class DetectedOperationService : IDetectedOperationService public async Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, 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; - + while (true) { var request = new TelemetryDataRequest { GeDate = beginDate, Take = take, - Order = 0 + Order = 0 }; - + var detectableTelemetries = (await telemetryDataSaubService.GetByTelemetryAsync(idTelemetry, request, token)) .Where(t => t.BlockPosition >= 0) .Select(t => new DetectableTelemetry - { - DateTime = t.DateTime, - 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) + { + DateTime = t.DateTime, + 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; @@ -180,14 +181,14 @@ public class DetectedOperationService : IDetectedOperationService { 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; } @@ -264,7 +265,7 @@ public class DetectedOperationService : IDetectedOperationService dto.OperationValue = operationValues.FirstOrDefault(v => v.IdOperationCategory == dto.IdCategory && v.DepthStart <= dto.DepthStart && v.DepthEnd > dto.DepthStart); - + var dateStart = dto.DateStart; var timeStart = new TimeDto(dateStart); var driller = schedules.FirstOrDefault(s => diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs index 559e1dc4..44b47554 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs @@ -32,6 +32,10 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors 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) { diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs index ac93fd45..e6d8a0dd 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs @@ -1,59 +1,67 @@ -// using AsbCloudDb.Model; -// -// namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors -// { -// -// /// -// /// Промывка -// /// -// internal class DetectorFlashing : DetectorAbstract -// { -// public DetectorFlashing() -// : base(WellOperationCategory.IdFlashing) -// { } -// -// protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end) -// => CalcDeltaMinutes(telemetry, begin, end); -// -// protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation) -// { -// if (!((previousOperation?.IdCategory == WellOperationCategory.IdRotor) || -// (previousOperation?.IdCategory == WellOperationCategory.IdSlide))) -// return false; -// -// var point0 = telemetry[position]; -// var delta = point0.WellDepth - point0.BitDepth; -// if (delta > 0.05d) -// return false; -// -// if (point0.Pressure < 15) -// return false; -// -// if (point0.BlockPosition < 3) -// return false; -// -// if (ContainsDeviationApprox(telemetry, t => t.WellDepth, position, 150, 0.0001)) -// return false; -// -// return true; -// } -// -// protected override int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation) -// { -// var point0 = telemetry[position]; -// var delta = point0.WellDepth - point0.BitDepth; -// if ((delta > 0.03d ) -// && (point0.Pressure > 15) -// && ContainsDeviationApprox(telemetry, t=>t.BlockPosition, position, 60, 0.03)) -// return IdReasonOfEnd_Custom1; -// -// return IdReasonOfEnd_NotDetected; -// } -// -// protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end) -// => IsValidByWellDepthDoesNotChange(telemetry, begin, end); -// } -// -// -// } -// +using AsbCloudApp.Data.DetectedOperation; +using AsbCloudDb.Model; +using System; +using System.Collections.Generic; + +namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors +{ + + /// + /// Промывка + /// + public class DetectorFlashing : DetectorAbstract + { + + protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end) + => CalcDeltaMinutes(telemetry, begin, end); + + protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation) + { + + var currentPoint = telemetry[position]; + if (currentPoint.Pressure < 10) + return false; + + var delta = currentPoint.WellDepth - currentPoint.BitDepth; + if (delta < 0.03d) + return false; + + if (currentPoint.RotorSpeed > 8) + return false; + + var nextIndexPoint = telemetry.Length <= position ? position : position + 1; + var nextPoint = telemetry[nextIndexPoint]; + if (Math.Abs(currentPoint.WellDepth - nextPoint.WellDepth) > 0) + return false; + + if (currentPoint.BitDepth < 150) + return false; + + return true; + + } + + protected override int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation) + { + var currentPoint = telemetry[position]; + + if (currentPoint.Pressure < 10) + return IdReasonOfEnd_PressureIsLo; + if ((currentPoint.WellDepth - currentPoint.BitDepth) < 0.03d) + return IdReasonOfEnd_DeltaWellDepthAndBithDepthIsLo; + if (currentPoint.RotorSpeed > 8) + return IdReasonOfEnd_RotorSpeedIsHi; + if (currentPoint.BitDepth < 150) + return IdReasonOfEnd_BithDepthIsLo; + return IdReasonOfEnd_NotDetected; + } + + protected override (int IdCategory, IDictionary ExtraData) GetSpecificInformation(DetectableTelemetry[] telemetry, + int begin, + int end) + { + return (WellOperationCategory.IdFlashing, new Dictionary()); + } + } +} + diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Specifications/Промывка.md b/AsbCloudInfrastructure/Services/DetectOperations/Specifications/Промывка.md index 9a57a784..760d28cb 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Specifications/Промывка.md +++ b/AsbCloudInfrastructure/Services/DetectOperations/Specifications/Промывка.md @@ -2,25 +2,26 @@ ## Описание -Промывка – операция, во время которой после добуривания очередной трубы происходит снижение осевой нагрузки и дифференциального давления, талевый блок остается условно неподвижным. +Промывка – операция, во время которой давление условно постоянное, а вращение колонны отсутствует, талевый блок при этом может быть как в движении, так и статичным. -Проработка перед наращиванием определяется как время между: -- окончанием операции бурения (ротор/ слайд/ ручное бурение) -- началом операции проработки/ шаблонировки перед наращивании +Промывка определяется как время между: +- окончанием операции бурения или выходом на режим буровых насосов (рост давления) +- началом операции проработки/шаблонировки перед наращиванием или остановкой буровых насосов (снижение давления). ## Метод определения Признак начала операции = - ( предыдущая операция == бурение в роторе или слайде) - ( расстояние от долота до забоя < 0,05м ) И - ( давление > 15 атм ) И - ( положение блока > 3м ) И - ( глубина забоя изменяется менее чем на 0,0001м в течении 150 сек) - + ( давление >= 10 атм ) И + ( обороты ротора <= 8 об/мин) И + ( расстояние от долота до забоя >= 0.03 м) И + ( глубина забоя не изменяется) И + ( глубина долота >= 150 м); + Признак окончания операции = - ( расстояние от долота до забоя > 0.03м ) И - ( давление > 15 атм ) И - ( высота блока изменяется больше чем на 0.03м в течении 60 сек с начала операции); + ( давление < 10 атм ) ИЛИ + ( расстояние от долота до забоя < 0.03 м ) ИЛИ + ( обороты ротора > 8 об/мин) ИЛИ + ( глубина долота < 150 м); ## Ключевой параметр diff --git a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs index f562e744..d001471e 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs @@ -44,7 +44,7 @@ public class WorkOperationDetection: Work var beginDate = lastDetectedDates.TryGetValue(telemetryId, out var date) ? date : (DateTimeOffset?)null; - onProgressCallback($"Start detecting telemetry: {telemetryId} from {beginDate}", i++ / telemetryIds.Length); + onProgressCallback($"Start detecting telemetry: {telemetryId} from {beginDate}", i / telemetryIds.Length); var detectedOperations = await detectedOperationService.DetectOperationsAsync(telemetryId, beginDate, token); if (detectedOperations.Any()) diff --git a/AsbCloudWebApi.Tests/Services/DetectedOperations/Detectors/DetectorFlashingTests.cs b/AsbCloudWebApi.Tests/Services/DetectedOperations/Detectors/DetectorFlashingTests.cs new file mode 100644 index 00000000..43203db9 --- /dev/null +++ b/AsbCloudWebApi.Tests/Services/DetectedOperations/Detectors/DetectorFlashingTests.cs @@ -0,0 +1,110 @@ +using AsbCloudDb.Model; +using AsbCloudInfrastructure.Services.DetectOperations; +using AsbCloudInfrastructure.Services.DetectOperations.Detectors; +using Xunit; + +namespace AsbCloudWebApi.Tests.Services.DetectedOperations.Detectors; + +/// +/// Тестирование автоопределения операции "Промывка" +/// +public class DetectorFlashingTests : DetectorFlashing +{ + private readonly DetectorFlashing detector = new(); + + /// + /// Операция, попадающая под автоопределение операции промывки + /// + private readonly DetectableTelemetry telemetry = new() + { + Pressure = 21, + WellDepth = 152, + BitDepth = 151, + RotorSpeed = 8, + DateTime = System.DateTimeOffset.Now + }; + + + [Fact] + public void DetectOperation_find_startOperation_notFind_endOperation() + { + //arrange + var point0 = telemetry.Copy(); + var point1 = telemetry.Copy(); + point1.DateTime = System.DateTimeOffset.Now.AddMinutes(5); + + var telemetries = new[] { point0, point1 }; + + //act + var isDetectOperation = detector.TryDetect(0, telemetries, 0, telemetries.Length - 1, null, out var result); + + //assert + Assert.True(isDetectOperation); + Assert.NotNull(result); + Assert.Equal(WellOperationCategory.IdFlashing, result.Operation.IdCategory); + Assert.Equal(IdReasonOfEnd_NotDetected, result.Operation.ExtraData["IdReasonOfEnd"]); + } + + [Fact] + public void DetectOperation_with_BitDepth_LE_150_is_fail() + { + //arrange + var point0 = telemetry.Copy(); + point0.BitDepth = 150; + + var point1 = telemetry.Copy(); + + var telemetries = new[] { point0, point1 }; + + //act + + var isDetectOperation = detector.TryDetect(0, telemetries, 0, telemetries.Length - 1, null, out var result); + + //assert + Assert.False(isDetectOperation); + Assert.NotNull(result); + Assert.Equal(WellOperationCategory.IdFlashing, result.Operation.IdCategory); + Assert.Equal(IdReasonOfEnd_NotDetected, result.Operation.ExtraData["IdReasonOfEnd"]); + } + + + [Fact] + public void DetectOperation_with_DeltaWellDepth_NotEqual_0_is_fail() + { + //arrange + var point0 = telemetry.Copy(); + var point1 = telemetry.Copy(); + point1.WellDepth = point0.WellDepth + 10; + + var telemetries = new[] { point0, point1 }; + + //act + var isDetectOperation = detector.TryDetect(0, telemetries, 0, telemetries.Length - 1, null, out var result); + + //assert + Assert.False(isDetectOperation); + Assert.Null(result); + } + + [Fact] + public void DetectOperations_Begin_And_End_by_Pressure_Less_10_is_success() + { + //arrange + var point0 = telemetry.Copy(); + var point1 = telemetry.Copy(); + point1.Pressure = 9; + point1.BitDepth = 140.0001f; + point1.RotorSpeed = 10; + + var telemetries = new[] { point0, point1 }; + + //act + var isDetectOperation = detector.TryDetect(0, telemetries, 0, telemetries.Length - 1, null, out var result); + + //assert + Assert.False(isDetectOperation); + Assert.NotNull(result); + Assert.Equal(WellOperationCategory.IdFlashing, result.Operation.IdCategory); + Assert.Equal(IdReasonOfEnd_PressureIsLo, result.Operation.ExtraData["IdReasonOfEnd"]); + } +} \ No newline at end of file