DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDrillingService.cs

412 lines
19 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Data.ProcessMaps.Operations;
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Extensions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudDb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.ProcessMaps.Report;
public class ProcessMapReportDrillingService : IProcessMapReportDrillingService
{
private readonly IWellService wellService;
private readonly IChangeLogRepository<ProcessMapPlanRotorDto, ProcessMapPlanBaseRequestWithWell> processMapPlanRotorRepository;
private readonly IChangeLogRepository<ProcessMapPlanSlideDto, ProcessMapPlanBaseRequestWithWell> processMapPlanSlideRepository;
private readonly IDataSaubStatRepository<DataSaubStatDto> dataSaubStatRepository;
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private readonly IWellOperationService wellOperationService;
public ProcessMapReportDrillingService(IWellService wellService,
IChangeLogRepository<ProcessMapPlanRotorDto, ProcessMapPlanBaseRequestWithWell> processMapPlanRotorRepository,
IChangeLogRepository<ProcessMapPlanSlideDto, ProcessMapPlanBaseRequestWithWell> processMapPlanSlideRepository,
IDataSaubStatRepository<DataSaubStatDto> dataSaubStatRepository,
IWellOperationRepository wellOperationRepository,
IWellOperationCategoryRepository wellOperationCategoryRepository,
IWellOperationService wellOperationService
)
{
this.wellService = wellService;
this.processMapPlanRotorRepository = processMapPlanRotorRepository;
this.processMapPlanSlideRepository = processMapPlanSlideRepository;
this.dataSaubStatRepository = dataSaubStatRepository;
this.wellOperationRepository = wellOperationRepository;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
this.wellOperationService = wellOperationService;
}
public async Task<IEnumerable<ProcessMapReportDataSaubStatDto>> GetAsync(int idWell, DataSaubStatRequest request, CancellationToken token)
{
var well = await wellService.GetOrDefaultAsync(idWell, token)
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважина с Id: {idWell} не найдена");
if (!well.IdTelemetry.HasValue)
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var requestProcessMapPlan = new ProcessMapPlanBaseRequestWithWell(idWell);
var changeLogProcessMapsRotor = await processMapPlanRotorRepository.GetChangeLogForDate(requestProcessMapPlan, null, token);
var changeLogProcessMapsSlide = await processMapPlanSlideRepository.GetChangeLogForDate(requestProcessMapPlan, null, token);
var changeLogProcessMaps = changeLogProcessMapsRotor
.Select(p => ConvertToChangeLogDtoWithProcessMapPlanBase(p))
.Union(changeLogProcessMapsSlide.Select(p => ConvertToChangeLogDtoWithProcessMapPlanBase(p)));
if (!changeLogProcessMaps.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var geDepth = changeLogProcessMaps.Min(p => p.Item.DepthStart);
var leDepth = changeLogProcessMaps.Max(p => p.Item.DepthEnd);
var requestWellOperationFact = new WellOperationRequest(new[] { idWell })
{
OperationType = WellOperation.IdOperationTypeFact,
GeDepth = geDepth,
LeDepth = leDepth
};
var wellOperations = await wellOperationService
.GetAsync(requestWellOperationFact, token);
var orderedWellOperations = wellOperations
.OrderBy(operation => operation.DateStart)
.ToArray();
if (!wellOperations.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var geDate = wellOperations.Min(p => p.DateStart);
var leDate = wellOperations.Max(p => (p.DateStart.AddHours(p.DurationHours)));
var dataSaubStats =
(await dataSaubStatRepository.GetAsync([well.IdTelemetry.Value], geDate, leDate, token)).ToArray();
if (!dataSaubStats.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var wellOperationCategories = wellOperationCategoryRepository.Get(false);
var wellSectionTypes = wellOperationRepository.GetSectionTypes();
var result = CalcByIntervals(
request,
changeLogProcessMaps,
dataSaubStats,
orderedWellOperations,
wellOperationCategories,
wellSectionTypes);
return result;
}
private ChangeLogDto<ProcessMapPlanBaseDto> ConvertToChangeLogDtoWithProcessMapPlanBase<T>(ChangeLogDto<T> p)
where T: ProcessMapPlanBaseDto
{
return new ChangeLogDto<ProcessMapPlanBaseDto>()
{
Item = p.Item,
Author = p.Author,
Creation = p.Creation,
Editor = p.Editor,
IdPrevious = p.IdPrevious,
IdState = p.IdState,
Obsolete = p.Obsolete,
};
}
private static IEnumerable<ProcessMapReportDataSaubStatDto> CalcByIntervals(
DataSaubStatRequest request,
IEnumerable<ChangeLogDto<ProcessMapPlanBaseDto>> changeLogProcessMaps,
Span<DataSaubStatDto> dataSaubStats,
IEnumerable<WellOperationDto> wellOperations,
IEnumerable<WellOperationCategoryDto> wellOperationCategories,
IEnumerable<WellSectionTypeDto> wellSectionTypes
)
{
var list = new List<ProcessMapReportDataSaubStatDto>();
var firstElemInInterval = dataSaubStats[0];
var orderedWellOperations = wellOperations
.OrderBy(o => o.DateStart)
.ToArray();
var lastFoundIndex = 0;
int GetSection(DataSaubStatDto data)
{
if (lastFoundIndex < orderedWellOperations.Length - 1)
{
lastFoundIndex = Array.FindIndex(orderedWellOperations, lastFoundIndex, o => o.DateStart > data.DateStart) - 1;
lastFoundIndex = lastFoundIndex < 0 ? orderedWellOperations.Length - 1 : lastFoundIndex;
}
var operation = orderedWellOperations[lastFoundIndex];
return operation.IdWellSectionType;
}
ProcessMapPlanBaseDto? GetProcessMapPlan(int idWellSectionType, DataSaubStatDto data)
=> changeLogProcessMaps
.Where(p => p.Item.IdWellSectionType == idWellSectionType)
.Where(p => p.Item.DepthStart <= data.DepthStart)
.Where(p => p.Item.DepthEnd >= data.DepthStart)
.Where(p => IsModeMatchOperationCategory(p.Item, data.IdCategory))
.WhereActualAtMoment(data.DateStart)
.Select(p => p.Item)
.FirstOrDefault();
var idWellSectionType = GetSection(firstElemInInterval);
var prevProcessMapPlan = GetProcessMapPlan(idWellSectionType, firstElemInInterval);
var indexStart = 0;
for (var i = 1; i < dataSaubStats.Length; i++)
{
var currentElem = dataSaubStats[i];
idWellSectionType = GetSection(currentElem);
var processMapPlan = GetProcessMapPlan(idWellSectionType, currentElem);
if (IsNewInterval(currentElem, firstElemInInterval, request) || i == dataSaubStats.Length - 1 || processMapPlan != prevProcessMapPlan)
{
prevProcessMapPlan = processMapPlan;
var length = i - indexStart;
var span = dataSaubStats.Slice(indexStart, length);
indexStart = i;
firstElemInInterval = currentElem;
var firstElemInSpan = span[0];
var lastElemInISpan = span[^1];
var wellOperationCategoryName = wellOperationCategories
.Where(c => c.Id == firstElemInSpan.IdCategory)
.FirstOrDefault()?.Name ?? string.Empty;
var wellSectionType = wellSectionTypes
.Where(c => c.Id == idWellSectionType)
.First();
var elem = CalcStat(processMapPlan, span, wellOperationCategoryName, wellSectionType);
if (elem is not null)
list.Add(elem);
}
}
return list;
}
private static bool IsModeMatchOperationCategory(ProcessMapPlanBaseDto dto, int idCategory)
{
return (dto is ProcessMapPlanRotorDto && idCategory == 5003) || (dto is ProcessMapPlanSlideDto && idCategory == 5002);
}
private static ProcessMapReportDataSaubStatDto? CalcStat(
ProcessMapPlanBaseDto? processMapPlanFilteredByDepth,
Span<DataSaubStatDto> span,
string wellOperationCategoryName,
WellSectionTypeDto wellSectionType
)
{
var firstElemInInterval = span[0];
var lastElemInInterval = span[^1];
var deltaDepth = lastElemInInterval.DepthEnd - firstElemInInterval.DepthStart;
var aggregatedValues = CalcAggregate(span);
var result = new ProcessMapReportDataSaubStatDto()
{
IdWellSectionType = wellSectionType.Id,
DateStart = firstElemInInterval.DateStart,
WellSectionTypeName = wellSectionType.Caption,
DepthStart = firstElemInInterval.DepthStart,
DepthEnd = lastElemInInterval.DepthEnd,
DeltaDepth = deltaDepth,
DrilledTime = aggregatedValues.DrilledTime,
DrillingMode = wellOperationCategoryName,
PressureDiff = new ProcessMapReportDataSaubStatParamsDto()
{
SetpointFact = firstElemInInterval.PressureSp - firstElemInInterval.PressureIdle,
FactWavg = aggregatedValues.Pressure,
SetpointUsage = aggregatedValues.SetpointUsagePressure
},
AxialLoad = new ProcessMapReportDataSaubStatParamsDto()
{
SetpointFact = aggregatedValues.AxialLoadSp,
FactWavg = aggregatedValues.AxialLoad,
SetpointUsage = aggregatedValues.SetpointUsageAxialLoad
},
TopDriveTorque = new ProcessMapReportDataSaubStatParamsDto()
{
SetpointFact = aggregatedValues.RotorTorqueSp,
FactWavg = aggregatedValues.RotorTorque,
FactMax = aggregatedValues.RotorTorqueMax,
SetpointUsage = aggregatedValues.SetpointUsageRotorTorque
},
SpeedLimit = new ProcessMapReportDataSaubStatParamsDto
{
SetpointFact = aggregatedValues.BlockSpeedSp,
FactWavg = deltaDepth / aggregatedValues.DrilledTime,
SetpointUsage = aggregatedValues.SetpointUsageRopPlan
},
TopDriveSpeed = new ProcessMapReportDataSaubStatParamsDto
{
FactWavg = aggregatedValues.RotorSpeed,
FactMax = aggregatedValues.RotorSpeedMax
},
Flow = new ProcessMapReportDataSaubStatParamsDto
{
FactWavg = aggregatedValues.MaxFlow,
},
Rop = new PlanFactDto<double?>
{
Fact = deltaDepth / aggregatedValues.DrilledTime
},
};
if(processMapPlanFilteredByDepth is ProcessMapPlanRotorDto processMapPlanRotorFilteredByDepth)
{
result.PressureDiff.SetpointPlan = processMapPlanRotorFilteredByDepth.DifferentialPressure;
result.PressureDiff.Limit = processMapPlanRotorFilteredByDepth.DifferentialPressureMax;
result.AxialLoad.SetpointPlan = processMapPlanRotorFilteredByDepth.WeightOnBit;
result.AxialLoad.Limit = processMapPlanRotorFilteredByDepth.WeightOnBitMax;
result.TopDriveTorque.SetpointPlan = processMapPlanRotorFilteredByDepth.TopDriveTorque;
result.TopDriveTorque.Limit = processMapPlanRotorFilteredByDepth.TopDriveTorqueMax;
result.SpeedLimit.SetpointPlan = processMapPlanRotorFilteredByDepth.RopMax;
result.TopDriveSpeed.SetpointPlan = processMapPlanRotorFilteredByDepth.Rpm;
result.Flow.SetpointPlan = processMapPlanRotorFilteredByDepth.FlowRate;
result.Flow.Limit = processMapPlanRotorFilteredByDepth.FlowRateMax;
result.Rop.Plan = processMapPlanRotorFilteredByDepth.RopMax;
}
if (processMapPlanFilteredByDepth is ProcessMapPlanSlideDto processMapPlanSlideFilteredByDepth)
{
result.PressureDiff.SetpointPlan = processMapPlanSlideFilteredByDepth.DifferentialPressure;
result.PressureDiff.Limit = processMapPlanSlideFilteredByDepth.DifferentialPressureMax;
result.AxialLoad.SetpointPlan = processMapPlanSlideFilteredByDepth.WeightOnBit;
result.AxialLoad.Limit = processMapPlanSlideFilteredByDepth.WeightOnBitMax;
result.SpeedLimit.SetpointPlan = processMapPlanSlideFilteredByDepth.RopMax;
result.Flow.SetpointPlan = processMapPlanSlideFilteredByDepth.FlowRate;
result.Flow.Limit = processMapPlanSlideFilteredByDepth.FlowRateMax;
result.Rop.Plan = processMapPlanSlideFilteredByDepth.RopMax;
}
return result;
}
private static (
double Pressure,
double AxialLoadSp,
double AxialLoad,
double RotorTorqueSp,
double RotorTorque,
double RotorTorqueMax,
double BlockSpeedSp,
double RotorSpeed,
double RotorSpeedMax,
double MaxFlow,
double SetpointUsagePressure,
double SetpointUsageAxialLoad,
double SetpointUsageRotorTorque,
double SetpointUsageRopPlan,
double DrilledTime
) CalcAggregate(Span<DataSaubStatDto> span)
{
var sumPressure = 0.0;
var sumAxialLoadSp = 0.0;
var sumAxialLoad = 0.0;
var sumRotorTorqueSp = 0.0;
var sumRotorTorque = 0.0;
var sumBlockSpeedSp = 0.0;
var sumRotorSpeed = 0.0;
var maxFlow = 0.0;
var maxRotorTorque = 0.0;
var maxRotorSpeed = 0.0;
var sumDiffDepthByPressure = 0.0;
var sumDiffDepthByAxialLoad = 0.0;
var sumDiffDepthByRotorTorque = 0.0;
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 - (span[i].PressureIdle ?? 0.0));
sumAxialLoadSp += diffDepth * (span[i].AxialLoadSp ?? 0);
sumAxialLoad += diffDepth * span[i].AxialLoad;
sumRotorTorqueSp += diffDepth * (span[i].RotorTorqueSp ?? 0);
sumRotorTorque += diffDepth * span[i].RotorTorque;
sumBlockSpeedSp += diffDepth * (span[i].BlockSpeedSp ?? 0);
sumRotorSpeed += diffDepth * span[i].RotorSpeed;
maxFlow = span[i].Flow > maxFlow ? span[i].Flow : maxFlow;
maxRotorTorque = span[i].RotorTorque > maxRotorTorque ? span[i].RotorTorque : maxRotorTorque;
maxRotorSpeed = span[i].RotorSpeed > maxRotorSpeed ? span[i].RotorSpeed : maxRotorSpeed;
if (span[i].IdFeedRegulator == LimitingParameterDto.Pressure)
sumDiffDepthByPressure += diffDepth;
if (span[i].IdFeedRegulator == LimitingParameterDto.AxialLoad)
sumDiffDepthByAxialLoad += diffDepth;
if (span[i].IdFeedRegulator == LimitingParameterDto.RotorTorque)
sumDiffDepthByRotorTorque += diffDepth;
if (span[i].IdFeedRegulator == LimitingParameterDto.RopPlan)
sumDiffDepthByRopPlan += diffDepth;
diffDepthTotal += diffDepth;
drilledTime += (span[i].DateEnd - span[i].DateStart).TotalHours;
}
return (
Pressure: sumPressure / diffDepthTotal,
AxialLoadSp: sumAxialLoadSp / diffDepthTotal,
AxialLoad: sumAxialLoad / diffDepthTotal,
RotorTorqueSp: sumRotorTorqueSp / diffDepthTotal,
RotorTorque: sumRotorTorque / diffDepthTotal,
RotorTorqueMax: maxRotorTorque,
BlockSpeedSp: sumBlockSpeedSp / diffDepthTotal,
RotorSpeed: sumRotorSpeed / diffDepthTotal,
RotorSpeedMax: maxRotorSpeed,
MaxFlow: maxFlow,
SetpointUsagePressure: sumDiffDepthByPressure * 100 / diffDepthTotal,
SetpointUsageAxialLoad: sumDiffDepthByAxialLoad * 100 / diffDepthTotal,
SetpointUsageRotorTorque: sumDiffDepthByRotorTorque * 100 / diffDepthTotal,
SetpointUsageRopPlan: sumDiffDepthByRopPlan * 100 / diffDepthTotal,
DrilledTime: drilledTime
);
}
private static bool IsNewInterval(DataSaubStatDto currentElem, DataSaubStatDto firstElem, DataSaubStatRequest request)
{
static bool IsNewElemBySpeed(double currentSpeed, double firstSpeed)
{
//2. Изменение уставки скорости подачи от первого значения в начале интервала при условии:
//скорость > 80 м/ч => изменение уставки на ± 20 м/ч;
//скорость > 30 м/ч => изменение уставки на ± 15 м/ч;
//скорость <= 30 м/ч => изменение уставки на ± 5 м/ч;
if (firstSpeed > 80)
return Math.Abs(currentSpeed - firstSpeed) >= 20;
else if (firstSpeed > 30)
return Math.Abs(currentSpeed - firstSpeed) >= 15;
else
return Math.Abs(currentSpeed - firstSpeed) >= 5;
}
var isNewElem = (currentElem.IdCategory != firstElem.IdCategory)
|| (Math.Abs(currentElem.Pressure - firstElem.Pressure) >= request.DeltaPressure)
|| (Math.Abs(currentElem.AxialLoad - firstElem.AxialLoad) >= request.DeltaAxialLoad)
|| (Math.Abs(currentElem.RotorTorque - firstElem.RotorTorque) >= request.DeltaRotorTorque)
|| (Math.Abs((currentElem.AxialLoadSp ?? 0) - (firstElem.AxialLoadSp ?? 0)) >= request.DeltaAxialLoadSp)
|| (Math.Abs((currentElem.RotorTorqueSp ?? 0) - (firstElem.RotorTorqueSp ?? 0)) >= request.DeltaRotorTorqueSp)
|| (IsNewElemBySpeed(currentElem.Speed, firstElem.Speed));
return isNewElem;
}
}