forked from ddrilling/AsbCloudServer
349 lines
17 KiB
C#
349 lines
17 KiB
C#
using AsbCloudApp.Data;
|
|
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;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using AsbCloudInfrastructure.Services.Subsystems;
|
|
|
|
namespace AsbCloudInfrastructure.Services.ProcessMap
|
|
{
|
|
#nullable enable
|
|
public partial class ProcessMapService : IProcessMapService
|
|
{
|
|
private readonly IWellService wellService;
|
|
private readonly IWellOperationRepository wellOperationRepository;
|
|
private readonly IProcessMapRepository processMapRepository;
|
|
private readonly ITelemetryDataSaubService telemetryDataSaubService;
|
|
private readonly ILimitingParameterRepository limitingParameterRepository;
|
|
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
|
|
|
|
public ProcessMapService(
|
|
IWellService wellService,
|
|
IWellOperationRepository wellOperationService,
|
|
IProcessMapRepository processMapRepository,
|
|
ITelemetryDataSaubService telemetryDataSaubService,
|
|
ILimitingParameterRepository limitingParameterRepository,
|
|
ISubsystemOperationTimeService subsystemOperationTimeService)
|
|
{
|
|
this.wellService = wellService;
|
|
this.wellOperationRepository = wellOperationService;
|
|
this.processMapRepository = processMapRepository;
|
|
this.telemetryDataSaubService = telemetryDataSaubService;
|
|
this.limitingParameterRepository = limitingParameterRepository;
|
|
this.subsystemOperationTimeService = subsystemOperationTimeService;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public async Task<IEnumerable<ProcessMapReportDto>> GetProcessMapAsync(int idWell, CancellationToken token)
|
|
{
|
|
var well = wellService.GetOrDefault(idWell)
|
|
?? throw new ArgumentInvalidException("idWell not found", nameof(idWell));
|
|
var idTelemetry = well.IdTelemetry
|
|
?? throw new ArgumentInvalidException("telemetry by well not found", nameof(idWell));
|
|
|
|
var processMap = (await processMapRepository.GetByIdWellAsync(idWell, token))!;
|
|
var factDrillingOperations = await GetFactDrillingOperationsAsync(idWell, token);
|
|
var telemetryDataStat = await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token);
|
|
var limitingParameters = await limitingParameterRepository.GetLimitingParametersAsync(new(), well, token);
|
|
var subsystemsOperationTime = await GetOperationTimeAsync(idWell, token);
|
|
|
|
var result = factDrillingOperations
|
|
.GroupBy(o => o.IdWellSectionType)
|
|
.SelectMany(sectionOperations =>
|
|
{
|
|
var sectionProcessMap = processMap.Where(p => p.IdWellSectionType == sectionOperations.Key);
|
|
return HandleSection(sectionOperations, sectionProcessMap, telemetryDataStat, limitingParameters, subsystemsOperationTime!);
|
|
})
|
|
.ToList();
|
|
|
|
return result;
|
|
}
|
|
|
|
private Task<IEnumerable<SubsystemOperationTimeDto>?> GetOperationTimeAsync(int idWell, CancellationToken token)
|
|
{
|
|
var request = new SubsystemOperationTimeRequest
|
|
{
|
|
IdWell = idWell,
|
|
IdsSubsystems = new int[] { SubsystemOperationTimeService.IdSubsystemAKB, SubsystemOperationTimeService.IdSubsystemSpin },
|
|
};
|
|
return subsystemOperationTimeService.GetOperationTimeAsync(request, token);
|
|
}
|
|
|
|
private async Task<IEnumerable<WellOperationDto>> GetFactDrillingOperationsAsync(int idWell, CancellationToken token)
|
|
{
|
|
var operationsRequest = new WellOperationRequest
|
|
{
|
|
IdWell = idWell,
|
|
OperationCategoryIds = WellOperationCategory.MechanicalDrillingSubIds,
|
|
OperationType = WellOperation.IdOperationTypeFact,
|
|
SortFields = new[] { nameof(WellOperation.DateStart) }
|
|
};
|
|
|
|
var allFactDrillingOperations = await wellOperationRepository.GetAsync(operationsRequest, token);
|
|
var factDrillingOperations = allFactDrillingOperations.Where(o => o.DepthEnd > o.DepthStart);
|
|
return factDrillingOperations;
|
|
}
|
|
|
|
private static IEnumerable<ProcessMapReportDto> HandleSection(
|
|
IEnumerable<WellOperationDto> sectionOperations,
|
|
IEnumerable<ProcessMapPlanDto> sectionProcessMap,
|
|
IEnumerable<TelemetryDataSaubStatDto> telemetryDataStat,
|
|
IEnumerable<LimitingParameterDataDto> limitingParameters,
|
|
IEnumerable<SubsystemOperationTimeDto> subsystemsOperationTime)
|
|
{
|
|
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, telemetryDataStat, limitingParameters, subsystemsOperationTime);
|
|
|
|
return result;
|
|
}
|
|
|
|
private static ProcessMapReportDto MakeProcessMapReportDto(
|
|
(double min, double max) depthInterval,
|
|
IEnumerable<WellOperationDto> sectionOperations,
|
|
IEnumerable<ProcessMapPlanDto> sectionProcessMap,
|
|
IEnumerable<TelemetryDataSaubStatDto> telemetryDataStat,
|
|
IEnumerable<LimitingParameterDataDto> limitingParameters,
|
|
IEnumerable<SubsystemOperationTimeDto> subsystemsOperationTime)
|
|
{
|
|
var dto = new ProcessMapReportDto{
|
|
DepthStart = depthInterval.min
|
|
};
|
|
|
|
// TODO: trim items by detpth intervals. Use linear interpolation.
|
|
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);
|
|
var intervalTelemetryDataStat = CalcIntervalTelemetryDataStat(depthInterval, telemetryDataStat);
|
|
var intervalLimitingParametrs = limitingParameters.Where(l => l.DepthEnd >= depthInterval.min && l.DepthStart <= depthInterval.max);
|
|
var intervalSubsystemsOperationTime = subsystemsOperationTime.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max);
|
|
|
|
var firstIntervalOperation = intervalOperations.FirstOrDefault();
|
|
if (firstIntervalOperation is not null)
|
|
{
|
|
dto.DateStart = GetInterpolatedDate(firstIntervalOperation, depthInterval.min);
|
|
dto.IdWell = firstIntervalOperation.IdWell;
|
|
dto.IdWellSectionType = firstIntervalOperation.IdWellSectionType;
|
|
dto.WellSectionTypeName = firstIntervalOperation.WellSectionTypeName ?? string.Empty;
|
|
dto.MechDrillingHours = CalcHours(depthInterval, intervalOperations);
|
|
}
|
|
|
|
// TODO: Разделить интервальные коллекции на ротор и слайд. Пока нет готовой методики.
|
|
var slideOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdSlide);
|
|
var rotorOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdRotor);
|
|
|
|
//dto.Slide = CalcDrillModeStat(depthInterval, slideOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime);
|
|
//dto.Rotor = CalcDrillModeStat(depthInterval, rotorOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime);
|
|
|
|
return dto;
|
|
}
|
|
|
|
private static TelemetryDataSaubStatDto? CalcIntervalTelemetryDataStat((double min, double max) depthInterval, IEnumerable<TelemetryDataSaubStatDto> telemetryDataStat)
|
|
{
|
|
TelemetryDataSaubStatDto[] data = telemetryDataStat
|
|
.Where(d => d.WellDepthMin <= depthInterval.max && d.WellDepthMax >= depthInterval.min)
|
|
.ToArray();
|
|
|
|
if (!data.Any())
|
|
return null;
|
|
|
|
if (data.Length == 1)
|
|
return data.First();
|
|
|
|
var result = new TelemetryDataSaubStatDto
|
|
{
|
|
WellDepthMin = data.Min(d => d.WellDepthMin),
|
|
WellDepthMax = data.Max(d => d.WellDepthMax),
|
|
DateMin = data.Min(d => d.DateMin),
|
|
DateMax = data.Max(d => d.DateMax),
|
|
};
|
|
|
|
var intervalDeltaDepth = result.WellDepthMax - result.WellDepthMin;
|
|
|
|
foreach (var item in data)
|
|
{
|
|
var itemWeight = (item.WellDepthMax - item.WellDepthMin) / intervalDeltaDepth;
|
|
|
|
result.Pressure += item.Pressure * itemWeight;
|
|
result.PressureSp += item.PressureSp * itemWeight;
|
|
result.PressureSpRotor += item.PressureSpSlide * itemWeight;
|
|
result.PressureIdle += item.PressureIdle * itemWeight;
|
|
result.PressureDelta += item.PressureDelta * itemWeight;
|
|
|
|
result.AxialLoad += item.AxialLoad * itemWeight;
|
|
result.AxialLoadSp += item.AxialLoadSp * itemWeight;
|
|
result.AxialLoadLimitMax += item.AxialLoadLimitMax * itemWeight;
|
|
|
|
result.RotorTorque += item.RotorTorque * itemWeight;
|
|
result.RotorTorqueSp += item.RotorTorqueSp * itemWeight;
|
|
result.RotorTorqueLimitMax += item.RotorTorqueLimitMax * itemWeight;
|
|
|
|
result.BlockSpeed += item.BlockSpeed * itemWeight;
|
|
result.BlockSpeedSp += item.BlockSpeedSp * itemWeight;
|
|
result.BlockSpeedSpRotor += item.BlockSpeedSpRotor * itemWeight;
|
|
result.BlockSpeedSpSlide += item.BlockSpeedSpSlide * itemWeight;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//private static ProcessMapReportRowDto CalcDrillModeStat(
|
|
// (double min, double max) depthInterval,
|
|
// IEnumerable<WellOperationDto> intervalModeOperations,
|
|
// IEnumerable<ProcessMapDto> intervalProcessMap,
|
|
// TelemetryDataSaubStatDto? telemetryDataStat,
|
|
// IEnumerable<LimitingParameterDataDto> intervalLimitingParametrs,
|
|
// IEnumerable<SubsystemOperationTimeDto> intervalSubsystemsOperationTime)
|
|
//{
|
|
// var dto = new ProcessMapReportRowDto();
|
|
// if (intervalModeOperations.Any())
|
|
// {
|
|
// var deltaDepth = CalcDeltaDepth(depthInterval, intervalModeOperations);
|
|
// dto.DeltaDepth = deltaDepth;
|
|
// dto.Rop = deltaDepth / CalcHours(depthInterval, intervalModeOperations);
|
|
// };
|
|
|
|
// if (intervalProcessMap.Any())
|
|
// {
|
|
// var processMapFirst = intervalProcessMap.First();
|
|
// dto.PressureDiff.SetpointPlan = processMapFirst.Pressure.Plan;
|
|
// dto.AxialLoad.SetpointPlan = processMapFirst.AxialLoad.Plan;
|
|
// dto.TopDriveTorque.SetpointPlan = processMapFirst.TopDriveTorque.Plan;
|
|
// //dto.SpeedLimit.SetpointPlan = null;
|
|
// }
|
|
|
|
// if (telemetryDataStat is not null)
|
|
// {
|
|
// dto.PressureDiff.SetpointFact = telemetryDataStat.PressureSp;
|
|
// dto.PressureDiff.Fact = telemetryDataStat.PressureDelta;
|
|
// dto.PressureDiff.Limit = telemetryDataStat.PressureDeltaLimitMax;
|
|
|
|
// dto.AxialLoad.SetpointFact = telemetryDataStat.AxialLoadSp;
|
|
// dto.AxialLoad.Fact = telemetryDataStat.AxialLoad;
|
|
// dto.AxialLoad.Limit = telemetryDataStat.AxialLoadLimitMax;
|
|
|
|
// dto.TopDriveTorque.SetpointFact = telemetryDataStat.RotorTorqueSp;
|
|
// dto.TopDriveTorque.Fact = telemetryDataStat.RotorTorque;
|
|
// dto.TopDriveTorque.Limit = telemetryDataStat.RotorTorqueLimitMax;
|
|
|
|
// dto.SpeedLimit.SetpointFact = telemetryDataStat.BlockSpeedSp;
|
|
// dto.SpeedLimit.Fact = telemetryDataStat.BlockSpeed;
|
|
// //dto.SpeedLimit.Limit = mull;
|
|
// }
|
|
|
|
// if(intervalLimitingParametrs.Any())
|
|
// {
|
|
// const int idLimParamRop = 1;
|
|
// const int idLimParamPressure = 2;
|
|
// const int idLimParamAxialLoad = 3;
|
|
// const int idLimParamTorque = 4;
|
|
|
|
// var intervalLimitingParametrsStat = intervalLimitingParametrs
|
|
// .GroupBy(p => p.IdFeedRegulator)
|
|
// .Select(g => new
|
|
// {
|
|
// IdLimParam = g.Key,
|
|
// SumDepth = g.Sum(p => p.DepthEnd - p.DepthStart),
|
|
// });
|
|
|
|
// var totalDepth = intervalLimitingParametrsStat
|
|
// .Sum(s => s.SumDepth);
|
|
|
|
// if (totalDepth > 0)
|
|
// {
|
|
// dto.AxialLoad.PercDrillingSetpoint = intervalLimitingParametrsStat
|
|
// .FirstOrDefault(s => s.IdLimParam == idLimParamAxialLoad)?.SumDepth / totalDepth;
|
|
|
|
// dto.PressureDiff.PercDrillingSetpoint = intervalLimitingParametrsStat
|
|
// .FirstOrDefault(s => s.IdLimParam == idLimParamPressure)?.SumDepth / totalDepth;
|
|
|
|
// dto.TopDriveTorque.PercDrillingSetpoint = intervalLimitingParametrsStat
|
|
// .FirstOrDefault(s => s.IdLimParam == idLimParamTorque)?.SumDepth / totalDepth;
|
|
|
|
// dto.SpeedLimit.PercDrillingSetpoint = intervalLimitingParametrsStat
|
|
// .FirstOrDefault(s => s.IdLimParam == idLimParamRop)?.SumDepth / totalDepth;
|
|
// }
|
|
// }
|
|
|
|
// if (intervalSubsystemsOperationTime.Any() && dto.DeltaDepth > 0)
|
|
// {
|
|
// dto.Usage = intervalSubsystemsOperationTime.Sum(t => t.DepthEnd - t.DepthStart) / dto.DeltaDepth.Value;
|
|
// }
|
|
|
|
// return dto;
|
|
//}
|
|
|
|
private static double CalcDeltaDepth((double min, double max) depthInterval, IEnumerable<WellOperationDto> intervalOperations)
|
|
{
|
|
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 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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
|
|
}
|