forked from ddrilling/AsbCloudServer
8bbaca0d0c
1. Поправел excel шаблон 2. Доработаны алгоритмы определения операций бурения 3. Небольшой рефакторинг DetectorAbstract, добавил метод для валидации 4. Закомментированы неиспользуемые детекторы. 5. Обновлена спецификация определения операций бурения 6. Добавлены тесты для определения операций бурения
153 lines
5.3 KiB
C#
153 lines
5.3 KiB
C#
using AsbCloudDb.Model;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
|
using AsbCloudInfrastructure.Background;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace AsbCloudInfrastructure.Services.DetectOperations;
|
|
|
|
public class WorkOperationDetection: Work
|
|
{
|
|
private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
|
|
{
|
|
new DetectorDrilling()
|
|
// new DetectorRotor(),
|
|
// new DetectorSlide(),
|
|
//new DetectorDevelopment(),
|
|
//new DetectorTemplating(),
|
|
//new DetectorStaticSurveying(),
|
|
//new DetectorFlashingBeforeConnection(),
|
|
//new DetectorFlashing(),
|
|
//new DetectorTemplatingWhileDrilling(),
|
|
};
|
|
|
|
public WorkOperationDetection()
|
|
:base("Operation detection")
|
|
{
|
|
Timeout = TimeSpan.FromMinutes(20);
|
|
OnErrorAsync = (id, exception, token) =>
|
|
{
|
|
var text = $"work {id}, when {CurrentState?.State}, throw error:{exception.Message}";
|
|
Trace.TraceWarning(text);
|
|
return Task.CompletedTask;
|
|
};
|
|
}
|
|
|
|
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token)
|
|
{
|
|
using var db = services.GetRequiredService<IAsbCloudDbContext>();
|
|
|
|
var lastDetectedDates = await db.DetectedOperations
|
|
.GroupBy(o => o.IdTelemetry)
|
|
.Select(g => new
|
|
{
|
|
IdTelemetry = g.Key,
|
|
LastDate = g.Max(o => o.DateEnd)
|
|
})
|
|
.ToListAsync(token);
|
|
|
|
var telemetryIds = await db.Telemetries
|
|
.Where(t => t.Info != null && t.TimeZone != null)
|
|
.Select(t => t.Id)
|
|
.ToListAsync(token);
|
|
|
|
var joinedlastDetectedDates = telemetryIds
|
|
.GroupJoin(lastDetectedDates,
|
|
t => t,
|
|
o => o.IdTelemetry,
|
|
(outer, inner) => new
|
|
{
|
|
IdTelemetry = outer,
|
|
inner.SingleOrDefault()?.LastDate,
|
|
});
|
|
|
|
var affected = 0;
|
|
var count = joinedlastDetectedDates.Count();
|
|
var i = 0d;
|
|
foreach (var item in joinedlastDetectedDates)
|
|
{
|
|
var stopwatch = Stopwatch.StartNew();
|
|
var startDate = item.LastDate ?? DateTimeOffset.MinValue;
|
|
onProgressCallback($"start detecting telemetry: {item.IdTelemetry} from {startDate}", i++ / count);
|
|
var newOperations = await DetectOperationsAsync(item.IdTelemetry, startDate, db, token);
|
|
stopwatch.Stop();
|
|
if (newOperations.Any())
|
|
{
|
|
db.DetectedOperations.AddRange(newOperations);
|
|
affected += await db.SaveChangesAsync(token);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
|
{
|
|
var query = db.TelemetryDataSaub
|
|
.AsNoTracking()
|
|
.Where(d => d.IdTelemetry == idTelemetry)
|
|
.Where(d => d.BlockPosition >= 0)
|
|
.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; // 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)
|
|
{
|
|
var data = await query
|
|
.Where(d => d.DateTime > startDate)
|
|
.ToArrayAsync(token);
|
|
|
|
if (data.Length < gap)
|
|
break;
|
|
|
|
var isDetected = false;
|
|
var positionBegin = 0;
|
|
var positionEnd = data.Length - gap;
|
|
while (positionEnd > positionBegin)
|
|
{
|
|
foreach (var detector in detectors)
|
|
{
|
|
if (!detector.TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out var result))
|
|
continue;
|
|
|
|
detectedOperations.Add(result!.Operation);
|
|
lastDetectedOperation = result.Operation;
|
|
isDetected = true;
|
|
positionBegin = result.TelemetryEnd;
|
|
break;
|
|
}
|
|
|
|
positionBegin += 1;
|
|
}
|
|
|
|
if (isDetected)
|
|
startDate = lastDetectedOperation!.DateEnd;
|
|
else
|
|
startDate = data[positionEnd].DateTime;
|
|
}
|
|
|
|
return detectedOperations;
|
|
}
|
|
}
|