forked from ddrilling/AsbCloudServer
Add DetectorService
This commit is contained in:
parent
f76cc52fc8
commit
6738bb3b35
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||||
|
{
|
||||||
|
public class DetectableTelemetry
|
||||||
|
{
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||||
|
{
|
||||||
|
public class DetectedOperation
|
||||||
|
{
|
||||||
|
public int IdType { get; set; }
|
||||||
|
public int IdUsersAtStart { get; set; }
|
||||||
|
public DateTimeOffset Begin { get; set; }
|
||||||
|
public DateTimeOffset End { get; set; }
|
||||||
|
public double DurationMinutes => (End - Begin).TotalMinutes;
|
||||||
|
public double BeginWellDepth { get; set; }
|
||||||
|
public double EndWellDepth { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
=> $"{IdType}\t{Begin:G}\t{End:G}\t{DurationMinutes:#0.#}\t{BeginWellDepth:#0.#}\t{EndWellDepth:#0.#}";
|
||||||
|
//=> $"{{\"type\": {IdType},\t\"begin\":\"{Begin:G}\",\t\"end\":\"{End:G}\",\t\"depthBegin\":\"{BeginWellDepth:#0.#}\",\t\"depthEnd\":\"{EndWellDepth:#0.#}\"}}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
using AsbCloudDb.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||||
|
{
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
abstract class DetectorAbstract
|
||||||
|
{
|
||||||
|
/* ## Концепт определения операций
|
||||||
|
* Есть словарь детекторов.
|
||||||
|
* Определить начальную позицию архива.
|
||||||
|
* Пройти детекторами до конца архива.
|
||||||
|
* Каждый детектор на небольшому фрагменту определяет начало операции.
|
||||||
|
* При нахождении начала ищет конец и смещает положение поиска
|
||||||
|
*/
|
||||||
|
public int StepLength { get; set; } = 3;
|
||||||
|
public int FragmentLength { get; set; } = 6;
|
||||||
|
public int IdOperationType { get; }
|
||||||
|
public string OperationName { get; }
|
||||||
|
|
||||||
|
// TODO: assert MaxDurationSeconds and MinDurationSeconds
|
||||||
|
public double MaxDurationSeconds { get; } = 31 * 24 * 60 * 60;
|
||||||
|
public double MinDurationSeconds { get; } = 3;
|
||||||
|
|
||||||
|
public DetectorAbstract(int idType, string operationName)
|
||||||
|
{
|
||||||
|
IdOperationType = idType;
|
||||||
|
OperationName = operationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual DetectedOperation? DetectOrDefault(DetectableTelemetry[] telemetry, ref int position)
|
||||||
|
{
|
||||||
|
if ((telemetry.Length > position + FragmentLength + StepLength) && DetectStart(telemetry, position))
|
||||||
|
{
|
||||||
|
var skip = position + StepLength;
|
||||||
|
while (telemetry.Length > skip + FragmentLength)
|
||||||
|
{
|
||||||
|
if (DetectEnd(telemetry, skip))
|
||||||
|
{
|
||||||
|
var result = new DetectedOperation
|
||||||
|
{
|
||||||
|
IdType = IdOperationType,
|
||||||
|
IdUsersAtStart = telemetry[position].IdUser ?? -1,
|
||||||
|
Begin = telemetry[position].DateTime,
|
||||||
|
End = telemetry[skip].DateTime,
|
||||||
|
BeginWellDepth = telemetry[position].WellDepth ?? -1d,
|
||||||
|
EndWellDepth = telemetry[skip].WellDepth ?? -1d,
|
||||||
|
};
|
||||||
|
position = skip + FragmentLength;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip = skip + StepLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract bool DetectStart(DetectableTelemetry[] telemetry, int position);
|
||||||
|
|
||||||
|
protected abstract bool DetectEnd(DetectableTelemetry[] telemetry, int position);
|
||||||
|
|
||||||
|
}
|
||||||
|
#nullable disable
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
using AsbCloudDb.Model;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||||
|
{
|
||||||
|
public class DetectorService
|
||||||
|
{
|
||||||
|
readonly IEnumerable<DetectorAbstract> detectors = new List<DetectorAbstract>
|
||||||
|
{
|
||||||
|
new Detectors.DetectorSlipsTime(),
|
||||||
|
// new Detectors.DetectorDrillingRotor(),
|
||||||
|
// new Detectors.DetectorDrillingSlide(),
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly int minStepLength;
|
||||||
|
private readonly int minFragmentLength;
|
||||||
|
|
||||||
|
public DetectorService()
|
||||||
|
{
|
||||||
|
minStepLength = detectors.Min(d => d.StepLength);
|
||||||
|
minStepLength = minStepLength > 0 ? minStepLength : 3;
|
||||||
|
|
||||||
|
minFragmentLength = detectors.Min(d => d.FragmentLength);
|
||||||
|
minFragmentLength = minFragmentLength > 0 ? minFragmentLength : 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = db.TelemetryDataSaub
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(d => d.IdTelemetry == idTelemetry)
|
||||||
|
.Select(d => new DetectableTelemetry{
|
||||||
|
DateTime = d.DateTime,
|
||||||
|
IdUser = d.IdUser,
|
||||||
|
WellDepth = d.WellDepth,
|
||||||
|
Pressure = d.Pressure,
|
||||||
|
HookWeight = d.HookWeight,
|
||||||
|
BlockPosition = d.BlockPosition,
|
||||||
|
BitDepth = d.BitDepth,
|
||||||
|
RotorSpeed = d.RotorSpeed,
|
||||||
|
})
|
||||||
|
.OrderBy(d => d.DateTime);
|
||||||
|
|
||||||
|
var take = 4 * 86_400;
|
||||||
|
var startDate = begin;
|
||||||
|
var detectedOperations = new List<DetectedOperation>(8);
|
||||||
|
|
||||||
|
var dbRequests_ = 0;
|
||||||
|
var dbTime_ = 0d;
|
||||||
|
var sw_ = new System.Diagnostics.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)
|
||||||
|
{
|
||||||
|
var isDetected1 = false;
|
||||||
|
|
||||||
|
foreach (var detector in detectors)
|
||||||
|
{
|
||||||
|
if(data.Length < skip + detector.StepLength + detector.FragmentLength)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var detectedOperation = detector.DetectOrDefault(data, ref skip);
|
||||||
|
if (detectedOperation is not null)
|
||||||
|
{
|
||||||
|
isDetected1 = true;
|
||||||
|
isDetected = true;
|
||||||
|
detectedOperations.Add(detectedOperation);
|
||||||
|
startDate = detectedOperation.End;
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return detectedOperations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||||
|
{
|
||||||
|
#nullable enable
|
||||||
|
class DetectorDrillingRotor : DetectorAbstract
|
||||||
|
{
|
||||||
|
public DetectorDrillingRotor() : base(10_002, "Бурение в роторе")
|
||||||
|
{
|
||||||
|
FragmentLength = 15;
|
||||||
|
StepLength = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool DetectStart(DetectableTelemetry[] telemetry, int position)
|
||||||
|
{
|
||||||
|
var fragment = telemetry[position .. (position + FragmentLength)];
|
||||||
|
|
||||||
|
const double minRop = 5; //м/час
|
||||||
|
const double minRotorSpeed = 5; //об/мин
|
||||||
|
const double ticksPerHour = 60 * 60 * 10_000_000d;
|
||||||
|
|
||||||
|
var lineBlockPosition = new InterpolationLine(fragment.Select(d => (d.BlockPosition ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||||
|
if (!lineBlockPosition.IsYDecreases(minRop))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var lineWellDepth = new InterpolationLine(fragment.Select(d => (d.WellDepth ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||||
|
if(!lineWellDepth.IsYIncreases(minRop))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var lineRotorSpeed = new InterpolationLine(fragment.Select(d => (d.RotorSpeed ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||||
|
if (!lineRotorSpeed.IsAverageYLessThanBound(minRotorSpeed))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position)
|
||||||
|
=> !DetectStart(telemetry, position);
|
||||||
|
|
||||||
|
}
|
||||||
|
#nullable disable
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||||
|
{
|
||||||
|
#nullable enable
|
||||||
|
class DetectorDrillingSlide : DetectorAbstract
|
||||||
|
{
|
||||||
|
public DetectorDrillingSlide() : base(10_003, "Бурение в слайде")
|
||||||
|
{
|
||||||
|
FragmentLength = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool DetectStart(DetectableTelemetry[] telemetry, int position)
|
||||||
|
{
|
||||||
|
var fragment = telemetry[position .. (position + FragmentLength)];
|
||||||
|
|
||||||
|
const double minRop = 5; //м/час
|
||||||
|
const double minRotorSpeed = 5; //об/мин
|
||||||
|
const double ticksPerHour = 60 * 60 * 10_000_000d;
|
||||||
|
|
||||||
|
var lineBlockPosition = new InterpolationLine(fragment.Select(d => (d.BlockPosition ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||||
|
if (!lineBlockPosition.IsYDecreases(minRop))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var lineWellDepth = new InterpolationLine(fragment.Select(d => (d.WellDepth ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||||
|
if(!lineWellDepth.IsYIncreases(minRop))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var lineRotorSpeed = new InterpolationLine(fragment.Select(d => (d.RotorSpeed ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||||
|
if (!lineRotorSpeed.IsAverageYMoreThanBound(minRotorSpeed))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position)
|
||||||
|
=> !DetectStart(telemetry, position);
|
||||||
|
|
||||||
|
}
|
||||||
|
#nullable disable
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||||
|
{
|
||||||
|
#nullable enable
|
||||||
|
class DetectorSlipsTime : DetectorAbstract
|
||||||
|
{
|
||||||
|
public DetectorSlipsTime() : base(10_001, "Удержание в клиньях")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public double HookWeightSP { get; set; } = 20;
|
||||||
|
public double PressureSP { get; set; } = 15;
|
||||||
|
public double PosisionSP { get; set; } = 8;
|
||||||
|
|
||||||
|
protected override bool DetectStart(DetectableTelemetry[] telemetry, int position)
|
||||||
|
{
|
||||||
|
var item = telemetry[position];
|
||||||
|
|
||||||
|
var result = item.HookWeight < HookWeightSP &&
|
||||||
|
item.Pressure < PressureSP &&
|
||||||
|
item.BlockPosition < PosisionSP;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position)
|
||||||
|
{
|
||||||
|
var item = telemetry[position];
|
||||||
|
|
||||||
|
var result = item.Pressure > PressureSP &&
|
||||||
|
item.BlockPosition > PosisionSP;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#nullable disable
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||||
|
{
|
||||||
|
public class InterpolationLine
|
||||||
|
{
|
||||||
|
private readonly double xSum;
|
||||||
|
private readonly double ySum;
|
||||||
|
private readonly double xySum;
|
||||||
|
private readonly double x2Sum;
|
||||||
|
private readonly int count;
|
||||||
|
|
||||||
|
public InterpolationLine(IEnumerable<(double Y, double X)> rawData)
|
||||||
|
{
|
||||||
|
var iterator = rawData.GetEnumerator();
|
||||||
|
while (iterator.MoveNext())
|
||||||
|
{
|
||||||
|
xSum += iterator.Current.X;
|
||||||
|
ySum += iterator.Current.Y;
|
||||||
|
xySum += iterator.Current.X * iterator.Current.Y;
|
||||||
|
x2Sum += iterator.Current.X * iterator.Current.X;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// tan(alpha)
|
||||||
|
/// </summary>
|
||||||
|
public double A =>
|
||||||
|
(xSum * ySum - count * xySum) /
|
||||||
|
(xSum * xSum - count * x2Sum);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// y offset
|
||||||
|
/// </summary>
|
||||||
|
public double B =>
|
||||||
|
(xSum * xySum - x2Sum * ySum) /
|
||||||
|
(xSum * xSum - count * x2Sum);
|
||||||
|
|
||||||
|
public bool IsYNotChanges(double upperBound = 0d, double lowerBound = 0d) =>
|
||||||
|
A < upperBound && A > lowerBound;
|
||||||
|
|
||||||
|
public bool IsYIncreases(double bound = 0d) =>
|
||||||
|
A > bound;
|
||||||
|
|
||||||
|
public bool IsYDecreases(double bound = 0d) =>
|
||||||
|
A < bound;
|
||||||
|
|
||||||
|
public bool IsAverageYLessThanBound(double bound) =>
|
||||||
|
(ySum / count) < bound;
|
||||||
|
|
||||||
|
public bool IsAverageYMoreThanBound(double bound) =>
|
||||||
|
(ySum / count) >= bound;
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace ConsoleApp1
|
namespace ConsoleApp1
|
||||||
{
|
{
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static void Main(/*string[] args*/)
|
static void Main(/*string[] args*/)
|
||||||
{
|
{
|
||||||
// use ServiceFactory to make services
|
// use ServiceFactory to make services
|
||||||
|
|
||||||
|
var db = ServiceFactory.MakeContext();
|
||||||
|
var service = new AsbCloudInfrastructure.Services.DetectOperations.DetectorService();
|
||||||
|
var start = new DateTimeOffset(2021, 1, 30, 23, 00, 00, TimeSpan.FromHours(0));
|
||||||
|
var operations = service.DetectOperationsAsync(146, start, db, CancellationToken.None).Result;
|
||||||
|
foreach (var operation in operations)
|
||||||
|
Console.WriteLine(operation);
|
||||||
|
|
||||||
Console.WriteLine("End of Test");
|
Console.WriteLine("End of program");
|
||||||
Console.ReadLine();
|
Console.ReadLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,14 @@ namespace ConsoleApp1
|
|||||||
static TimezoneService TimezoneService { get; } = new TimezoneService();
|
static TimezoneService TimezoneService { get; } = new TimezoneService();
|
||||||
public static AsbCloudDbContext Context { get; } = MakeContext();
|
public static AsbCloudDbContext Context { get; } = MakeContext();
|
||||||
public static AsbCloudDbContext MakeContext()
|
public static AsbCloudDbContext MakeContext()
|
||||||
|
=> MakeContext(options);
|
||||||
|
|
||||||
|
public static AsbCloudDbContext MakeContext(DbContextOptions<AsbCloudDbContext> options)
|
||||||
=> new AsbCloudDbContext(options);
|
=> new AsbCloudDbContext(options);
|
||||||
|
|
||||||
|
public static AsbCloudDbContext MakeContext(string cusomConnectionString)
|
||||||
|
=> MakeContext(new DbContextOptionsBuilder<AsbCloudDbContext>().UseNpgsql(cusomConnectionString).Options);
|
||||||
|
|
||||||
public static void MapsterSetup()
|
public static void MapsterSetup()
|
||||||
=> AsbCloudInfrastructure.DependencyInjection.MapsterSetup();
|
=> AsbCloudInfrastructure.DependencyInjection.MapsterSetup();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user