diff --git a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs
index 51a96966..6e4eadaf 100644
--- a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs
+++ b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs
@@ -1,11 +1,10 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Requests;
-using AsbCloudApp.Services;
-using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using AsbCloudApp.Services;
namespace AsbCloudApp.Repositories;
@@ -21,7 +20,7 @@ public interface IDetectedOperationRepository : ITelemetryDataEditorService
///
/// количество добавленных
Task InsertRangeAsync(IEnumerable dtos, CancellationToken token);
-
+
///
/// Обновить несколько записей
///
@@ -37,7 +36,7 @@ public interface IDetectedOperationRepository : ITelemetryDataEditorService
///
///
Task DeleteRangeAsync(IEnumerable ids, CancellationToken token);
-
+
///
/// Получить автоматически определенные операции по телеметрии
///
@@ -53,13 +52,13 @@ public interface IDetectedOperationRepository : ITelemetryDataEditorService
///
///
Task> GetPageAsync(DetectedOperationByTelemetryRequest request, CancellationToken token);
-
+
///
- /// Получение дат последних определённых операций
+ /// Получение последних авто определённых операций
///
///
///
- Task> GetLastDetectedDatesAsync(CancellationToken token);
+ Task> GetLastDetectedOperationsAsync(CancellationToken token);
///
/// Удалить операции
diff --git a/AsbCloudApp/Requests/TelemetryRequest.cs b/AsbCloudApp/Requests/TelemetryRequest.cs
index 732d8075..04d4ffb4 100644
--- a/AsbCloudApp/Requests/TelemetryRequest.cs
+++ b/AsbCloudApp/Requests/TelemetryRequest.cs
@@ -55,5 +55,4 @@ public class TelemetryDataRequest
///
[Range(1, MaxTake)]
public int Take { get; set; } = 1024;
-
}
diff --git a/AsbCloudApp/Services/IDetectedOperationService.cs b/AsbCloudApp/Services/IDetectedOperationService.cs
index ac7d650c..631046c5 100644
--- a/AsbCloudApp/Services/IDetectedOperationService.cs
+++ b/AsbCloudApp/Services/IDetectedOperationService.cs
@@ -6,82 +6,85 @@ using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
-namespace AsbCloudApp.Services
+namespace AsbCloudApp.Services;
+
+///
+/// Сервис автоматически определенных по телеметрии операций
+///
+public interface IDetectedOperationService
{
///
- /// Сервис автоматически определенных по телеметрии операций
+ /// Добавление операций
///
- public interface IDetectedOperationService
- {
- ///
- /// Добавление операций
- ///
- ///
- ///
- ///
- ///
- ///
- Task InsertRangeManualAsync(int idEditor, int idWell, IEnumerable dtos, CancellationToken token);
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task InsertRangeManualAsync(int idEditor, int idWell, IEnumerable dtos, CancellationToken token);
- ///
- /// Редактирование операций
- ///
- ///
- ///
- ///
- ///
- ///
- Task UpdateRangeManualAsync(int idEditor, int idWell, IEnumerable dtos, CancellationToken token);
+ ///
+ /// Редактирование операций
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task UpdateRangeManualAsync(int idEditor, int idWell, IEnumerable dtos, CancellationToken token);
- ///
- /// Список названий операций.
- /// Если указан idWell, то возвращается список названий операций найденных на указанной скважине.
- ///
- ///
- ///
- ///
- Task> GetCategoriesAsync(int? idWell, CancellationToken token);
+ ///
+ /// Список названий операций.
+ /// Если указан idWell, то возвращается список названий операций найденных на указанной скважине.
+ ///
+ ///
+ ///
+ ///
+ Task> GetCategoriesAsync(int? idWell, CancellationToken token);
- ///
- /// Получить автоматически определенные по телеметрии операции с анализом по бурильщикам
- ///
- ///
- ///
- ///
- Task GetAsync(DetectedOperationByWellRequest request, CancellationToken token);
-
- ///
- /// Получить автоматически определенные по телеметрии операции
- ///
- ///
- ///
- ///
- Task> GetOperationsAsync(DetectedOperationByWellRequest request, CancellationToken token);
+ ///
+ /// Получить автоматически определенные по телеметрии операции с анализом по бурильщикам
+ ///
+ ///
+ ///
+ ///
+ Task GetAsync(DetectedOperationByWellRequest request, CancellationToken token);
+
+ ///
+ /// Получить автоматически определенные по телеметрии операции
+ ///
+ ///
+ ///
+ ///
+ Task> GetOperationsAsync(DetectedOperationByWellRequest request, CancellationToken token);
- ///
- /// Удалить операции
- ///
- ///
- ///
- ///
- Task DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token);
+ ///
+ /// Удалить операции
+ ///
+ ///
+ ///
+ ///
+ Task DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token);
- ///
- /// Статистика по операциям
- ///
- ///
- ///
- ///
- [Obsolete]
- Task> GetOperationsStatAsync(DetectedOperationByWellRequest request, CancellationToken token);
+ ///
+ /// Статистика по операциям
+ ///
+ ///
+ ///
+ ///
+ [Obsolete]
+ Task> GetOperationsStatAsync(DetectedOperationByWellRequest request, CancellationToken token);
- ///
- /// Определение операций
- ///
- ///
- ///
- ///
- ///
- Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, CancellationToken token);
- }
+ ///
+ /// Определение операций
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task<(DateTimeOffset LastDate, IEnumerable Items)> DetectOperationsAsync(int idTelemetry,
+ TelemetryDataRequest request,
+ DetectedOperationDto? lastDetectedOperation,
+ CancellationToken token);
}
diff --git a/AsbCloudApp/Services/ITelemetryDataSaubService.cs b/AsbCloudApp/Services/ITelemetryDataSaubService.cs
index e9f2d1ac..3823788a 100644
--- a/AsbCloudApp/Services/ITelemetryDataSaubService.cs
+++ b/AsbCloudApp/Services/ITelemetryDataSaubService.cs
@@ -5,44 +5,43 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
-namespace AsbCloudApp.Services
+namespace AsbCloudApp.Services;
+
+///
+/// Телеметрия САУБ
+///
+public interface ITelemetryDataSaubService : ITelemetryDataService
{
///
- /// Телеметрия САУБ
+ /// Получение телеметрии для РТК статистики
///
- public interface ITelemetryDataSaubService : ITelemetryDataService
- {
- ///
- /// Получение телеметрии для РТК статистики
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- Task> Get(int idTelemetry, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token);
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> Get(int idTelemetry, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token);
- ///
- /// усредненная статистика по 1м за весь период
- ///
- /// МЕДЛЕННЫЙ ЗАПРОС
- ///
- ///
- ///
- ///
- ///
- Task> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token);
+ ///
+ /// усредненная статистика по 1м за весь период
+ ///
+ /// МЕДЛЕННЫЙ ЗАПРОС
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token);
- ///
- /// Получить упакованый csv файл
- ///
- ///
- ///
- ///
- ///
- ///
- Task GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token);
- }
+ ///
+ /// Получить упакованный csv файл
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token);
}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs b/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs
index 10889a3d..7d664066 100644
--- a/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs
+++ b/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs
@@ -26,7 +26,24 @@ public class DetectedOperationRepository
{
this.telemetryService = telemetryService;
}
-
+
+ public async Task> GetLastDetectedOperationsAsync(CancellationToken token)
+ {
+ var entities = await dbContext.Set()
+ .GroupBy(o => o.IdTelemetry)
+ .Select(g => new
+ {
+ IdTelemetry = g.Key,
+ LastDetectedOperation = g.OrderBy(o => o.DateEnd).Last()
+ })
+ .ToArrayAsync(token);
+
+ var dtos = entities.ToDictionary(x => x.IdTelemetry,
+ x => Convert(x.LastDetectedOperation));
+
+ return dtos;
+ }
+
public async Task DeleteAsync(DetectedOperationByTelemetryRequest request, CancellationToken token)
{
var query = BuildQuery(request);
@@ -65,17 +82,7 @@ public class DetectedOperationRepository
return paginationContainer;
}
-
- public async Task> GetLastDetectedDatesAsync(CancellationToken token) =>
- await dbContext.Set()
- .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> Get(DetectedOperationByTelemetryRequest request, CancellationToken token)
{
var query = BuildQuery(request)
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs
index bc8869b4..daffc4e3 100644
--- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs
+++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs
@@ -1,6 +1,5 @@
using AsbCloudDb.Model;
using ClosedXML.Excel;
-using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -14,210 +13,219 @@ using AsbCloudApp.Exceptions;
using AsbCloudApp.Services;
using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
+using AsbCloudApp.Requests;
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
namespace AsbCloudInfrastructure.Services.DetectOperations;
public class DetectedOperationExportService
{
- private readonly IWellService wellService;
- private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
- private readonly IDetectedOperationService detectedOperationService;
- private const int headerRowsCount = 1;
+ private readonly IWellService wellService;
+ private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
+ private readonly IDetectedOperationRepository detectedOperationRepository;
+ private const int headerRowsCount = 1;
- private const string cellDepositName = "B1";
- private const string cellClusterName = "B2";
- private const string cellWellName = "B3";
- private const string cellDeltaDate = "H2";
+ private const string cellDepositName = "B1";
+ private const string cellClusterName = "B2";
+ private const string cellWellName = "B3";
+ private const string cellDeltaDate = "H2";
- private const int columnOperationName = 1;
- private const int columnDateStart = 2;
- private const int columnDateEnd = 3;
- private const int columnDuration = 4;
- private const int columnDepthStart = 5;
- private const int columnDepthEnd = 6;
- private const int columnDeltaDepth = 7;
- private const int columnDepth = 8;
- private const int columnIdReasonOfEnd = 9;
- private const int columnComment = 10;
+ private const int columnOperationName = 1;
+ private const int columnDateStart = 2;
+ private const int columnDateEnd = 3;
+ private const int columnDuration = 4;
+ private const int columnDepthStart = 5;
+ private const int columnDepthEnd = 6;
+ private const int columnDeltaDepth = 7;
+ private const int columnDepth = 8;
+ private const int columnIdReasonOfEnd = 9;
+ private const int columnComment = 10;
- public DetectedOperationExportService(IWellService wellService,
- IWellOperationCategoryRepository wellOperationCategoryRepository,
- IDetectedOperationService detectedOperationService)
- {
- this.wellService = wellService;
- this.wellOperationCategoryRepository = wellOperationCategoryRepository;
- this.detectedOperationService = detectedOperationService;
- }
+ public DetectedOperationExportService(IWellService wellService,
+ IWellOperationCategoryRepository wellOperationCategoryRepository,
+ IDetectedOperationRepository detectedOperationRepository)
+ {
+ this.wellService = wellService;
+ this.wellOperationCategoryRepository = wellOperationCategoryRepository;
+ this.detectedOperationRepository = detectedOperationRepository;
+ }
- ///
- /// Экспорт excel файла с операциями по скважине
- ///
- /// ключ скважины
- /// хост
- ///
- ///
- ///
- public async Task ExportAsync(int idWell, string host, CancellationToken token)
- {
- var well = await wellService.GetOrDefaultAsync(idWell, token);
+ ///
+ /// Экспорт excel файла с операциями по скважине
+ ///
+ /// ключ скважины
+ /// хост
+ ///
+ ///
+ ///
+ public async Task ExportAsync(int idWell, string host, CancellationToken token)
+ {
+ var well = await wellService.GetOrDefaultAsync(idWell, token);
- if (well is null)
- throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} does not exist");
+ if (well is null)
+ throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} does not exist");
- if (!well.IdTelemetry.HasValue)
- throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} has no telemetry");
+ if (!well.IdTelemetry.HasValue)
+ throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} has no telemetry");
- var operations = await detectedOperationService.DetectOperationsAsync(well.IdTelemetry.Value, DateTime.UnixEpoch, token);
+ var request = new DetectedOperationByTelemetryRequest
+ {
+ IdTelemetry = well.IdTelemetry.Value
+ };
- return await GenerateExcelFileStreamAsync(well, host, operations, token);
- }
+ var operations = await detectedOperationRepository.Get(request, token);
- private async Task GenerateExcelFileStreamAsync(WellDto well, string host, IEnumerable operationDetectorResults,
- CancellationToken cancellationToken)
- {
- using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken);
+ return await GenerateExcelFileStreamAsync(well, host, operations, token);
+ }
- using var workbook = new XLWorkbook(excelTemplateStream);
+ private async Task GenerateExcelFileStreamAsync(WellDto well,
+ string host,
+ IEnumerable operationDetectorResults,
+ CancellationToken cancellationToken)
+ {
+ using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken);
- AddToWorkbook(workbook, well, host, operationDetectorResults);
+ using var workbook = new XLWorkbook(excelTemplateStream);
- MemoryStream memoryStream = new MemoryStream();
- workbook.SaveAs(memoryStream, new SaveOptions { });
- memoryStream.Seek(0, SeekOrigin.Begin);
- return memoryStream;
- }
+ AddToWorkbook(workbook, well, host, operationDetectorResults);
- private void AddToWorkbook(XLWorkbook workbook, WellDto well, string host, IEnumerable operations)
- {
- const string sheetName = "Операции";
+ MemoryStream memoryStream = new MemoryStream();
+ workbook.SaveAs(memoryStream, new SaveOptions { });
+ memoryStream.Seek(0, SeekOrigin.Begin);
+ return memoryStream;
+ }
- if (!operations.Any())
- return;
+ private void AddToWorkbook(XLWorkbook workbook, WellDto well, string host, IEnumerable operations)
+ {
+ const string sheetName = "Операции";
- var sheet = workbook.GetWorksheet(sheetName);
+ if (!operations.Any())
+ return;
- var orderedOperations = operations
- .OrderBy(x => x.DateStart)
- .ThenBy(x => x.DepthStart).ToArray();
+ var sheet = workbook.GetWorksheet(sheetName);
- AddToSheet(sheet, well, host, orderedOperations);
- }
+ var orderedOperations = operations
+ .OrderBy(x => x.DateStart)
+ .ThenBy(x => x.DepthStart).ToArray();
- private void AddToSheet(IXLWorksheet sheet, WellDto well, string host, IList operations)
- {
- var wellOperationCategories = wellOperationCategoryRepository.Get(true);
+ AddToSheet(sheet, well, host, orderedOperations);
+ }
- sheet.Cell(cellDepositName).SetCellValue(well.Deposit);
- sheet.Cell(cellClusterName).SetCellValue(well.Cluster);
- sheet.Cell(cellWellName).SetCellValue(well.Caption);
+ private void AddToSheet(IXLWorksheet sheet, WellDto well, string host, IList operations)
+ {
+ var wellOperationCategories = wellOperationCategoryRepository.Get(true);
- var deltaDate = operations.Max(o => o.DateEnd - o.DateStart);
-
- sheet.Cell(cellDeltaDate).SetCellValue(deltaDate);
+ sheet.Cell(cellDepositName).SetCellValue(well.Deposit);
+ sheet.Cell(cellClusterName).SetCellValue(well.Cluster);
+ sheet.Cell(cellWellName).SetCellValue(well.Caption);
- for (int i = 0; i < operations.Count; i++)
- {
- var current = operations[i];
- var dateStart = current.DateStart.DateTime;
- var dateEnd = current.DateEnd.DateTime;
+ var deltaDate = operations.Max(o => o.DateEnd - o.DateStart);
- var row = sheet.Row(5 + i + headerRowsCount);
+ sheet.Cell(cellDeltaDate).SetCellValue(deltaDate);
- var categoryName = GetCategoryName(wellOperationCategories, current);
-
- row.Cell(columnDateStart).SetCellValue(dateStart);
- row.Cell(columnOperationName).SetCellValue(categoryName);
- row.Cell(columnDateEnd).SetCellValue(dateEnd);
- row.Cell(columnDuration).SetCellValue((dateEnd - dateStart).TotalMinutes);
- row.Cell(columnDepthStart).SetCellValue(current.DepthStart);
- row.Cell(columnDepthEnd).SetCellValue(current.DepthEnd);
- row.Cell(columnDepth).SetCellValue(current.DepthEnd - current.DepthStart);
+ for (int i = 0; i < operations.Count; i++)
+ {
+ var current = operations[i];
+ var dateStart = current.DateStart.DateTime;
+ var dateEnd = current.DateEnd.DateTime;
- if (current.ExtraData.TryGetValue("IdReasonOfEnd", out object? idReasonOfEndObject)
- && idReasonOfEndObject is int idReasonOfEnd)
- {
- var reasonOfEnd = GetIdReasonOfEnd(idReasonOfEnd);
- row.Cell(columnIdReasonOfEnd).SetCellValue(reasonOfEnd);
- }
+ var row = sheet.Row(5 + i + headerRowsCount);
- var query = new QueryBuilder();
- query.Add("end", dateStart.AddSeconds(1800 * 0.9).ToString("yyyy-MM-ddTHH:mm:ss.fff"));
- query.Add("range", "1800");
+ var categoryName = GetCategoryName(wellOperationCategories, current);
- var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}";
- row.Cell(columnDateStart).SetHyperlink(link);
-
- var deltaDepth = i > 0 && i + 1 < operations.Count
- ? current.DepthStart - operations[i - 1].DepthEnd
- : 0;
+ row.Cell(columnDateStart).SetCellValue(dateStart);
+ row.Cell(columnOperationName).SetCellValue(categoryName);
+ row.Cell(columnDateEnd).SetCellValue(dateEnd);
+ row.Cell(columnDuration).SetCellValue((dateEnd - dateStart).TotalMinutes);
+ row.Cell(columnDepthStart).SetCellValue(current.DepthStart);
+ row.Cell(columnDepthEnd).SetCellValue(current.DepthEnd);
+ row.Cell(columnDepth).SetCellValue(current.DepthEnd - current.DepthStart);
- row.Cell(columnDeltaDepth).SetCellValue(deltaDepth);
+ if (current.ExtraData.TryGetValue("IdReasonOfEnd", out object? idReasonOfEndObject)
+ && idReasonOfEndObject is int idReasonOfEnd)
+ {
+ var reasonOfEnd = GetIdReasonOfEnd(idReasonOfEnd);
+ row.Cell(columnIdReasonOfEnd).SetCellValue(reasonOfEnd);
+ }
- var comment = CreateComment(operations[i]);
- row.Cell(columnComment).SetCellValue(comment);
- }
- }
+ var query = new QueryBuilder();
+ query.Add("end", dateStart.AddSeconds(1800 * 0.9).ToString("yyyy-MM-ddTHH:mm:ss.fff"));
+ query.Add("range", "1800");
- private static string GetCategoryName(IEnumerable wellOperationCategories, DetectedOperationDto current)
- {
- var idCategory = current.IdCategory;
- if (idCategory == WellOperationCategory.IdSlide && current.EnabledSubsystems.IsAutoOscillation)
- return "Бурение в слайде с осцилляцией";
+ var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}";
+ row.Cell(columnDateStart).SetHyperlink(link);
- var category = wellOperationCategories.FirstOrDefault(o => o.Id == current.IdCategory);
-
- if(category is not null)
- return category.Name;
+ var deltaDepth = i > 0 && i + 1 < operations.Count
+ ? current.DepthStart - operations[i - 1].DepthEnd
+ : 0;
- return $"Операция №{idCategory}";
- }
+ row.Cell(columnDeltaDepth).SetCellValue(deltaDepth);
- private static string GetIdReasonOfEnd(int idReasonOfEnd)
- => idReasonOfEnd switch {
- 0 => "Не определена",
- 1 => "Не определено начало операции",
- 101 => "Разница глубин забоя и положением долота",
- 300 => "Низкое давление",
- 301 => "Высокое давление",
- 700 => "Изменение глубины долота и осевая нагрузка < веса на крюке",
- _ => idReasonOfEnd.ToString($"Причина № {idReasonOfEnd}"),
+ var comment = CreateComment(operations[i]);
+ row.Cell(columnComment).SetCellValue(comment);
+ }
+ }
- };
+ private static string GetCategoryName(IEnumerable wellOperationCategories, DetectedOperationDto current)
+ {
+ var idCategory = current.IdCategory;
+ if (idCategory == WellOperationCategory.IdSlide && current.EnabledSubsystems.IsAutoOscillation)
+ return "Бурение в слайде с осцилляцией";
- private async Task GetExcelTemplateStreamAsync(CancellationToken cancellationToken)
- {
- string resourceName = Assembly.GetExecutingAssembly()
- .GetManifestResourceNames()
- .FirstOrDefault(n => n.EndsWith("DetectOperations.xlsx"))!;
+ var category = wellOperationCategories.FirstOrDefault(o => o.Id == current.IdCategory);
- using var stream = Assembly.GetExecutingAssembly()
- .GetManifestResourceStream(resourceName)!;
+ if (category is not null)
+ return category.Name;
- var memoryStream = new MemoryStream();
- await stream.CopyToAsync(memoryStream, cancellationToken);
- memoryStream.Position = 0;
+ return $"Операция №{idCategory}";
+ }
- return memoryStream;
- }
-
- private static string CreateComment(DetectedOperationDto operation)
- {
- switch (operation.IdCategory)
- {
- case WellOperationCategory.IdRotor:
- case WellOperationCategory.IdSlide:
- var comment = "";
- if (operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyAvgRotorSpeed, out object? oAvgRotorSpeed))
- comment += $"Средняя скорость оборотов ротора: {oAvgRotorSpeed}\r\n";
+ private static string GetIdReasonOfEnd(int idReasonOfEnd)
+ => idReasonOfEnd switch
+ {
+ 0 => "Не определена",
+ 1 => "Не определено начало операции",
+ 101 => "Разница глубин забоя и положением долота",
+ 300 => "Низкое давление",
+ 301 => "Высокое давление",
+ 700 => "Изменение глубины долота и осевая нагрузка < веса на крюке",
+ _ => idReasonOfEnd.ToString($"Причина № {idReasonOfEnd}"),
+ };
- if (operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyDispersionOfNormalizedRotorSpeed, out object? oDispersionOfNormalizedRotorSpeed))
- comment += $"Дисперсия нормированных оборотов ротора: {oDispersionOfNormalizedRotorSpeed}";
-
- return comment;
-
- default:
- return string.Empty;
- }
- }
+ private async Task GetExcelTemplateStreamAsync(CancellationToken cancellationToken)
+ {
+ string resourceName = Assembly.GetExecutingAssembly()
+ .GetManifestResourceNames()
+ .FirstOrDefault(n => n.EndsWith("DetectOperations.xlsx"))!;
+
+ using var stream = Assembly.GetExecutingAssembly()
+ .GetManifestResourceStream(resourceName)!;
+
+ var memoryStream = new MemoryStream();
+ await stream.CopyToAsync(memoryStream, cancellationToken);
+ memoryStream.Position = 0;
+
+ return memoryStream;
+ }
+
+ private static string CreateComment(DetectedOperationDto operation)
+ {
+ switch (operation.IdCategory)
+ {
+ case WellOperationCategory.IdRotor:
+ case WellOperationCategory.IdSlide:
+ var comment = "";
+ if (operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyAvgRotorSpeed, out object? oAvgRotorSpeed))
+ comment += $"Средняя скорость оборотов ротора: {oAvgRotorSpeed}\r\n";
+
+ if (operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyDispersionOfNormalizedRotorSpeed,
+ out object? oDispersionOfNormalizedRotorSpeed))
+ comment += $"Дисперсия нормированных оборотов ротора: {oDispersionOfNormalizedRotorSpeed}";
+
+ return comment;
+
+ default:
+ return string.Empty;
+ }
+ }
}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs
index 299db028..aacfe853 100644
--- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs
+++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs
@@ -32,7 +32,7 @@ public class DetectedOperationService : IDetectedOperationService
new DetectorFlashing(),
new DetectorConditioning(),
};
-
+
public DetectedOperationService(
IDetectedOperationRepository operationRepository,
IWellOperationCategoryRepository wellOperationCategoryRepository,
@@ -110,7 +110,7 @@ public class DetectedOperationService : IDetectedOperationService
private async Task GetIdTelemetryByWell(int idWell, CancellationToken token)
{
var well = await wellService.GetOrDefaultAsync(idWell, token) ??
- throw new ArgumentInvalidException(nameof(idWell), "Well doesn`t exist");
+ throw new ArgumentInvalidException(nameof(idWell), "Well doesn't exist");
var idTelemetry = well.IdTelemetry ??
throw new ArgumentInvalidException(nameof(idWell), "У скважины отсутствует телеметрия");
@@ -177,72 +177,75 @@ public class DetectedOperationService : IDetectedOperationService
return dtos;
}
- public async Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, CancellationToken token)
+ public async Task<(DateTimeOffset LastDate, IEnumerable Items)> DetectOperationsAsync(int idTelemetry,
+ TelemetryDataRequest request,
+ DetectedOperationDto? lastDetectedOperation,
+ CancellationToken token)
{
- const int take = 4 * 86_400;
-
- var detectedOperations = new List();
- DetectedOperationDto? lastDetectedOperation = null;
const int minOperationLength = 5;
const int maxDetectorsInterpolationFrameLength = 30;
const int gap = maxDetectorsInterpolationFrameLength + minOperationLength;
- var timezone = telemetryService.GetTimezone(idTelemetry);
- while (true)
+ 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);
+
+ if (telemetries.Count() <= gap)
{
- var request = new TelemetryDataRequest
- {
- GeDate = beginDate,
- Take = take,
- Order = 0
- };
-
- var dtos = await telemetryDataSaubService.GetByTelemetryAsync(idTelemetry, request, token);
- var detectableTelemetries = dtos
- .Where(t => t.BlockPosition >= 0)
- .Select(t => new DetectableTelemetry
- {
- DateTime = new DateTimeOffset(t.DateTime, timezone.Offset),
- IdUser = t.IdUser,
- Mode = t.Mode,
- WellDepth = t.WellDepth,
- Pressure = t.Pressure,
- HookWeight = t.HookWeight,
- BlockPosition = t.BlockPosition,
- BitDepth = t.BitDepth,
- RotorSpeed = t.RotorSpeed,
- AxialLoad = t.AxialLoad,
- }).ToArray();
-
- if (detectableTelemetries.Length <= gap)
- break;
-
- var isDetected = false;
- var positionBegin = 0;
- var positionEnd = detectableTelemetries.Length - gap;
- while (positionEnd > positionBegin)
- {
- foreach (var detector in detectors)
- {
- if (!detector.TryDetect(idTelemetry, detectableTelemetries, positionBegin, positionEnd, lastDetectedOperation, out var result))
- continue;
-
- detectedOperations.Add(result!.Operation);
- lastDetectedOperation = result.Operation;
- isDetected = true;
- positionBegin = result.TelemetryEnd;
- break;
- }
-
- positionBegin += 1;
- }
-
- beginDate = isDetected
- ? lastDetectedOperation!.DateEnd
- : detectableTelemetries[positionEnd].DateTime;
+ var lastTelemetry = telemetries.Last();
+ var lastDateTelemetry = new DateTimeOffset(lastTelemetry.DateTime, timeZone.Offset);
+ return (lastDateTelemetry, Enumerable.Empty());
}
- return detectedOperations;
+ var detectedOperations = new List();
+
+ var detectableTelemetries = telemetries
+ .Where(t => t.BlockPosition >= 0)
+ .Select(t => new DetectableTelemetry
+ {
+ DateTime = new DateTimeOffset(t.DateTime, timeZone.Offset),
+ IdUser = t.IdUser,
+ Mode = t.Mode,
+ WellDepth = t.WellDepth,
+ Pressure = t.Pressure,
+ HookWeight = t.HookWeight,
+ BlockPosition = t.BlockPosition,
+ BitDepth = t.BitDepth,
+ RotorSpeed = t.RotorSpeed,
+ AxialLoad = t.AxialLoad,
+ }).ToArray();
+
+ var positionBegin = 0;
+ var positionEnd = detectableTelemetries.Length - gap;
+
+ while (positionEnd > positionBegin)
+ {
+ foreach (var detector in detectors)
+ {
+ if (!detector.TryDetect(idTelemetry, detectableTelemetries, positionBegin, positionEnd, lastDetectedOperation,
+ out var result))
+ continue;
+
+ detectedOperations.Add(result!.Operation);
+ lastDetectedOperation = result.Operation;
+ positionBegin = result.TelemetryEnd;
+ break;
+ }
+
+ var skip = 1;
+
+ while (IsChangingTelemetryInterval(detectableTelemetries[positionBegin], detectableTelemetries[positionBegin + skip]))
+ skip++;
+
+ positionBegin += skip;
+ }
+
+ return (detectableTelemetries[positionBegin].DateTime, detectedOperations);
}
public async Task DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token)
@@ -256,6 +259,23 @@ public class DetectedOperationService : IDetectedOperationService
return result;
}
+ private static bool IsChangingTelemetryInterval(DetectableTelemetry telemetryBegin, DetectableTelemetry telemetryEnd)
+ {
+ return telemetryBegin.Mode == telemetryEnd.Mode &&
+ EqualParameter(telemetryBegin.WellDepth, telemetryEnd.WellDepth, 0.01f) &&
+ EqualParameter(telemetryBegin.Pressure, telemetryEnd.Pressure, 0.1f) &&
+ EqualParameter(telemetryBegin.HookWeight, telemetryEnd.HookWeight, 0.1f) &&
+ EqualParameter(telemetryBegin.BlockPosition, telemetryEnd.BlockPosition, 0.01f) &&
+ EqualParameter(telemetryBegin.BitDepth, telemetryEnd.BitDepth, 0.01f) &&
+ EqualParameter(telemetryBegin.RotorSpeed, telemetryEnd.RotorSpeed, 0.01f) &&
+ EqualParameter(telemetryBegin.AxialLoad, telemetryEnd.AxialLoad, 0.1f);
+
+ static bool EqualParameter(float value, float origin, float tolerance)
+ {
+ return value <= origin + tolerance && value >= origin - tolerance;
+ }
+ }
+
private static IEnumerable GetOperationsDrillersStat(IEnumerable operations)
{
var groups = operations.GroupBy(o => o.Driller);
@@ -305,7 +325,6 @@ public class DetectedOperationService : IDetectedOperationService
};
}
-
private static DetectedOperationWithDrillerDto Convert(DetectedOperationDto operation, IEnumerable operationValues, IEnumerable schedules)
{
var dto = operation.Adapt();
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs
index c751dfd5..5f17a248 100644
--- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs
+++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs
@@ -2,410 +2,410 @@ using System;
using System.Collections.Generic;
using AsbCloudApp.Data.DetectedOperation;
-namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
+namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors;
+
+public abstract class DetectorAbstract
{
- public abstract class DetectorAbstract
+ protected const int IdReasonOfEnd_NotDetected = 0;
+ protected const int IdReasonOfEnd_NotDetectBegin = 1;
+
+ protected const int IdReasonOfEnd_DeltaDepthIsLo = 100;
+ protected const int IdReasonOfEnd_DeltaDepthIsHi = 101;
+ protected const int IdReasonOfEnd_DeltaDepthOutOfRange = 102;
+ protected const int IdReasonOfEnd_WellDepthDeviates = 200;
+
+ protected const int IdReasonOfEnd_PressureIsLo = 300;
+ protected const int IdReasonOfEnd_PressureIsHi = 301;
+ protected const int IdReasonOfEnd_PressureOutOfRange = 302;
+ protected const int IdReasonOfEnd_PressureIsRising = 303;
+
+ protected const int IdReasonOfEnd_RotorSpeedIsLo = 400;
+ protected const int IdReasonOfEnd_RotorSpeedIsHi = 401;
+ protected const int IdReasonOfEnd_AvgRotorSpeedIsHi = 402;
+ protected const int IdReasonOfEnd_AvgRotorSpeedIsLo = 403;
+
+ protected const int IdReasonOfEnd_BlockPositionIsLo = 500;
+ protected const int IdReasonOfEnd_BlockPositionIsHi = 501;
+ protected const int IdReasonOfEnd_BlockPositionDeviates = 502;
+
+ protected const int IdReasonOfEnd_Drilling = 600;
+
+ protected const int IdReasonOfEnd_ChangeBitDepthAndAxiLoadLessHookWeight = 700;
+
+ protected const int IdReasonOfEnd_DeltaWellDepthAndBitDepthIsLo = 800;
+
+ protected const int IdReasonOfEnd_BitDepthIsLo = 900;
+
+ public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperationDto? previousOperation,
+ out OperationDetectorResult? result)
{
- protected const int IdReasonOfEnd_NotDetected = 0;
- protected const int IdReasonOfEnd_NotDetectBegin = 1;
-
- protected const int IdReasonOfEnd_DeltaDepthIsLo = 100;
- protected const int IdReasonOfEnd_DeltaDepthIsHi = 101;
- protected const int IdReasonOfEnd_DeltaDepthOutOfRange = 102;
- protected const int IdReasonOfEnd_WellDepthDeviates = 200;
-
- protected const int IdReasonOfEnd_PressureIsLo = 300;
- protected const int IdReasonOfEnd_PressureIsHi = 301;
- protected const int IdReasonOfEnd_PressureOutOfRange = 302;
- protected const int IdReasonOfEnd_PressureIsRising = 303;
-
- protected const int IdReasonOfEnd_RotorSpeedIsLo = 400;
- protected const int IdReasonOfEnd_RotorSpeedIsHi = 401;
- protected const int IdReasonOfEnd_AvgRotorSpeedIsHi = 402;
- protected const int IdReasonOfEnd_AvgRotorSpeedIsLo = 403;
-
- protected const int IdReasonOfEnd_BlockPositionIsLo = 500;
- protected const int IdReasonOfEnd_BlockPositionIsHi = 501;
- protected const int IdReasonOfEnd_BlockPositionDeviates = 502;
-
- protected const int IdReasonOfEnd_Drilling = 600;
-
- protected const int IdReasonOfEnd_ChangeBithDepthAndAxiloadLessHookWeight = 700;
-
- protected const int IdReasonOfEnd_DeltaWellDepthAndBithDepthIsLo = 800;
-
- protected const int IdReasonOfEnd_BithDepthIsLo = 900;
-
- public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperationDto? previousOperation,
- out OperationDetectorResult? result)
+ // Проверка соответствия критерию начала операции
+ if (DetectBegin(telemetry, begin, previousOperation))
{
- // Проверка соответствия критерию начала операции
- if (DetectBegin(telemetry, begin, previousOperation))
- {
- // Поиск окончания соответствия критерию
- int idReasonOfEnd = 0;
- var positionEnd = begin;
-
- while (positionEnd < end)
- {
- positionEnd += 1;
- if (positionEnd > end)
- break;
-
- idReasonOfEnd = DetectEnd(telemetry, positionEnd, previousOperation);
-
- if (idReasonOfEnd != IdReasonOfEnd_NotDetected)
- break;
- }
-
- var (Begin, End) = RefineEdges(telemetry, begin, positionEnd);
-
- result = MakeOperationDetectorResult(idTelemetry, telemetry, Begin, End, idReasonOfEnd);
-
- return IsValidOperationDetectorResult(result);
- }
-
- result = null;
- return false;
- }
-
- protected virtual (int Begin, int End) RefineEdges(DetectableTelemetry[] telemetry, int begin, int end)
- => (begin, end);
-
- protected virtual bool IsValidOperationDetectorResult(OperationDetectorResult operationDetectorResult)
- => operationDetectorResult.Operation.DateEnd - operationDetectorResult.Operation.DateStart > TimeSpan.FromSeconds(3);
-
- protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation);
-
- protected virtual int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation)
- => DetectBegin(telemetry, position, previousOperation)
- ? IdReasonOfEnd_NotDetected
- : IdReasonOfEnd_NotDetectBegin;
-
- private OperationDetectorResult MakeOperationDetectorResult(
- int idTelemetry,
- DetectableTelemetry[] telemetry,
- int begin,
- int end,
- int idReasonOfEnd)
- {
- var operation = MakeDetectedOperation(idTelemetry, telemetry, begin, end);
-
- operation.ExtraData["IdReasonOfEnd"] = idReasonOfEnd;
-
- var result = new OperationDetectorResult
- {
- TelemetryBegin = begin,
- TelemetryEnd = end,
- Operation = operation,
- };
-
- return result;
- }
-
- private DetectedOperationDto MakeDetectedOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end)
- {
- var pBegin = telemetry[begin];
- var pEnd = telemetry[end];
- var (IdCategory, ExtraData) = GetSpecificInformation(telemetry, begin, end);
- var operation = new DetectedOperationDto
- {
- IdCategory = IdCategory,
- IdTelemetry = idTelemetry,
- IdUserAtStart = pBegin.IdUser ?? -1,
- DateStart = pBegin.DateTime,
- DateEnd = pEnd.DateTime,
- DepthStart = (double)pBegin.WellDepth,
- DepthEnd = (double)pEnd.WellDepth,
- ExtraData = ExtraData,
- Value = CalcValue(telemetry, begin, end),
- EnabledSubsystems = DetectEnabledSubsystems(telemetry, begin, end, ExtraData)
- };
-
- return operation;
- }
-
- ///
- /// Получение информации специфичной для конкретного детектора
- /// IdCategory - одна из констант WellOperationCategory
- /// ExtraData - дополнительная информация для отладки алгоритмов авто определения
- ///
- ///
- protected abstract (int IdCategory, IDictionary ExtraData) GetSpecificInformation(DetectableTelemetry[] telemetry, int begin, int end);
-
- ///
- /// Расчет ключевого параметра операции
- ///
- ///
- ///
- ///
- ///
- protected abstract double CalcValue(DetectableTelemetry[] telemetry, int begin, int end);
-
- ///
- /// Определение включенных подсистем во время выполнения операции
- ///
- ///
- ///
- ///
- ///
- ///
- private static int DetectEnabledSubsystems(DetectableTelemetry[] telemetry, int begin, int end, IDictionary extraData)
- {
- var enabledSubsystems = 0;
-
- if (extraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out var hasOscillation)
- && hasOscillation is true)
- enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoOscillation;
+ // Поиск окончания соответствия критерию
+ int idReasonOfEnd = 0;
+ var positionEnd = begin;
- for (var i = begin; i < end; i += 2)
+ while (positionEnd < end)
{
- var mode = telemetry[i].Mode;
+ positionEnd += 1;
+ if (positionEnd > end)
+ break;
+
+ //TODO: поиск провалов телеметрий. Следует обсудить, так как алгоритмы теряют в точности.
- if(mode == 1)
- enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoRotor;
+ idReasonOfEnd = DetectEnd(telemetry, positionEnd, previousOperation);
- if (mode == 3)
- enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSlide;
-
- if (mode == 2)
- enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoConditionig;
-
- if (mode == 4)
- enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSinking;
-
- if (mode == 5)
- enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLifting;
-
- if (mode == 6)
- enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLiftingWithConditionig;
-
- if (mode == 10)
- enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoBlocknig;
+ if (idReasonOfEnd != IdReasonOfEnd_NotDetected)
+ break;
}
+
+ var (Begin, End) = RefineEdges(telemetry, begin, positionEnd);
+
+ result = MakeOperationDetectorResult(idTelemetry, telemetry, Begin, End, idReasonOfEnd);
- return enabledSubsystems;
+ return IsValidOperationDetectorResult(result);
}
- ///
- /// расчет продолжительности операции
- ///
- ///
- ///
- ///
- ///
- protected static double CalcDeltaMinutes(DetectableTelemetry[] telemetry, int begin, int end)
+ result = null;
+ return false;
+ }
+
+ protected virtual (int Begin, int End) RefineEdges(DetectableTelemetry[] telemetry, int begin, int end)
+ => (begin, end);
+
+ protected virtual bool IsValidOperationDetectorResult(OperationDetectorResult operationDetectorResult)
+ => operationDetectorResult.Operation.DateEnd - operationDetectorResult.Operation.DateStart > TimeSpan.FromSeconds(3);
+
+ protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation);
+
+ protected virtual int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation)
+ => DetectBegin(telemetry, position, previousOperation)
+ ? IdReasonOfEnd_NotDetected
+ : IdReasonOfEnd_NotDetectBegin;
+
+ private OperationDetectorResult MakeOperationDetectorResult(
+ int idTelemetry,
+ DetectableTelemetry[] telemetry,
+ int begin,
+ int end,
+ int idReasonOfEnd)
+ {
+ var operation = MakeDetectedOperation(idTelemetry, telemetry, begin, end);
+
+ operation.ExtraData["IdReasonOfEnd"] = idReasonOfEnd;
+
+ var result = new OperationDetectorResult
{
- var pBegin = telemetry[begin];
- var pEnd = telemetry[end];
- var result = (pEnd.DateTime - pBegin.DateTime).TotalMinutes;
- return result;
+ TelemetryBegin = begin,
+ TelemetryEnd = end,
+ Operation = operation,
+ };
+
+ return result;
+ }
+
+ private DetectedOperationDto MakeDetectedOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end)
+ {
+ var pBegin = telemetry[begin];
+ var pEnd = telemetry[end];
+ var (IdCategory, ExtraData) = GetSpecificInformation(telemetry, begin, end);
+ var operation = new DetectedOperationDto
+ {
+ IdCategory = IdCategory,
+ IdTelemetry = idTelemetry,
+ IdUserAtStart = pBegin.IdUser ?? -1,
+ DateStart = pBegin.DateTime,
+ DateEnd = pEnd.DateTime,
+ DepthStart = (double)pBegin.WellDepth,
+ DepthEnd = (double)pEnd.WellDepth,
+ ExtraData = ExtraData,
+ Value = CalcValue(telemetry, begin, end),
+ EnabledSubsystems = DetectEnabledSubsystems(telemetry, begin, end, ExtraData)
+ };
+
+ return operation;
+ }
+
+ ///
+ /// Получение информации специфичной для конкретного детектора
+ /// IdCategory - одна из констант WellOperationCategory
+ /// ExtraData - дополнительная информация для отладки алгоритмов авто определения
+ ///
+ ///
+ protected abstract (int IdCategory, IDictionary ExtraData) GetSpecificInformation(DetectableTelemetry[] telemetry, int begin, int end);
+
+ ///
+ /// Расчет ключевого параметра операции
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected abstract double CalcValue(DetectableTelemetry[] telemetry, int begin, int end);
+
+ ///
+ /// Определение включенных подсистем во время выполнения операции
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static int DetectEnabledSubsystems(DetectableTelemetry[] telemetry, int begin, int end, IDictionary extraData)
+ {
+ var enabledSubsystems = 0;
+
+ if (extraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out var hasOscillation)
+ && hasOscillation is true)
+ enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoOscillation;
+
+ for (var i = begin; i < end; i += 2)
+ {
+ var mode = telemetry[i].Mode;
+
+ if(mode == 1)
+ enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoRotor;
+
+ if (mode == 3)
+ enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSlide;
+
+ if (mode == 2)
+ enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoConditionig;
+
+ if (mode == 4)
+ enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSinking;
+
+ if (mode == 5)
+ enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLifting;
+
+ if (mode == 6)
+ enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLiftingWithConditionig;
+
+ if (mode == 10)
+ enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoBlocknig;
}
- ///
- /// часто используемый предикат для определения отсутствия изменения глубины ствола скважины
- ///
- ///
- ///
- ///
- ///
- protected static bool IsValidByWellDepthDoesNotChange(DetectableTelemetry[] telemetry, int begin, int end)
- {
- var pBegin = telemetry[begin];
- var pEnd = telemetry[end];
- if (Math.Abs((double)(pBegin.WellDepth - pEnd.WellDepth)) > 0.01)
- return false;
- return true;
- }
+ return enabledSubsystems;
+ }
- protected static bool IsValidByWellDepthIncreasing(DetectableTelemetry[] telemetry, int begin, int end)
- {
- var pBegin = telemetry[begin];
- var pEnd = telemetry[end];
- if (pBegin.WellDepth >= pEnd.WellDepth)
- return false;
- return true;
- }
-
- protected static double CalcRop(DetectableTelemetry[] telemetry, int begin, int end)
- {
- var pBegin = telemetry[begin];
- var pEnd = telemetry[end];
- var result = (double)(pEnd.WellDepth - pBegin.WellDepth) / (pEnd.DateTime - pBegin.DateTime).TotalHours;
- return result;
- }
-
- ///
- /// Расчет статистики по массиву данных за интервал
- ///
- ///
- ///
- ///
- ///
- ///
- protected static (double min, double max, double sum, int count) CalcStat(
- DetectableTelemetry[] telemetry,
- Func getter,
- int begin,
- int count)
- {
- var sum = 0d;
- var min = double.MaxValue;
- var max = double.MinValue;
- var end = begin + count;
- end = end < telemetry.Length ? end : telemetry.Length;
-
- for (var i = begin; i < end; i++)
- {
- var item = telemetry[i];
- var itemValue = getter(item);
- if (min > itemValue)
- min = itemValue;
- if (max < itemValue)
- max = itemValue;
- sum += itemValue;
- }
-
- return (min, max, sum, end - begin);
- }
-
- ///
- /// Максимальное отклонение от среднего за интервал
- ///
- ///
- ///
- ///
- ///
- ///
- protected static double CalcMaxDeviation(
- DetectableTelemetry[] telemetry,
- Func getter,
- int begin,
- int count)
- {
- var stat = CalcStat(telemetry, getter, begin, count);
- var avg = stat.sum / stat.count;
- var dev1 = avg - stat.min;
- var dev2 = stat.max - avg;
- var dev = dev1 > dev2 ? dev1 : dev2;
- return dev;
- }
-
- ///
- /// Определяет наличие разброса значений в интервале большего указанного значения.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- protected static bool ContainsDeviation(
- DetectableTelemetry[] telemetry,
- Func getter,
- int begin,
- int count,
- double deviation)
- {
- var min = double.MaxValue;
- var max = double.MinValue;
- var end = begin + count;
- end = end < telemetry.Length ? end : telemetry.Length;
-
- for (var i = begin; i < end; i++)
- {
- var item = telemetry[i];
- var itemValue = getter(item);
- if (min > itemValue)
- min = itemValue;
- if (max < itemValue)
- max = itemValue;
- if (max - min > deviation)
- return true;
- }
+ ///
+ /// расчет продолжительности операции
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected static double CalcDeltaMinutes(DetectableTelemetry[] telemetry, int begin, int end)
+ {
+ var pBegin = telemetry[begin];
+ var pEnd = telemetry[end];
+ var result = (pEnd.DateTime - pBegin.DateTime).TotalMinutes;
+ return result;
+ }
+ ///
+ /// часто используемый предикат для определения отсутствия изменения глубины ствола скважины
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected static bool IsValidByWellDepthDoesNotChange(DetectableTelemetry[] telemetry, int begin, int end)
+ {
+ var pBegin = telemetry[begin];
+ var pEnd = telemetry[end];
+ if (Math.Abs((double)(pBegin.WellDepth - pEnd.WellDepth)) > 0.01)
return false;
- }
-
- ///
- /// Определяет наличие разброса значений в интервале большего указанного значения. По нескольким значениям из интервала.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- protected static bool ContainsDeviationApprox(
- DetectableTelemetry[] telemetry,
- Func getter,
- int begin,
- int count,
- double deviation)
- {
- var min = double.MaxValue;
- var max = double.MinValue;
- var end = begin + count;
- end = end < telemetry.Length ? end : telemetry.Length;
- var step = count > 15 ? count / 5 : count > 3 ? 3 : 1;
- for (var i = begin; i < end; i += step)
- {
- var item = telemetry[i];
- var itemValue = getter(item);
- if (min > itemValue)
- min = itemValue;
- if (max < itemValue)
- max = itemValue;
- if (max - min > deviation)
- return true;
- }
+ return true;
+ }
+ protected static bool IsValidByWellDepthIncreasing(DetectableTelemetry[] telemetry, int begin, int end)
+ {
+ var pBegin = telemetry[begin];
+ var pEnd = telemetry[end];
+ if (pBegin.WellDepth >= pEnd.WellDepth)
return false;
- }
+ return true;
+ }
- protected static bool DeviatesFromBegin(
- DetectableTelemetry[] telemetry,
- Func getter,
- int begin,
- int count,
- double deviation)
+ protected static double CalcRop(DetectableTelemetry[] telemetry, int begin, int end)
+ {
+ var pBegin = telemetry[begin];
+ var pEnd = telemetry[end];
+ var result = (double)(pEnd.WellDepth - pBegin.WellDepth) / (pEnd.DateTime - pBegin.DateTime).TotalHours;
+ return result;
+ }
+
+ ///
+ /// Расчет статистики по массиву данных за интервал
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected static (double min, double max, double sum, int count) CalcStat(
+ DetectableTelemetry[] telemetry,
+ Func getter,
+ int begin,
+ int count)
+ {
+ var sum = 0d;
+ var min = double.MaxValue;
+ var max = double.MinValue;
+ var end = begin + count;
+ end = end < telemetry.Length ? end : telemetry.Length;
+
+ for (var i = begin; i < end; i++)
{
- var beginPointValue = getter(telemetry[begin]);
- var end = begin + count;
- end = end < telemetry.Length ? end : telemetry.Length;
- var step = count > 15 ? count / 5 : count > 3 ? 3 : 1;
- for (var i = begin; i < end; i += step)
- {
- var item = telemetry[i];
- var itemValue = getter(item);
- if (Math.Abs(beginPointValue - itemValue) > deviation)
- return true;
- }
-
- return false;
+ var item = telemetry[i];
+ var itemValue = getter(item);
+ if (min > itemValue)
+ min = itemValue;
+ if (max < itemValue)
+ max = itemValue;
+ sum += itemValue;
}
- protected static bool RisesFromBegin(
- DetectableTelemetry[] telemetry,
- Func getter,
- int begin,
- int count,
- double deviation)
+ return (min, max, sum, end - begin);
+ }
+
+ ///
+ /// Максимальное отклонение от среднего за интервал
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected static double CalcMaxDeviation(
+ DetectableTelemetry[] telemetry,
+ Func getter,
+ int begin,
+ int count)
+ {
+ var stat = CalcStat(telemetry, getter, begin, count);
+ var avg = stat.sum / stat.count;
+ var dev1 = avg - stat.min;
+ var dev2 = stat.max - avg;
+ var dev = dev1 > dev2 ? dev1 : dev2;
+ return dev;
+ }
+
+ ///
+ /// Определяет наличие разброса значений в интервале большего указанного значения.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected static bool ContainsDeviation(
+ DetectableTelemetry[] telemetry,
+ Func getter,
+ int begin,
+ int count,
+ double deviation)
+ {
+ var min = double.MaxValue;
+ var max = double.MinValue;
+ var end = begin + count;
+ end = end < telemetry.Length ? end : telemetry.Length;
+
+ for (var i = begin; i < end; i++)
{
- var beginPointValue = getter(telemetry[begin]);
- var end = begin + count;
- end = end < telemetry.Length ? end : telemetry.Length;
- var step = count > 15 ? count / 5 : count > 3 ? 3 : 1;
- for (var i = begin; i < end; i += step)
- {
- var item = telemetry[i];
- var itemValue = getter(item);
- if (itemValue - beginPointValue > deviation)
- return true;
- }
-
- return false;
+ var item = telemetry[i];
+ var itemValue = getter(item);
+ if (min > itemValue)
+ min = itemValue;
+ if (max < itemValue)
+ max = itemValue;
+ if (max - min > deviation)
+ return true;
}
+
+ return false;
+ }
+
+ ///
+ /// Определяет наличие разброса значений в интервале большего указанного значения. По нескольким значениям из интервала.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected static bool ContainsDeviationApprox(
+ DetectableTelemetry[] telemetry,
+ Func getter,
+ int begin,
+ int count,
+ double deviation)
+ {
+ var min = double.MaxValue;
+ var max = double.MinValue;
+ var end = begin + count;
+ end = end < telemetry.Length ? end : telemetry.Length;
+ var step = count > 15 ? count / 5 : count > 3 ? 3 : 1;
+ for (var i = begin; i < end; i += step)
+ {
+ var item = telemetry[i];
+ var itemValue = getter(item);
+ if (min > itemValue)
+ min = itemValue;
+ if (max < itemValue)
+ max = itemValue;
+ if (max - min > deviation)
+ return true;
+ }
+
+ return false;
+ }
+
+ protected static bool DeviatesFromBegin(
+ DetectableTelemetry[] telemetry,
+ Func getter,
+ int begin,
+ int count,
+ double deviation)
+ {
+ var beginPointValue = getter(telemetry[begin]);
+ var end = begin + count;
+ end = end < telemetry.Length ? end : telemetry.Length;
+ var step = count > 15 ? count / 5 : count > 3 ? 3 : 1;
+ for (var i = begin; i < end; i += step)
+ {
+ var item = telemetry[i];
+ var itemValue = getter(item);
+ if (Math.Abs(beginPointValue - itemValue) > deviation)
+ return true;
+ }
+
+ return false;
+ }
+
+ protected static bool RisesFromBegin(
+ DetectableTelemetry[] telemetry,
+ Func getter,
+ int begin,
+ int count,
+ double deviation)
+ {
+ var beginPointValue = getter(telemetry[begin]);
+ var end = begin + count;
+ end = end < telemetry.Length ? end : telemetry.Length;
+ var step = count > 15 ? count / 5 : count > 3 ? 3 : 1;
+ for (var i = begin; i < end; i += step)
+ {
+ var item = telemetry[i];
+ var itemValue = getter(item);
+ if (itemValue - beginPointValue > deviation)
+ return true;
+ }
+
+ return false;
}
}
-
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorConditioning.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorConditioning.cs
index 1a5142e3..6ef413ef 100644
--- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorConditioning.cs
+++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorConditioning.cs
@@ -41,9 +41,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
if (currentPoint.RotorSpeed <=8)
return IdReasonOfEnd_RotorSpeedIsHi;
if ((currentPoint.WellDepth - currentPoint.BitDepth) < 0.03d)
- return IdReasonOfEnd_DeltaWellDepthAndBithDepthIsLo;
+ return IdReasonOfEnd_DeltaWellDepthAndBitDepthIsLo;
if (currentPoint.BitDepth < 150)
- return IdReasonOfEnd_BithDepthIsLo;
+ return IdReasonOfEnd_BitDepthIsLo;
return IdReasonOfEnd_NotDetected;
}
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs
index 24b69219..f300f1c5 100644
--- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs
+++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorFlashing.cs
@@ -48,11 +48,11 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
if (currentPoint.Pressure < 10)
return IdReasonOfEnd_PressureIsLo;
if ((currentPoint.WellDepth - currentPoint.BitDepth) < 0.01d)
- return IdReasonOfEnd_DeltaWellDepthAndBithDepthIsLo;
+ return IdReasonOfEnd_DeltaWellDepthAndBitDepthIsLo;
if (currentPoint.RotorSpeed > 8)
return IdReasonOfEnd_RotorSpeedIsHi;
if (currentPoint.BitDepth < 150)
- return IdReasonOfEnd_BithDepthIsLo;
+ return IdReasonOfEnd_BitDepthIsLo;
return IdReasonOfEnd_NotDetected;
}
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs
index 47208183..af2e3db0 100644
--- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs
+++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs
@@ -50,7 +50,7 @@ public class DetectorSlipsTime : DetectorAbstract
var deltaBitDepth = Math.Abs(currentPoint.BitDepth - prevPoint.BitDepth);
if (deltaBitDepth > 0.001d && currentPoint.AxialLoad < currentPoint.HookWeight)
- return IdReasonOfEnd_ChangeBithDepthAndAxiloadLessHookWeight;
+ return IdReasonOfEnd_ChangeBitDepthAndAxiLoadLessHookWeight;
return IdReasonOfEnd_NotDetected;
}
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs
index 9b50f67d..93a8b9c3 100644
--- a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs
+++ b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs
@@ -1,54 +1,91 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
+using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
+using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Background;
using Microsoft.Extensions.DependencyInjection;
namespace AsbCloudInfrastructure.Services.DetectOperations;
-public class WorkOperationDetection: Work
+public class WorkOperationDetection : Work
{
+ private static readonly IDictionary CacheOfStartDatesByTelemetryId = new Dictionary();
- 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;
- };
- }
+ public WorkOperationDetection()
+ : base("Operation detection")
+ {
+ Timeout = TimeSpan.FromMinutes(20);
+ OnErrorAsync = (id, exception, _) =>
+ {
+ 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 onProgressCallback, CancellationToken token)
- {
- var telemetryRepository = services.GetRequiredService>();
- var detectedOperationRepository = services.GetRequiredService();
- var detectedOperationService = services.GetRequiredService();
+ protected override async Task Action(string id,
+ IServiceProvider services,
+ Action onProgressCallback,
+ CancellationToken token)
+ {
+ var telemetryRepository = services.GetRequiredService>();
+ var detectedOperationRepository = services.GetRequiredService();
+ var detectedOperationService = services.GetRequiredService();
+ var telemetryDataCache = services.GetRequiredService>();
- var telemetryIds = (await telemetryRepository.GetAllAsync(token))
- .Select(t => t.Id)
- .ToArray();
+ var idsTelemetry = (await telemetryRepository.GetAllAsync(token))
+ .Select(t => t.Id)
+ .ToArray();
- var lastDetectedDates = await detectedOperationRepository.GetLastDetectedDatesAsync(token);
+ var lastDetectedOperations = await detectedOperationRepository.GetLastDetectedOperationsAsync(token);
- for (var i = 0; i < telemetryIds.Length; i++)
- {
- var telemetryId = telemetryIds[i];
-
- var beginDate = lastDetectedDates.TryGetValue(telemetryId, out var date) ? date : (DateTimeOffset?)null;
+ for (int i = 0; i < idsTelemetry.Length; i++)
+ {
+ var idTelemetry = idsTelemetry[i];
- onProgressCallback($"Start detecting telemetry: {telemetryId} from {beginDate}", i / telemetryIds.Length);
- var detectedOperations = await detectedOperationService.DetectOperationsAsync(telemetryId, beginDate, token);
+ var telemetryDateRange = telemetryDataCache.GetOrDefaultWellDataDateRange(idTelemetry);
+
+ if(telemetryDateRange == null)
+ continue;
- if (detectedOperations.Any())
- await detectedOperationRepository.InsertRangeAsync(detectedOperations, token);
- }
- }
-}
+ var dateBegin = telemetryDateRange.From;
+ var dateEnd = telemetryDateRange.To;
+
+ if (lastDetectedOperations.TryGetValue(idTelemetry, out var lastDetectedOperation))
+ dateBegin = lastDetectedOperation.DateEnd;
+
+ if (CacheOfStartDatesByTelemetryId.TryGetValue(idTelemetry, out var dateBeginFromCache))
+ dateBegin = dateBeginFromCache;
+
+ 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
+ };
+
+ var detectedOperations =
+ await detectedOperationService.DetectOperationsAsync(idTelemetry, request, lastDetectedOperation, token);
+
+ dateBegin = detectedOperations.LastDate;
+
+ CacheOfStartDatesByTelemetryId[idTelemetry] = dateBegin;
+
+ await detectedOperationRepository.InsertRangeAsync(detectedOperations.Items, token);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs
index b3705109..31bf9a3f 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs
@@ -13,299 +13,298 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-namespace AsbCloudInfrastructure.Services.SAUB
+namespace AsbCloudInfrastructure.Services.SAUB;
+
+public abstract class TelemetryDataBaseService : ITelemetryDataService
+ where TDto : AsbCloudApp.Data.ITelemetryData
+ where TEntity : class, AsbCloudDb.Model.ITelemetryData
{
- public abstract class TelemetryDataBaseService : ITelemetryDataService
- where TDto : AsbCloudApp.Data.ITelemetryData
- where TEntity : class, AsbCloudDb.Model.ITelemetryData
+ protected readonly IAsbCloudDbContext db;
+ protected readonly ITelemetryService telemetryService;
+ protected readonly ITelemetryDataCache telemetryDataCache;
+
+ protected TelemetryDataBaseService(
+ IAsbCloudDbContext db,
+ ITelemetryService telemetryService,
+ ITelemetryDataCache telemetryDataCache)
{
- protected readonly IAsbCloudDbContext db;
- protected readonly ITelemetryService telemetryService;
- protected readonly ITelemetryDataCache telemetryDataCache;
+ this.db = db;
+ this.telemetryService = telemetryService;
+ this.telemetryDataCache = telemetryDataCache;
+ }
- protected TelemetryDataBaseService(
- IAsbCloudDbContext db,
- ITelemetryService telemetryService,
- ITelemetryDataCache telemetryDataCache)
+ ///
+ public virtual async Task UpdateDataAsync(string uid, IEnumerable dtos, CancellationToken token = default)
+ {
+ if (dtos == default || !dtos.Any())
+ return 0;
+
+ var dtosList = dtos.OrderBy(d => d.DateTime).ToList();
+
+ var dtoMinDate = dtosList.First().DateTime;
+ var dtoMaxDate = dtosList.Last().DateTime;
+
+ if (dtosList.Count > 1)
{
- this.db = db;
- this.telemetryService = telemetryService;
- this.telemetryDataCache = telemetryDataCache;
+ var duplicates = new List(8);
+ for (int i = 1; i < dtosList.Count; i++)
+ if (dtosList[i].DateTime - dtosList[i - 1].DateTime < TimeSpan.FromMilliseconds(100))
+ duplicates.Add(dtosList[i - 1]);
+ foreach (var duplicate in duplicates)
+ dtosList.Remove(duplicate);
}
- ///
- public virtual async Task UpdateDataAsync(string uid, IEnumerable dtos, CancellationToken token = default)
+ var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid);
+ var timeZone = telemetryService.GetTimezone(telemetry.Id);
+
+ telemetryDataCache.AddRange(telemetry.Id, dtos);
+
+ var entities = dtosList.Select(dto =>
{
- if (dtos == default || !dtos.Any())
- return 0;
+ var entity = Convert(dto, timeZone.Hours);
+ entity.IdTelemetry = telemetry.Id;
+ return entity;
+ });
- var dtosList = dtos.OrderBy(d => d.DateTime).ToList();
-
- var dtoMinDate = dtosList.First().DateTime;
- var dtoMaxDate = dtosList.Last().DateTime;
-
- if (dtosList.Count > 1)
- {
- var duplicates = new List(8);
- for (int i = 1; i < dtosList.Count; i++)
- if (dtosList[i].DateTime - dtosList[i - 1].DateTime < TimeSpan.FromMilliseconds(100))
- duplicates.Add(dtosList[i - 1]);
- foreach (var duplicate in duplicates)
- dtosList.Remove(duplicate);
- }
-
- var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid);
- var timezone = telemetryService.GetTimezone(telemetry.Id);
-
- telemetryDataCache.AddRange(telemetry.Id, dtos);
-
- var entities = dtosList.Select(dto =>
- {
- var entity = Convert(dto, timezone.Hours);
- entity.IdTelemetry = telemetry.Id;
- return entity;
- });
-
- var stopwatch = Stopwatch.StartNew();
- var dbSet = db.Set();
- try
- {
- return await db.Database.ExecInsertOrUpdateAsync(dbSet, entities, token).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- stopwatch.Stop();
- Trace.WriteLine($"Fail to save data telemetry " +
- $"uid: {uid}, " +
- $"idTelemetry {telemetry.Id}, " +
- $"count: {entities.Count()}, " +
- $"dataDate: {entities.FirstOrDefault()?.DateTime}, " +
- $"dbSaveDurationTime:{stopwatch.ElapsedMilliseconds}ms. " +
- $"Message: {ex.Message}");
- return 0;
- }
+ var stopwatch = Stopwatch.StartNew();
+ var dbSet = db.Set();
+ try
+ {
+ return await db.Database.ExecInsertOrUpdateAsync(dbSet, entities, token).ConfigureAwait(false);
}
-
- ///
- public virtual async Task> GetByWellAsync(int idWell,
- DateTime dateBegin = default, double intervalSec = 600d,
- int approxPointsCount = 1024, CancellationToken token = default)
+ catch (Exception ex)
{
- var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
- if (telemetry is null)
- return Enumerable.Empty();
-
- var timezone = telemetryService.GetTimezone(telemetry.Id);
-
- var filterByDateEnd = dateBegin != default;
- DateTimeOffset dateBeginUtc;
- if (dateBegin == default)
- {
- var dateRange = telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id);
- dateBeginUtc = (dateRange?.To.ToUniversalTime() ?? DateTimeOffset.UtcNow)
- .AddSeconds(-intervalSec);
- }
- else
- {
- dateBeginUtc = dateBegin.ToUtcDateTimeOffset(timezone.Hours);
- }
-
- var cacheData = telemetryDataCache.GetOrDefault(telemetry.Id, dateBeginUtc.ToRemoteDateTime(timezone.Hours), intervalSec, approxPointsCount);
- if (cacheData is not null)
- return cacheData;
-
- var dateEnd = dateBeginUtc.AddSeconds(intervalSec);
- var dbSet = db.Set();
-
- var query = dbSet
- .Where(d => d.IdTelemetry == telemetry.Id
- && d.DateTime >= dateBeginUtc);
-
- if (filterByDateEnd)
- query = query.Where(d => d.DateTime <= dateEnd);
-
- var fullDataCount = await query.CountAsync(token)
- .ConfigureAwait(false);
-
- if (fullDataCount == 0)
- return Enumerable.Empty();
-
- if (fullDataCount > 1.75 * approxPointsCount)
- {
- var m = (int)Math.Round(1d * fullDataCount / approxPointsCount);
- if (m > 1)
- query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0);
- }
-
- var entities = await query
- .AsNoTracking()
- .ToArrayAsync(token);
-
- var dtos = entities.Select(e => Convert(e, timezone.Hours));
-
- return dtos;
- }
-
- ///
- public virtual async Task> GetByWellAsync(int idWell, TelemetryDataRequest request, CancellationToken token)
- {
- var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
- if (telemetry is null)
- return Enumerable.Empty();
-
- return await GetByTelemetryAsync(telemetry.Id, request, token);
- }
-
- public async Task> GetByTelemetryAsync(int idTelemetry, TelemetryDataRequest request, CancellationToken token)
- {
- var timezone = telemetryService.GetTimezone(idTelemetry);
-
- var cache = telemetryDataCache.GetOrDefault(idTelemetry, request);
-
- if (cache is not null)
- return cache;
-
- var query = BuildQuery(idTelemetry, request);
-
- var entities = await query
- .AsNoTracking()
- .ToArrayAsync(token);
-
- var dtos = entities.Select(e => Convert(e, timezone.Hours));
-
- return dtos;
- }
-
- private IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request)
- {
- var dbSet = db.Set();
-
- var query = dbSet
- .Where(d => d.IdTelemetry == idTelemetry);
-
- if (request.GeDate.HasValue)
- {
- var geDate = request.GeDate.Value.UtcDateTime;
- query = query.Where(d => d.DateTime >= geDate);
- }
-
- if (request.LeDate.HasValue)
- {
- var leDate = request.LeDate.Value.UtcDateTime;
- query = query.Where(d => d.DateTime <= leDate);
- }
-
- if (request.Divider > 1)
- query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0);
-
- switch (request.Order)
- {
- case 1:// Поздние вперед
- query = query
- .OrderByDescending(d => d.DateTime)
- .Skip(request.Skip)
- .Take(request.Take)
- .OrderBy(d => d.DateTime);
- break;
- default:// Ранние вперед
- query = query
- .OrderBy(d => d.DateTime)
- .Skip(request.Skip)
- .Take(request.Take);
- break;
- }
-
- return query;
- }
-
- private IQueryable BuildQuery(TelemetryPartDeleteRequest request)
- {
- var query = db.Set()
- .Where(o => o.IdTelemetry == request.IdTelemetry);
-
- if (request.GeDate is not null)
- {
- var geDate = request.GeDate.Value.ToUniversalTime();
- query = query.Where(o => o.DateTime <= geDate);
- }
-
- if (request.LeDate is not null)
- {
- var leDate = request.LeDate.Value.ToUniversalTime();
- query = query.Where(o => o.DateTime >= leDate);
- }
-
- return query;
- }
-
- ///
- public async Task GetRangeAsync(int idWell, DateTimeOffset geDate, DateTimeOffset? leDate, CancellationToken token)
- {
- var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell)
- ?? throw new ArgumentInvalidException(nameof(idWell), $"По скважине id:{idWell} нет телеметрии");
-
- if ((DateTimeOffset.UtcNow - geDate) < TimeSpan.FromHours(12))
- {
- // пробуем обойтись кэшем
- var cachedRange = telemetryDataCache.GetOrDefaultCachedDataDateRange(telemetry.Id);
- if (cachedRange is not null)
- {
- var datesRange = new DatesRangeDto { From = cachedRange.From, To = cachedRange.To };
- if (geDate >= cachedRange.From)
- datesRange.From = geDate.ToOffset(cachedRange.From.Offset);
-
- if (leDate.HasValue && leDate <= cachedRange.To)
- datesRange.To = leDate.Value.ToOffset(cachedRange.To.Offset);
-
- return datesRange;
- }
- }
-
- var query = db.Set()
- .Where(entity => entity.IdTelemetry == telemetry.Id)
- .Where(entity => entity.DateTime >= geDate.ToUniversalTime());
-
- if (leDate.HasValue)
- query = query.Where(entity => entity.DateTime <= leDate.Value.ToUniversalTime());
-
- var groupQuery = query
- .GroupBy(entity => entity.IdTelemetry)
- .Select(group => new
- {
- MinDate = group.Min(entity => entity.DateTime),
- MaxDate = group.Max(entity => entity.DateTime),
- });
-
- var result = await groupQuery.FirstOrDefaultAsync(token);
- if (result is null)
- return null;
-
- var range = new DatesRangeDto
- {
- From = result.MinDate.ToOffset(telemetry.TimeZone!.Offset),
- To = result.MaxDate.ToOffset(telemetry.TimeZone!.Offset),
- };
- return range;
- }
-
- public DatesRangeDto? GetRange(int idWell)
- {
- var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
- if (telemetry is null)
- return default;
-
- return telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id);
- }
-
- protected abstract TDto Convert(TEntity src, double timezoneOffset);
-
- protected abstract TEntity Convert(TDto src, double timezoneOffset);
-
- public async Task DeleteAsync(TelemetryPartDeleteRequest request, CancellationToken token)
- {
- var query = BuildQuery(request);
- db.Set().RemoveRange(query);
- return await db.SaveChangesAsync(token);
+ stopwatch.Stop();
+ Trace.WriteLine($"Fail to save data telemetry " +
+ $"uid: {uid}, " +
+ $"idTelemetry {telemetry.Id}, " +
+ $"count: {entities.Count()}, " +
+ $"dataDate: {entities.FirstOrDefault()?.DateTime}, " +
+ $"dbSaveDurationTime:{stopwatch.ElapsedMilliseconds}ms. " +
+ $"Message: {ex.Message}");
+ return 0;
}
}
+
+ ///
+ public virtual async Task> GetByWellAsync(int idWell,
+ DateTime dateBegin = default, double intervalSec = 600d,
+ int approxPointsCount = 1024, CancellationToken token = default)
+ {
+ var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
+ if (telemetry is null)
+ return Enumerable.Empty();
+
+ var timezone = telemetryService.GetTimezone(telemetry.Id);
+
+ var filterByDateEnd = dateBegin != default;
+ DateTimeOffset dateBeginUtc;
+ if (dateBegin == default)
+ {
+ var dateRange = telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id);
+ dateBeginUtc = (dateRange?.To.ToUniversalTime() ?? DateTimeOffset.UtcNow)
+ .AddSeconds(-intervalSec);
+ }
+ else
+ {
+ dateBeginUtc = dateBegin.ToUtcDateTimeOffset(timezone.Hours);
+ }
+
+ var cacheData = telemetryDataCache.GetOrDefault(telemetry.Id, dateBeginUtc.ToRemoteDateTime(timezone.Hours), intervalSec, approxPointsCount);
+ if (cacheData is not null)
+ return cacheData;
+
+ var dateEnd = dateBeginUtc.AddSeconds(intervalSec);
+ var dbSet = db.Set();
+
+ var query = dbSet
+ .Where(d => d.IdTelemetry == telemetry.Id
+ && d.DateTime >= dateBeginUtc);
+
+ if (filterByDateEnd)
+ query = query.Where(d => d.DateTime <= dateEnd);
+
+ var fullDataCount = await query.CountAsync(token)
+ .ConfigureAwait(false);
+
+ if (fullDataCount == 0)
+ return Enumerable.Empty();
+
+ if (fullDataCount > 1.75 * approxPointsCount)
+ {
+ var m = (int)Math.Round(1d * fullDataCount / approxPointsCount);
+ if (m > 1)
+ query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0);
+ }
+
+ var entities = await query
+ .AsNoTracking()
+ .ToArrayAsync(token);
+
+ var dtos = entities.Select(e => Convert(e, timezone.Hours));
+
+ return dtos;
+ }
+
+ ///
+ public virtual async Task> GetByWellAsync(int idWell, TelemetryDataRequest request, CancellationToken token)
+ {
+ var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
+ if (telemetry is null)
+ return Enumerable.Empty();
+
+ return await GetByTelemetryAsync(telemetry.Id, request, token);
+ }
+
+ public async Task> GetByTelemetryAsync(int idTelemetry, TelemetryDataRequest request, CancellationToken token)
+ {
+ var timeZone = telemetryService.GetTimezone(idTelemetry);
+
+ var cache = telemetryDataCache.GetOrDefault(idTelemetry, request);
+
+ if (cache is not null)
+ return cache;
+
+ var query = BuildQuery(idTelemetry, request);
+
+ var entities = await query
+ .AsNoTracking()
+ .ToArrayAsync(token);
+
+ var dtos = entities.Select(e => Convert(e, timeZone.Hours));
+
+ return dtos;
+ }
+
+ private IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request)
+ {
+ var dbSet = db.Set();
+
+ var query = dbSet
+ .Where(d => d.IdTelemetry == idTelemetry);
+
+ if (request.GeDate.HasValue)
+ {
+ var geDate = request.GeDate.Value.UtcDateTime;
+ query = query.Where(d => d.DateTime >= geDate);
+ }
+
+ if (request.LeDate.HasValue)
+ {
+ var leDate = request.LeDate.Value.UtcDateTime;
+ query = query.Where(d => d.DateTime <= leDate);
+ }
+
+ if (request.Divider > 1)
+ query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0);
+
+ switch (request.Order)
+ {
+ case 1:// Поздние вперед
+ query = query
+ .OrderByDescending(d => d.DateTime)
+ .Skip(request.Skip)
+ .Take(request.Take)
+ .OrderBy(d => d.DateTime);
+ break;
+ default:// Ранние вперед
+ query = query
+ .OrderBy(d => d.DateTime)
+ .Skip(request.Skip)
+ .Take(request.Take);
+ break;
+ }
+
+ return query;
+ }
+
+ private IQueryable BuildQuery(TelemetryPartDeleteRequest request)
+ {
+ var query = db.Set()
+ .Where(o => o.IdTelemetry == request.IdTelemetry);
+
+ if (request.GeDate is not null)
+ {
+ var geDate = request.GeDate.Value.ToUniversalTime();
+ query = query.Where(o => o.DateTime <= geDate);
+ }
+
+ if (request.LeDate is not null)
+ {
+ var leDate = request.LeDate.Value.ToUniversalTime();
+ query = query.Where(o => o.DateTime >= leDate);
+ }
+
+ return query;
+ }
+
+ ///
+ public async Task GetRangeAsync(int idWell, DateTimeOffset geDate, DateTimeOffset? leDate, CancellationToken token)
+ {
+ var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell)
+ ?? throw new ArgumentInvalidException(nameof(idWell), $"По скважине id:{idWell} нет телеметрии");
+
+ if ((DateTimeOffset.UtcNow - geDate) < TimeSpan.FromHours(12))
+ {
+ // пробуем обойтись кэшем
+ var cachedRange = telemetryDataCache.GetOrDefaultCachedDataDateRange(telemetry.Id);
+ if (cachedRange is not null)
+ {
+ var datesRange = new DatesRangeDto { From = cachedRange.From, To = cachedRange.To };
+ if (geDate >= cachedRange.From)
+ datesRange.From = geDate.ToOffset(cachedRange.From.Offset);
+
+ if (leDate.HasValue && leDate <= cachedRange.To)
+ datesRange.To = leDate.Value.ToOffset(cachedRange.To.Offset);
+
+ return datesRange;
+ }
+ }
+
+ var query = db.Set()
+ .Where(entity => entity.IdTelemetry == telemetry.Id)
+ .Where(entity => entity.DateTime >= geDate.ToUniversalTime());
+
+ if (leDate.HasValue)
+ query = query.Where(entity => entity.DateTime <= leDate.Value.ToUniversalTime());
+
+ var groupQuery = query
+ .GroupBy(entity => entity.IdTelemetry)
+ .Select(group => new
+ {
+ MinDate = group.Min(entity => entity.DateTime),
+ MaxDate = group.Max(entity => entity.DateTime),
+ });
+
+ var result = await groupQuery.FirstOrDefaultAsync(token);
+ if (result is null)
+ return null;
+
+ var range = new DatesRangeDto
+ {
+ From = result.MinDate.ToOffset(telemetry.TimeZone!.Offset),
+ To = result.MaxDate.ToOffset(telemetry.TimeZone!.Offset),
+ };
+ return range;
+ }
+
+ public DatesRangeDto? GetRange(int idWell)
+ {
+ var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
+ if (telemetry is null)
+ return default;
+
+ return telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id);
+ }
+
+ protected abstract TDto Convert(TEntity src, double timeZoneOffset);
+
+ protected abstract TEntity Convert(TDto src, double timeZoneOffset);
+
+ public async Task DeleteAsync(TelemetryPartDeleteRequest request, CancellationToken token)
+ {
+ var query = BuildQuery(request);
+ db.Set().RemoveRange(query);
+ return await db.SaveChangesAsync(token);
+ }
}
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
index f80ccaa7..da0a9486 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
@@ -152,9 +152,9 @@ public class TelemetryDataCache : ITelemetryDataCache where TDto : A
if (cacheItem.LastData.Count == 0)
return null;
-
- var to = FromDate(cacheItem.FirstByDate.DateTime, cacheItem.TimezoneOffset);
- var from = FromDate(cacheItem.LastData[^1].DateTime, cacheItem.TimezoneOffset);
+
+ var to = FromDate(cacheItem.LastData[^1].DateTime, cacheItem.TimezoneOffset);
+ var from = FromDate(cacheItem.FirstByDate.DateTime, cacheItem.TimezoneOffset);
return new DatesRangeDto { From = from, To = to };
}
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs
index 78a63b2c..2516bd65 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs
@@ -13,6 +13,8 @@ using System.Linq;
using System.Text.Csv;
using System.Threading;
using System.Threading.Tasks;
+using AsbCloudApp.Data;
+using AsbCloudApp.Requests;
namespace AsbCloudInfrastructure.Services.SAUB;
@@ -174,4 +176,4 @@ public class TelemetryDataSaubService : TelemetryDataBaseService
- /// Получить список автоопределенных операций для редактирования
+ /// Получить список авто определенных операций для редактирования
///
///
///
@@ -136,7 +136,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
}
///
- /// Получить статистику по автоопределенным операциям
+ /// Получить статистику по авто определенным операциям
///
///
///
@@ -167,13 +167,13 @@ namespace AsbCloudWebApi.Controllers.SAUB
public async Task ExportAsync(int idWell, CancellationToken token)
{
var idCompany = User.GetCompanyId();
-
+
if (idCompany is null)
return Forbid();
-
+
var host = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}";
var stream = await detectedOperationExportService.ExportAsync(idWell, host, token);
-
+
return File(stream, "application/octet-stream", "operations.xlsx");
}