DetectedOperationExportService replace DetectOperationsAsync(..) by WorkOperationDetection.DetectOperationsAsync(..)

This commit is contained in:
ngfrolov 2024-02-08 12:23:23 +05:00
parent b7dcf313a2
commit bb4c11bd3e
Signed by: ng.frolov
GPG Key ID: E99907A0357B29A7
2 changed files with 43 additions and 114 deletions

View File

@ -1,6 +1,5 @@
using AsbCloudDb.Model; using AsbCloudDb.Model;
using ClosedXML.Excel; using ClosedXML.Excel;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -9,22 +8,21 @@ using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Data.DetectedOperation;
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Http.Extensions;
using AsbCloudApp.Exceptions; using AsbCloudApp.Exceptions;
using AsbCloudApp.Services;
using AsbCloudApp.Data;
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
namespace AsbCloudInfrastructure.Services.DetectOperations; namespace AsbCloudInfrastructure.Services.DetectOperations;
public class DetectedOperationExportService public class DetectedOperationExportService
{ {
private readonly DetectorAbstract[] detectors = private readonly IAsbCloudDbContext db;
{ private readonly IWellService wellService;
new DetectorDrilling(), private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
new DetectorSlipsTime() private const int headerRowsCount = 1;
};
private const int headerRowsCount = 1;
private const string cellDepositName = "B1"; private const string cellDepositName = "B1";
private const string cellClusterName = "B2"; private const string cellClusterName = "B2";
@ -42,14 +40,14 @@ public class DetectedOperationExportService
private const int columnIdReasonOfEnd = 9; private const int columnIdReasonOfEnd = 9;
private const int columnComment = 10; private const int columnComment = 10;
//TODO: удалить неиспользуемую зависимость public DetectedOperationExportService(
private readonly IAsbCloudDbContext dbContext; IAsbCloudDbContext db,
private readonly IWellOperationRepository wellOperationRepository; IWellService wellService,
IWellOperationCategoryRepository wellOperationCategoryRepository)
public DetectedOperationExportService(IAsbCloudDbContext dbContext, IWellOperationRepository wellOperationRepository)
{ {
this.dbContext = dbContext; this.db = db;
this.wellOperationRepository = wellOperationRepository; this.wellService = wellService;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
} }
/// <summary> /// <summary>
@ -57,15 +55,12 @@ public class DetectedOperationExportService
/// </summary> /// </summary>
/// <param name="idWell">ключ скважины</param> /// <param name="idWell">ключ скважины</param>
/// <param name="host">хост</param> /// <param name="host">хост</param>
/// <param name="cancellationToken"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="ArgumentInvalidException"></exception> /// <exception cref="ArgumentInvalidException"></exception>
public async Task<Stream> ExportAsync(int idWell, string host, CancellationToken cancellationToken) public async Task<Stream> ExportAsync(int idWell, string host, CancellationToken token)
{ {
var well = await dbContext.Set<Well>() var well = await wellService.GetOrDefaultAsync(idWell, token);
.Include(w => w.Cluster)
.ThenInclude(c => c.Deposit)
.FirstOrDefaultAsync(w => w.Id == idWell, cancellationToken);
if (well is null) if (well is null)
throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} does not exist"); throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} does not exist");
@ -73,19 +68,19 @@ public class DetectedOperationExportService
if (!well.IdTelemetry.HasValue) if (!well.IdTelemetry.HasValue)
throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} has no telemetry"); throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} has no telemetry");
var operations = await DetectOperationsAsync(well.IdTelemetry.Value, DateTime.UnixEpoch, cancellationToken); var operations = await WorkOperationDetection.DetectOperationsAsync(well.IdTelemetry.Value, DateTime.UnixEpoch, db, token);
return await GenerateExcelFileStreamAsync(well, host, operations, cancellationToken); return await GenerateExcelFileStreamAsync(well, host, operations, token);
} }
private async Task<Stream> GenerateExcelFileStreamAsync(Well well, string host, IEnumerable<OperationDetectorResult> operationDetectorResults, private async Task<Stream> GenerateExcelFileStreamAsync(WellDto well, string host, IEnumerable<DetectedOperation> operationDetectorResults,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken); using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken);
using var workbook = new XLWorkbook(excelTemplateStream); using var workbook = new XLWorkbook(excelTemplateStream);
await AddToWorkbookAsync(workbook, well, host, operationDetectorResults, cancellationToken); AddToWorkbook(workbook, well, host, operationDetectorResults);
MemoryStream memoryStream = new MemoryStream(); MemoryStream memoryStream = new MemoryStream();
workbook.SaveAs(memoryStream, new SaveOptions { }); workbook.SaveAs(memoryStream, new SaveOptions { });
@ -93,36 +88,34 @@ public class DetectedOperationExportService
return memoryStream; return memoryStream;
} }
private async Task AddToWorkbookAsync(XLWorkbook workbook, Well well, string host, IEnumerable<OperationDetectorResult> operationDetectorResults, private void AddToWorkbook(XLWorkbook workbook, WellDto well, string host, IEnumerable<DetectedOperation> operations)
CancellationToken cancellationToken)
{ {
const string sheetName = "Операции"; const string sheetName = "Операции";
if (!operationDetectorResults.Any()) if (!operations.Any())
return; return;
var sheet = workbook.GetWorksheet(sheetName); var sheet = workbook.GetWorksheet(sheetName);
await AddToSheetAsync(sheet, well, host, operationDetectorResults var orderedOperations = operations
.OrderBy(x => x.Operation.DateStart).ThenBy(x => x.Operation.DepthStart).ToArray(), .OrderBy(x => x.DateStart)
cancellationToken); .ThenBy(x => x.DepthStart).ToArray();
AddToSheet(sheet, well, host, orderedOperations);
} }
private async Task AddToSheetAsync(IXLWorksheet sheet, Well well, string host, IList<OperationDetectorResult> operationDetectorResults, private void AddToSheet(IXLWorksheet sheet, WellDto well, string host, IList<DetectedOperation> operations)
CancellationToken cancellationToken)
{ {
var wellOperationCategories = await dbContext.WellOperationCategories.ToListAsync(cancellationToken); var wellOperationCategories = wellOperationCategoryRepository.Get(true);
sheet.Cell(cellDepositName).SetCellValue(well.Cluster.Deposit.Caption); sheet.Cell(cellDepositName).SetCellValue(well.Deposit);
sheet.Cell(cellClusterName).SetCellValue(well.Cluster.Caption); sheet.Cell(cellClusterName).SetCellValue(well.Cluster);
sheet.Cell(cellWellName).SetCellValue(well.Caption); sheet.Cell(cellWellName).SetCellValue(well.Caption);
sheet.Cell(cellDeltaDate).SetCellValue(operationDetectorResults.Max(o => o.Operation.DateEnd) - operationDetectorResults.Min(o => o.Operation.DateStart)); sheet.Cell(cellDeltaDate).SetCellValue((TimeSpan)(Enumerable.Max<DetectedOperation, DateTimeOffset>(operations, (Func<DetectedOperation, DateTimeOffset>)(o => o.DateEnd)) - Enumerable.Min<DetectedOperation, DateTimeOffset>(operations, (Func<DetectedOperation, DateTimeOffset>)(o => o.DateStart))));
var detectedOperations = operationDetectorResults.Select(o => o.Operation).ToArray(); for (int i = 0; i < operations.Count; i++)
for (int i = 0; i < operationDetectorResults.Count; i++)
{ {
var current = detectedOperations[i]; var current = operations[i];
var dateStart = current.DateStart.ToRemoteDateTime(well.Timezone.Hours); var dateStart = current.DateStart.ToRemoteDateTime(well.Timezone.Hours);
var dateEnd = current.DateEnd.ToRemoteDateTime(well.Timezone.Hours); var dateEnd = current.DateEnd.ToRemoteDateTime(well.Timezone.Hours);
@ -153,17 +146,18 @@ public class DetectedOperationExportService
var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}"; var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}";
row.Cell(columnDateStart).SetHyperlink(link); row.Cell(columnDateStart).SetHyperlink(link);
var deltaDepth = i > 0 && i + 1 < detectedOperations.Length var deltaDepth = i > 0 && i + 1 < operations.Count
? current.DepthStart - detectedOperations[i - 1].DepthEnd ? current.DepthStart - operations[i - 1].DepthEnd
: 0; : 0;
row.Cell(columnDeltaDepth).SetCellValue(deltaDepth); row.Cell(columnDeltaDepth).SetCellValue(deltaDepth);
var comment = CreateComment(operationDetectorResults[i]); var comment = CreateComment(operations[i]);
row.Cell(columnComment).SetCellValue(comment); row.Cell(columnComment).SetCellValue(comment);
} }
} }
private static string GetCategoryName(IEnumerable<WellOperationCategory> wellOperationCategories, DetectedOperation current) private static string GetCategoryName(IEnumerable<WellOperationCategoryDto> wellOperationCategories, DetectedOperation current)
{ {
var idCategory = current.IdCategory; var idCategory = current.IdCategory;
if (idCategory == WellOperationCategory.IdSlide && if (idCategory == WellOperationCategory.IdSlide &&
@ -204,9 +198,8 @@ public class DetectedOperationExportService
return memoryStream; return memoryStream;
} }
private static string CreateComment(OperationDetectorResult operationDetectorResult) private static string CreateComment(DetectedOperation operation)
{ {
var operation = operationDetectorResult.Operation;
switch (operation.IdCategory) switch (operation.IdCategory)
{ {
case WellOperationCategory.IdRotor: case WellOperationCategory.IdRotor:
@ -224,69 +217,4 @@ public class DetectedOperationExportService
return string.Empty; return string.Empty;
} }
} }
private async Task<IEnumerable<OperationDetectorResult>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin,
CancellationToken token)
{
var query = dbContext.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 startDate = begin;
var detectedOperationResults = new List<OperationDetectorResult>(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;
detectedOperationResults.Add(result!);
lastDetectedOperation = result!.Operation;
isDetected = true;
positionBegin = result.TelemetryEnd;
break;
}
positionBegin += 1;
}
if (isDetected)
startDate = lastDetectedOperation!.DateEnd;
else
startDate = data[positionEnd].DateTime;
}
return detectedOperationResults;
}
} }

View File

@ -86,7 +86,8 @@ public class WorkOperationDetection: Work
} }
} }
private static async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) //todo: move this logic to DetectedOperationsService
internal static async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
{ {
var query = db.TelemetryDataSaub var query = db.TelemetryDataSaub
.AsNoTracking() .AsNoTracking()