diff --git a/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs b/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs
index 40514429..8c7b3198 100644
--- a/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs
+++ b/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs
@@ -100,7 +100,7 @@ namespace AsbCloudApp.Data.SAUB
///
/// Режим САУБ
///
- public short Mode { get; set; }
+ public short IdMode { get; set; }
///
/// Текущий критерий бурения
diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs
index 9cd63e0e..9cd788a8 100644
--- a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs
+++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs
@@ -1,13 +1,8 @@
-using AsbCloudApp.Data;
-using AsbCloudApp.Data.ProcessMap;
+using AsbCloudApp.Data.ProcessMap;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
-using AsbCloudApp.Requests;
using AsbCloudApp.Services;
-using AsbCloudApp.Services.Subsystems;
-using AsbCloudDb.Model;
-using AsbCloudApp.Data.Subsystems;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -23,23 +18,17 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
private readonly IWellOperationRepository wellOperationRepository;
private readonly IProcessMapPlanRepository processMapPlanRepository;
private readonly ITelemetryDataSaubService telemetryDataSaubService;
- private readonly ILimitingParameterRepository limitingParameterRepository;
- private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
public ProcessMapReportService(
IWellService wellService,
- IWellOperationRepository wellOperationService,
+ IWellOperationRepository wellOperationRepository,
IProcessMapPlanRepository processMapPlanRepository,
- ITelemetryDataSaubService telemetryDataSaubService,
- ILimitingParameterRepository limitingParameterRepository,
- ISubsystemOperationTimeService subsystemOperationTimeService)
+ ITelemetryDataSaubService telemetryDataSaubService)
{
this.wellService = wellService;
- this.wellOperationRepository = wellOperationService;
+ this.wellOperationRepository = wellOperationRepository;
this.processMapPlanRepository = processMapPlanRepository;
this.telemetryDataSaubService = telemetryDataSaubService;
- this.limitingParameterRepository = limitingParameterRepository;
- this.subsystemOperationTimeService = subsystemOperationTimeService;
}
///
@@ -53,50 +42,298 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
var processMapPlan = await processMapPlanRepository.GetByIdWellAsync(idWell, token);
- if(!processMapPlan.Any())
+ if (!processMapPlan.Any())
return Enumerable.Empty();
- var telemetryDataStat = await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token);
+ var telemetryDataStat = (await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token)).ToArray();
+ if (!telemetryDataStat.Any())
+ return Enumerable.Empty();
var result = CalcByIntervals(processMapPlan, telemetryDataStat);
return result;
}
- private IEnumerable CalcByIntervals(IEnumerable processMapPlan, IEnumerable telemetryDataStat)
+ private IEnumerable CalcByIntervals(IEnumerable processMapPlan, TelemetryDataSaubStatDto[] telemetryDataStat)
{
- var result = new List(processMapPlan.Count() * 4);
- var intervals = GetProcessMapIntervals(processMapPlan);
-
+ var processMapIntervals = processMapPlan
+ .Select(p => (p.DepthStart, p.DepthEnd))
+ .Distinct()
+ .OrderBy(i => i.DepthStart);
+
+ var result = new List(processMapIntervals.Count() * 4);
+
+ var telemetryIndexStart = Array.FindIndex(telemetryDataStat, t => t.WellDepthMin >= processMapIntervals.First().DepthStart);
+ if (telemetryIndexStart < 0)
+ return Enumerable.Empty();
+
+ IDictionary sectionTypes = wellOperationRepository.GetSectionTypes();
+
+ foreach (var interval in processMapIntervals)
+ {
+ var processMapPlanInterval = processMapPlan
+ .Where(p => p.DepthStart >= interval.DepthStart && p.DepthEnd <= interval.DepthEnd);
+
+ var telemetryIndexEnd = Array.FindIndex(telemetryDataStat, telemetryIndexStart, t => t.WellDepthMin >= interval.DepthEnd);
+ var telemetryDataInterval = telemetryDataStat.AsSpan(telemetryIndexStart, telemetryIndexEnd - telemetryIndexStart);
+
+ IEnumerable subIntervalsResult = CalcSubIntervals(interval, processMapPlanInterval, telemetryDataInterval, sectionTypes);
+
+ result.AddRange(subIntervalsResult);
+ telemetryIndexStart = telemetryIndexEnd;
+ }
+
return result;
}
- private IEnumerable<(double, double)> GetProcessMapIntervals(IEnumerable processMapPlan)
+ private IEnumerable CalcSubIntervals(
+ (double DepthStart, double DepthEnd) interval,
+ IEnumerable processMapPlanInterval,
+ Span telemetryDataInterval,
+ IDictionary sectionTypes)
{
-
- return Enumerable.Empty<(double, double)>();
- }
+ var telemetryDataIntervalLength = telemetryDataInterval.Length;
+ if (telemetryDataInterval.Length == 0)
+ return Enumerable.Empty();
- private static DateTime GetInterpolatedDate(WellOperationDto operation, double depth)
- {
- var ratio = (depth - operation.DepthStart) / (operation.DepthEnd - operation.DepthStart);
- var deltaHours = operation.DurationHours * ratio;
- var interpolatedDate = operation.DateStart + TimeSpan.FromHours(deltaHours);
- return interpolatedDate;
- }
+ var result = new List();
+ var telemetryIndexStart = 0;
+ var subInterval = interval;
- private static IEnumerable<(double min, double max)> SplitByIntervals(double min, double max)
- {
- const double step = 100;
- var iMin = min;
- var iMax = (1 + (int)(min / step)) * step;
- for (; iMax < max; iMax += step)
+ for (var i = telemetryIndexStart; i < telemetryDataIntervalLength; i++)
{
- yield return (iMin, iMax);
- iMin = iMax;
+ if (!IsSimilar(telemetryDataInterval[telemetryIndexStart], telemetryDataInterval[i]))
+ {
+ subInterval.DepthEnd = telemetryDataInterval[i].WellDepthMax;
+
+ var intervalReportRow = CalcSubIntervalReportRow(subInterval, processMapPlanInterval, telemetryDataInterval[telemetryIndexStart..i], sectionTypes);
+ result.Add(intervalReportRow);
+ telemetryIndexStart = i;
+ subInterval.DepthStart = subInterval.DepthEnd;
+ }
}
- yield return (iMin, max);
+
+ subInterval.DepthEnd = interval.DepthEnd;
+ var intervalReportRowLast = CalcSubIntervalReportRow(subInterval, processMapPlanInterval, telemetryDataInterval[telemetryIndexStart..telemetryDataIntervalLength], sectionTypes);
+ result.Add(intervalReportRowLast);
+ return result;
}
+
+ private ProcessMapReportDto CalcSubIntervalReportRow(
+ (double DepthStart, double DepthEnd) subInterval,
+ IEnumerable processMap,
+ Span telemetryRowSpan,
+ IDictionary sectionTypes)
+ {
+ var telemetryFirst = telemetryRowSpan[0];
+ var telemetryLast = telemetryRowSpan[^1];
+ var mode = GetIdMode(telemetryRowSpan);
+ var processMapByMode = processMap.FirstOrDefault(p => p.IdMode == mode.IdMode);
+ var processMapFirst = processMap.First();
+ var idWellSectionType = processMapByMode?.IdWellSectionType ?? processMapFirst.IdWellSectionType;
+
+ var telemetryStat = AnalyzeTelemetry(telemetryRowSpan);
+
+ var result = new ProcessMapReportDto
+ {
+ IdWell = processMapByMode?.IdWell ?? processMapFirst.IdWell,
+ IdWellSectionType = idWellSectionType,
+ WellSectionTypeName = sectionTypes[idWellSectionType],
+
+ DepthStart = subInterval.DepthStart,
+ DepthEnd = subInterval.DepthEnd,
+ DateStart = telemetryFirst.DateMin,
+
+ MechDrillingHours = (telemetryLast.DateMax - telemetryFirst.DateMin).TotalHours,
+ DrillingMode = mode.ModeName,
+
+ DeltaDepth = telemetryLast.WellDepthMax - telemetryFirst.WellDepthMin,
+
+ PressureDiff = telemetryStat.Pressure.MakeParams(processMapByMode?.Pressure.Plan),
+ AxialLoad = telemetryStat.AxialLoad.MakeParams(processMapByMode?.AxialLoad.Plan),
+ TopDriveTorque = telemetryStat.RotorTorque.MakeParams(processMapByMode?.TopDriveTorque.Plan),
+ SpeedLimit = telemetryStat.BlockSpeed.MakeParams(processMapByMode?.RopPlan),
+
+ Rop = telemetryStat.Rop,
+ Usage = telemetryStat.UsageSaub,
+ };
+ return result;
+ }
+
+ private static TelemetryStat AnalyzeTelemetry(Span telemetry)
+ {
+ var stat = new TelemetryStat();
+
+ for (int i = 0; i < telemetry.Length; i++)
+ stat.UpdateStat(telemetry[i]);
+
+ return stat;
+ }
+
+ private static (int IdMode, string ModeName) GetIdMode(Span telemetryRowSpan)
+ {
+ /// Режим работы САУБ в телеметрии:
+ /// 0 - "РУЧНОЙ"
+ /// 1 - "БУРЕНИЕ В РОТОРЕ"
+ /// 3 - "БУРЕНИЕ В СЛАЙДЕ"
+
+ for (int i = 0; i < telemetryRowSpan.Length; i++)
+ {
+ var idMode = telemetryRowSpan[i].IdMode;
+
+ if (idMode == 0)
+ return (0, "Ручной");
+
+ if (idMode == 1)
+ return (1, "Ротор");
+
+ if (idMode == 3)
+ return (2, "Слайд");
+ }
+
+ return (0, "Ручной");
+ }
+
+ private static bool IsSimilar(TelemetryDataSaubStatDto telemetry1, TelemetryDataSaubStatDto telemetry2)
+ {
+ if (telemetry1.IdMode != telemetry2.IdMode)
+ return false;
+
+ if (Math.Abs(telemetry1.PressureSp - telemetry2.PressureSp) > 5d)
+ return false;
+
+ if (Math.Abs(telemetry1.AxialLoadSp - telemetry2.AxialLoadSp) > 1d)
+ return false;
+
+ if (Math.Abs(telemetry1.RotorTorqueSp - telemetry2.RotorTorqueSp) > 5d)
+ return false;
+
+ var blockSpeedSpDiff = Math.Abs(telemetry1.BlockSpeedSp - telemetry2.BlockSpeedSp);
+ if (blockSpeedSpDiff > 5d)
+ {
+ if (telemetry1.BlockSpeedSp < 30)
+ return false;
+ else if (telemetry1.BlockSpeedSp > 30 && blockSpeedSpDiff > 15d)
+ return false;
+ else if (telemetry1.BlockSpeedSp > 80 && blockSpeedSpDiff > 20d)
+ return false;
+ }
+
+ return true;
+ }
+
}
+
+ class ParamStat
+ {
+ private double spWSum;
+ private double pvWSum;
+ private double? limitMaxWSum;
+ private double spUsageDepth;
+
+ private double deltaDepthSum;
+
+ private readonly Func getterSp;
+ private readonly Func getterPv;
+ private readonly Func? getterLimitMax;
+
+ private readonly int idFeedRegulator;
+
+ private TelemetryDataSaubStatDto? previous;
+
+ public ParamStat(Func getterSp,
+ Func getterPv,
+ Func? getterLimitMax,
+ int idFeedRegulator)
+ {
+ this.getterSp = getterSp;
+ this.getterPv = getterPv;
+ this.getterLimitMax = getterLimitMax;
+ this.idFeedRegulator = idFeedRegulator;
+ }
+
+ public void UpdateStat(TelemetryDataSaubStatDto current)
+ {
+ if(previous is not null)
+ {
+ var deltaDepth = current.WellDepthMin - previous.WellDepthMin;
+ if (deltaDepth > 0)
+ {
+ var deltaDepthHalf = deltaDepth / 2;
+ double CalculateWeight(Func getter) => (getter(previous!) + getter(current)) * deltaDepthHalf;
+
+ spWSum = CalculateWeight(getterSp);
+ pvWSum = CalculateWeight(getterPv);
+ if(getterLimitMax is not null)
+ limitMaxWSum = CalculateWeight(getterLimitMax!);
+
+ if (current.IdFeedRegulator == idFeedRegulator)
+ spUsageDepth += deltaDepth;
+
+ deltaDepthSum += deltaDepth;
+ }
+ }
+
+ previous = current;
+ }
+
+ public ProcessMapReportParamsDto MakeParams(double? spPlan)
+ => new ProcessMapReportParamsDto
+ {
+ SetpointPlan = spPlan,
+ SetpointFact = spWSum / deltaDepthSum,
+ Fact = pvWSum / deltaDepthSum,
+ Limit = limitMaxWSum / deltaDepthSum,
+ PercDrillingBySetpoint = spUsageDepth / deltaDepthSum,
+ };
+ }
+
+ class TelemetryStat {
+ public ParamStat Pressure { get; }
+ public ParamStat AxialLoad {get; }
+ public ParamStat RotorTorque {get; }
+ public ParamStat BlockSpeed {get; }
+
+ private TelemetryDataSaubStatDto? previous;
+ private double depthSum = 0d;
+ private double hoursSum = 0d;
+
+ public double Rop => depthSum / hoursSum;
+
+ private double depthWithSaub = 0d;
+ public double UsageSaub => depthWithSaub / depthSum;
+
+ public TelemetryStat()
+ {
+ BlockSpeed = new(t => t.BlockSpeedSp, t => t.BlockSpeed, null, 1);
+ Pressure = new(t => t.PressureSp, t => t.Pressure, t=>t.PressureDeltaLimitMax, 2);
+ RotorTorque = new(t => t.RotorTorqueSp, t => t.RotorTorque, t=>t.RotorTorqueLimitMax, 3);
+ AxialLoad = new(t => t.AxialLoadSp, t => t.AxialLoad, t=>t.AxialLoadLimitMax, 4);
+ }
+
+ public void UpdateStat(TelemetryDataSaubStatDto current)
+ {
+ if(previous is not null)
+ {
+ var deltaDepth = current.WellDepthMin - previous.WellDepthMin;
+ if(deltaDepth > 0)
+ {
+ var deltaHours = (current.DateMin - previous.DateMax).TotalHours;
+ depthSum += deltaDepth;
+ hoursSum += deltaHours;
+
+ if(current.IdMode == 1 || current.IdMode == 3)
+ depthWithSaub += deltaDepth;
+ }
+ }
+ previous = current;
+
+ Pressure.UpdateStat(current);
+ AxialLoad.UpdateStat(current);
+ RotorTorque.UpdateStat(current);
+ BlockSpeed.UpdateStat(current);
+ }
+ };
+
#nullable disable
}
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs
index 8bf021b8..ddebda4b 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs
@@ -42,9 +42,9 @@ namespace AsbCloudInfrastructure.Services.SAUB
.Where(t => t.IdTelemetry == idTelemetry)
.Where(t => t.BlockPosition > 0.0001)
.Where(t => t.WellDepth > 0.0001)
- .Where(t => t.WellDepth - t.BitDepth < 0.01)
.Where(t => t.Mode != null)
.Where(t => modes.Contains(t.Mode.Value))
+ .Where(t => t.WellDepth - t.BitDepth < 0.01)
.GroupBy(t => new {
t.DateTime.Hour,
WellDepthX10 = Math.Truncate(t.WellDepth!.Value * 10),