Операции определяются правильнее и быстрее

This commit is contained in:
ngfrolov 2022-06-29 13:40:06 +05:00
parent 9ab41cd24e
commit 050711c34b
6 changed files with 159 additions and 123 deletions

View File

@ -1,7 +1,7 @@
using AsbCloudDb.Model;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
@ -15,10 +15,13 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
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)
@ -26,8 +29,10 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.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,
@ -36,20 +41,30 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
this.detectStart = detectStart;
this.detectEnd = detectEnd;
this.detectors = JoinDetectors(detector, detectors);
Name = name;
}
public FragmentDetector(Func<DetectableTelemetry[], int, bool> detectStart, IOperationDetector operation)
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(Func<DetectableTelemetry[], int, bool> detectStart, Func<DetectableTelemetry[], int, bool> detectEnd, IOperationDetector operation)
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)
@ -61,7 +76,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
return joined;
}
public static Func<DetectableTelemetry[], int, bool> MakeInstantDelegate(Func<DetectableTelemetry, bool> instantValueCondition)
public static Func<DetectableTelemetry[], int, bool> MakeInstantDelegate(
Func<DetectableTelemetry, bool> instantValueCondition
)
{
var detect = (DetectableTelemetry[] telemetry, int position) =>
{
@ -80,10 +97,10 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
var detect = (DetectableTelemetry[] telemetry, int position) =>
{
DetectableTelemetry[] data;
if (fragmentLength > 0 && fragmentLength < telemetry.Length)
if (fragmentLength > 0 && (position + fragmentLength) < telemetry.Length)
data = telemetry[position..(position + fragmentLength)];
else
data = telemetry;
data = telemetry[position..];
var line = new InterpolationLine(data.Select(d => (yGetter(d), (d.DateTime - telemetry[0].DateTime).TotalHours)));
var result = interpolationValueCondition(line);
return result;
@ -91,40 +108,55 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
return detect;
}
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, out IEnumerable<DetectedOperation> operations)
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, out IEnumerable<OperationDetectorResult> results)
{
var positionStart = 0;
var operationsList = new List<DetectedOperation>();
// проверка соответствия критерию начала операции
if (detectStart(telemetryFragment, positionStart))
List<OperationDetectorResult>? totaltResultList = null;
var positionBegin = begin;
// Поиск начала соответствия критерию начала операции
while (end > positionBegin + fragmentLength + stepLength)
{
// Поиск окончания соответствия критерию
var positionEnd = positionStart + stepLength;
while (telemetryFragment.Length > positionEnd + FragmentLength)
if (detectStart(telemetry, positionBegin))
{
if (detectEnd(telemetryFragment, positionEnd))
// Поиск окончания соответствия критерию
var positionEnd = positionBegin;
while (positionEnd < end)
{
var innerFragment = telemetryFragment[positionStart..positionEnd];
var detectorEnumerator = detectors.GetEnumerator();
while (detectorEnumerator.MoveNext())
if (detectorEnumerator.Current.TryDetect(idTelemetry, innerFragment, out IEnumerable<DetectedOperation> result))
operationsList.AddRange(result);
positionEnd += stepLength;
if ((positionEnd > end))
positionEnd = end;
break;
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;
}
}
positionEnd += stepLength;
positionBegin = positionEnd;
}
else
{
positionBegin += stepLength;
}
}
if(totaltResultList?.Any() == true)
{
results = totaltResultList!;
return true;
}
else
{
operations = Enumerable.Empty<DetectedOperation>();
results = Enumerable.Empty<OperationDetectorResult>();
return false;
}
operations = operationsList;
return operationsList.Any();
}
}
public override string ToString()
=> $"frame detector {Name}";
}
#nullable disable
}

View File

@ -6,7 +6,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
internal interface IDetector
{
bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, out IEnumerable<DetectedOperation> operations);
bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, int begin, int end, out IEnumerable<OperationDetectorResult> operations);
}
internal interface IOperationDetector : IDetector

View File

@ -5,62 +5,62 @@ 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[], bool> isValid = (_) => true;
protected Func<DetectableTelemetry[], int, int, bool> isValid = (_,_,_) => true;
protected Func<DetectableTelemetry[], double> calcValue = (_) => 0d;
protected Func<DetectableTelemetry[], int, int, double> calcValue = (_, _, _) => 0d;
public OperationDetector(int idOperation)
{
this.idOperation = idOperation;
}
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, out IEnumerable<DetectedOperation> operations)
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, int begin, int end, out IEnumerable<OperationDetectorResult> operations)
{
if(!telemetryFragment.Any() || !isValid(telemetryFragment))
if(!telemetryFragment.Any() || !isValid(telemetryFragment, begin, end))
{
operations = Enumerable.Empty<DetectedOperation>();
operations = Enumerable.Empty<OperationDetectorResult>();
return false;
}
var operation = MakeOperation(idTelemetry, telemetryFragment);
var operation = MakeOperation(idTelemetry, telemetryFragment, begin, end);
operations = new List<DetectedOperation> { operation };
operations = new List<OperationDetectorResult> { operation };
return true;
}
private DetectedOperation MakeOperation(int idTelemetry, DetectableTelemetry[] telemetryFragment)
private OperationDetectorResult MakeOperation(int idTelemetry, DetectableTelemetry[] telemetryFragment, int begin, int end)
{
var pBegin = telemetryFragment.First();
var pEnd = telemetryFragment.Last();
var operation = new DetectedOperation
var pBegin = telemetryFragment[begin];
var pEnd = telemetryFragment[end];
var result = new OperationDetectorResult
{
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),
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 operation;
}
public OperationDetector SetIsValidDelegate(Func<DetectableTelemetry[], bool> isValid)
{
this.isValid = isValid;
return this;
}
public OperationDetector SetCalcValueDelegate(Func<DetectableTelemetry[], double> calcValue)
{
this.calcValue = calcValue;
return this;
return result;
}
}
}

View File

@ -8,20 +8,20 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
public OperationDrilling(int idOperation)
:base(idOperation)
{
isValid = (DetectableTelemetry[] telemetryFragment) =>
isValid = (DetectableTelemetry[] fragment, int begin, int end) =>
{
var pBegin = telemetryFragment.First();
var pEnd = telemetryFragment.Last();
var pBegin = fragment[begin];
var pEnd = fragment[end];
if (pBegin.WellDepth >= pEnd.WellDepth)
return false;
return true;
};
calcValue = (DetectableTelemetry[] telemetryFragment) =>
calcValue = (DetectableTelemetry[] fragment, int begin, int end) =>
{
var pBegin = telemetryFragment.First();
var pEnd = telemetryFragment.Last();
var pBegin = fragment[begin];
var pEnd = fragment[end];
var result = (double)(pEnd.WellDepth - pBegin.WellDepth) / (pEnd.DateTime - pBegin.DateTime).TotalHours;
return result;
};

View File

@ -8,20 +8,20 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
public OperationSlipsTime()
: base(14)
{
isValid = (DetectableTelemetry[] telemetryFragment) =>
isValid = (DetectableTelemetry[] fragment, int begin, int end) =>
{
var pBegin = telemetryFragment.First();
var pEnd = telemetryFragment.Last();
var pBegin = fragment[begin];
var pEnd = fragment[end];
if (Math.Abs((double)(pBegin.WellDepth - pEnd.WellDepth)) > 0.01)
return false;
return true;
};
calcValue = (DetectableTelemetry[] telemetryFragment) =>
calcValue = (DetectableTelemetry[] fragment, int begin, int end) =>
{
var pBegin = telemetryFragment.First();
var pEnd = telemetryFragment.Last();
var pBegin = fragment[begin];
var pEnd = fragment[end];
var result = (pEnd.DateTime - pBegin.DateTime).TotalHours;
return result;
};

View File

@ -14,30 +14,39 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
{
public class OperationDetectionBackgroundService : BackgroundService
{
private readonly int minStepLength = 3;
private readonly int minFragmentLength = 6;
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> isBitAtTheBottom = FragmentDetector.MakeInstantDelegate(d => (double)(d.WellDepth - d.BitDepth) < 0.001d);
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 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>
{
new FragmentDetector(isBitAtTheBottom,
new FragmentDetector(isPressureGt25,
new FragmentDetector(isRotorSpeedAvgGt5, new OperationDrilling(3)),
new FragmentDetector(isRotorSpeedAvgLt5, new OperationDrilling(2))
),
new FragmentDetector(isPressureLt15,
new FragmentDetector(isBlockPositionLt8,
new FragmentDetector(isHookWeightLt20, new OperationSlipsTime())))
)
};
{
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())))),
};
public OperationDetectionBackgroundService(IConfiguration configuration)
{
@ -147,48 +156,43 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
.Take(take)
.ToArrayAsync(token);
if (data.Length < minFragmentLength)
if (data.Length < 2 * fragmentLength + stepLength)
break;
var isDetected = false;
var positionStart = 0;
while (data.Length > positionStart + minFragmentLength + minStepLength)
var positionBegin = 0;
var positionEnd = data.Length - fragmentLength;
foreach (var detector in detectors)
{
var telemetryFragment = data[positionStart..];
var isDetected1 = false;
foreach (var detector in detectors)
if (detector is FragmentDetector fragmentDetector)
{
if (detector is FragmentDetector fragmentDetector)
{
var minLengthToDetect = fragmentDetector.StepLength + fragmentDetector.FragmentLength;
if (telemetryFragment.Length < minLengthToDetect)
continue;
var minLengthToDetect = fragmentDetector.StepLength + fragmentDetector.FragmentLength;
if (data.Length < positionBegin + minLengthToDetect)
continue;
if (fragmentDetector.TryDetect(idTelemetry, data, out IEnumerable<DetectedOperation> operations))
{
isDetected = true;
isDetected1 = true;
detectedOperations.AddRange(operations);
startDate = operations.Last().DateEnd;
positionStart = 0;
data = data
.Where(d => d.DateTime > startDate)
.ToArray();
break;
}
if (fragmentDetector.TryDetect(idTelemetry, data, positionBegin, positionEnd, out IEnumerable<OperationDetectorResult> results))
{
isDetected = true;
var operations = results.Select(r => r.Operation);
detectedOperations.AddRange(operations);
positionBegin = results.Max(r=>r.TelemetryEnd) + 1;
break;
}
}
if (!isDetected1)
positionStart += minStepLength;
}
if (!isDetected)
if (isDetected)
{
if (data.Length < take)
startDate = detectedOperations.Max(o => o.DateEnd);
}
else
{
int i = positionEnd - (int)(data.Length * 0.8);
if (i < 0)
break;
startDate = startDate.AddSeconds(0.95 * take);
startDate = data[i].DateTime;
}
}