Operation detection algorithm adapt.

This commit is contained in:
ngfrolov 2022-06-30 17:37:57 +05:00
parent 93c293a11c
commit 69ac4c74d5
18 changed files with 6570 additions and 374 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Add_new_well_operations_17_18 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData(
table: "t_well_operation_category",
columns: new[] { "id", "code", "name" },
values: new object[,]
{
{ 18, 0, "Проработка перед наращиванием" },
{ 19, 0, "Шаблонировка перед наращиванием" }
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "t_well_operation_category",
keyColumn: "id",
keyValue: 18);
migrationBuilder.DeleteData(
table: "t_well_operation_category",
keyColumn: "id",
keyValue: 19);
}
}
}

View File

@ -1,6 +1,5 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
@ -52,7 +51,7 @@ namespace AsbCloudDb.Migrations
.HasColumnType("double precision")
.HasColumnName("longitude");
b.Property<SimpleTimezone>("Timezone")
b.Property<string>("Timezone")
.HasColumnType("jsonb")
.HasColumnName("timezone")
.HasComment("Смещение часового пояса от UTC");
@ -149,7 +148,7 @@ namespace AsbCloudDb.Migrations
.HasColumnName("start_date")
.HasComment("Дата отчёта");
b.Property<DailyReportInfo>("Info")
b.Property<string>("Info")
.HasColumnType("jsonb")
.HasColumnName("info")
.HasComment("Список параметров для отчёта");
@ -184,7 +183,7 @@ namespace AsbCloudDb.Migrations
.HasColumnType("double precision")
.HasColumnName("longitude");
b.Property<SimpleTimezone>("Timezone")
b.Property<string>("Timezone")
.HasColumnType("jsonb")
.HasColumnName("timezone")
.HasComment("Смещение часового пояса от UTC");
@ -704,7 +703,7 @@ namespace AsbCloudDb.Migrations
.HasColumnName("name")
.HasComment("Название файла");
b.Property<FilePublishInfo>("PublishInfo")
b.Property<string>("PublishInfo")
.HasColumnType("jsonb")
.HasColumnName("publish_info")
.HasComment("Информация о файле в облаке");
@ -791,7 +790,7 @@ namespace AsbCloudDb.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<RawData>("Data")
b.Property<string>("Data")
.HasColumnType("jsonb")
.HasColumnName("data")
.HasComment("Данные таблицы последних данных");
@ -2727,7 +2726,7 @@ namespace AsbCloudDb.Migrations
.HasColumnName("obsolescence")
.HasComment("сек. до устаревания");
b.Property<Dictionary<string, double>>("Setpoints")
b.Property<string>("Setpoints")
.HasColumnType("jsonb")
.HasColumnName("setpoint_set")
.HasComment("Набор уставок");
@ -2756,7 +2755,7 @@ namespace AsbCloudDb.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<TelemetryInfo>("Info")
b.Property<string>("Info")
.HasColumnType("jsonb")
.HasColumnName("info")
.HasComment("Информация с панели о скважине");
@ -2766,7 +2765,7 @@ namespace AsbCloudDb.Migrations
.HasColumnName("remote_uid")
.HasComment("Идентификатор передающего устройства. Может повторяться в списке, так как комплекты оборудования переезжают от скв. к скв.");
b.Property<SimpleTimezone>("TimeZone")
b.Property<string>("TimeZone")
.HasColumnType("jsonb")
.HasColumnName("timezone")
.HasComment("Смещение часового пояса от UTC");
@ -3912,7 +3911,7 @@ namespace AsbCloudDb.Migrations
.HasColumnType("double precision")
.HasColumnName("longitude");
b.Property<SimpleTimezone>("Timezone")
b.Property<string>("Timezone")
.HasColumnType("jsonb")
.HasColumnName("timezone")
.HasComment("Смещение часового пояса от UTC");
@ -4164,6 +4163,18 @@ namespace AsbCloudDb.Migrations
Name = "На поверхности"
},
new
{
Id = 18,
Code = 0,
Name = "Проработка перед наращиванием"
},
new
{
Id = 19,
Code = 0,
Name = "Шаблонировка перед наращиванием"
},
new
{
Id = 1001,
Code = 0,

View File

@ -680,6 +680,9 @@ namespace AsbCloudDb.Model
new WellOperationCategory {Id = 15, Name = "Неподвижное состояние", Code = 0 },
new WellOperationCategory {Id = 16, Name = "Вращение без циркуляции", Code = 0 },
new WellOperationCategory {Id = 17, Name = "На поверхности", Code = 0 },
new WellOperationCategory {Id = 18, Name = "Проработка перед наращиванием", Code = 0 },
new WellOperationCategory {Id = 19, Name = "Шаблонировка перед наращиванием", Code = 0 },
// Операции ручного ввода
new WellOperationCategory {Id = 1001, Name = "Бурение", Code = 0 },
new WellOperationCategory {Id = 1002, Name = "ГИС", Code = 0 },

View File

@ -6,11 +6,11 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
{
public DateTimeOffset DateTime { 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 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; }
}
}

View File

@ -0,0 +1,139 @@
using AsbCloudDb.Model;
using System;
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
internal abstract class DetectorAbstract
{
private readonly int idOperation;
private readonly int stepLength = 3;
protected DetectorAbstract(int idOperation)
{
this.idOperation = idOperation;
}
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperation? previousOperation, out OperationDetectorResult? result)
{
// Проверка соответствия критерию начала операции
if (DetectBegin(telemetry, begin, previousOperation))
{
// Поиск окончания соответствия критерию
var positionEnd = begin;
while (positionEnd < end)
{
positionEnd += stepLength;
if ((positionEnd > end))
positionEnd = end;
if ((positionEnd == end) || DetectEnd(telemetry, positionEnd, previousOperation))
{
result = MakeOperation(idTelemetry, telemetry, begin, positionEnd);
return true;
}
}
}
result = null;
return false;
}
protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation);
protected virtual bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
=> !DetectBegin(telemetry, position, previousOperation);
private OperationDetectorResult MakeOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end)
{
var pBegin = telemetry[begin];
var pEnd = telemetry[end];
var result = new OperationDetectorResult
{
TelemetryBegin = begin,
TelemetryEnd = end,
Operation = new DetectedOperation
{
IdTelemetry = idTelemetry,
IdCategory = idOperation,
IdUsersAtStart = pBegin.IdUser ?? -1,
DateStart = pBegin.DateTime,
DateEnd = pEnd.DateTime,
DepthStart = (double)pBegin.WellDepth,
DepthEnd = (double)pEnd.WellDepth,
Value = CalcValue(telemetry, begin, end),
},
};
return result;
}
protected abstract bool IsValid(DetectableTelemetry[] telemetry, int begin, int end);
protected abstract double CalcValue(DetectableTelemetry[] telemetry, int begin, int end);
public static InterpolationLine MakeInterpolationLine(
Func<DetectableTelemetry, double> yGetter,
DetectableTelemetry[] telemetry,
int begin,
int fragmentLength)
{
DetectableTelemetry[] data;
if (fragmentLength > 0 && (begin + fragmentLength) < telemetry.Length)
data = telemetry[begin..(begin + fragmentLength)];
else
data = telemetry[begin..];
var line = new InterpolationLine(data.Select(d => (yGetter(d), (d.DateTime - telemetry[0].DateTime).TotalHours)));
return line;
}
/// <summary>
/// расчет продолжительности операции
/// </summary>
/// <param name="telemetry"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <returns></returns>
protected static double CalcDeltaTime(DetectableTelemetry[] telemetry, int begin, int end)
{
var pBegin = telemetry[begin];
var pEnd = telemetry[end];
var result = (pEnd.DateTime - pBegin.DateTime).TotalHours;
return result;
}
/// <summary>
/// часто используемый предикат для определения отсутствия изменения глубины ствола скважины
/// </summary>
/// <param name="telemetry"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <returns></returns>
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;
}
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;
}
}
#nullable disable
}

View File

@ -0,0 +1,42 @@
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
internal class DetectorDevelopment : DetectorAbstract
{
public DetectorDevelopment()
: base(18) { }
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
=> CalcDeltaTime(telemetry, begin, end);
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
{
if (previousOperation?.IdCategory == 14)
return false;
var point0 = telemetry[position];
var delta = point0.WellDepth - point0.BitDepth;
if (delta < 0.03d || delta > 30)
return false;
if (point0.Pressure < 15)
return false;
if (point0.BlockPosition > 31)
return false;
if (point0.RotorSpeed < 10)
return false;
return true;
}
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
}
#nullable disable
}

View File

@ -0,0 +1,63 @@
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
internal class DetectorRotor : DetectorAbstract
{
public DetectorRotor()
: base(2) { }
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
{
var point0 = telemetry[position];
var delta = point0.WellDepth - point0.BitDepth;
if (delta > 0.03d)
return false;
if (point0.Pressure < 25)
return false;
if (point0.RotorSpeed < 5)
return false;
var point1 = telemetry[position + 1];
if (point1.WellDepth - point0.WellDepth <= 0.003)
return false;
return true;
}
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
{
var point0 = telemetry[position];
var delta = point0.WellDepth - point0.BitDepth;
if (delta > 0.03d)
return true;
if (point0.Pressure < 25)
return true;
var lineRotorSpeed = MakeInterpolationLine(d => d.RotorSpeed, telemetry, position, 10);
if (lineRotorSpeed.IsAverageYLessThan(5))
return true;
var lineWellDepth = MakeInterpolationLine(d => d.WellDepth, telemetry, position, 30);
if (!lineWellDepth.IsYIncreases(1))
return true;
return false;
}
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
=> IsValidByWellDepthIncreasing(telemetry, begin, end);
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
=> CalcRop(telemetry, begin, end);
}
#nullable disable
}

View File

@ -0,0 +1,63 @@
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
internal class DetectorSlide : DetectorAbstract
{
public DetectorSlide()
: base(3) { }
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
{
var point0 = telemetry[position];
var delta = point0.WellDepth - point0.BitDepth;
if (delta > 0.03d)
return false;
if (point0.Pressure < 25)
return false;
if (point0.RotorSpeed > 5)
return false;
var point1 = telemetry[position + 1];
if (point1.WellDepth - point0.WellDepth <= 0.003)
return false;
return true;
}
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
{
var point0 = telemetry[position];
var delta = point0.WellDepth - point0.BitDepth;
if (delta > 0.03d)
return true;
if (point0.Pressure < 25)
return true;
var lineRotorSpeed = MakeInterpolationLine(d => d.RotorSpeed, telemetry, position, 10);
if (lineRotorSpeed.IsAverageYGreaterThan(5))
return true;
var lineWellDepth = MakeInterpolationLine(d => d.WellDepth, telemetry, position, 30);
if (!lineWellDepth.IsYIncreases(1))
return true;
return false;
}
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
=> IsValidByWellDepthIncreasing(telemetry, begin, end);
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
=> CalcRop(telemetry, begin, end);
}
#nullable disable
}

View File

@ -0,0 +1,36 @@
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
internal class DetectorSlipsTime : DetectorAbstract
{
public DetectorSlipsTime()
: base(14) { }
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
=> CalcDeltaTime(telemetry, begin, end);
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
{
var point0 = telemetry[position];
var delta = point0.WellDepth - point0.BitDepth;
if (delta > 2.5d)
return false;
if (point0.BlockPosition > 8)
return false;
if (point0.HookWeight > 20)
return false;
return true;
}
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
}
#nullable disable
}

View File

@ -0,0 +1,42 @@
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
internal class DetectorTemplating : DetectorAbstract
{
public DetectorTemplating()
: base(19) { }
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
=> CalcDeltaTime(telemetry, begin, end);
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
{
if(previousOperation?.IdCategory == 14)
return false;
var point0 = telemetry[position];
var delta = point0.WellDepth - point0.BitDepth;
if (delta < 0.03d || delta > 30)
return false;
if (point0.Pressure < 15)
return false;
if (point0.BlockPosition > 31)
return false;
if (point0.RotorSpeed > 10)
return false;
return true;
}
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
}
#nullable disable
}

View File

@ -1,162 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
internal class FragmentDetector : IFragmentDetector
{
private int fragmentLength = 12;
private int stepLength = 3;
protected IEnumerable<IDetector> detectors = Enumerable.Empty<IDetector>();
protected Func<DetectableTelemetry[], int, bool> detectStart;
protected Func<DetectableTelemetry[], int, bool> detectEnd;
public string Name { get; set; }
public int FragmentLength { get => fragmentLength; set => fragmentLength = value; }
public int StepLength { get => stepLength; set => stepLength = value; }
public FragmentDetector(
string name,
Func<DetectableTelemetry[], int, bool> detectStart,
IFragmentDetector detector,
params IFragmentDetector[] detectors)
{
this.detectStart = detectStart;
this.detectors = JoinDetectors(detector, detectors);
detectEnd = (f, i) => !detectStart(f, i);
Name = name;
}
public FragmentDetector(
string name,
Func<DetectableTelemetry[], int, bool> detectStart,
Func<DetectableTelemetry[], int, bool> detectEnd,
IFragmentDetector detector,
params IFragmentDetector[] detectors)
{
this.detectStart = detectStart;
this.detectEnd = detectEnd;
this.detectors = JoinDetectors(detector, detectors);
Name = name;
}
public FragmentDetector(
string name,
Func<DetectableTelemetry[], int, bool> detectStart,
IOperationDetector operation)
{
this.detectStart = detectStart;
detectors = new IOperationDetector[] { operation };
detectEnd = (f, i) => !detectStart(f, i);
Name = name;
}
public FragmentDetector(
string name,
Func<DetectableTelemetry[], int, bool> detectStart,
Func<DetectableTelemetry[], int, bool> detectEnd,
IOperationDetector operation)
{
this.detectStart = detectStart;
this.detectEnd = detectEnd;
detectors = new IOperationDetector[] { operation };
Name = name;
}
private static IEnumerable<IFragmentDetector> JoinDetectors(IFragmentDetector detector, params IFragmentDetector[] detectors)
{
var joined = new IFragmentDetector[1 + detectors.Length];
joined[0] = detector;
if (detectors.Length > 0)
detectors.CopyTo(joined, 1);
return joined;
}
public static Func<DetectableTelemetry[], int, bool> MakeInstantDelegate(
Func<DetectableTelemetry, bool> instantValueCondition
)
{
var detect = (DetectableTelemetry[] telemetry, int position) =>
{
var firstItem = telemetry[position];
var result = instantValueCondition(firstItem);
return result;
};
return detect;
}
public static Func<DetectableTelemetry[], int, bool> MakeInterpolationDelegate(
Func<DetectableTelemetry, double> yGetter,
Func<InterpolationLine, bool> interpolationValueCondition,
int fragmentLength)
{
var detect = (DetectableTelemetry[] telemetry, int position) =>
{
DetectableTelemetry[] data;
if (fragmentLength > 0 && (position + fragmentLength) < telemetry.Length)
data = telemetry[position..(position + fragmentLength)];
else
data = telemetry[position..];
var line = new InterpolationLine(data.Select(d => (yGetter(d), (d.DateTime - telemetry[0].DateTime).TotalHours)));
var result = interpolationValueCondition(line);
return result;
};
return detect;
}
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, out IEnumerable<OperationDetectorResult> results)
{
List<OperationDetectorResult>? totaltResultList = null;
var positionBegin = begin;
// Поиск начала соответствия критерию начала операции
while (end > positionBegin + fragmentLength + stepLength)
{
if (detectStart(telemetry, positionBegin))
{
// Поиск окончания соответствия критерию
var positionEnd = positionBegin;
while (positionEnd < end)
{
positionEnd += stepLength;
if ((positionEnd > end))
positionEnd = end;
if ((positionEnd == end) || detectEnd(telemetry, positionEnd))
{
totaltResultList = totaltResultList ?? new List<OperationDetectorResult>();
var detectorsEnumerator = detectors.GetEnumerator();
while (detectorsEnumerator.MoveNext())
if (detectorsEnumerator.Current.TryDetect(idTelemetry, telemetry, positionBegin, positionEnd, out IEnumerable<OperationDetectorResult> innerResult))
totaltResultList.AddRange(innerResult);
break;
}
}
positionBegin = positionEnd;
}
else
{
positionBegin += stepLength;
}
}
if(totaltResultList?.Any() == true)
{
results = totaltResultList!;
return true;
}
else
{
results = Enumerable.Empty<OperationDetectorResult>();
return false;
}
}
public override string ToString()
=> $"frame detector {Name}";
}
#nullable disable
}

View File

@ -1,17 +0,0 @@
using AsbCloudDb.Model;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
internal interface IDetector
{
bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, int begin, int end, out IEnumerable<OperationDetectorResult> operations);
}
internal interface IOperationDetector : IDetector
{ }
internal interface IFragmentDetector: IDetector
{ }
}

View File

@ -1,66 +0,0 @@
using AsbCloudDb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
class OperationDetectorResult
{
public int TelemetryBegin { get; set; }
public int TelemetryEnd { get; set; }
public DetectedOperation Operation { get; set; }
}
internal class OperationDetector : IOperationDetector
{
private readonly int idOperation;
protected Func<DetectableTelemetry[], int, int, bool> isValid = (_,_,_) => true;
protected Func<DetectableTelemetry[], int, int, double> calcValue = (_, _, _) => 0d;
public OperationDetector(int idOperation)
{
this.idOperation = idOperation;
}
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, int begin, int end, out IEnumerable<OperationDetectorResult> operations)
{
if(!telemetryFragment.Any() || !isValid(telemetryFragment, begin, end))
{
operations = Enumerable.Empty<OperationDetectorResult>();
return false;
}
var operation = MakeOperation(idTelemetry, telemetryFragment, begin, end);
operations = new List<OperationDetectorResult> { operation };
return true;
}
private OperationDetectorResult MakeOperation(int idTelemetry, DetectableTelemetry[] telemetryFragment, int begin, int end)
{
var pBegin = telemetryFragment[begin];
var pEnd = telemetryFragment[end];
var result = new OperationDetectorResult
{
TelemetryBegin = begin,
TelemetryEnd = end,
Operation = new DetectedOperation
{
IdTelemetry = idTelemetry,
IdCategory = idOperation,
IdUsersAtStart = pBegin.IdUser ?? -1,
DateStart = pBegin.DateTime,
DateEnd = pEnd.DateTime,
DepthStart = (double)pBegin.WellDepth,
DepthEnd = (double)pEnd.WellDepth,
Value = calcValue(telemetryFragment, begin, end),
},
};
return result;
}
}
}

View File

@ -0,0 +1,11 @@
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
class OperationDetectorResult
{
public int TelemetryBegin { get; set; }
public int TelemetryEnd { get; set; }
public DetectedOperation Operation { get; set; }
}
}

View File

@ -1,30 +0,0 @@
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
internal class OperationDrilling : OperationDetector
{
public OperationDrilling(int idOperation)
:base(idOperation)
{
isValid = (DetectableTelemetry[] fragment, int begin, int end) =>
{
var pBegin = fragment[begin];
var pEnd = fragment[end];
if (pBegin.WellDepth >= pEnd.WellDepth)
return false;
return true;
};
calcValue = (DetectableTelemetry[] fragment, int begin, int end) =>
{
var pBegin = fragment[begin];
var pEnd = fragment[end];
var result = (double)(pEnd.WellDepth - pBegin.WellDepth) / (pEnd.DateTime - pBegin.DateTime).TotalHours;
return result;
};
}
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
internal class OperationSlipsTime : OperationDetector
{
public OperationSlipsTime()
: base(14)
{
isValid = (DetectableTelemetry[] fragment, int begin, int end) =>
{
var pBegin = fragment[begin];
var pEnd = fragment[end];
if (Math.Abs((double)(pBegin.WellDepth - pEnd.WellDepth)) > 0.01)
return false;
return true;
};
calcValue = (DetectableTelemetry[] fragment, int begin, int end) =>
{
var pBegin = fragment[begin];
var pEnd = fragment[end];
var result = (pEnd.DateTime - pBegin.DateTime).TotalHours;
return result;
};
}
}
}

View File

@ -14,38 +14,16 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
{
public class OperationDetectionBackgroundService : BackgroundService
{
private readonly int stepLength = 3;
private readonly int fragmentLength = 6;
private readonly string connectionString;
private readonly TimeSpan period = TimeSpan.FromHours(1);
private static readonly Func<DetectableTelemetry[], int, bool> isBitLt0_03mToBottom = FragmentDetector.MakeInstantDelegate(d =>
(double)(d.WellDepth - d.BitDepth) < 0.03d);
private static readonly Func<DetectableTelemetry[], int, bool> isBitLt2_5mToBottom = FragmentDetector.MakeInstantDelegate(d =>
(double)(d.WellDepth - d.BitDepth) < 2.5d);
private static readonly Func<DetectableTelemetry[], int, bool> isPressureGt25 = FragmentDetector.MakeInstantDelegate(d =>
d.Pressure > 25);
private static readonly Func<DetectableTelemetry[], int, bool> isPressureLt15 = FragmentDetector.MakeInstantDelegate(d =>
d.Pressure < 15);
private static readonly Func<DetectableTelemetry[], int, bool> isBlockPositionLt8 = FragmentDetector.MakeInstantDelegate(d =>
d.BlockPosition < 8);
private static readonly Func<DetectableTelemetry[], int, bool> isHookWeightLt20 = FragmentDetector.MakeInstantDelegate(d =>
d.HookWeight < 20);
private static readonly Func<DetectableTelemetry[], int, bool> isRotorSpeedAvgGt5 = FragmentDetector.MakeInterpolationDelegate(d => (double)d.RotorSpeed, line =>
line.IsAverageYGreaterThan(5), 12);
private static readonly Func<DetectableTelemetry[], int, bool> isRotorSpeedAvgLt5 = FragmentDetector.MakeInterpolationDelegate(d => (double)d.RotorSpeed, line =>
line.IsAverageYLessThan(5), 12);
private static readonly List<IDetector> detectors = new List<IDetector>
private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
{
new FragmentDetector("isBitLt2_5mToBottom", isBitLt2_5mToBottom,
new FragmentDetector("isBitLt0_03mToBottom", isBitLt0_03mToBottom,
new FragmentDetector("isPressureGt25", isPressureGt25,
new FragmentDetector("isRotorSpeedAvgGt5", isRotorSpeedAvgGt5, new OperationDrilling(2)),
new FragmentDetector("isRotorSpeedAvgLt5", isRotorSpeedAvgLt5, new OperationDrilling(3)))),
new FragmentDetector("isPressureLt15", isPressureLt15,
new FragmentDetector("isBlockPositionLt8", isBlockPositionLt8,
new FragmentDetector("isHookWeightLt20", isHookWeightLt20, new OperationSlipsTime())))),
new DetectorRotor(),
new DetectorSlide(),
new DetectorDevelopment(),
new DetectorTemplating(),
new DetectorSlipsTime(),
};
public OperationDetectionBackgroundService(IConfiguration configuration)
@ -136,18 +114,22 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
{
DateTime = d.DateTime,
IdUser = d.IdUser,
WellDepth = d.WellDepth,
Pressure = d.Pressure,
HookWeight = d.HookWeight,
BlockPosition = d.BlockPosition,
BitDepth = d.BitDepth,
RotorSpeed = d.RotorSpeed,
WellDepth = (float)d.WellDepth,
Pressure = (float)d.Pressure,
HookWeight = (float)d.HookWeight,
BlockPosition = (float)d.BlockPosition,
BitDepth = (float)d.BitDepth,
RotorSpeed = (float)d.RotorSpeed,
})
.OrderBy(d => d.DateTime);
var take = 4 * 86_400; // 4 дня
var startDate = begin;
var detectedOperations = new List<DetectedOperation>(8);
DetectedOperation? lastDetectedOperation = null;
const int minOperationLength = 5;
const int maxDetectorsInterpolationFrameLength = 30;
const int gap = maxDetectorsInterpolationFrameLength + minOperationLength;
while (true)
{
@ -156,43 +138,35 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
.Take(take)
.ToArrayAsync(token);
if (data.Length < 2 * fragmentLength + stepLength)
if (data.Length < gap)
break;
var isDetected = false;
var positionBegin = 0;
var positionEnd = data.Length - fragmentLength;
foreach (var detector in detectors)
var positionEnd = data.Length - gap;
while (positionEnd > positionBegin)
{
if (detector is FragmentDetector fragmentDetector)
for (int i = 0; i < detectors.Length; i++)
{
var minLengthToDetect = fragmentDetector.StepLength + fragmentDetector.FragmentLength;
if (data.Length < positionBegin + minLengthToDetect)
continue;
if (fragmentDetector.TryDetect(idTelemetry, data, positionBegin, positionEnd, out IEnumerable<OperationDetectorResult> results))
if (detectors[i].TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out OperationDetectorResult result))
{
detectedOperations.Add(result.Operation);
lastDetectedOperation = result.Operation;
isDetected = true;
var operations = results.Select(r => r.Operation);
detectedOperations.AddRange(operations);
positionBegin = results.Max(r=>r.TelemetryEnd) + 1;
positionBegin = result.TelemetryEnd;
break;
}
}
positionBegin++;
}
if (isDetected)
{
startDate = detectedOperations.Max(o => o.DateEnd);
startDate = detectedOperations.Last().DateEnd;
}
else
{
int i = positionEnd - (int)(data.Length * 0.8);
if (i < 0)
break;
startDate = data[i].DateTime;
startDate = data[positionEnd].DateTime;
}
}