diff --git a/AsbCloudApp/Data/LimitingParameterDto.cs b/AsbCloudApp/Data/LimitingParameterDto.cs index 73a8a5b7..19b182a5 100644 --- a/AsbCloudApp/Data/LimitingParameterDto.cs +++ b/AsbCloudApp/Data/LimitingParameterDto.cs @@ -11,27 +11,27 @@ namespace AsbCloudApp.Data /// /// Нет ограничения /// - public static int NoLimit = 0; + public const int NoLimit = 0; /// /// МСП /// - public static int RopPlan = 1; + public const int RopPlan = 1; /// /// Давление /// - public static int Pressure = 2; + public const int Pressure = 2; /// /// Осевая нагрузка /// - public static int AxialLoad = 3; + public const int AxialLoad = 3; /// /// Момент /// - public static int RotorTorque = 4; + public const int RotorTorque = 4; /// /// Идентификатор скважины /// diff --git a/AsbCloudApp/Data/ProcessMaps/Report/ProcessMapReportDataSaubStatDto.cs b/AsbCloudApp/Data/ProcessMaps/Report/ProcessMapReportDataSaubStatDto.cs new file mode 100644 index 00000000..abcef62b --- /dev/null +++ b/AsbCloudApp/Data/ProcessMaps/Report/ProcessMapReportDataSaubStatDto.cs @@ -0,0 +1,98 @@ +using System; + +namespace AsbCloudApp.Data.ProcessMaps.Report; + +/// +/// Модель РТК +/// +public class ProcessMapReportDataSaubStatDto +{ + /// + /// Время, затраченное на бурение интервала, в часах + /// + public double DrilledTime { get; set; } = 0; + + /// + /// Идентификатор скважины + /// + public int IdWell { get; set; } + + /// + /// Id секции скважины + /// + public int IdWellSectionType { get; set; } + + /// + /// Название секции скважины + /// + public string WellSectionTypeName { get; set; } = null!; + + /// + /// Глубина по стволу от, м + /// + /// на начало интервала + /// + /// + public double DepthStart { get; set; } + + /// + /// Глубина по стволу до, м + /// + /// на конец интервала + /// + /// + public double DepthEnd { get; set; } + + /// + /// Дата/ время + /// + /// на начало интервала + /// + /// + public DateTime DateStart { get; set; } + + /// + /// Режим бурения (Ротор/слайд/ручной) + /// + public string DrillingMode { get; set; } = null!; + + /// + /// Проходка, м + /// + public double? DeltaDepth { get; set; } + + /// + /// Перепад давления, атм + /// + public ProcessMapReportDataSaubStatParamsDto PressureDiff { get; set; } = new(); + + /// + /// Нагрузка, т + /// + public ProcessMapReportDataSaubStatParamsDto AxialLoad { get; set; } = new(); + + /// + /// Момент на ВСП, кНхМ + /// + public ProcessMapReportDataSaubStatParamsDto TopDriveTorque { get; set; } = new(); + + /// + /// Ограничение скорости, м/ч + /// + public ProcessMapReportDataSaubStatParamsDto SpeedLimit { get; set; } = new(); + + /// + /// Обороты ВСП, об/мин + /// + public ProcessMapReportDataSaubStatParamsDto Turnover { get; set; } = new(); + + /// + /// Расход, л/с + /// + public ProcessMapReportDataSaubStatParamsDto Flow { get; set; } = new(); + + /// + /// Механическая скорость, м/ч + /// + public PlanFactDto Rop { get; set; } = new(); +} \ No newline at end of file diff --git a/AsbCloudApp/Extensions/ChangeLogExtensions.cs b/AsbCloudApp/Extensions/ChangeLogExtensions.cs new file mode 100644 index 00000000..c52e33dd --- /dev/null +++ b/AsbCloudApp/Extensions/ChangeLogExtensions.cs @@ -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 +{ + /// + /// Расширения для поиска в истории + /// + public static class ChangeLogExtensions + { + /// + /// Действительные на момент времени значения + /// + /// + /// + /// + /// + public static IEnumerable WhereActualAtMoment(this IEnumerable 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; + } + } +} diff --git a/AsbCloudApp/Repositories/IDataSaubStatRepository.cs b/AsbCloudApp/Repositories/IDataSaubStatRepository.cs index d03554ea..941d6465 100644 --- a/AsbCloudApp/Repositories/IDataSaubStatRepository.cs +++ b/AsbCloudApp/Repositories/IDataSaubStatRepository.cs @@ -14,9 +14,11 @@ namespace AsbCloudApp.Repositories /// Получение записей по ключу телеметрии /// /// ключ телеметрии + /// начальная глубина + /// конечная глубина /// /// - Task> GetAsync(int idTelemetry, CancellationToken token); + Task> GetAsync(int idTelemetry, double geDepth, double leDepth, CancellationToken token); /// /// Получение последних по дате окончания бурения записей в разрезе телеметрий diff --git a/AsbCloudApp/Requests/DataSaubStatRequest.cs b/AsbCloudApp/Requests/DataSaubStatRequest.cs index 78bedc14..b4400f3e 100644 --- a/AsbCloudApp/Requests/DataSaubStatRequest.cs +++ b/AsbCloudApp/Requests/DataSaubStatRequest.cs @@ -1,4 +1,6 @@ -namespace AsbCloudApp.Requests +using System.ComponentModel.DataAnnotations; + +namespace AsbCloudApp.Requests { /// /// Параметры запроса для построения отчёта @@ -7,18 +9,24 @@ { /// /// Изменение уставки факт перепада давления от первого значения в начале интервала + /// Не менее 5 атм и не более 15(50) атм; /// - public double DeltaPressure { get; set; } + [Range(5, 15, ErrorMessage = "Изменение уставки факт перепада давления не может быть меньше 5 и больше 15 атм")] + public double DeltaPressure { get; set; } = 5d; /// - /// Изменение уставки факт осевой нагрузки от первого значения в начале интервала + /// Изменение уставки факт осевой нагрузки от первого значения в начале интервала + /// Не менее 1 т и не более 5(20) т; /// - public double DeltaAxialLoad { get; set; } + [Range(1, 5, ErrorMessage = "Изменение уставки факт осевой нагрузки не может быть меньше 1 и больше 5 т")] + public double DeltaAxialLoad { get; set; } = 1d; /// - /// Изменение уставки момента от первого значения в начале интервала + /// Изменение уставки момента от первого значения в начале интервала + /// Не менее 5 кН*м и не более 10(20) кН*м. /// - public double DeltaRotorTorque { get; set; } + [Range(5, 10, ErrorMessage = "Изменение уставки момента не может быть меньше 5 и больше 10 кН*м")] + public double DeltaRotorTorque { get; set; } = 5d; /// /// Изменение ограничения нагрузки от первого значения в начале интервала diff --git a/AsbCloudInfrastructure/Repository/DataSaubStatRepository.cs b/AsbCloudInfrastructure/Repository/DataSaubStatRepository.cs index 3e18e42e..72737a0b 100644 --- a/AsbCloudInfrastructure/Repository/DataSaubStatRepository.cs +++ b/AsbCloudInfrastructure/Repository/DataSaubStatRepository.cs @@ -40,12 +40,14 @@ namespace AsbCloudInfrastructure.Repository return result; } - public async Task> GetAsync(int idTelemetry, CancellationToken token) + public async Task> GetAsync(int idTelemetry, double geDepth, double leDepth, CancellationToken token) { var timeSpan = TimeSpan.FromHours(telemetryService.GetTimezone(idTelemetry).Hours); var stats = await db.Set() .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)); diff --git a/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatService.cs b/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatService.cs index 93751e36..35bf06a8 100644 --- a/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatService.cs +++ b/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatService.cs @@ -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(); - var dataSaubStats = - (await dataSaubStatRepository.GetAsync(well.IdTelemetry.Value, token)).ToArray(); - - if (!dataSaubStats.Any()) - return Enumerable.Empty(); + 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(); - 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(); + + 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 processMapPlanWellDrillings, Span dataSaubStats, IEnumerable wellOperations, - TimeSpan timeZone + IEnumerable wellOperationCategories ) { var list = new List(); @@ -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 processMapPlanDrillingDtos, - Span dataSaubStats, - int indexStart, - int length, - IEnumerable wellOperations, - TimeSpan timeZone + ProcessMapPlanDrillingDto[] processMapPlanFilteredByDepth, + Span 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 { 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 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 ); }