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

369 lines
16 KiB
C#
Raw Normal View History

using AsbCloudApp.Data;
2024-02-21 15:08:51 +05:00
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Exceptions;
2024-02-13 16:35:01 +05:00
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;
using AsbCloudApp.Data.WellOperation;
using AsbCloudDb.Model.ProcessMaps;
2024-02-14 13:43:19 +05:00
namespace AsbCloudInfrastructure.Services.ProcessMaps.Report;
2024-02-21 15:08:51 +05:00
public class ProcessMapReportDrillingService : IProcessMapReportDrillingService
{
2024-02-14 13:43:19 +05:00
private readonly IWellService wellService;
private readonly IChangeLogRepository<ProcessMapPlanDrilling, ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanBaseRepository;
2024-02-14 13:43:19 +05:00
private readonly IDataSaubStatRepository dataSaubStatRepository;
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
2024-02-21 15:08:51 +05:00
public ProcessMapReportDrillingService(IWellService wellService,
IChangeLogRepository<ProcessMapPlanDrilling, ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanBaseRepository,
2024-02-14 13:43:19 +05:00
IDataSaubStatRepository dataSaubStatRepository,
IWellOperationRepository wellOperationRepository,
IWellOperationCategoryRepository wellOperationCategoryRepository
)
{
2024-02-14 13:43:19 +05:00
this.wellService = wellService;
this.processMapPlanBaseRepository = processMapPlanBaseRepository;
this.dataSaubStatRepository = dataSaubStatRepository;
this.wellOperationRepository = wellOperationRepository;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
}
2024-02-14 13:43:19 +05:00
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} не найдена");
2024-02-14 13:43:19 +05:00
if (!well.IdTelemetry.HasValue)
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
2024-02-14 13:43:19 +05:00
var requestProcessMapPlan = new ProcessMapPlanBaseRequestWithWell(idWell);
2024-05-31 15:58:28 +05:00
var changeLogProcessMaps = await processMapPlanBaseRepository.GetChangeLogForDate(requestProcessMapPlan, null, token);
if (!changeLogProcessMaps.Any())
2024-02-14 13:43:19 +05:00
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 })
2024-02-14 13:43:19 +05:00
{
OperationType = WellOperation.IdOperationTypeFact,
GeDepth = geDepth,
LeDepth = leDepth
};
var wellOperations = await wellOperationRepository
.GetAsync(requestWellOperationFact, token);
var orderedWellOperations = wellOperations
.OrderBy(operation => operation.DateStart)
.ToArray();
2024-02-14 13:43:19 +05:00
if (!wellOperations.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var geDate = wellOperations.Min(p => p.DateStart);
var leDate = wellOperations.Max(p => (p.DateStart.AddHours(p.DurationHours)));
2024-02-14 13:43:19 +05:00
var dataSaubStats =
(await dataSaubStatRepository.GetAsync(well.IdTelemetry.Value, geDate, leDate, token)).ToArray();
2024-02-14 13:43:19 +05:00
if (!dataSaubStats.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var wellOperationCategories = wellOperationCategoryRepository.Get(false);
2024-02-14 13:43:19 +05:00
var wellSectionTypes = wellOperationRepository.GetSectionTypes();
var result = CalcByIntervals(
request,
changeLogProcessMaps,
dataSaubStats,
orderedWellOperations,
2024-02-14 13:43:19 +05:00
wellOperationCategories,
wellSectionTypes);
return result;
}
private static IEnumerable<ProcessMapReportDataSaubStatDto> CalcByIntervals(
2024-02-14 13:43:19 +05:00
DataSaubStatRequest request,
IEnumerable<ChangeLogDto<ProcessMapPlanDrillingDto>> changeLogProcessMaps,
2024-02-14 13:43:19 +05:00
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;
}
2024-02-14 13:43:19 +05:00
ProcessMapPlanDrillingDto? 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.IdMode, data.IdCategory))
2024-02-14 13:43:19 +05:00
.WhereActualAtMoment(data.DateStart)
.Select(p => p.Item)
2024-02-14 13:43:19 +05:00
.FirstOrDefault();
var idWellSectionType = GetSection(firstElemInInterval);
var prevProcessMapPlan = GetProcessMapPlan(idWellSectionType, firstElemInInterval);
var indexStart = 0;
for (var i = 1; i < dataSaubStats.Length; i++)
{
2024-02-14 13:43:19 +05:00
var currentElem = dataSaubStats[i];
idWellSectionType = GetSection(currentElem);
var processMapPlan = GetProcessMapPlan(idWellSectionType, currentElem);
2024-02-13 17:29:20 +05:00
2024-02-14 13:43:19 +05:00
if (IsNewInterval(currentElem, firstElemInInterval, request) || i == dataSaubStats.Length - 1 || processMapPlan != prevProcessMapPlan)
{
prevProcessMapPlan = processMapPlan;
var length = i - indexStart;
2024-02-13 16:35:01 +05:00
2024-02-14 13:43:19 +05:00
var span = dataSaubStats.Slice(indexStart, length);
2024-02-14 13:43:19 +05:00
indexStart = i;
firstElemInInterval = currentElem;
2024-02-13 16:35:01 +05:00
2024-02-14 13:43:19 +05:00
var firstElemInSpan = span[0];
var lastElemInISpan = span[^1];
2024-02-13 16:35:01 +05:00
2024-02-14 13:43:19 +05:00
var wellOperationCategoryName = wellOperationCategories
.Where(c => c.Id == firstElemInSpan.IdCategory)
.FirstOrDefault()?.Name ?? string.Empty;
2024-02-14 11:33:35 +05:00
var wellSectionType = wellSectionTypes
2024-02-14 13:43:19 +05:00
.Where(c => c.Id == idWellSectionType)
.First();
2024-02-14 11:33:35 +05:00
var elem = CalcStat(processMapPlan, span, wellOperationCategoryName, wellSectionType);
2024-02-14 13:43:19 +05:00
if (elem is not null)
list.Add(elem);
}
2024-02-13 17:29:20 +05:00
}
2024-02-14 13:43:19 +05:00
return list;
}
2024-02-13 17:29:20 +05:00
2024-02-14 13:43:19 +05:00
private static bool IsModeMatchOperationCategory(int idMode, int idCategory)
{
return (idMode == 1 && idCategory == 5003) || (idMode == 2 && idCategory == 5002);
}
2024-02-13 16:35:01 +05:00
private static ProcessMapReportDataSaubStatDto? CalcStat(
2024-02-14 13:43:19 +05:00
ProcessMapPlanDrillingDto? processMapPlanFilteredByDepth,
Span<DataSaubStatDto> span,
string wellOperationCategoryName,
WellSectionTypeDto wellSectionType
2024-02-14 13:43:19 +05:00
)
{
var firstElemInInterval = span[0];
var lastElemInInterval = span[^1];
2024-02-14 13:43:19 +05:00
var deltaDepth = lastElemInInterval.DepthEnd - firstElemInInterval.DepthStart;
2024-02-14 13:43:19 +05:00
var aggregatedValues = CalcAggregate(span);
var result = new ProcessMapReportDataSaubStatDto()
{
IdWellSectionType = wellSectionType.Id,
DateStart = firstElemInInterval.DateStart,
WellSectionTypeName = wellSectionType.Caption,
2024-02-14 13:43:19 +05:00
DepthStart = firstElemInInterval.DepthStart,
DepthEnd = lastElemInInterval.DepthEnd,
DeltaDepth = deltaDepth,
DrilledTime = aggregatedValues.DrilledTime,
DrillingMode = wellOperationCategoryName,
PressureDiff = new ProcessMapReportDataSaubStatParamsDto()
{
2024-02-14 13:43:19 +05:00
SetpointPlan = processMapPlanFilteredByDepth?.DeltaPressurePlan,
SetpointFact = firstElemInInterval.PressureSp - firstElemInInterval.PressureIdle,
FactWavg = aggregatedValues.Pressure,
Limit = processMapPlanFilteredByDepth?.DeltaPressureLimitMax,
SetpointUsage = aggregatedValues.SetpointUsagePressure
},
AxialLoad = new ProcessMapReportDataSaubStatParamsDto()
{
SetpointPlan = processMapPlanFilteredByDepth?.AxialLoadPlan,
SetpointFact = aggregatedValues.AxialLoadSp,
FactWavg = aggregatedValues.AxialLoad,
Limit = processMapPlanFilteredByDepth?.AxialLoadLimitMax,
SetpointUsage = aggregatedValues.SetpointUsageAxialLoad
},
TopDriveTorque = new ProcessMapReportDataSaubStatParamsDto()
{
SetpointPlan = processMapPlanFilteredByDepth?.TopDriveTorquePlan,
SetpointFact = aggregatedValues.RotorTorqueSp,
FactWavg = aggregatedValues.RotorTorque,
FactMax = aggregatedValues.RotorTorqueMax,
Limit = processMapPlanFilteredByDepth?.TopDriveTorqueLimitMax,
SetpointUsage = aggregatedValues.SetpointUsageRotorTorque
},
SpeedLimit = new ProcessMapReportDataSaubStatParamsDto
{
SetpointPlan = processMapPlanFilteredByDepth?.RopPlan,
SetpointFact = aggregatedValues.BlockSpeedSp,
FactWavg = deltaDepth / aggregatedValues.DrilledTime,
SetpointUsage = aggregatedValues.SetpointUsageRopPlan
},
TopDriveSpeed = new ProcessMapReportDataSaubStatParamsDto
{
SetpointPlan = processMapPlanFilteredByDepth?.TopDriveSpeedPlan,
FactWavg = aggregatedValues.RotorSpeed,
FactMax = aggregatedValues.RotorSpeedMax
},
Flow = new ProcessMapReportDataSaubStatParamsDto
{
SetpointPlan = processMapPlanFilteredByDepth?.FlowPlan,
FactWavg = aggregatedValues.MaxFlow,
Limit = processMapPlanFilteredByDepth?.FlowLimitMax,
},
Rop = new PlanFactDto<double?>
{
Plan = processMapPlanFilteredByDepth?.RopPlan,
Fact = deltaDepth / aggregatedValues.DrilledTime
},
};
return result;
2024-02-14 13:43:19 +05:00
}
private static (
2024-02-14 13:43:19 +05:00
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++)
{
2024-02-14 13:43:19 +05:00
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;
}
2024-02-14 13:43:19 +05:00
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,
2024-02-14 13:43:19 +05:00
DrilledTime: drilledTime
);
}
private static bool IsNewInterval(DataSaubStatDto currentElem, DataSaubStatDto firstElem, DataSaubStatRequest request)
2024-02-14 13:43:19 +05:00
{
static bool IsNewElemBySpeed(double currentSpeed, double firstSpeed)
{
2024-02-14 13:43:19 +05:00
//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;
}
2024-02-14 13:43:19 +05:00
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));
2024-02-14 13:43:19 +05:00
return isNewElem;
}
}