2022-12-27 14:30:52 +05:00
|
|
|
|
using AsbCloudApp.Data;
|
|
|
|
|
using AsbCloudApp.Data.ProcessMap;
|
2022-12-30 15:24:48 +05:00
|
|
|
|
using AsbCloudApp.Data.SAUB;
|
2022-12-28 17:38:53 +05:00
|
|
|
|
using AsbCloudApp.Repositories;
|
|
|
|
|
using AsbCloudApp.Requests;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
using AsbCloudApp.Services;
|
|
|
|
|
using AsbCloudDb.Model;
|
2022-12-30 15:24:48 +05:00
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace AsbCloudInfrastructure.Services.ProcessMap
|
|
|
|
|
{
|
|
|
|
|
#nullable enable
|
2022-12-30 15:24:48 +05:00
|
|
|
|
public partial class ProcessMapService : IProcessMapService
|
2022-12-27 14:30:52 +05:00
|
|
|
|
{
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private readonly IAsbCloudDbContext db;
|
2022-12-28 17:38:53 +05:00
|
|
|
|
private readonly IWellOperationRepository wellOperationRepository;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
private readonly IProcessMapRepository processMapRepository;
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private readonly ITelemetryService telemetryService;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
public ProcessMapService(
|
|
|
|
|
IAsbCloudDbContext db,
|
|
|
|
|
IWellOperationRepository wellOperationService,
|
|
|
|
|
IProcessMapRepository processMapRepository,
|
|
|
|
|
ITelemetryService telemetryService)
|
|
|
|
|
{
|
|
|
|
|
this.db = db;
|
2022-12-28 17:38:53 +05:00
|
|
|
|
this.wellOperationRepository = wellOperationService;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
this.processMapRepository = processMapRepository;
|
2022-12-30 15:24:48 +05:00
|
|
|
|
this.telemetryService = telemetryService;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<IEnumerable<ProcessMapReportDto>> GetProcessMapAsync(int idWell, CancellationToken token)
|
|
|
|
|
{
|
2022-12-28 17:38:53 +05:00
|
|
|
|
var operationsRequest = new WellOperationRequest
|
|
|
|
|
{
|
|
|
|
|
IdWell = idWell,
|
2022-12-30 15:24:48 +05:00
|
|
|
|
OperationCategoryIds = WellOperationCategory.MechanicalDrillingSubIds,
|
|
|
|
|
OperationType = WellOperation.IdOperationTypeFact,
|
2022-12-28 17:38:53 +05:00
|
|
|
|
SortFields = new[]{ nameof(WellOperation.DateStart) }
|
|
|
|
|
};
|
2022-12-30 15:24:48 +05:00
|
|
|
|
var allFactDrillingOperations = (await wellOperationRepository.GetAsync(operationsRequest, token))
|
|
|
|
|
.Where(o => o.DepthEnd > o.DepthStart);
|
|
|
|
|
|
|
|
|
|
var processMapDtos = (await processMapRepository.GetByIdWellAsync(idWell, token))!;
|
|
|
|
|
|
|
|
|
|
var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell)!.Value;
|
|
|
|
|
IEnumerable<ProcessTelemetrySaubStat> telemetryStat = await GetTelemetryDataAsync(idTelemetry, token);
|
|
|
|
|
|
|
|
|
|
var result = allFactDrillingOperations
|
|
|
|
|
.GroupBy(o => o.IdWellSectionType)
|
|
|
|
|
.SelectMany(sectionOperations =>
|
|
|
|
|
{
|
|
|
|
|
var sectionProcessMap = processMapDtos.Where(p => p.IdWellSectionType == sectionOperations.Key);
|
|
|
|
|
return HandleSections(sectionOperations, sectionProcessMap);
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
2022-12-27 14:30:52 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
return result;
|
|
|
|
|
}
|
2022-12-28 17:38:53 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private async Task<IEnumerable<ProcessTelemetrySaubStat>> GetTelemetryDataAsync(int idTelemetry, CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
var timezone = telemetryService.GetTimezone(idTelemetry);
|
|
|
|
|
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
|
|
|
|
|
|
|
|
|
|
var query = db.Set<TelemetryDataSaub>()
|
|
|
|
|
.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;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private static IEnumerable<ProcessMapReportDto> HandleSections(
|
|
|
|
|
IEnumerable<WellOperationDto> sectionOperations,
|
|
|
|
|
IEnumerable<ProcessMapDto> sectionProcessMap )
|
2022-12-27 14:30:52 +05:00
|
|
|
|
{
|
2022-12-30 15:24:48 +05:00
|
|
|
|
var minDepth = sectionOperations.Min(o => o.DepthStart);
|
|
|
|
|
var maxDepth = sectionOperations.Max(o => o.DepthEnd);
|
2022-12-27 14:30:52 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
var depthIntervals = SplitByIntervals(minDepth, maxDepth).ToArray();
|
|
|
|
|
var result = new ProcessMapReportDto[depthIntervals.Length];
|
2022-12-27 14:30:52 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
for (var i = 0; i < depthIntervals.Length; i++ )
|
|
|
|
|
result[i] = MakeProcessMapReportDto(depthIntervals[i], sectionOperations, sectionProcessMap);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2022-12-27 14:30:52 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private static ProcessMapReportDto MakeProcessMapReportDto(
|
|
|
|
|
(double min, double max) depthInterval,
|
|
|
|
|
IEnumerable<WellOperationDto> sectionOperations,
|
|
|
|
|
IEnumerable<ProcessMapDto> sectionProcessMap)
|
|
|
|
|
{
|
|
|
|
|
var dto = new ProcessMapReportDto{
|
|
|
|
|
DepthStart = depthInterval.min
|
|
|
|
|
};
|
2022-12-27 14:30:52 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
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;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private static ProcessMapReportRowDto CalcDrillStat(
|
|
|
|
|
(double min, double max) depthInterval,
|
|
|
|
|
IEnumerable<WellOperationDto> intervalModeOperations,
|
|
|
|
|
IEnumerable<ProcessMapDto> intervalProcessMap)
|
|
|
|
|
{
|
|
|
|
|
var dto = new ProcessMapReportRowDto();
|
|
|
|
|
if(intervalModeOperations.Any())
|
2022-12-27 14:30:52 +05:00
|
|
|
|
{
|
2022-12-30 15:24:48 +05:00
|
|
|
|
var deltaDepth = CalcDeltaDepth(depthInterval, intervalModeOperations);
|
|
|
|
|
dto.DeltaDepth = deltaDepth;
|
|
|
|
|
dto.Rop = deltaDepth / CalcHours(depthInterval, intervalModeOperations);
|
|
|
|
|
|
|
|
|
|
dto.PressureDiff = CalcPressureDiff(depthInterval, intervalProcessMap);
|
2022-12-27 14:30:52 +05:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return dto;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private static ProcessMapReportParamsDto CalcPressureDiff(
|
|
|
|
|
(double min, double max) depthInterval,
|
|
|
|
|
IEnumerable<ProcessMapDto> intervalProcessMap)
|
2022-12-27 14:30:52 +05:00
|
|
|
|
{
|
2022-12-30 15:24:48 +05:00
|
|
|
|
var dto = new ProcessMapReportParamsDto();
|
|
|
|
|
if (intervalProcessMap.Any())
|
|
|
|
|
{
|
|
|
|
|
dto.SetPointPlan = intervalProcessMap.First().Pressure.Plan;
|
|
|
|
|
}
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
2022-12-27 14:30:52 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private static double CalcDeltaDepth((double min, double max) depthInterval, IEnumerable<WellOperationDto> intervalOperations)
|
|
|
|
|
{
|
|
|
|
|
var ddepth = 0d;
|
|
|
|
|
foreach (var operation in intervalOperations)
|
2022-12-27 14:30:52 +05:00
|
|
|
|
{
|
2022-12-30 15:24:48 +05:00
|
|
|
|
var depthStart = operation.DepthStart > depthInterval.min
|
|
|
|
|
? operation.DepthStart
|
|
|
|
|
: depthInterval.min;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
var depthEnd = operation.DepthEnd < depthInterval.max
|
|
|
|
|
? operation.DepthEnd
|
|
|
|
|
: depthInterval.max;
|
|
|
|
|
|
|
|
|
|
ddepth += (depthEnd - depthEnd);
|
2022-12-27 14:30:52 +05:00
|
|
|
|
}
|
2022-12-30 15:24:48 +05:00
|
|
|
|
return ddepth;
|
|
|
|
|
}
|
2022-12-27 14:30:52 +05:00
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private static double CalcHours((double min, double max) depthInterval, IEnumerable<WellOperationDto> intervalOperations)
|
|
|
|
|
{
|
|
|
|
|
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;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private static DateTime GetInterpolatedDate(WellOperationDto operation, double depth)
|
2022-12-27 14:30:52 +05:00
|
|
|
|
{
|
2022-12-30 15:24:48 +05:00
|
|
|
|
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;
|
2022-12-27 14:30:52 +05:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-30 15:24:48 +05:00
|
|
|
|
private static IEnumerable<(double min, double max)> SplitByIntervals(double min, double max)
|
2022-12-27 14:30:52 +05:00
|
|
|
|
{
|
2022-12-30 15:24:48 +05:00
|
|
|
|
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);
|
2022-12-27 14:30:52 +05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#nullable disable
|
|
|
|
|
}
|