doesn't work. Wrong handle begin of operation.

This commit is contained in:
ngfrolov 2022-06-27 10:20:54 +05:00
parent 85c253b82b
commit d0386b0182
13 changed files with 322 additions and 320 deletions

View File

@ -1,97 +0,0 @@
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services.DetectOperations
{
#nullable enable
abstract class DetectorAbstract
{
public int StepLength { get; set; } = 3;
public int FragmentLength { get; set; } = 6;
public int IdCategory { get; }
// TODO: assert MaxDurationSeconds and MinDurationSeconds
public double MaxDurationSeconds { get; } = 24 * 60 * 60;
public double MinDurationSeconds { get; } = 3;
/// <summary>
/// Конструктор детектора.
/// Словарь с IdCategory в дефолтных данных AsbCloudDbContext для таблицы WellOperationCategory
/// </summary>
/// <param name="IdCategory">ключ названия/описания операции из таблицы WellOperationCategory</param>
public DetectorAbstract(int IdCategory)
{
this.IdCategory = IdCategory;
}
public virtual DetectedOperation? DetectOrDefault(DetectableTelemetry[] telemetry, ref int positionStart)
{
if ((telemetry.Length > positionStart + FragmentLength + StepLength) && DetectStart(telemetry, positionStart))
{
var skip = positionStart + StepLength;
while (telemetry.Length > skip + FragmentLength)
{
if (DetectEnd(telemetry, skip))
{
var dateStart = telemetry[positionStart].DateTime;
var dateEnd = telemetry[skip].DateTime;
var durationSec = (dateEnd - dateStart).TotalSeconds;
if (durationSec < MinDurationSeconds || durationSec > MaxDurationSeconds)
return null;
var result = new DetectedOperation
{
IdCategory = IdCategory,
IdUsersAtStart = telemetry[positionStart].IdUser ?? -1,
DateStart = dateStart,
DateEnd = dateEnd,
DepthStart = telemetry[positionStart].WellDepth ?? -1d,
DepthEnd = telemetry[skip].WellDepth ?? -1d,
Value = CalcValue(telemetry, positionStart, skip),
};
if (!IsValid(result))
return null;
positionStart = skip;// + FragmentLength;
return result;
}
skip = skip + StepLength;
}
}
return null;
}
/// <summary>
/// Расчет ключевого параметра
/// </summary>
/// <param name="result"></param>
protected abstract double CalcValue(DetectableTelemetry[] telemetry, int positionBegin, int positionEnd);
/// <summary>
/// Определение начала операции
/// </summary>
/// <param name="telemetry"></param>
/// <param name="position"></param>
/// <returns></returns>
protected abstract bool DetectStart(DetectableTelemetry[] telemetry, int position);
/// <summary>
/// Определение окончания операции
/// </summary>
/// <param name="telemetry"></param>
/// <param name="position"></param>
/// <returns></returns>
protected abstract bool DetectEnd(DetectableTelemetry[] telemetry, int position);
/// <summary>
/// Валидация операции
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
protected abstract bool IsValid(DetectedOperation result);
}
#nullable disable
}

View File

@ -1,86 +0,0 @@
using AsbCloudDb.Model;
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
internal abstract class DetectorDrillingAbstract : DetectorAbstract
{
/* # РАСЧЕТ minRop
* шаг энкодера = 0.006м;
* 2 шага за 10 секунд не считается, так как может быть простым шумом;
* minRop = 0.006 * 2 / 10 = 0.0012 м/сек
* minRop > 4.32 м/ч & minRop < 6.48 м/ч (3 шага за 10 сек);
*/
protected const double minRop = 5.4; //м/час
protected const double minRotorSpeed = 5; //об/мин
protected const double minPressure = 25;
protected const double minDeltaDepth = 0.01;
public DetectorDrillingAbstract(int IdCategory) : base(IdCategory)
{
FragmentLength = 12;
StepLength = 3;
}
protected override bool DetectStart(DetectableTelemetry[] telemetry, int position)
{
var firstItem = telemetry[position];
var deltaDepth = firstItem.WellDepth - firstItem.BitDepth;
if (deltaDepth is not null &&
System.Math.Abs((float)deltaDepth) > minDeltaDepth)
return false;
if (firstItem.Pressure < minPressure)
return false;
var fragment = telemetry[position..(position + FragmentLength)];
var lineBlockPosition = new InterpolationLine(fragment.Select(d => (d.BlockPosition ?? 0d, (d.DateTime - firstItem.DateTime).TotalHours)));
if (!lineBlockPosition.IsYDecreases(-minRop))
return false;
var lineWellDepth = new InterpolationLine(fragment.Select(d => ((d.WellDepth - firstItem.WellDepth) ?? 0d, (d.DateTime - firstItem.DateTime).TotalHours)));
if (!lineWellDepth.IsYIncreases(minRop))
return false;
if (!ModeCondition(fragment))
return false;
return true;
}
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position)
{
var firstItem = telemetry[position];
var deltaDepth = firstItem.WellDepth - firstItem.BitDepth;
if (deltaDepth is not null &&
System.Math.Abs((float)deltaDepth) > minDeltaDepth)
return true;
if (firstItem.Pressure < minPressure)
return true;
var fragment = telemetry[position..(position + FragmentLength)];
if (!ModeCondition(fragment))
return true;
return false;
}
protected abstract bool ModeCondition(DetectableTelemetry[] telemetryFragment);
/// <summary>
/// Рассчитываем МСП, м/час
/// </summary>
/// <param name="result"></param>
protected override double CalcValue(DetectableTelemetry[] telemetry, int positionBegin, int positionEnd)
{
var pBegin = telemetry[positionBegin];
var pEnd = telemetry[positionEnd];
var result = (double)(pEnd.WellDepth - pBegin.WellDepth) / (pEnd.DateTime - pBegin.DateTime).TotalHours;
return result;
}
protected override bool IsValid(DetectedOperation result)
=> result.Value > 0;
}
}

View File

@ -1,19 +0,0 @@
using AsbCloudDb.Model;
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
class DetectorDrillingRotor : DetectorDrillingAbstract
{
public DetectorDrillingRotor()
: base(2){}
protected override bool ModeCondition(DetectableTelemetry[] telemetryFragment)
{
var lineRotorSpeed = new InterpolationLine(telemetryFragment.Select(d => (d.RotorSpeed ?? 0d, (d.DateTime - telemetryFragment[0].DateTime).TotalHours)));
return lineRotorSpeed.IsAverageYMoreThanBound(minRotorSpeed);
}
}
#nullable disable
}

View File

@ -1,18 +0,0 @@
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
class DetectorDrillingSlide : DetectorDrillingAbstract
{
public DetectorDrillingSlide()
: base(3){}
protected override bool ModeCondition(DetectableTelemetry[] telemetryFragment)
{
var lineRotorSpeed = new InterpolationLine(telemetryFragment.Select(d => (d.RotorSpeed ?? 0d, (d.DateTime - telemetryFragment[0].DateTime).TotalHours)));
return lineRotorSpeed.IsAverageYLessThanBound(minRotorSpeed);
}
}
#nullable disable
}

View File

@ -1,50 +0,0 @@
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
class DetectorSlipsTime : DetectorAbstract
{
public DetectorSlipsTime() : base(14) { }
public double HookWeightSP { get; set; } = 20;
public double PressureSP { get; set; } = 15;
public double PosisionSP { get; set; } = 8;
public double DeltaWellDepthMax { get; set; } = 2.5;
protected override bool DetectStart(DetectableTelemetry[] telemetry, int position)
{
var item = telemetry[position];
var result =
item.HookWeight < HookWeightSP &&
item.Pressure < PressureSP &&
item.BlockPosition < PosisionSP &&
(item.WellDepth - item.BitDepth) < DeltaWellDepthMax;
return result;
}
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position)
{
var item = telemetry[position];
var result = item.Pressure > PressureSP &&
item.BlockPosition > PosisionSP;
return result;
}
protected override double CalcValue(DetectableTelemetry[] telemetry, int positionBegin, int positionEnd)
{
var pBegin = telemetry[positionBegin];
var pEnd = telemetry[positionEnd];
var result = (pEnd.DateTime - pBegin.DateTime).TotalMinutes;
return result;
}
protected override bool IsValid(DetectedOperation result)
=> result.Value > 0;
}
#nullable disable
}

View File

@ -0,0 +1,144 @@
using AsbCloudDb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
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 int FragmentLength { get => fragmentLength; set => fragmentLength = value; }
public int StepLength { get => stepLength; set => stepLength = value; }
public FragmentDetector(
Func<DetectableTelemetry[], int, bool> detectStart,
IFragmentDetector detector,
params IFragmentDetector[] detectors)
{
this.detectStart = detectStart;
this.detectors = JoinDetectors(detector, detectors);
detectEnd = (f, i) => !detectStart(f,i);
}
public FragmentDetector(
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);
}
public FragmentDetector(Func<DetectableTelemetry[], int, bool> detectStart, IOperationDetector operation)
{
this.detectStart = detectStart;
detectors = new IOperationDetector[] { operation };
detectEnd = (f, i) => !detectStart(f, i);
}
public FragmentDetector(Func<DetectableTelemetry[], int, bool> detectStart, Func<DetectableTelemetry[], int, bool> detectEnd, IOperationDetector operation)
{
this.detectStart = detectStart;
this.detectEnd = detectEnd;
detectors = new IOperationDetector[] { operation };
}
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 && fragmentLength < telemetry.Length)
data = telemetry[position..(position + fragmentLength)];
else
data = telemetry;
var line = new InterpolationLine(data.Select(d => (yGetter(d), (d.DateTime - telemetry[0].DateTime).TotalHours)));
var result = interpolationValueCondition(line);
return result;
};
return detect;
}
public IFragmentDetector AddChildDetector(params IFragmentDetector[] detectors)
{
throw new NotImplementedException();
}
public IDetector AddOperationDetector(IOperationDetector operation)
{
detectors = new IOperationDetector[] { operation};
return this;
}
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, out IEnumerable<DetectedOperation> operations)
{
var positionStart = 0;
var operationsList = new List<DetectedOperation>();
// поиск начала соответствия критерию
while (telemetryFragment.Length > positionStart + FragmentLength + stepLength)
{
if (detectStart(telemetryFragment, positionStart))
{
// Поиск окончания соответствия критерию
var positionEnd = positionStart + stepLength;
while (telemetryFragment.Length > positionEnd + FragmentLength)
{
if (detectEnd(telemetryFragment, positionEnd))
{
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);
break;
}
positionEnd += stepLength;
}
positionStart = positionEnd;
}
else
{
positionStart += stepLength;
}
}
operations = operationsList;
return operationsList.Any();
}
}
#nullable disable
}

View File

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

View File

@ -0,0 +1,66 @@
using AsbCloudDb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
internal class OperationDetector : IOperationDetector
{
private readonly int idOperation;
protected Func<DetectableTelemetry[], bool> isValid = (_) => true;
protected Func<DetectableTelemetry[], double> calcValue = (_) => 0d;
public OperationDetector(int idOperation)
{
this.idOperation = idOperation;
}
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, out IEnumerable<DetectedOperation> operations)
{
if(!telemetryFragment.Any() || !isValid(telemetryFragment))
{
operations = Enumerable.Empty<DetectedOperation>();
return false;
}
var operation = MakeOperation(idTelemetry, telemetryFragment);
operations = new List<DetectedOperation> { operation };
return true;
}
private DetectedOperation MakeOperation(int idTelemetry, DetectableTelemetry[] telemetryFragment)
{
var pBegin = telemetryFragment.First();
var pEnd = telemetryFragment.Last();
var 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),
};
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;
}
}
}

View File

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

View File

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

View File

@ -46,10 +46,10 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
public bool IsYDecreases(double bound = 0d) =>
A < bound;
public bool IsAverageYLessThanBound(double bound) =>
public bool IsAverageYLessThan(double bound) =>
(ySum / count) < bound;
public bool IsAverageYMoreThanBound(double bound) =>
public bool IsAverageYGreaterThan(double bound) =>
(ySum / count) >= bound;
}
}

View File

@ -8,31 +8,39 @@ using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
namespace AsbCloudInfrastructure.Services.DetectOperations
{
public class OperationDetectionBackgroundService : BackgroundService
{
private readonly IEnumerable<DetectorAbstract> detectors = new List<DetectorAbstract>
{
new Detectors.DetectorSlipsTime(),
new Detectors.DetectorDrillingRotor(),
new Detectors.DetectorDrillingSlide(),
};
private readonly int minStepLength;
private readonly int minFragmentLength;
private readonly int minStepLength = 3;
private readonly int minFragmentLength = 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 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())))
)
};
public OperationDetectionBackgroundService(IConfiguration configuration)
{
minStepLength = detectors.Min(d => d.StepLength);
minStepLength = minStepLength > 0 ? minStepLength : 3;
minFragmentLength = detectors.Min(d => d.FragmentLength);
minFragmentLength = minFragmentLength > 0 ? minFragmentLength : 6;
connectionString = configuration.GetConnectionString("DefaultConnection");
}
@ -128,70 +136,46 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
})
.OrderBy(d => d.DateTime);
var take = 4 * 86_400;
var take = 4 * 86_400;// 4 дня
var startDate = begin;
var detectedOperations = new List<DetectedOperation>(8);
var dbRequests_ = 0;
var dbTime_ = 0d;
var sw_ = new Stopwatch();
var otherTime_ = 0d;
while (true)
{
sw_.Restart();
var data = await query
.Where(d => d.DateTime > startDate)
.Take(take)
.ToArrayAsync(token);
sw_.Stop();
dbTime_ += sw_.ElapsedMilliseconds;
dbRequests_++;
sw_.Restart();
if (data.Length < minFragmentLength)
break;
var skip = 0;
var isDetected = false;
while (data.Length > skip + minFragmentLength)
foreach (var detector in detectors)
{
var isDetected1 = false;
foreach (var detector in detectors)
if (detector is FragmentDetector fragmentDetector)
{
if (data.Length < skip + detector.StepLength + detector.FragmentLength)
var minLengthToDetect = fragmentDetector.StepLength + fragmentDetector.FragmentLength;
if (data.Length < minLengthToDetect)
continue;
var detectedOperation = detector.DetectOrDefault(data, ref skip);
if (detectedOperation is not null)
if (fragmentDetector.TryDetect(idTelemetry, data, out IEnumerable<DetectedOperation> operations))
{
isDetected1 = true;
isDetected = true;
detectedOperation.IdTelemetry = idTelemetry;
detectedOperations.Add(detectedOperation);
startDate = detectedOperation.DateEnd;
detectedOperations.AddRange(operations);
startDate = operations.Last().DateEnd;
break;
}
}
if (!isDetected1)
skip += minStepLength;
}
sw_.Stop();
otherTime_ += sw_.ElapsedMilliseconds;
if (!isDetected)
{
if (data.Length < take)
break;
var lastPartDate = data.Last().DateTime;
startDate = startDate + (0.75 * (lastPartDate - startDate));
startDate = startDate.AddSeconds(0.95 * take);
}
}