правки после ревью

This commit is contained in:
Olga Nemt 2024-02-13 16:35:01 +05:00
parent 4f2bc9244e
commit 0fdb1ede72
7 changed files with 217 additions and 55 deletions

View File

@ -11,27 +11,27 @@ namespace AsbCloudApp.Data
/// <summary>
/// Нет ограничения
/// </summary>
public static int NoLimit = 0;
public const int NoLimit = 0;
/// <summary>
/// МСП
/// </summary>
public static int RopPlan = 1;
public const int RopPlan = 1;
/// <summary>
/// Давление
/// </summary>
public static int Pressure = 2;
public const int Pressure = 2;
/// <summary>
/// Осевая нагрузка
/// </summary>
public static int AxialLoad = 3;
public const int AxialLoad = 3;
/// <summary>
/// Момент
/// </summary>
public static int RotorTorque = 4;
public const int RotorTorque = 4;
/// <summary>
/// Идентификатор скважины
/// </summary>

View File

@ -0,0 +1,98 @@
using System;
namespace AsbCloudApp.Data.ProcessMaps.Report;
/// <summary>
/// Модель РТК
/// </summary>
public class ProcessMapReportDataSaubStatDto
{
/// <summary>
/// Время, затраченное на бурение интервала, в часах
/// </summary>
public double DrilledTime { get; set; } = 0;
/// <summary>
/// Идентификатор скважины
/// </summary>
public int IdWell { get; set; }
/// <summary>
/// Id секции скважины
/// </summary>
public int IdWellSectionType { get; set; }
/// <summary>
/// Название секции скважины
/// </summary>
public string WellSectionTypeName { get; set; } = null!;
/// <summary>
/// Глубина по стволу от, м
/// <para>
/// на начало интервала
/// </para>
/// </summary>
public double DepthStart { get; set; }
/// <summary>
/// Глубина по стволу до, м
/// <para>
/// на конец интервала
/// </para>
/// </summary>
public double DepthEnd { get; set; }
/// <summary>
/// Дата/ время
/// <para>
/// на начало интервала
/// </para>
/// </summary>
public DateTime DateStart { get; set; }
/// <summary>
/// Режим бурения (Ротор/слайд/ручной)
/// </summary>
public string DrillingMode { get; set; } = null!;
/// <summary>
/// Проходка, м
/// </summary>
public double? DeltaDepth { get; set; }
/// <summary>
/// Перепад давления, атм
/// </summary>
public ProcessMapReportDataSaubStatParamsDto PressureDiff { get; set; } = new();
/// <summary>
/// Нагрузка, т
/// </summary>
public ProcessMapReportDataSaubStatParamsDto AxialLoad { get; set; } = new();
/// <summary>
/// Момент на ВСП, кНхМ
/// </summary>
public ProcessMapReportDataSaubStatParamsDto TopDriveTorque { get; set; } = new();
/// <summary>
/// Ограничение скорости, м/ч
/// </summary>
public ProcessMapReportDataSaubStatParamsDto SpeedLimit { get; set; } = new();
/// <summary>
/// Обороты ВСП, об/мин
/// </summary>
public ProcessMapReportDataSaubStatParamsDto Turnover { get; set; } = new();
/// <summary>
/// Расход, л/с
/// </summary>
public ProcessMapReportDataSaubStatParamsDto Flow { get; set; } = new();
/// <summary>
/// Механическая скорость, м/ч
/// </summary>
public PlanFactDto<double?> Rop { get; set; } = new();
}

View File

@ -0,0 +1,32 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AsbCloudApp.Extensions
{
/// <summary>
/// Расширения для поиска в истории
/// </summary>
public static class ChangeLogExtensions
{
/// <summary>
/// Действительные на момент времени значения
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="items"></param>
/// <param name="moment"></param>
/// <returns></returns>
public static IEnumerable<T> WhereActualAtMoment<T>(this IEnumerable<T> items, DateTimeOffset moment)
where T : ChangeLogAbstract
{
var actualItems = items
.Where(item => item.Creation >= moment)
.Where(item => item.Obsolete is null || item.Obsolete <= moment);
return actualItems;
}
}
}

View File

@ -14,9 +14,11 @@ namespace AsbCloudApp.Repositories
/// Получение записей по ключу телеметрии
/// </summary>
/// <param name="idTelemetry">ключ телеметрии</param>
/// <param name="geDepth">начальная глубина</param>
/// <param name="leDepth">конечная глубина</param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DataSaubStatDto>> GetAsync(int idTelemetry, CancellationToken token);
Task<IEnumerable<DataSaubStatDto>> GetAsync(int idTelemetry, double geDepth, double leDepth, CancellationToken token);
/// <summary>
/// Получение последних по дате окончания бурения записей в разрезе телеметрий

View File

@ -1,4 +1,6 @@
namespace AsbCloudApp.Requests
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Requests
{
/// <summary>
/// Параметры запроса для построения отчёта
@ -7,18 +9,24 @@
{
/// <summary>
/// Изменение уставки факт перепада давления от первого значения в начале интервала
/// Не менее 5 атм и не более 15(50) атм;
/// </summary>
public double DeltaPressure { get; set; }
[Range(5, 15, ErrorMessage = "Изменение уставки факт перепада давления не может быть меньше 5 и больше 15 атм")]
public double DeltaPressure { get; set; } = 5d;
/// <summary>
/// Изменение уставки факт осевой нагрузки от первого значения в начале интервала
/// Изменение уставки факт осевой нагрузки от первого значения в начале интервала
/// Не менее 1 т и не более 5(20) т;
/// </summary>
public double DeltaAxialLoad { get; set; }
[Range(1, 5, ErrorMessage = "Изменение уставки факт осевой нагрузки не может быть меньше 1 и больше 5 т")]
public double DeltaAxialLoad { get; set; } = 1d;
/// <summary>
/// Изменение уставки момента от первого значения в начале интервала
/// Изменение уставки момента от первого значения в начале интервала
/// Не менее 5 кН*м и не более 10(20) кН*м.
/// </summary>
public double DeltaRotorTorque { get; set; }
[Range(5, 10, ErrorMessage = "Изменение уставки момента не может быть меньше 5 и больше 10 кН*м")]
public double DeltaRotorTorque { get; set; } = 5d;
/// <summary>
/// Изменение ограничения нагрузки от первого значения в начале интервала

View File

@ -40,12 +40,14 @@ namespace AsbCloudInfrastructure.Repository
return result;
}
public async Task<IEnumerable<DataSaubStatDto>> GetAsync(int idTelemetry, CancellationToken token)
public async Task<IEnumerable<DataSaubStatDto>> GetAsync(int idTelemetry, double geDepth, double leDepth, CancellationToken token)
{
var timeSpan = TimeSpan.FromHours(telemetryService.GetTimezone(idTelemetry).Hours);
var stats = await db.Set<DataSaubStat>()
.Where(s => s.IdTelemetry == idTelemetry)
.Where(s => s.DepthStart >= geDepth)
.Where(s => s.DepthEnd <= leDepth)
.ToArrayAsync(token);
var result = stats.Select(s => ConvertToDto(s, timeSpan));

View File

@ -2,6 +2,7 @@
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Extensions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
@ -48,24 +49,30 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
if (!processMapPlanWellDrillings.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var dataSaubStats =
(await dataSaubStatRepository.GetAsync(well.IdTelemetry.Value, token)).ToArray();
if (!dataSaubStats.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var geDepth = processMapPlanWellDrillings.Min(p => p.DepthStart);
var leDepth = processMapPlanWellDrillings.Max(p => p.DepthEnd);
var requestWellOperationFact = new WellOperationRequest()
{
IdWell = idWell,
OperationType = WellOperation.IdOperationTypeFact
OperationType = WellOperation.IdOperationTypeFact,
GeDepth = geDepth,
LeDepth = leDepth
};
var wellOperations = await wellOperationRepository
.GetAsync(requestWellOperationFact, token);
if (!wellOperations.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var timeZone = TimeSpan.FromHours(wellService.GetTimezone(idWell).Hours);
var result = CalcByIntervals(request, processMapPlanWellDrillings, dataSaubStats, wellOperations, timeZone);
var dataSaubStats =
(await dataSaubStatRepository.GetAsync(well.IdTelemetry.Value, geDepth, leDepth, token)).ToArray();
if (!dataSaubStats.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var wellOperationCategories = wellOperationRepository.GetCategories(false);
var result = CalcByIntervals(request, processMapPlanWellDrillings, dataSaubStats, wellOperations, wellOperationCategories);
return result;
}
@ -75,7 +82,7 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
IEnumerable<ProcessMapPlanDrillingDto> processMapPlanWellDrillings,
Span<DataSaubStatDto> dataSaubStats,
IEnumerable<WellOperationDto> wellOperations,
TimeSpan timeZone
IEnumerable<WellOperationCategoryDto> wellOperationCategories
)
{
var list = new List<ProcessMapReportDataSaubStatDto>();
@ -88,56 +95,66 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
if (IsNewInterval(currentElem, firstElemInInterval, request) || i == dataSaubStats.Length - 1)
{
var length = i - indexStart;
var elem = CalcStat(processMapPlanWellDrillings, dataSaubStats, indexStart, length, wellOperations, timeZone);
if (elem != null)
list.Add(elem);
var span = dataSaubStats.Slice(indexStart, length);
indexStart = i;
firstElemInInterval = currentElem;
var firstElemInSpan = span[0];
var lastElemInISpan = span[^1];
var nearestOperation = wellOperations.MinBy(o => firstElemInSpan.DateStart - o.DateStart);
if (nearestOperation is null)
continue;
var processMapPlanFilteredByDepth = processMapPlanWellDrillings
.Where(x => x.IdWellSectionType == nearestOperation.IdWellSectionType)
.Where(x => x.DepthStart >= firstElemInSpan.DepthStart)
.Where(x => x.DepthEnd <= lastElemInISpan.DepthEnd)
.WhereActualAtMoment(DateTimeOffset.Now)
.ToArray();
if (!processMapPlanFilteredByDepth.Any())
continue;
var wellOperationCategoryName = wellOperationCategories.
Where(c => c.Id == currentElem.IdCategory)
.FirstOrDefault()
?.Name ?? string.Empty;
var elem = CalcStat(processMapPlanFilteredByDepth, span, nearestOperation, wellOperationCategoryName);
if (elem is not null)
list.Add(elem);
}
}
return list;
}
private ProcessMapReportDataSaubStatDto? CalcStat(
IEnumerable<ProcessMapPlanDrillingDto> processMapPlanDrillingDtos,
Span<DataSaubStatDto> dataSaubStats,
int indexStart,
int length,
IEnumerable<WellOperationDto> wellOperations,
TimeSpan timeZone
ProcessMapPlanDrillingDto[] processMapPlanFilteredByDepth,
Span<DataSaubStatDto> span,
WellOperationDto nearestOperation,
string wellOperationCategoryName
)
{
var span = dataSaubStats.Slice(indexStart, length);
var firstElemInInterval = span[0];
var lastElemInInterval = span[^1];
var nearestOperation = wellOperations?.MinBy(o => firstElemInInterval.DateStart - o.DateStart);
if (nearestOperation is null)
return null;
var processMapPlanFilteredByDepth = processMapPlanDrillingDtos
.Where(x => x.IdWellSectionType == nearestOperation.IdWellSectionType)
.Where(x => x.DepthStart >= firstElemInInterval.DepthStart)
.Where(x => x.DepthEnd <= lastElemInInterval.DepthEnd)
.ToArray();
if (!processMapPlanFilteredByDepth.Any())
return null;
var deltaDepth = lastElemInInterval.DepthEnd - firstElemInInterval.DepthStart;
var drilledTime = (lastElemInInterval.DateEnd - firstElemInInterval.DateStart).TotalHours;
var aggregatedValues = CalcAggregate(span);
return new ProcessMapReportDataSaubStatDto()
{
DateStart = firstElemInInterval.DateStart.ToOffset(timeZone).DateTime,
DateStart = firstElemInInterval.DateStart.DateTime,
WellSectionTypeName = nearestOperation.WellSectionTypeName ?? string.Empty,
DepthStart = firstElemInInterval.DepthStart,
DepthEnd = lastElemInInterval.DepthEnd,
DeltaDepth = deltaDepth,
DrilledTime = drilledTime,
DrillingMode = nearestOperation.CategoryName ?? string.Empty,
DrilledTime = aggregatedValues.DrilledTime,
DrillingMode = wellOperationCategoryName,
PressureDiff = new ProcessMapReportDataSaubStatParamsDto()
{
SetpointPlanMax = processMapPlanFilteredByDepth.Max(p => p.DeltaPressurePlan),
@ -171,7 +188,7 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
SetpointPlanMax = processMapPlanFilteredByDepth.Max(p => p.RopPlan),
SetpointPlanMin = processMapPlanFilteredByDepth.Min(p => p.RopPlan),
SetpointFact = aggregatedValues.BlockSpeedSp,
FactWavg = deltaDepth / drilledTime,
FactWavg = deltaDepth / aggregatedValues.DrilledTime,
SetpointUsage = aggregatedValues.SetpointUsageRopPlan
},
Turnover = new ProcessMapReportDataSaubStatParamsDto
@ -191,7 +208,7 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
Rop = new PlanFactDto<double?>
{
Plan = CalcRopPlan(processMapPlanFilteredByDepth),
Fact = deltaDepth / drilledTime
Fact = deltaDepth / aggregatedValues.DrilledTime
},
};
}
@ -210,7 +227,8 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
double SetpointUsagePressure,
double SetpointUsageAxialLoad,
double SetpointUsageRotorTorque,
double SetpointUsageRopPlan
double SetpointUsageRopPlan,
double DrilledTime
) CalcAggregate(Span<DataSaubStatDto> span)
{
var sumPressure = 0.0;
@ -229,11 +247,13 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
var sumDiffDepthByRopPlan = 0.0;
var diffDepthTotal = 0.0;
var drilledTime = 0.0;
for (var i = 0; i < span.Length; i++)
{
var diffDepth = span[i].DepthEnd - span[i].DepthStart;
sumPressure += diffDepth * span[i].Pressure;
sumPressure += diffDepth * ((span[i].PressureIdle ?? 0) - span[i].Pressure);
sumAxialLoadSp += diffDepth * (span[i].AxialLoadSp ?? 0);
sumAxialLoad += diffDepth * span[i].AxialLoad;
sumRotorTorqueSp += diffDepth * (span[i].RotorTorqueSp ?? 0);
@ -254,8 +274,7 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
sumDiffDepthByRopPlan += span[i].DepthEnd - span[i].DepthStart;
diffDepthTotal += diffDepth;
drilledTime += (span[i].DateEnd - span[i].DateStart).TotalHours;
}
return (
Pressure: sumPressure / diffDepthTotal,
@ -271,7 +290,8 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
SetpointUsagePressure: sumDiffDepthByPressure / diffDepthTotal,
SetpointUsageAxialLoad: sumDiffDepthByAxialLoad / diffDepthTotal,
SetpointUsageRotorTorque: sumDiffDepthByRotorTorque / diffDepthTotal,
SetpointUsageRopPlan: sumDiffDepthByRopPlan / diffDepthTotal
SetpointUsageRopPlan: sumDiffDepthByRopPlan / diffDepthTotal,
DrilledTime: drilledTime
);
}