DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatService.cs
2024-02-14 10:51:20 +05:00

339 lines
16 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.ProcessMapPlan;
using AsbCloudApp.Data.ProcessMaps.Report;
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 ProcessMapReportDataSaubStatService : IProcessMapReportDataSaubStatService
{
private readonly IWellService wellService;
private readonly IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanBaseRepository;
private readonly IDataSaubStatRepository dataSaubStatRepository;
private readonly IWellOperationRepository wellOperationRepository;
public ProcessMapReportDataSaubStatService(IWellService wellService,
IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanBaseRepository,
IDataSaubStatRepository dataSaubStatRepository,
IWellOperationRepository wellOperationRepository
)
{
this.wellService = wellService;
this.processMapPlanBaseRepository = processMapPlanBaseRepository;
this.dataSaubStatRepository = dataSaubStatRepository;
this.wellOperationRepository = wellOperationRepository;
}
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 processMapPlanWellDrillings = await processMapPlanBaseRepository.Get(requestProcessMapPlan, token);
if (!processMapPlanWellDrillings.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var geDepth = processMapPlanWellDrillings.Min(p => p.DepthStart);
var leDepth = processMapPlanWellDrillings.Max(p => p.DepthEnd);
var requestWellOperationFact = new WellOperationRequest()
{
IdWell = idWell,
OperationType = WellOperation.IdOperationTypeFact,
GeDepth = geDepth,
LeDepth = leDepth
};
var wellOperations = await wellOperationRepository
.GetAsync(requestWellOperationFact, token);
if (!wellOperations.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var dataSaubStats =
(await dataSaubStatRepository.GetAsync(well.IdTelemetry.Value, geDepth, leDepth, token)).ToArray();
if (!dataSaubStats.Any())
return Enumerable.Empty<ProcessMapReportDataSaubStatDto>();
var wellOperationCategories = wellOperationRepository.GetCategories(false);
var result = CalcByIntervals(request, processMapPlanWellDrillings, dataSaubStats, wellOperations, wellOperationCategories);
return result;
}
private IEnumerable<ProcessMapReportDataSaubStatDto> CalcByIntervals(
DataSaubStatRequest request,
IEnumerable<ProcessMapPlanDrillingDto> processMapPlanWellDrillings,
Span<DataSaubStatDto> dataSaubStats,
IEnumerable<WellOperationDto> wellOperations,
IEnumerable<WellOperationCategoryDto> wellOperationCategories
)
{
var list = new List<ProcessMapReportDataSaubStatDto>();
var firstElemInInterval = dataSaubStats[0];
var indexStart = 0;
for (var i = 1; i < dataSaubStats.Length; i++)
{
var currentElem = dataSaubStats[i];
if (IsNewInterval(currentElem, firstElemInInterval, request) || i == dataSaubStats.Length - 1)
{
var length = i - indexStart;
var span = dataSaubStats.Slice(indexStart, length);
indexStart = i;
firstElemInInterval = currentElem;
var firstElemInSpan = span[0];
var lastElemInISpan = span[^1];
var nearestOperation = wellOperations.MinBy(o => firstElemInSpan.DateStart - o.DateStart);
if (nearestOperation is null)
continue;
var processMapPlanFilteredByDepth = processMapPlanWellDrillings
.Where(x => x.IdWellSectionType == nearestOperation.IdWellSectionType)
.Where(x => x.DepthStart >= firstElemInSpan.DepthStart)
.Where(x => x.DepthEnd <= lastElemInISpan.DepthEnd)
.WhereActualAtMoment(DateTimeOffset.Now)
.ToArray();
if (!processMapPlanFilteredByDepth.Any())
continue;
var wellOperationCategoryName = wellOperationCategories.
Where(c => c.Id == currentElem.IdCategory)
.FirstOrDefault()
?.Name ?? string.Empty;
var elem = CalcStat(processMapPlanFilteredByDepth, span, nearestOperation, wellOperationCategoryName);
if (elem is not null)
list.Add(elem);
}
}
return list;
}
private ProcessMapReportDataSaubStatDto? CalcStat(
ProcessMapPlanDrillingDto[] processMapPlanFilteredByDepth,
Span<DataSaubStatDto> span,
WellOperationDto nearestOperation,
string wellOperationCategoryName
)
{
var firstElemInInterval = span[0];
var lastElemInInterval = span[^1];
var deltaDepth = lastElemInInterval.DepthEnd - firstElemInInterval.DepthStart;
var aggregatedValues = CalcAggregate(span);
return new ProcessMapReportDataSaubStatDto()
{
DateStart = firstElemInInterval.DateStart.DateTime,
WellSectionTypeName = nearestOperation.WellSectionTypeName ?? string.Empty,
DepthStart = firstElemInInterval.DepthStart,
DepthEnd = lastElemInInterval.DepthEnd,
DeltaDepth = deltaDepth,
DrilledTime = aggregatedValues.DrilledTime,
DrillingMode = wellOperationCategoryName,
PressureDiff = new ProcessMapReportDataSaubStatParamsDto()
{
SetpointPlanMax = processMapPlanFilteredByDepth.Max(p => p.DeltaPressurePlan),
SetpointPlanMin = processMapPlanFilteredByDepth.Min(p => p.DeltaPressurePlan),
SetpointFact = firstElemInInterval.PressureSp - firstElemInInterval.PressureIdle,
FactWavg = aggregatedValues.Pressure,
Limit = processMapPlanFilteredByDepth.Max(p => p.DeltaPressureLimitMax),
SetpointUsage = aggregatedValues.SetpointUsagePressure
},
AxialLoad = new ProcessMapReportDataSaubStatParamsDto()
{
SetpointPlanMax = processMapPlanFilteredByDepth.Max(p => p.AxialLoadPlan),
SetpointPlanMin = processMapPlanFilteredByDepth.Min(p => p.AxialLoadPlan),
SetpointFact = aggregatedValues.AxialLoadSp,
FactWavg = aggregatedValues.AxialLoad,
Limit = processMapPlanFilteredByDepth.Max(p => p.AxialLoadLimitMax),
SetpointUsage = aggregatedValues.SetpointUsageAxialLoad
},
TopDriveTorque = new ProcessMapReportDataSaubStatParamsDto()
{
SetpointPlanMax = processMapPlanFilteredByDepth.Max(p => p.TopDriveTorquePlan),
SetpointPlanMin = processMapPlanFilteredByDepth.Min(p => p.TopDriveTorquePlan),
SetpointFact = aggregatedValues.RotorTorqueSp,
FactWavg = aggregatedValues.RotorTorque,
FactMax = aggregatedValues.RotorTorqueMax,
Limit = processMapPlanFilteredByDepth.Max(p => p.TopDriveTorqueLimitMax),
SetpointUsage = aggregatedValues.SetpointUsageRotorTorque
},
SpeedLimit = new ProcessMapReportDataSaubStatParamsDto
{
SetpointPlanMax = processMapPlanFilteredByDepth.Max(p => p.RopPlan),
SetpointPlanMin = processMapPlanFilteredByDepth.Min(p => p.RopPlan),
SetpointFact = aggregatedValues.BlockSpeedSp,
FactWavg = deltaDepth / aggregatedValues.DrilledTime,
SetpointUsage = aggregatedValues.SetpointUsageRopPlan
},
Turnover = new ProcessMapReportDataSaubStatParamsDto
{
SetpointPlanMax = processMapPlanFilteredByDepth.Max(p => p.TopDriveSpeedPlan),
SetpointPlanMin = processMapPlanFilteredByDepth.Min(p => p.TopDriveSpeedPlan),
FactWavg = aggregatedValues.RotorSpeed,
FactMax = aggregatedValues.RotorSpeedMax
},
Flow = new ProcessMapReportDataSaubStatParamsDto
{
SetpointPlanMax = processMapPlanFilteredByDepth.Max(p => p.FlowPlan),
SetpointPlanMin = processMapPlanFilteredByDepth.Min(p => p.FlowPlan),
FactWavg = aggregatedValues.MaxFlow,
Limit = processMapPlanFilteredByDepth.Max(p => p.FlowLimitMax),
},
Rop = new PlanFactDto<double?>
{
Plan = CalcRopPlan(processMapPlanFilteredByDepth),
Fact = deltaDepth / aggregatedValues.DrilledTime
},
};
}
private (
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 / diffDepthTotal,
SetpointUsageAxialLoad: sumDiffDepthByAxialLoad / diffDepthTotal,
SetpointUsageRotorTorque: sumDiffDepthByRotorTorque / diffDepthTotal,
SetpointUsageRopPlan: sumDiffDepthByRopPlan / diffDepthTotal,
DrilledTime: drilledTime
);
}
private double CalcRopPlan(ProcessMapPlanDrillingDto[] processMapPlanFilteredByDepth)
{
var sumRopPlan = 0.0;
var diffDepthTotal = 0.0;
for (var i = 0; i < processMapPlanFilteredByDepth.Length; i++)
{
var diffDepth = processMapPlanFilteredByDepth[i].DepthEnd - processMapPlanFilteredByDepth[i].DepthStart;
sumRopPlan += diffDepth * processMapPlanFilteredByDepth[i].RopPlan;
diffDepthTotal += diffDepth;
}
return sumRopPlan / diffDepthTotal;
}
private bool IsNewInterval(DataSaubStatDto currentElem, DataSaubStatDto firstElem, DataSaubStatRequest request)
{
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;
}
}
}