forked from ddrilling/AsbCloudServer
Merge pull request '#28129910 Новый алгоритм определения операции удержание в клиньях' (#230) from feature/detected_slips_time into dev
Reviewed-on: http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer/pulls/230
This commit is contained in:
commit
d35d66ee85
@ -13,4 +13,5 @@ public class DetectableTelemetry
|
|||||||
public float BlockPosition { get; set; }
|
public float BlockPosition { get; set; }
|
||||||
public float BitDepth { get; set; }
|
public float BitDepth { get; set; }
|
||||||
public float RotorSpeed { get; set; }
|
public float RotorSpeed { get; set; }
|
||||||
}
|
public float AxialLoad { get; set; }
|
||||||
|
}
|
@ -118,13 +118,14 @@ public class DetectedOperationExportService
|
|||||||
for (int i = 0; i < operations.Count; i++)
|
for (int i = 0; i < operations.Count; i++)
|
||||||
{
|
{
|
||||||
var current = operations[i];
|
var current = operations[i];
|
||||||
var dateStart = current.DateStart.ToRemoteDateTime(well.Timezone.Hours);
|
var dateStart = current.DateStart.DateTime;
|
||||||
var dateEnd = current.DateEnd.ToRemoteDateTime(well.Timezone.Hours);
|
var dateEnd = current.DateEnd.DateTime;
|
||||||
|
|
||||||
var row = sheet.Row(5 + i + headerRowsCount);
|
var row = sheet.Row(5 + i + headerRowsCount);
|
||||||
|
|
||||||
var categoryName = GetCategoryName(wellOperationCategories, current);
|
var categoryName = GetCategoryName(wellOperationCategories, current);
|
||||||
|
|
||||||
|
row.Cell(columnDateStart).SetCellValue(dateStart);
|
||||||
row.Cell(columnOperationName).SetCellValue(categoryName);
|
row.Cell(columnOperationName).SetCellValue(categoryName);
|
||||||
row.Cell(columnDateEnd).SetCellValue(dateEnd);
|
row.Cell(columnDateEnd).SetCellValue(dateEnd);
|
||||||
row.Cell(columnDuration).SetCellValue((dateEnd - dateStart).TotalMinutes);
|
row.Cell(columnDuration).SetCellValue((dateEnd - dateStart).TotalMinutes);
|
||||||
@ -143,9 +144,7 @@ public class DetectedOperationExportService
|
|||||||
query.Add("end", dateStart.AddSeconds(1800 * 0.9).ToString("yyyy-MM-ddTHH:mm:ss.fff"));
|
query.Add("end", dateStart.AddSeconds(1800 * 0.9).ToString("yyyy-MM-ddTHH:mm:ss.fff"));
|
||||||
query.Add("range", "1800");
|
query.Add("range", "1800");
|
||||||
|
|
||||||
row.Cell(columnDateStart).SetCellValue(dateStart);
|
var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}";
|
||||||
|
|
||||||
var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}";
|
|
||||||
row.Cell(columnDateStart).SetHyperlink(link);
|
row.Cell(columnDateStart).SetHyperlink(link);
|
||||||
|
|
||||||
var deltaDepth = i > 0 && i + 1 < operations.Count
|
var deltaDepth = i > 0 && i + 1 < operations.Count
|
||||||
@ -180,6 +179,8 @@ public class DetectedOperationExportService
|
|||||||
1 => "Не определено начало операции",
|
1 => "Не определено начало операции",
|
||||||
101 => "Разница глубин забоя и положением долота",
|
101 => "Разница глубин забоя и положением долота",
|
||||||
300 => "Низкое давление",
|
300 => "Низкое давление",
|
||||||
|
301 => "Высокое давление",
|
||||||
|
700 => "Изменение глубины долота и осевая нагрузка < веса на крюке",
|
||||||
_ => idReasonOfEnd.ToString($"Причина № {idReasonOfEnd}"),
|
_ => idReasonOfEnd.ToString($"Причина № {idReasonOfEnd}"),
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -164,6 +164,7 @@ public class DetectedOperationService : IDetectedOperationService
|
|||||||
BlockPosition = t.BlockPosition,
|
BlockPosition = t.BlockPosition,
|
||||||
BitDepth = t.BitDepth,
|
BitDepth = t.BitDepth,
|
||||||
RotorSpeed = t.RotorSpeed,
|
RotorSpeed = t.RotorSpeed,
|
||||||
|
AxialLoad = t.AxialLoad,
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
if (detectableTelemetries.Length < gap)
|
if (detectableTelemetries.Length < gap)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using AsbCloudDb.Model;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AsbCloudApp.Data.DetectedOperation;
|
using AsbCloudApp.Data.DetectedOperation;
|
||||||
|
|
||||||
@ -7,8 +6,6 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
|||||||
{
|
{
|
||||||
public abstract class DetectorAbstract
|
public abstract class DetectorAbstract
|
||||||
{
|
{
|
||||||
private readonly int stepLength = 3;
|
|
||||||
|
|
||||||
protected const int IdReasonOfEnd_NotDetected = 0;
|
protected const int IdReasonOfEnd_NotDetected = 0;
|
||||||
protected const int IdReasonOfEnd_NotDetectBegin = 1;
|
protected const int IdReasonOfEnd_NotDetectBegin = 1;
|
||||||
|
|
||||||
@ -33,7 +30,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
|||||||
|
|
||||||
protected const int IdReasonOfEnd_Drilling = 600;
|
protected const int IdReasonOfEnd_Drilling = 600;
|
||||||
|
|
||||||
protected const int IdReasonOfEnd_Custom1 = 10_000;
|
protected const int IdReasonOfEnd_ChangeBithDepthAndAxiloadLessHookWeight = 700;
|
||||||
|
|
||||||
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperationDto? previousOperation,
|
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperationDto? previousOperation,
|
||||||
out OperationDetectorResult? result)
|
out OperationDetectorResult? result)
|
||||||
@ -44,9 +41,10 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
|||||||
// Поиск окончания соответствия критерию
|
// Поиск окончания соответствия критерию
|
||||||
int idReasonOfEnd = 0;
|
int idReasonOfEnd = 0;
|
||||||
var positionEnd = begin;
|
var positionEnd = begin;
|
||||||
|
|
||||||
while (positionEnd < end)
|
while (positionEnd < end)
|
||||||
{
|
{
|
||||||
positionEnd += stepLength;
|
positionEnd += 1;
|
||||||
if (positionEnd > end)
|
if (positionEnd > end)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -55,15 +53,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
|||||||
if (idReasonOfEnd != IdReasonOfEnd_NotDetected)
|
if (idReasonOfEnd != IdReasonOfEnd_NotDetected)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (Begin, End) = RefineEdges(telemetry, begin, positionEnd);
|
var (Begin, End) = RefineEdges(telemetry, begin, positionEnd);
|
||||||
|
|
||||||
if (!IsValidTelemetryRange(telemetry, Begin, End))
|
|
||||||
{
|
|
||||||
result = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = MakeOperationDetectorResult(idTelemetry, telemetry, Begin, End, idReasonOfEnd);
|
result = MakeOperationDetectorResult(idTelemetry, telemetry, Begin, End, idReasonOfEnd);
|
||||||
|
|
||||||
return IsValidOperationDetectorResult(result);
|
return IsValidOperationDetectorResult(result);
|
||||||
@ -72,10 +64,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
|||||||
result = null;
|
result = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool IsValidTelemetryRange(DetectableTelemetry[] telemetry, int begin, int end)
|
|
||||||
=> end - begin > 1;
|
|
||||||
|
|
||||||
protected virtual (int Begin, int End) RefineEdges(DetectableTelemetry[] telemetry, int begin, int end)
|
protected virtual (int Begin, int End) RefineEdges(DetectableTelemetry[] telemetry, int begin, int end)
|
||||||
=> (begin, end);
|
=> (begin, end);
|
||||||
|
|
||||||
|
@ -12,29 +12,56 @@ public class DetectorSlipsTime : DetectorAbstract
|
|||||||
|
|
||||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation)
|
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation)
|
||||||
{
|
{
|
||||||
var point0 = telemetry[position];
|
var currentPoint = telemetry[position];
|
||||||
var delta = point0.WellDepth - point0.BitDepth;
|
if (currentPoint.BitDepth < 150)
|
||||||
if (delta > 2.5d)
|
return false;
|
||||||
|
|
||||||
|
if (currentPoint.Pressure > 20)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (point0.Pressure > 15)
|
var delta = currentPoint.WellDepth - currentPoint.BitDepth;
|
||||||
|
if (delta < 0.1d)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (point0.BlockPosition > 8)
|
var nextIndexPoint = telemetry.Length <= position ? position : position + 1;
|
||||||
|
var nextPoint = telemetry[nextIndexPoint];
|
||||||
|
var deltaBitDepth = Math.Abs(currentPoint.BitDepth - nextPoint.BitDepth);
|
||||||
|
if (deltaBitDepth > 0.001d)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (point0.HookWeight > 20)
|
var deltaBlockPosition = Math.Abs(currentPoint.BlockPosition - nextPoint.BlockPosition);
|
||||||
|
if (deltaBlockPosition < 0.001d)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override (int IdCategory, IDictionary<string, object> ExtraData) GetSpecificInformation(DetectableTelemetry[] telemetry, int begin, int end)
|
protected override int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation)
|
||||||
{
|
{
|
||||||
|
var currentPoint = telemetry[position];
|
||||||
|
|
||||||
|
if (currentPoint.Pressure > 20)
|
||||||
|
return IdReasonOfEnd_PressureIsHi;
|
||||||
|
|
||||||
|
var prevPointIndex = position <= 0 ? 0 : position - 1;
|
||||||
|
|
||||||
|
var prevPoint = telemetry[prevPointIndex];
|
||||||
|
|
||||||
|
var deltaBitDepth = Math.Abs(currentPoint.BitDepth - prevPoint.BitDepth);
|
||||||
|
|
||||||
|
if (deltaBitDepth > 0.001d && currentPoint.AxialLoad < currentPoint.HookWeight)
|
||||||
|
return IdReasonOfEnd_ChangeBithDepthAndAxiloadLessHookWeight;
|
||||||
|
|
||||||
|
return IdReasonOfEnd_NotDetected;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override (int IdCategory, IDictionary<string, object> ExtraData) GetSpecificInformation(DetectableTelemetry[] telemetry,
|
||||||
|
int begin,
|
||||||
|
int end)
|
||||||
|
{
|
||||||
return (WellOperationCategory.IdSlipsTime, new Dictionary<string, object>());
|
return (WellOperationCategory.IdSlipsTime, new Dictionary<string, object>());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool IsValidOperationDetectorResult(OperationDetectorResult operationDetectorResult) =>
|
|
||||||
Math.Abs(operationDetectorResult.Operation.DepthStart - operationDetectorResult.Operation.DepthEnd) > 0.01;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
protected override bool IsValidOperationDetectorResult(OperationDetectorResult operationDetectorResult) =>
|
||||||
|
Math.Abs((operationDetectorResult.Operation.DateStart - operationDetectorResult.Operation.DateEnd).TotalMinutes) < 30;
|
||||||
|
}
|
@ -3,19 +3,26 @@
|
|||||||
|
|
||||||
Наращивание бурильного инструмента – операция, во время которой после добуривания очередной трубы/ свечи циркуляция выключается, инструмент разгружается в клиньях (остается только вес крюкоблока и ВСП), происходит развинчивание трубы от верхнего силового привода, берется очередная труба/ свеча, свинчивается с инструментом в клиньях, свинчивается с верхним силовым приводом, происходит подъем инструмента, вес на крюке увеличивается. Далее включается циркуляция и происходит механическое бурение.
|
Наращивание бурильного инструмента – операция, во время которой после добуривания очередной трубы/ свечи циркуляция выключается, инструмент разгружается в клиньях (остается только вес крюкоблока и ВСП), происходит развинчивание трубы от верхнего силового привода, берется очередная труба/ свеча, свинчивается с инструментом в клиньях, свинчивается с верхним силовым приводом, происходит подъем инструмента, вес на крюке увеличивается. Далее включается циркуляция и происходит механическое бурение.
|
||||||
|
|
||||||
Наращивается определяется как время между:
|
Наращивание определяется как время между:
|
||||||
- разгрузкой инструмента на клинья (остается только вес крюкоблока и ВСП). При этом давление менее 15 атм. В случае давления более 15 атм считать началом операции как снижение давления менее 15 атм и началом движения талевого блока вверх.
|
- началом разгрузки инструмента на клинья (остается только вес крюкоблока и ВСП). При этом расстояние от долота до забоя в диапазоне от 0.1 до 3м., давление менее 20 атм. В случае Если происходит движение блока без изменения глубины долота—-> идем назад и ищем падение давления ниже 20атм.
|
||||||
- снятие инструмента с клиньев (вес увеличивается более, чем на 1т). При этом движение талевого блока происходит вверх.
|
- снятие инструмента с клиньев (вес увеличивается более, чем на 1т). При этом движение талевого блока происходит вверх ИЛИ увеличение давления больше 20 атм.
|
||||||
|
|
||||||
|
|
||||||
## Метод определения
|
## Метод определения
|
||||||
|
|
||||||
Признак начала операции =
|
Признак начала операции =
|
||||||
( расстояние от долота до забоя < 2.5м ) И
|
( Расстояние от долота до забоя > 0.1 м) И
|
||||||
( положение талевого блока < 8 ) И
|
( давление < 20атм) И
|
||||||
( вес на крюке < 20 тонн ) И
|
( движение блока без изменения глубины долота) И
|
||||||
( давление < 15 атм );
|
( глубина долота > 150 м);
|
||||||
|
|
||||||
Признак окончания операции = НЕ выполняется признак начала операции;
|
Признак окончания операции =
|
||||||
|
( давление > 20атм) ИЛИ
|
||||||
|
( время продолжительности > 30 мин) ИЛИ
|
||||||
|
( изменение глубины долота) И
|
||||||
|
( осевая нагрузка < веса на крюке);
|
||||||
|
|
||||||
## Ключевой параметр
|
## Ключевой параметр
|
||||||
Продолжительность операции.
|
Продолжительность операции.
|
||||||
|
|
||||||
|
Предел времени операции 30 минут, всё что больше 30 минут это уже не наращивание - а НПВ.
|
19
AsbCloudWebApi.Tests/CommonExtensions.cs
Normal file
19
AsbCloudWebApi.Tests/CommonExtensions.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Mapster;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests;
|
||||||
|
|
||||||
|
public static class CommonExtensions
|
||||||
|
{
|
||||||
|
public static T Copy<T>(this T obj)
|
||||||
|
{
|
||||||
|
var copy = obj.Adapt<T>();
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Mutate<T>(this T obj, Action<T> mutation)
|
||||||
|
{
|
||||||
|
var copy = obj.Copy();
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
using System;
|
||||||
|
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||||
|
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests.Services.DetectedOperations.Detectors;
|
||||||
|
|
||||||
|
public class DetectorSlipsTimeTests
|
||||||
|
{
|
||||||
|
private const int IdSlipsTime = 5011;
|
||||||
|
|
||||||
|
private readonly DetectableTelemetry telemetry = new() {
|
||||||
|
WellDepth = 300,
|
||||||
|
Pressure = 15,
|
||||||
|
HookWeight = 20,
|
||||||
|
BlockPosition = 20,
|
||||||
|
BitDepth = 151,
|
||||||
|
AxialLoad = 19,
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly DetectorSlipsTime sut = new();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DetectOperation_by_change_block_position_and_axial_load_less_hook_weight_is_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var point0 = telemetry.Copy();
|
||||||
|
|
||||||
|
var point1 = telemetry.Copy();
|
||||||
|
point1.BlockPosition = 21;
|
||||||
|
|
||||||
|
var telemetries = new[] { point0, point1 };
|
||||||
|
|
||||||
|
//act
|
||||||
|
var isDetectOperation = sut.TryDetect(0, telemetries, 0, telemetries.Length - 1, null, out var result);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.True(isDetectOperation);
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(IdSlipsTime, result.Operation.IdCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DetectOperation_by_high_pressure_is_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var point0 = telemetry.Copy();
|
||||||
|
|
||||||
|
var point1 = telemetry.Copy();
|
||||||
|
point1.BlockPosition = 21;
|
||||||
|
point1.AxialLoad = 30;
|
||||||
|
point1.HookWeight = 20;
|
||||||
|
point1.Pressure = 23;
|
||||||
|
|
||||||
|
var telemetries = new[] { point0, point1 };
|
||||||
|
|
||||||
|
//act
|
||||||
|
var isDetectOperation = sut.TryDetect(0, telemetries, 0, telemetries.Length - 1, null, out var result);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.True(isDetectOperation);
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(IdSlipsTime, result.Operation.IdCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidateOperation_with_duration_more_30_minutes_is_invalid()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var point0 = telemetry.Copy();
|
||||||
|
|
||||||
|
var point1 = telemetry.Copy();
|
||||||
|
point1.BlockPosition = 21;
|
||||||
|
point1.DateTime = DateTimeOffset.UtcNow.AddMinutes(30);
|
||||||
|
|
||||||
|
var telemetries = new[] { point0, point1 };
|
||||||
|
|
||||||
|
//act
|
||||||
|
var isDetectOperation = sut.TryDetect(0, telemetries, 0, telemetries.Length - 1, null, out var result);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.False(isDetectOperation);
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(IdSlipsTime, result.Operation.IdCategory);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user