forked from ddrilling/AsbCloudServer
Автоопределение операций
This commit is contained in:
parent
e29b2be423
commit
d7e9c4f893
@ -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>
|
||||||
/// Удалить операции
|
/// Удалить операции
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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>();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user