Автоопределение операций

This commit is contained in:
Степанов Дмитрий 2024-07-24 13:19:13 +03:00
parent e29b2be423
commit d7e9c4f893
9 changed files with 205 additions and 113 deletions

View File

@ -1,11 +1,9 @@
using System;
using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading; using System.Threading;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
namespace AsbCloudApp.Repositories; namespace AsbCloudApp.Repositories;
@ -55,11 +53,11 @@ public interface IDetectedOperationRepository
Task<PaginationContainer<DetectedOperationDto>> GetPageAsync(DetectedOperationByTelemetryRequest request, CancellationToken token); Task<PaginationContainer<DetectedOperationDto>> GetPageAsync(DetectedOperationByTelemetryRequest request, CancellationToken token);
/// <summary> /// <summary>
/// Получение дат последних определённых операций /// Получение последних автоопределённых операций
/// </summary> /// </summary>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IDictionary<int, DateTimeOffset>> GetLastDetectedDatesAsync(CancellationToken token); Task<IDictionary<int, DetectedOperationDto>> GetLastDetectedOperationsAsync(CancellationToken token);
/// <summary> /// <summary>
/// Удалить операции /// Удалить операции

View File

@ -79,9 +79,13 @@ namespace AsbCloudApp.Services
/// Определение операций /// Определение операций
/// </summary> /// </summary>
/// <param name="idTelemetry"></param> /// <param name="idTelemetry"></param>
/// <param name="beginDate"></param> /// <param name="request"></param>
/// <param name="lastDetectedOperation"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<DetectedOperationDto>> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, CancellationToken token); Task<(DateTimeOffset LastDate, IEnumerable<DetectedOperationDto> Items)> DetectOperationsAsync(int idTelemetry,
TelemetryDataRequest request,
DetectedOperationDto? lastDetectedOperation,
CancellationToken token);
} }
} }

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {
@ -44,5 +45,12 @@ namespace AsbCloudApp.Services
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<Stream> GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token); Task<Stream> GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token);
/// <summary>
/// Получение диапозона дат телеметрий
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<IDictionary<int, DatesRangeDto>> GetDateRangesAsync(CancellationToken token);
} }
} }

View File

@ -26,6 +26,28 @@ public class DetectedOperationRepository : CrudRepositoryBase<DetectedOperationD
this.telemetryService = telemetryService; this.telemetryService = telemetryService;
} }
public async Task<IDictionary<int, DetectedOperationDto>> GetLastDetectedOperationsAsync(CancellationToken token)
{
var entities = await dbContext.Set<DetectedOperation>()
.GroupBy(o => o.IdTelemetry)
.Select(g => new
{
IdTelemetry = g.Key,
LastDetectedOperation = g.OrderBy(o => o.DateEnd).Last()
})
.ToDictionaryAsync(x => x.IdTelemetry, x => x.LastDetectedOperation, token);
var dtos = entities.ToDictionary(x => x.Key, x =>
{
if (x.Value == null)
throw new ArgumentNullException(nameof(x.Value), "The value of the last detected operation cannot be null");
return Convert(x.Value);
});
return dtos;
}
public async Task<int> DeleteAsync(DetectedOperationByTelemetryRequest request, CancellationToken token) public async Task<int> DeleteAsync(DetectedOperationByTelemetryRequest request, CancellationToken token)
{ {
var query = BuildQuery(request); var query = BuildQuery(request);
@ -58,16 +80,6 @@ public class DetectedOperationRepository : CrudRepositoryBase<DetectedOperationD
return paginationContainer; return paginationContainer;
} }
public async Task<IDictionary<int, DateTimeOffset>> GetLastDetectedDatesAsync(CancellationToken token) =>
await dbContext.Set<DetectedOperation>()
.GroupBy(o => o.IdTelemetry)
.Select(g => new
{
IdTelemetry = g.Key,
LastDate = g.Max(o => o.DateEnd)
})
.ToDictionaryAsync(x => x.IdTelemetry, x => x.LastDate, token);
public async Task<IEnumerable<DetectedOperationDto>> Get(DetectedOperationByTelemetryRequest request, CancellationToken token) public async Task<IEnumerable<DetectedOperationDto>> Get(DetectedOperationByTelemetryRequest request, CancellationToken token)
{ {
var query = BuildQuery(request) var query = BuildQuery(request)

View File

@ -177,30 +177,34 @@ public class DetectedOperationService : IDetectedOperationService
return dtos; return dtos;
} }
public async Task<IEnumerable<DetectedOperationDto>> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, CancellationToken token) public async Task<(DateTimeOffset LastDate, IEnumerable<DetectedOperationDto> Items)> DetectOperationsAsync(int idTelemetry,
TelemetryDataRequest request,
DetectedOperationDto? lastDetectedOperation,
CancellationToken token)
{ {
const int take = 4 * 86_400;
var detectedOperations = new List<DetectedOperationDto>();
DetectedOperationDto? lastDetectedOperation = null;
const int minOperationLength = 5; const int minOperationLength = 5;
const int maxDetectorsInterpolationFrameLength = 30; const int maxDetectorsInterpolationFrameLength = 30;
const int gap = maxDetectorsInterpolationFrameLength + minOperationLength; const int gap = maxDetectorsInterpolationFrameLength + minOperationLength;
var telemetries = await telemetryDataSaubService.GetByTelemetryAsync(idTelemetry, request, token);
var count = telemetries.Count();
if (count == 0)
throw new InvalidOperationException("InvalidOperation_EmptyTelemetries");
var timezone = telemetryService.GetTimezone(idTelemetry); var timezone = telemetryService.GetTimezone(idTelemetry);
while (true) if (telemetries.Count() <= gap)
{ {
var request = new TelemetryDataRequest var lastTelemetry = telemetries.Last();
{ var lastDateTelemetry = new DateTimeOffset(lastTelemetry.DateTime, timezone.Offset);
GeDate = beginDate, return (lastDateTelemetry, Enumerable.Empty<DetectedOperationDto>());
Take = take, }
Order = 0
};
var dtos = await telemetryDataSaubService.GetByTelemetryAsync(idTelemetry, request, token); var detectedOperations = new List<DetectedOperationDto>();
var detectableTelemetries = dtos
.Where(t => t.BlockPosition >= 0) var detectableTelemetries = telemetries.Select(t => new DetectableTelemetry
.Select(t => new DetectableTelemetry
{ {
DateTime = new DateTimeOffset(t.DateTime, timezone.Offset), DateTime = new DateTimeOffset(t.DateTime, timezone.Offset),
IdUser = t.IdUser, IdUser = t.IdUser,
@ -214,22 +218,19 @@ public class DetectedOperationService : IDetectedOperationService
AxialLoad = t.AxialLoad, AxialLoad = t.AxialLoad,
}).ToArray(); }).ToArray();
if (detectableTelemetries.Length <= gap)
break;
var isDetected = false;
var positionBegin = 0; var positionBegin = 0;
var positionEnd = detectableTelemetries.Length - gap; var positionEnd = detectableTelemetries.Length - gap;
while (positionEnd > positionBegin) while (positionEnd > positionBegin)
{ {
foreach (var detector in detectors) foreach (var detector in detectors)
{ {
if (!detector.TryDetect(idTelemetry, detectableTelemetries, positionBegin, positionEnd, lastDetectedOperation, out var result)) if (!detector.TryDetect(idTelemetry, detectableTelemetries, positionBegin, positionEnd, lastDetectedOperation,
out var result))
continue; continue;
detectedOperations.Add(result!.Operation); detectedOperations.Add(result!.Operation);
lastDetectedOperation = result.Operation; lastDetectedOperation = result.Operation;
isDetected = true;
positionBegin = result.TelemetryEnd; positionBegin = result.TelemetryEnd;
break; break;
} }
@ -237,12 +238,9 @@ public class DetectedOperationService : IDetectedOperationService
positionBegin += 1; positionBegin += 1;
} }
beginDate = isDetected var lastDate = lastDetectedOperation?.DateEnd ?? detectableTelemetries[positionEnd].DateTime;
? lastDetectedOperation!.DateEnd
: detectableTelemetries[positionEnd].DateTime;
}
return detectedOperations; return (lastDate, detectedOperations);
} }
public async Task<int> DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token) public async Task<int> DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token)

View File

@ -48,6 +48,8 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
while (positionEnd < end) while (positionEnd < end)
{ {
//TODO: поиск провалов телеметрии
positionEnd += 1; positionEnd += 1;
if (positionEnd > end) if (positionEnd > end)
break; break;

View File

@ -1,24 +1,27 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudInfrastructure.Background; using AsbCloudInfrastructure.Background;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace AsbCloudInfrastructure.Services.DetectOperations; namespace AsbCloudInfrastructure.Services.DetectOperations;
public class WorkOperationDetection: Work public class WorkOperationDetection : Work
{ {
private static readonly IDictionary<int, DateTime> CacheOfStartDatesByTelemetryId = new Dictionary<int, DateTime>();
public WorkOperationDetection() public WorkOperationDetection()
:base("Operation detection") : base("Operation detection")
{ {
Timeout = TimeSpan.FromMinutes(20); Timeout = TimeSpan.FromMinutes(20);
OnErrorAsync = (id, exception, token) => OnErrorAsync = (id, exception, _) =>
{ {
var text = $"work {id}, when {CurrentState?.State}, throw error:{exception.Message}"; var text = $"work {id}, when {CurrentState?.State}, throw error:{exception.Message}";
Trace.TraceWarning(text); Trace.TraceWarning(text);
@ -26,29 +29,65 @@ public class WorkOperationDetection: Work
}; };
} }
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token) protected override async Task Action(string id,
IServiceProvider services,
Action<string, double?> onProgressCallback,
CancellationToken token)
{ {
var telemetryRepository = services.GetRequiredService<ICrudRepository<TelemetryDto>>(); var telemetryRepository = services.GetRequiredService<ICrudRepository<TelemetryDto>>();
var detectedOperationRepository = services.GetRequiredService<IDetectedOperationRepository>(); var detectedOperationRepository = services.GetRequiredService<IDetectedOperationRepository>();
var detectedOperationService = services.GetRequiredService<IDetectedOperationService>(); var detectedOperationService = services.GetRequiredService<IDetectedOperationService>();
var telemetryDataSaubService = services.GetRequiredService<ITelemetryDataSaubService>();
var telemetryIds = (await telemetryRepository.GetAllAsync(token)) var idsTelemetry = (await telemetryRepository.GetAllAsync(token))
.Select(t => t.Id) .Select(t => t.Id)
.ToArray(); .ToArray();
var lastDetectedDates = await detectedOperationRepository.GetLastDetectedDatesAsync(token); var telemetriesDateRanges = await telemetryDataSaubService.GetDateRangesAsync(token);
for (var i = 0; i < telemetryIds.Length; i++) var lastDetectedOperations = await detectedOperationRepository.GetLastDetectedOperationsAsync(token);
for (int i = 0; i < idsTelemetry.Length; i++)
{ {
var telemetryId = telemetryIds[i]; var idTelemetry = idsTelemetry[i];
var beginDate = lastDetectedDates.TryGetValue(telemetryId, out var date) ? date : (DateTimeOffset?)null; if (!telemetriesDateRanges.TryGetValue(idTelemetry, out var telemetryDateRange))
continue;
onProgressCallback($"Start detecting telemetry: {telemetryId} from {beginDate}", i / telemetryIds.Length); var dateBegin = telemetryDateRange.From.DateTime;
var detectedOperations = await detectedOperationService.DetectOperationsAsync(telemetryId, beginDate, token); var dateEnd = telemetryDateRange.To.DateTime;
if (detectedOperations.Any()) if (lastDetectedOperations.TryGetValue(idTelemetry, out var lastDetectedOperation))
await detectedOperationRepository.InsertRangeAsync(detectedOperations, token); dateBegin = lastDetectedOperation.DateEnd.UtcDateTime;
if (CacheOfStartDatesByTelemetryId.TryGetValue(idTelemetry, out var dateBeginFromCahce))
dateBegin = dateBeginFromCahce;
onProgressCallback.Invoke($"Start detecting telemetry: {idTelemetry} from {dateBegin}", i / idsTelemetry.Length);
const int pointsCount = 4 * 86_400;
while (dateBegin < dateEnd)
{
var request = new TelemetryDataRequest
{
GeDate = dateBegin,
Take = pointsCount,
Order = 0,
GeBlockPosition = 0
};
var detectedOperations =
await detectedOperationService.DetectOperationsAsync(idTelemetry, request, lastDetectedOperation, token);
await detectedOperationRepository.InsertRangeAsync(detectedOperations.Items, token);
dateBegin = detectedOperations.LastDate.UtcDateTime;
CacheOfStartDatesByTelemetryId[idTelemetry] = dateBegin;
await detectedOperationRepository.InsertRangeAsync(detectedOperations.Items, token);
}
} }
} }
} }

View File

@ -177,7 +177,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
return dtos; return dtos;
} }
private IQueryable<TEntity> BuildQuery(int idTelemetry, TelemetryDataRequest request) protected virtual IQueryable<TEntity> BuildQuery(int idTelemetry, TelemetryDataRequest request)
{ {
var dbSet = db.Set<TEntity>(); var dbSet = db.Set<TEntity>();

View File

@ -13,6 +13,8 @@ using System.Linq;
using System.Text.Csv; using System.Text.Csv;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
namespace AsbCloudInfrastructure.Services.SAUB; namespace AsbCloudInfrastructure.Services.SAUB;
@ -174,4 +176,33 @@ public class TelemetryDataSaubService : TelemetryDataBaseService<TelemetryDataSa
outStream.Seek(0, SeekOrigin.Begin); outStream.Seek(0, SeekOrigin.Begin);
return outStream; return outStream;
} }
public async Task<IDictionary<int, DatesRangeDto>> GetDateRangesAsync(CancellationToken token)
{
return await db.Set<TelemetryDataSaub>().GroupBy(x => x.IdTelemetry)
.Select(g => new
{
IdTelemetry = g.Key,
From = g.Min(x => x.DateTime),
To = g.Max(x => x.DateTime)
})
.ToDictionaryAsync(x => x.IdTelemetry, x => new DatesRangeDto
{
From = x.From,
To = x.To
}, token);
}
protected override IQueryable<TelemetryDataSaub> BuildQuery(int idTelemetry, TelemetryDataRequest request)
{
var query = base.BuildQuery(idTelemetry, request);
if (request.GeBlockPosition.HasValue)
query = query.Where(e => e.BlockPosition >= request.GeBlockPosition);
if (request.LeBlockPosition.HasValue)
query = query.Where(e => e.BlockPosition <= request.LeBlockPosition);
return query;
}
} }