Правки по результатам ревью

This commit is contained in:
Olga Nemt 2024-02-01 13:44:27 +05:00
parent 9c69adb10c
commit fe28df93e7
7 changed files with 133 additions and 56 deletions

View File

@ -72,5 +72,12 @@ namespace AsbCloudApp.Repositories
/// </summary>
/// <returns></returns>
IEnumerable<TelemetryDataStatDto> GetStat();
/// <summary>
/// Получить ключи телеметрии по параметрам запроса
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
IEnumerable<int>? GetIds(TelemetryDataRequest request);
}
}

View File

@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace AsbCloudDb.Migrations
{
[DbContext(typeof(AsbCloudDbContext))]
[Migration("20240131104814_Add_Table_DataSaubStat")]
[Migration("20240201060511_Add_Table_DataSaubStat")]
partial class Add_Table_DataSaubStat
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -368,11 +368,6 @@ namespace AsbCloudDb.Migrations
.HasColumnName("depth_start")
.HasComment("Глубина забоя по стволу начальная");
b.Property<int>("DetectedOperationCategoryId")
.HasColumnType("integer")
.HasColumnName("detected_operation_category_id")
.HasComment("Название автоопределённой операции");
b.Property<int>("EnabledSubsystems")
.HasColumnType("integer")
.HasColumnName("enabled_subsystems")
@ -388,6 +383,11 @@ namespace AsbCloudDb.Migrations
.HasColumnName("has_oscillation")
.HasComment("Наличие или отсутствие осцилляции");
b.Property<int>("IdCategory")
.HasColumnType("integer")
.HasColumnName("id_category")
.HasComment("Название автоопределённой операции");
b.Property<short?>("IdFeedRegulator")
.HasColumnType("smallint")
.HasColumnName("id_feed_regulator")
@ -440,6 +440,8 @@ namespace AsbCloudDb.Migrations
b.HasKey("Id");
b.HasIndex("IdCategory");
b.HasIndex("IdTelemetry");
b.ToTable("t_data_saub_stat");
@ -8424,12 +8426,20 @@ namespace AsbCloudDb.Migrations
modelBuilder.Entity("AsbCloudDb.Model.DataSaubStat", b =>
{
b.HasOne("AsbCloudDb.Model.WellOperationCategory", "OperationCategory")
.WithMany()
.HasForeignKey("IdCategory")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.Telemetry", "Telemetry")
.WithMany()
.HasForeignKey("IdTelemetry")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("OperationCategory");
b.Navigation("Telemetry");
});

View File

@ -33,7 +33,7 @@ namespace AsbCloudDb.Migrations
rotor_torque_limit_max = table.Column<double>(type: "double precision", nullable: true, comment: "Максимально допустимый момент"),
id_feed_regulator = table.Column<short>(type: "smallint", nullable: true, comment: "Работа при достижении ограничения"),
rotor_speed = table.Column<double>(type: "double precision", nullable: false, comment: "Фактическая скорость оборотов ВСП"),
detected_operation_category_id = table.Column<int>(type: "integer", nullable: false, comment: "Название автоопределённой операции"),
id_category = table.Column<int>(type: "integer", nullable: false, comment: "Название автоопределённой операции"),
enabled_subsystems = table.Column<int>(type: "integer", nullable: false, comment: "Флаги подсистем"),
has_oscillation = table.Column<bool>(type: "boolean", nullable: false, comment: "Наличие или отсутствие осцилляции"),
flow = table.Column<double>(type: "double precision", nullable: false, comment: "Фактический расход"),
@ -48,9 +48,20 @@ namespace AsbCloudDb.Migrations
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_data_saub_stat_t_well_operation_category_id_category",
column: x => x.id_category,
principalTable: "t_well_operation_category",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "Кеш-таблица для хранения данных для РТК-отчета");
migrationBuilder.CreateIndex(
name: "IX_t_data_saub_stat_id_category",
table: "t_data_saub_stat",
column: "id_category");
migrationBuilder.CreateIndex(
name: "IX_t_data_saub_stat_id_telemetry",
table: "t_data_saub_stat",

View File

@ -366,11 +366,6 @@ namespace AsbCloudDb.Migrations
.HasColumnName("depth_start")
.HasComment("Глубина забоя по стволу начальная");
b.Property<int>("DetectedOperationCategoryId")
.HasColumnType("integer")
.HasColumnName("detected_operation_category_id")
.HasComment("Название автоопределённой операции");
b.Property<int>("EnabledSubsystems")
.HasColumnType("integer")
.HasColumnName("enabled_subsystems")
@ -386,6 +381,11 @@ namespace AsbCloudDb.Migrations
.HasColumnName("has_oscillation")
.HasComment("Наличие или отсутствие осцилляции");
b.Property<int>("IdCategory")
.HasColumnType("integer")
.HasColumnName("id_category")
.HasComment("Название автоопределённой операции");
b.Property<short?>("IdFeedRegulator")
.HasColumnType("smallint")
.HasColumnName("id_feed_regulator")
@ -438,6 +438,8 @@ namespace AsbCloudDb.Migrations
b.HasKey("Id");
b.HasIndex("IdCategory");
b.HasIndex("IdTelemetry");
b.ToTable("t_data_saub_stat");
@ -8422,12 +8424,20 @@ namespace AsbCloudDb.Migrations
modelBuilder.Entity("AsbCloudDb.Model.DataSaubStat", b =>
{
b.HasOne("AsbCloudDb.Model.WellOperationCategory", "OperationCategory")
.WithMany()
.HasForeignKey("IdCategory")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.Telemetry", "Telemetry")
.WithMany()
.HasForeignKey("IdTelemetry")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("OperationCategory");
b.Navigation("Telemetry");
});

View File

@ -64,8 +64,8 @@ namespace AsbCloudDb.Model
[Column("rotor_speed"), Comment("Фактическая скорость оборотов ВСП")]
public double RotorSpeed { get; set; }
[Column("detected_operation_category_id"), Comment("Название автоопределённой операции")]
public int DetectedOperationCategoryId { get; set; }
[Column("id_category"), Comment("Название автоопределённой операции")]
public int IdCategory { get; set; }
[Column("enabled_subsystems"), Comment("Флаги подсистем")]
public int EnabledSubsystems { get; set; }
@ -81,5 +81,9 @@ namespace AsbCloudDb.Model
[ForeignKey(nameof(IdTelemetry))]
public virtual Telemetry Telemetry { get; set; } = null!;
[JsonIgnore]
[ForeignKey(nameof(IdCategory))]
public virtual WellOperationCategory OperationCategory { get; set; } = null!;
}
}

View File

@ -1,7 +1,12 @@
using AsbCloudDb.Model;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -14,72 +19,81 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
internal class WorkDataSaubStat : Work
{
private int MechanicalDrillingCategoryId = 4001;
private int Gap = 60;
public WorkDataSaubStat() : base("Generate DataSaubStat entries and save them into Db")
{
Timeout = TimeSpan.FromMinutes(10);
}
protected override 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)
{
//1 найти последнюю запись в кеш-таблице (по полям "Дата до")
//2 определяем дату с которой начинаем анализ
//3 находим автоопределнные операции по скважине, начиная с начальной даты из пункта 2
// 3.1 только те, которые связанные с бурением (idParent = 4001)
// 3.2 выбираем 500 операций
// 3.3. выбираем минимальную дату начала и максимальную дату окончания
//4 по полученным в пункте выше данным выбираем записи из telemetry_data_saub
// 4.1.выбираем те у которых (bit_depth == well_depth)
//5. для каждой операции из 3.2 находим соответствующий ей кусок телеметрии (по дате начала и окончания)
// и храним индексы этого куска в виде span
//6. кусок телеметрии, полученный в пункте 5 (span) и соответствующая ей операция направляется на разбивку диапазонов
//7/ разбивка диапазонов:
// параметры метода: массив из
using var db = services.GetRequiredService<IAsbCloudDbContext>();
var telemetryDataCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
var telemetryIds = telemetryDataCache.GetIds(new TelemetryDataRequest()
{
GeDate = DateTime.UtcNow.AddDays(-Gap)
});
if (telemetryIds == null || !telemetryIds.Any())
return;
var dateEnd = db.Set<DataSaubStat>()
.OrderByDescending(c => c.DateEnd)
.FirstOrDefault()?.DateEnd
?? DateTimeOffset.MinValue;
var detectedOperations = db.Set<DetectedOperation>()
var detectedOperations = await db.Set<DetectedOperation>()
.Where(o => o.DateStart > dateEnd)
.Where(o => o.OperationCategory.IdParent == MechanicalDrillingCategoryId)
.Where(o => telemetryIds.Contains(o.IdTelemetry))
.OrderBy(o => o.DateStart)
.Take(500)
.ToArray();
.ToArrayAsync(token);
if (!detectedOperations.Any())
return;
var minDate = detectedOperations.FirstOrDefault()?.DateStart;
var maxDate = detectedOperations.OrderByDescending(d => d.DateEnd).FirstOrDefault()?.DateEnd;
var telemetryDataSaub = db.Set<TelemetryDataSaub>()
var telemetryDataSaub = (await db.Set<TelemetryDataSaub>()
.Where(t => t.DateTime >= minDate)
.Where(t => t.DateTime <= maxDate)
.Where(t => Math.Abs(t.BitDepth - t.WellDepth) < 0.0001)
.OrderBy(t => t.DateTime)
.ToArray();
.Where(t => telemetryIds.Contains(t.IdTelemetry))
.ToArrayAsync(token))
.GroupBy(t => t.IdTelemetry)
.ToDictionary(g => g.Key, g => g.OrderBy(t => t.DateTime).ToArray());
CreateDataSaubStat(db, detectedOperations, telemetryDataSaub);
}
private static void CreateDataSaubStat(IAsbCloudDbContext db, DetectedOperation[] detectedOperations, Dictionary<int, TelemetryDataSaub[]> telemetryDataSaub)
{
var indexStart = 0;
var indexEnd = 0;
foreach (var operation in detectedOperations)
{
indexStart = Array.FindIndex(telemetryDataSaub, indexEnd, t => t.DateTime >= operation.DateStart);
indexEnd = Array.FindIndex(telemetryDataSaub, indexStart, t => t.DateTime > operation.DateEnd) - 1;
if (!telemetryDataSaub.TryGetValue(operation.IdTelemetry, out TelemetryDataSaub[]? telemetryDataSaubPart))
break;
indexStart = Array.FindIndex(telemetryDataSaubPart, indexEnd, t => t.DateTime >= operation.DateStart);
indexEnd = Array.FindIndex(telemetryDataSaubPart, indexStart, t => t.DateTime > operation.DateEnd) - 1;
if (indexStart >= 0 && indexEnd >= indexStart)
{
var length = indexEnd - indexStart;
var subset = telemetryDataSaub.AsSpan(indexStart, length + 1);
var result = CalcStats(operation, subset, db);
var subset = telemetryDataSaubPart.AsSpan(indexStart, length + 1);
CalcStats(operation, subset, db);
db.SaveChanges();
}
}
return Task.CompletedTask;
}
private int CalcStats(DetectedOperation operation, Span<TelemetryDataSaub> telemetryDataSaub, IAsbCloudDbContext db)
private static void CalcStats(DetectedOperation operation, Span<TelemetryDataSaub> telemetryDataSaub, IAsbCloudDbContext db)
{
var indexStart = 0;
for (var i = 1; i < telemetryDataSaub.Length; i++)
@ -96,15 +110,14 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
db.Set<DataSaubStat>().Add(dataSaubStatItem);
}
}
return db.SaveChanges();
}
private DataSaubStat CalcStat(DetectedOperation operation, Span<TelemetryDataSaub> span)
private static DataSaubStat CalcStat(DetectedOperation operation, Span<TelemetryDataSaub> span)
{
var hasOscillation = operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out object? hasOscillationObject)
&& hasOscillationObject is true;
var wavg = CalcWavg(span);
var aggregatedValues = CalcAggregate(span);
var processMapDrillingCacheItem = new DataSaubStat
{
DateStart = operation.DateStart,
@ -113,33 +126,33 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
DepthEnd = operation.DepthEnd,
Speed = (operation.DepthEnd - operation.DepthStart) / ((operation.DateEnd - operation.DateStart).TotalHours),
BlockSpeedSp = span[0].BlockSpeedSp,
Pressure = wavg.Pressure,
Pressure = aggregatedValues.Pressure,
PressureIdle = span[0].PressureIdle,
PressureSp = span[0].PressureSp,
AxialLoad = wavg.AxialLoad,
AxialLoad = aggregatedValues.AxialLoad,
AxialLoadSp = span[0].AxialLoadSp,
AxialLoadLimitMax = span[0].AxialLoadLimitMax,
RotorTorque = wavg.RotorTorque,
RotorTorque = aggregatedValues.RotorTorque,
RotorTorqueSp = span[0].RotorTorqueSp,
RotorTorqueLimitMax = span[0].RotorTorqueLimitMax,
IdFeedRegulator = span[0].IdFeedRegulator,
RotorSpeed = wavg.RotorSpeed,
DetectedOperationCategoryId = operation.IdCategory,
RotorSpeed = aggregatedValues.RotorSpeed,
IdCategory = operation.IdCategory,
EnabledSubsystems = operation.EnabledSubsystems,
HasOscillation = hasOscillation,
IdTelemetry = operation.IdTelemetry,
Flow = wavg.Flow
Flow = aggregatedValues.Flow
};
return processMapDrillingCacheItem;
}
private (
private static (
double Pressure,
double AxialLoad,
double RotorTorque,
double RotorSpeed,
double Flow
) CalcWavg(Span<TelemetryDataSaub> span)
) CalcAggregate(Span<TelemetryDataSaub> span)
{
var sumPressure = 0.0;
var sumAxialLoad = 0.0;
@ -154,7 +167,7 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
sumAxialLoad += weigth * span[i].AxialLoad;
sumRotorTorque += weigth * span[i].RotorTorque;
sumRotorSpeed += weigth * span[i].RotorSpeed;
flow = span[i + 1].Flow > flow ? span[i + 1].Flow ?? 0.0 :flow;
flow = span[i + 1].Flow > flow ? span[i + 1].Flow ?? 0.0 : flow;
}
return (
Pressure: sumPressure / diffDepthTotal,
@ -165,7 +178,7 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
);
}
private bool IsNewCacheItem(TelemetryDataSaub previous, TelemetryDataSaub current)
private static bool IsNewCacheItem(TelemetryDataSaub previous, TelemetryDataSaub current)
{
return !(current.Mode == previous.Mode)
|| !(current.BlockSpeedSp == previous.BlockSpeedSp)

View File

@ -324,5 +324,27 @@ namespace AsbCloudInfrastructure.Services.SAUB
return data;
}
public IEnumerable<int>? GetIds(TelemetryDataRequest request)
{
var data = new Dictionary<int, TelemetryDataCacheItem>();
if (request.GeDate.HasValue)
{
data = caches
.Where(item => item.Value.LastData.Any(d => d.DateTime >= request.GeDate.Value.ToRemoteDateTime(item.Value.TimezoneHours)))
.ToDictionary(item => item.Key, item => item.Value);
}
if (request.LeDate.HasValue)
{
data = caches
.Where(item => item.Value.LastData.Any(d => d.DateTime <= request.LeDate.Value.ToRemoteDateTime(item.Value.TimezoneHours)))
.ToDictionary(item => item.Key, item => item.Value);
}
var telemetryIds = data.Select(item => item.Key);
return telemetryIds;
}
}
}