diff --git a/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs b/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs
index 51e77911..6bc8ace1 100644
--- a/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs
+++ b/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs
@@ -15,18 +15,24 @@ namespace AsbCloudApp.Data.ProcessMap
///
/// Глубина по стволу, м
+ ///
+ /// на начало интервала
+ ///
///
- public double Depth { get; set; }
+ public double DepthStart { get; set; }
///
/// Дата/ время
+ ///
+ /// на начало интервала
+ ///
///
- public DateTimeOffset Date { get; set; }
+ public DateTimeOffset DateStart { get; set; }
///
- /// Т мех бурения, ч
+ /// Время мех бурения, ч
///
- public double MechDrillingTime { get; set; }
+ public double MechDrillingHours { get; set; }
///
/// Слайд
@@ -41,22 +47,12 @@ namespace AsbCloudApp.Data.ProcessMap
///
/// название секции скважины
///
- public string? WellSectionTypeName { get; set; }
+ public int IdWellSectionType { get; set; }
///
/// название секции скважины
///
- public int? IdWellSectionType { get; set; }
-
- ///
- /// Категория
- ///
- public string? Category { get; set; }
-
- ///
- /// Идентификатор категории
- ///
- public int? IdCategory { get; set; }
+ public string WellSectionTypeName { get; set; } = null!;
}
#nullable disable
}
diff --git a/AsbCloudApp/Data/ProcessMap/ProcessMapReportRowDto.cs b/AsbCloudApp/Data/ProcessMap/ProcessMapReportRowDto.cs
index 6b4e942d..0c1ae626 100644
--- a/AsbCloudApp/Data/ProcessMap/ProcessMapReportRowDto.cs
+++ b/AsbCloudApp/Data/ProcessMap/ProcessMapReportRowDto.cs
@@ -12,15 +12,20 @@ namespace AsbCloudApp.Data.ProcessMap
///
public class ProcessMapReportRowDto
{
+ ///
+ /// Проходка, м
+ ///
+ public double? DeltaDepth { get; set; }
+
///
/// Перепад давления, атм
///
- public ProcessMapReportParamsDto PressureDrop { get; set; } = null!;
+ public ProcessMapReportParamsDto PressureDiff { get; set; } = null!;
///
/// Нагрузка, т
///
- public ProcessMapReportParamsDto Load { get; set; } = null!;
+ public ProcessMapReportParamsDto AxialLoad { get; set; } = null!;
///
/// Момент на ВСП, кНхМ
@@ -35,17 +40,12 @@ namespace AsbCloudApp.Data.ProcessMap
///
/// Процент использования системы АПД, %
///
- public double PercentageADFSystemUsage { get; set; }
+ public double Usage { get; set; }
///
/// Фактическая механическая скорость, м/ч
///
- public double ActualMechanicalSpeed { get; set; }
-
- ///
- /// Проходка, м
- ///
- public double? SectionPenetration { get; set; }
+ public double Rop { get; set; }
}
#nullable disable
}
diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs
index 0dfab7df..8f81b317 100644
--- a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs
+++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs
@@ -1,9 +1,11 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMap;
+using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
+using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -13,151 +15,236 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.ProcessMap
{
#nullable enable
- public class ProcessMapService : IProcessMapService
+ public partial class ProcessMapService : IProcessMapService
{
+ private readonly IAsbCloudDbContext db;
private readonly IWellOperationRepository wellOperationRepository;
private readonly IProcessMapRepository processMapRepository;
+ private readonly ITelemetryService telemetryService;
- public ProcessMapService(IWellOperationRepository wellOperationService,
- IProcessMapRepository processMapRepository)
- {
+ public ProcessMapService(
+ IAsbCloudDbContext db,
+ IWellOperationRepository wellOperationService,
+ IProcessMapRepository processMapRepository,
+ ITelemetryService telemetryService)
+ {
+ this.db = db;
this.wellOperationRepository = wellOperationService;
this.processMapRepository = processMapRepository;
+ this.telemetryService = telemetryService;
}
public async Task> GetProcessMapAsync(int idWell, CancellationToken token)
{
- var categoryIds = new int[] { WellOperationCategory.IdSlide, WellOperationCategory.IdRotor };
-
var operationsRequest = new WellOperationRequest
{
IdWell = idWell,
- OperationCategoryIds = categoryIds,
- OperationType = 1,
+ OperationCategoryIds = WellOperationCategory.MechanicalDrillingSubIds,
+ OperationType = WellOperation.IdOperationTypeFact,
SortFields = new[]{ nameof(WellOperation.DateStart) }
};
- var allOperations = await wellOperationRepository.GetPageAsync(operationsRequest, token);
- throw new NotImplementedException();
- //var processMapDtos = await processMapRepository.GetByIdWellAsync(idWell, token).ConfigureAwait(false);
+ var allFactDrillingOperations = (await wellOperationRepository.GetAsync(operationsRequest, token))
+ .Where(o => o.DepthEnd > o.DepthStart);
+
+ var processMapDtos = (await processMapRepository.GetByIdWellAsync(idWell, token))!;
- //var result = allOperations
- // .GroupBy(x => x.IdWellSectionType)
- // .SelectMany(x => handleSections(allOperations, processMapDtos!, x))
- // .ToList();
-
- //return result;
- }
-
- private static List handleSections(IEnumerable allWellOperation, IEnumerable processMap, IEnumerable wellOperation)
- {
- var result = new List();
- var minDepth = wellOperation.Min(o => o.DepthStart);
- var maxDepth = wellOperation.Max(o => o.DepthEnd);
-
- for (var depth = minDepth; depth <= maxDepth; depth += 100)
- {
- var currentDepth = result.Count() > 0 ? depth + (100 - depth % 100) : depth;
- var operation = allWellOperation.First(x => x.DepthEnd >= currentDepth);
- var minDate = operation.DateStart;
- var maxDate = operation.DateStart.AddHours(operation.DurationHours);
- var currentDate = GetDate(currentDepth, minDepth, maxDepth, minDate, maxDate);
- var currentHours = GetHourse(currentDepth, minDepth, maxDepth, operation.DurationHours);
- var processMapData = processMap.FirstOrDefault(x => x.IdWellSectionType == operation.IdWellSectionType);
-
- var dto = GetRecord(currentDepth, currentDate, currentHours, operation, processMap);
-
- if (operation.DepthStart < currentDepth)
+ var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell)!.Value;
+ IEnumerable telemetryStat = await GetTelemetryDataAsync(idTelemetry, token);
+
+ var result = allFactDrillingOperations
+ .GroupBy(o => o.IdWellSectionType)
+ .SelectMany(sectionOperations =>
{
- var prevOperation = allWellOperation.FirstOrDefault(x => x.DepthEnd == operation.DepthStart);
- if (prevOperation is not null)
- {
- var prevDepth = currentDepth - prevOperation.DepthEnd;
- var prevMinDate = prevOperation.DateStart;
- var prevMaxDate = operation.DateStart.AddHours(operation.DurationHours);
- var prevDate = GetDate(prevDepth, prevOperation.DepthStart, prevOperation.DepthEnd, minDate, maxDate);
- var prevHours = GetHourse(currentDepth, prevOperation.DepthStart, prevOperation.DepthEnd, prevOperation.DurationHours);
-
- if (dto.IdCategory != prevOperation.IdCategory)
- FillRecordRow(prevDepth, prevHours, dto, prevOperation.IdCategory, processMap);
-
- dto.MechDrillingTime = currentHours + prevHours;
- }
- }
-
- result.Add(dto);
- }
+ var sectionProcessMap = processMapDtos.Where(p => p.IdWellSectionType == sectionOperations.Key);
+ return HandleSections(sectionOperations, sectionProcessMap);
+ })
+ .ToList();
return result;
}
- private static ProcessMapReportDto GetRecord(double depth, DateTimeOffset sate, double hours, WellOperationDto operation, IEnumerable processMap)
- {
- var dto = new ProcessMapReportDto
- {
- IdWell = operation.IdWell,
- Depth = depth,
- Date = sate,
- MechDrillingTime = hours,
- Category = operation.IdCategory == WellOperationCategory.IdSlide ? "Слайд" : "Ротор",
- IdCategory = operation.IdCategory,
- IdWellSectionType = operation.IdWellSectionType,
- WellSectionTypeName = operation.WellSectionTypeName
+ private async Task> GetTelemetryDataAsync(int idTelemetry, CancellationToken token)
+ {
+ var timezone = telemetryService.GetTimezone(idTelemetry);
+ var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
+
+ var query = db.Set()
+ .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)
+ .GroupBy(t => new { H = t.DateTime.Hour, W = Math.Truncate(t.WellDepth!.Value) })
+ .Select(g => new ProcessTelemetrySaubStat
+ {
+ Count = g.Count(),
+
+ DateMin = g.Min(t => t.DateTime.UtcDateTime),
+ DateMax = g.Max(t => t.DateTime.UtcDateTime),
+
+ WellDepthMin = g.Min(t => t.WellDepth!.Value),
+ WellDepthMax = g.Max(t => t.WellDepth!.Value),
+
+ Pressure = g.Average(t => t.Pressure!.Value),
+ PressureSp = g.Average(t => t.PressureSp!.Value),
+ PressureSpRotor = g.Average(t => t.PressureSpRotor!.Value),
+ PressureSpSlide = g.Average(t => t.PressureSpSlide!.Value),
+ PressureIdle = g.Average(t => t.PressureIdle!.Value),
+ PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
+
+ AxialLoad = g.Average(t => t.AxialLoad!.Value),
+ AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value),
+ AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value),
+
+ RotorTorque = g.Average(t => t.RotorTorque!.Value),
+ RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value),
+ RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value),
+
+ BlockSpeed = g.Average(t => t.BlockSpeed!.Value),
+ BlockSpeedSp = g.Average(t => t.BlockSpeedSp!.Value),
+ BlockSpeedSpRotor = g.Average(t => t.BlockSpeedSpRotor!.Value),
+ BlockSpeedSpSlide = g.Average(t => t.BlockSpeedSpSlide!.Value),
+ })
+ .Where(s => s.WellDepthMin != s.WellDepthMax)
+ .Where(s => s.Count > 3)
+ .OrderBy(t => t.DateMin);
+
+ var data = await query.ToArrayAsync(token);
+ return data;
+ }
+
+ private static IEnumerable HandleSections(
+ IEnumerable sectionOperations,
+ IEnumerable sectionProcessMap )
+ {
+ var minDepth = sectionOperations.Min(o => o.DepthStart);
+ var maxDepth = sectionOperations.Max(o => o.DepthEnd);
+
+ var depthIntervals = SplitByIntervals(minDepth, maxDepth).ToArray();
+ var result = new ProcessMapReportDto[depthIntervals.Length];
+
+ for (var i = 0; i < depthIntervals.Length; i++ )
+ result[i] = MakeProcessMapReportDto(depthIntervals[i], sectionOperations, sectionProcessMap);
+
+ return result;
+ }
+
+ private static ProcessMapReportDto MakeProcessMapReportDto(
+ (double min, double max) depthInterval,
+ IEnumerable sectionOperations,
+ IEnumerable sectionProcessMap)
+ {
+ var dto = new ProcessMapReportDto{
+ DepthStart = depthInterval.min
+ };
+
+ var intervalOperations = sectionOperations.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max);
+ var intervalProcessMap = sectionProcessMap.Where(map => map.DepthEnd >= depthInterval.min && map.DepthStart <= depthInterval.max);
+ if (intervalOperations.Any())
+ {
+ var firstIntervalOperation = intervalOperations.First();
+ var slideOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdSlide);
+ var rotorOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdRotor);
+
+ dto.DepthStart = depthInterval.min;
+ dto.DateStart = GetInterpolatedDate(firstIntervalOperation, depthInterval.min);
+ dto.IdWell = firstIntervalOperation.IdWell;
+ dto.IdWellSectionType = firstIntervalOperation.IdWellSectionType;
+ dto.WellSectionTypeName = firstIntervalOperation.WellSectionTypeName;
+ dto.MechDrillingHours = CalcHours(depthInterval, sectionOperations);
+ dto.Slide = CalcDrillStat(depthInterval, slideOperations, intervalProcessMap);
+ dto.Rotor = CalcDrillStat(depthInterval, rotorOperations, intervalProcessMap);
+ }
+ return dto;
+ }
+
+ private static ProcessMapReportRowDto CalcDrillStat(
+ (double min, double max) depthInterval,
+ IEnumerable intervalModeOperations,
+ IEnumerable intervalProcessMap)
+ {
+ var dto = new ProcessMapReportRowDto();
+ if(intervalModeOperations.Any())
+ {
+ var deltaDepth = CalcDeltaDepth(depthInterval, intervalModeOperations);
+ dto.DeltaDepth = deltaDepth;
+ dto.Rop = deltaDepth / CalcHours(depthInterval, intervalModeOperations);
+
+ dto.PressureDiff = CalcPressureDiff(depthInterval, intervalProcessMap);
};
- FillRecordRow(depth, hours, dto, operation.IdCategory, processMap);
return dto;
}
- private static void FillRecordRow(double depth, double hours, ProcessMapReportDto dto, int idCategory, IEnumerable processMap)
+ private static ProcessMapReportParamsDto CalcPressureDiff(
+ (double min, double max) depthInterval,
+ IEnumerable intervalProcessMap)
{
- var row = new ProcessMapReportRowDto {
- SectionPenetration = depth,
- ActualMechanicalSpeed = depth / hours,
- PercentageADFSystemUsage = dto.Depth / depth * 100
- };
-
- var processMapData = processMap.FirstOrDefault(x => x.IdWell == dto.IdWell && x.IdWellSectionType == dto.IdWellSectionType);
- if (processMapData is not null)
+ var dto = new ProcessMapReportParamsDto();
+ if (intervalProcessMap.Any())
{
- row.PressureDrop = new ProcessMapReportParamsDto
- {
- SetPointPlan = processMapData.Pressure.Plan
- };
- row.Load = new ProcessMapReportParamsDto
- {
- SetPointPlan = processMapData.AxialLoad.Plan
- };
- row.TopDriveTorque = new ProcessMapReportParamsDto
- {
- SetPointPlan = processMapData.TopDriveTorque.Plan
- };
- row.SpeedLimit = new ProcessMapReportParamsDto
- {
-
- };
+ dto.SetPointPlan = intervalProcessMap.First().Pressure.Plan;
}
-
- if (idCategory == WellOperationCategory.IdSlide)
- dto.Slide = row;
- else
- dto.Rotor = row;
+ throw new NotImplementedException();
}
- private static DateTimeOffset GetDate(double depth, double deptStart, double deptEnd, DateTimeOffset dateStart, DateTimeOffset dateEnd)
+ private static double CalcDeltaDepth((double min, double max) depthInterval, IEnumerable intervalOperations)
{
- var a = depth - deptStart;
- var b = deptEnd - deptStart;
- var c = dateEnd - dateStart;
- var result = dateStart + (a / b) * c;
- return result;
+ var ddepth = 0d;
+ foreach (var operation in intervalOperations)
+ {
+ var depthStart = operation.DepthStart > depthInterval.min
+ ? operation.DepthStart
+ : depthInterval.min;
+
+ var depthEnd = operation.DepthEnd < depthInterval.max
+ ? operation.DepthEnd
+ : depthInterval.max;
+
+ ddepth += (depthEnd - depthEnd);
+ }
+ return ddepth;
}
- private static double GetHourse(double depth, double deptStart, double deptEnd, double hourse)
+ private static double CalcHours((double min, double max) depthInterval, IEnumerable intervalOperations)
{
- var a = depth - deptStart;
- var b = deptEnd - deptStart;
- var result = 0 + (a / b) * hourse;
- return result;
+ var hours = 0d;
+ foreach (var operation in intervalOperations)
+ {
+ var dateStart = operation.DepthStart > depthInterval.min
+ ? operation.DateStart
+ : GetInterpolatedDate(operation, depthInterval.min);
+
+ var dateEnd = operation.DepthEnd < depthInterval.max
+ ? operation.DateStart + TimeSpan.FromHours(operation.DurationHours)
+ : GetInterpolatedDate(operation, depthInterval.max);
+
+ hours += (dateEnd - dateStart).TotalHours;
+ }
+ return hours;
+ }
+
+ private static DateTime GetInterpolatedDate(WellOperationDto operation, double depth)
+ {
+ if (operation.DepthStart > depth)
+ throw new ArgumentOutOfRangeException(nameof(depth));
+
+ var ratio = (depth - operation.DepthStart) / (operation.DepthEnd - operation.DepthStart);
+ var deltaHours = operation.DurationHours * ratio;
+ var interpolatedDate = operation.DateStart + TimeSpan.FromHours(deltaHours);
+ return interpolatedDate;
+ }
+
+ 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)
+ {
+ yield return (iMin, iMax);
+ iMin = iMax;
+ }
+ yield return (iMin, max);
}
}
#nullable disable
diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessTelemetrySaubStat.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessTelemetrySaubStat.cs
new file mode 100644
index 00000000..9c09d2ea
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessTelemetrySaubStat.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace AsbCloudInfrastructure.Services.ProcessMap
+{
+#nullable enable
+ class ProcessTelemetrySaubStat {
+ public int Count { get; set; }
+ public DateTime DateMin { get; set; }
+ public DateTime DateMax { get; set; }
+
+ public float WellDepthMin { get; set; }
+ public float WellDepthMax { get; set; }
+
+ public float Pressure { get; set; }
+ public float PressureSp { get; set; }
+ public float PressureIdle { get; set; }
+ public float PressureSpRotor { get; set; }
+ public float PressureSpSlide { get; set; }
+ public float PressureDeltaLimitMax { get; set; }
+
+ public float AxialLoad { get; set; }
+ public float AxialLoadSp { get; set; }
+ public float AxialLoadLimitMax { get; set; }
+
+ public float RotorTorque { get; set; }
+ public float RotorTorqueSp { get; set; }
+ public float RotorTorqueLimitMax { get; set; }
+
+ public float BlockSpeed { get; set; }
+ public float BlockSpeedSp { get; set; }
+ public float BlockSpeedSpRotor { get; set; }
+ public float BlockSpeedSpSlide { get; set; }
+ }
+#nullable disable
+}
diff --git a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationImportService.cs b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationImportService.cs
index 81771165..e9ed3d11 100644
--- a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationImportService.cs
+++ b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationImportService.cs
@@ -65,6 +65,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
}
}
+ // TODO: use WellOperationRepository instead of DB
public WellOperationImportService(IAsbCloudDbContext db, IWellService wellService)
{
this.db = db;
diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs
index 19720e16..af1ac385 100644
--- a/ConsoleApp1/Program.cs
+++ b/ConsoleApp1/Program.cs
@@ -4,6 +4,7 @@ using AsbCloudInfrastructure;
using AsbCloudInfrastructure.Repository;
using Microsoft.Extensions.Caching.Memory;
using System;
+using System.Linq;
using System.Threading;
namespace ConsoleApp1
@@ -18,12 +19,51 @@ namespace ConsoleApp1
DependencyInjection.MapsterSetup();
var sw = System.Diagnostics.Stopwatch.StartNew();
- var repo = new WellOperationRepository(db, new MemoryCache(new MemoryCacheOptions()), ServiceFactory.MakeWellService());
- var req = new WellOperationRequest { IdWell = 88, OperationType = 1, Skip = 70};
- var res = repo.GetPageAsync(req, CancellationToken.None).Result;
+ var idTelemetry = 5;
+ var query = db.Set()
+ .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)
+ .GroupBy(t => new { H = t.DateTime.Hour, W = Math.Truncate(t.WellDepth!.Value) })
+ .Select(g => new
+ {
+ Count = g.Count(),
+
+ DateMin = g.Min(t => t.DateTime),
+ DateMax = g.Max(t => t.DateTime),
+
+ WellDepthMin = g.Min(t => t.WellDepth),
+ WellDepthMax = g.Max(t => t.WellDepth),
+
+ Pressure = g.Average(t => t.Pressure),
+ PressureSp = g.Average(t => t.PressureSp),
+ PressureSpRotor = g.Average(t => t.PressureSpRotor),
+ PressureSpSlide = g.Average(t => t.PressureSpSlide),
+ PressureIdle = g.Average(t => t.PressureIdle),
+ PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax),
+
+ AxialLoad = g.Average(t => t.AxialLoad),
+ AxialLoadSp = g.Average(t => t.AxialLoadSp),
+ AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax),
+
+ RotorTorque = g.Average(t => t.RotorTorque),
+ RotorTorqueSp = g.Average(t => t.RotorTorqueSp),
+ RotorTorqueIdle = g.Average(t => t.RotorTorqueIdle),
+
+ BlockSpeed = g.Average(t => t.BlockSpeed),
+ BlockSpeedSp = g.Average(t => t.BlockSpeedSp),
+ BlockSpeedSpRotor = g.Average(t => t.BlockSpeedSpRotor),
+ BlockSpeedSpSlide = g.Average(t => t.BlockSpeedSpSlide),
+ })
+ .Where(s => s.WellDepthMin != s.WellDepthMax)
+ .Where(s => s.Count > 3)
+ .OrderBy(t => t.DateMin);
+ var data = query.ToArray();
sw.Stop();
Console.WriteLine($"total time: {sw.ElapsedMilliseconds} ms");
+ var count = data.Length;
Console.ReadLine();
}
}