forked from ddrilling/AsbCloudServer
Рефакторинг отчета РТК бурение
This commit is contained in:
parent
4bd4deafa4
commit
14ea9c06f5
@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using AsbCloudApp.Data.ProcessMaps.Report;
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ProcessMaps.WellDrillingProcessMap.Report.Data;
|
||||
|
||||
internal class ParamStat
|
||||
{
|
||||
private double spWSum;
|
||||
private double pvWSum;
|
||||
private double limitMaxWSum;
|
||||
|
||||
private double deltaDepthSum;
|
||||
|
||||
private readonly Func<TelemetryDataSaubStatDto, double> getterSp;
|
||||
private readonly Func<TelemetryDataSaubStatDto, double> getterPv;
|
||||
private readonly Func<TelemetryDataSaubStatDto, double>? getterLimitMax;
|
||||
|
||||
private readonly int idFeedRegulator;
|
||||
private readonly int idMode;
|
||||
private TelemetryDataSaubStatDto? previous;
|
||||
|
||||
public double SpUsageDepth { get; private set; }
|
||||
private static double spUsageTotal;
|
||||
|
||||
public ParamStat(Func<TelemetryDataSaubStatDto, double> getterSp,
|
||||
Func<TelemetryDataSaubStatDto, double> getterPv,
|
||||
Func<TelemetryDataSaubStatDto, double>? getterLimitMax,
|
||||
int idFeedRegulator,
|
||||
int idMode)
|
||||
{
|
||||
this.getterSp = getterSp;
|
||||
this.getterPv = getterPv;
|
||||
this.getterLimitMax = getterLimitMax;
|
||||
this.idFeedRegulator = idFeedRegulator;
|
||||
this.idMode = idMode;
|
||||
spUsageTotal = 0d;
|
||||
}
|
||||
|
||||
public void UpdateStat(TelemetryDataSaubStatDto current)
|
||||
{
|
||||
if (previous is not null)
|
||||
{
|
||||
var deltaDepth = current.WellDepthMin - previous.WellDepthMin;
|
||||
if (deltaDepth > 0)
|
||||
{
|
||||
var deltaDepthHalf = deltaDepth / 2;
|
||||
|
||||
double CalculateWeight(Func<TelemetryDataSaubStatDto, double> getter) =>
|
||||
(getter(previous!) + getter(current)) * deltaDepthHalf;
|
||||
|
||||
spWSum += CalculateWeight(getterSp);
|
||||
pvWSum += CalculateWeight(getterPv);
|
||||
if (getterLimitMax is not null)
|
||||
limitMaxWSum += CalculateWeight(getterLimitMax!);
|
||||
|
||||
if (current.IdFeedRegulator is not null)
|
||||
{
|
||||
if (current.IdFeedRegulator == idFeedRegulator)
|
||||
{
|
||||
SpUsageDepth += deltaDepth;
|
||||
spUsageTotal += deltaDepth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var pvErr = (getterSp(current) - getterPv(current)) / getterSp(current);
|
||||
if (pvErr < 0.03d) //3%
|
||||
{
|
||||
SpUsageDepth += deltaDepth;
|
||||
spUsageTotal += deltaDepth;
|
||||
}
|
||||
}
|
||||
|
||||
deltaDepthSum += deltaDepth;
|
||||
}
|
||||
}
|
||||
|
||||
previous = current;
|
||||
}
|
||||
|
||||
public WellDrillingProcessMapReportParamsDto MakeParams(double? spPlan)
|
||||
{
|
||||
var result = new WellDrillingProcessMapReportParamsDto
|
||||
{
|
||||
SetpointPlan = spPlan,
|
||||
Fact = DivideValByDepth(pvWSum),
|
||||
};
|
||||
|
||||
if (idMode == 0)
|
||||
{
|
||||
result.SetpointFact = null;
|
||||
result.Limit = null;
|
||||
result.SetpointUsage = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.SetpointFact = DivideValByDepth(spWSum);
|
||||
result.Limit = getterLimitMax is not null ? DivideValByDepth(limitMaxWSum) : null;
|
||||
result.SetpointUsage = deltaDepthSum > 0d ? 100d * SpUsageDepth / spUsageTotal : null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private double? DivideValByDepth(double? val)
|
||||
{
|
||||
if (val is null || val == 0d || deltaDepthSum == 0d)
|
||||
return null;
|
||||
return val / deltaDepthSum;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ProcessMaps.WellDrillingProcessMap.Report.Data;
|
||||
|
||||
internal class TelemetryStat
|
||||
{
|
||||
public ParamStat Pressure { get; }
|
||||
public ParamStat AxialLoad { get; }
|
||||
public ParamStat RotorTorque { get; }
|
||||
public ParamStat BlockSpeed { get; }
|
||||
|
||||
private TelemetryDataSaubStatDto? previous;
|
||||
private double depthSum = 0d;
|
||||
private double hoursSum = 0d;
|
||||
|
||||
public double? Rop => hoursSum == 0d ? null : depthSum / hoursSum;
|
||||
|
||||
private double depthWithSaub = 0d;
|
||||
public double UsageSaub { get; }
|
||||
public double UsagePredictPlan { get; }
|
||||
public DateTime DateStart { get; }
|
||||
public float DeltaDepth { get; }
|
||||
public int IdMode { get; }
|
||||
public string ModeName { get; }
|
||||
public double MechDrillingHours { get; }
|
||||
|
||||
public TelemetryStat(Span<TelemetryDataSaubStatDto> telemetry)
|
||||
{
|
||||
var telemetryFirst = telemetry[0];
|
||||
var telemetryLast = telemetry[^1];
|
||||
|
||||
IdMode = telemetryFirst.IdMode;
|
||||
ModeName = GetModeName(IdMode);
|
||||
DateStart = telemetryFirst.DateMin;
|
||||
DeltaDepth = telemetryLast.WellDepthMax - telemetryFirst.WellDepthMin;
|
||||
MechDrillingHours = (telemetryLast.DateMax - telemetryFirst.DateMin).TotalHours;
|
||||
|
||||
BlockSpeed = new(t => t.BlockSpeedSp, t => t.BlockSpeed, null, 1, IdMode);
|
||||
Pressure = new(t => t.PressureSpDelta, t => t.PressureDelta, t => t.PressureDeltaLimitMax, 2, IdMode);
|
||||
RotorTorque = new(t => t.RotorTorqueSp, t => t.RotorTorque, t => t.RotorTorqueLimitMax, 3, IdMode);
|
||||
AxialLoad = new(t => t.AxialLoadSp, t => t.AxialLoad, t => t.AxialLoadLimitMax, 4, IdMode);
|
||||
|
||||
foreach (var t in telemetry)
|
||||
UpdateStat(t);
|
||||
|
||||
UsageSaub = 100d * depthWithSaub / depthSum;
|
||||
UsagePredictPlan = IdMode != 0 ? 100d : 0d;
|
||||
}
|
||||
|
||||
private void UpdateStat(TelemetryDataSaubStatDto current)
|
||||
{
|
||||
if (previous is not null)
|
||||
{
|
||||
var deltaDepth = current.WellDepthMin - previous.WellDepthMin;
|
||||
|
||||
if (deltaDepth > 0)
|
||||
{
|
||||
var deltaHours = (current.DateMin - previous.DateMax).TotalHours;
|
||||
depthSum += deltaDepth;
|
||||
hoursSum += deltaHours;
|
||||
|
||||
if (current.IdMode == 1 || current.IdMode == 3)
|
||||
depthWithSaub += deltaDepth;
|
||||
}
|
||||
}
|
||||
|
||||
previous = current;
|
||||
Pressure.UpdateStat(current);
|
||||
AxialLoad.UpdateStat(current);
|
||||
RotorTorque.UpdateStat(current);
|
||||
BlockSpeed.UpdateStat(current);
|
||||
}
|
||||
|
||||
private static string GetModeName(int idMode)
|
||||
=> idMode switch
|
||||
{
|
||||
1 => "Ротор",
|
||||
3 => "Слайд",
|
||||
_ => "Ручной",
|
||||
};
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.ProcessMaps.Report;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.ProcessMaps;
|
||||
using AsbCloudApp.Services.ProcessMaps.WellDrillingProcessMap;
|
||||
using ClosedXML.Excel;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ProcessMaps.WellDrillingProcessMap.Report;
|
||||
|
||||
public class WellDrillingProcessMapReportExportService : IProcessMapReportExportService
|
||||
{
|
||||
const int firstColumn = 2;
|
||||
const int lastColumn = 42;
|
||||
|
||||
const int headerRowsCount = 5;
|
||||
|
||||
private readonly IWellService wellService;
|
||||
private readonly IWellDrillingProcessMapReportService wellDrillingProcessMapReportService;
|
||||
|
||||
public WellDrillingProcessMapReportExportService(IWellService wellService,
|
||||
IWellDrillingProcessMapReportService wellDrillingProcessMapReportService)
|
||||
{
|
||||
this.wellService = wellService;
|
||||
this.wellDrillingProcessMapReportService = wellDrillingProcessMapReportService;
|
||||
}
|
||||
|
||||
|
||||
public async Task<(string Name, Stream File)?> ExportAsync(int idWell, CancellationToken cancellationToken)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken);
|
||||
|
||||
if (well is null)
|
||||
return null;
|
||||
|
||||
var stream = GetExcelTemplateStream();
|
||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
||||
|
||||
var data = await wellDrillingProcessMapReportService.GetAsync(idWell, cancellationToken);
|
||||
|
||||
FillProcessMapToWorkbook(workbook, data);
|
||||
|
||||
MemoryStream memoryStream = new();
|
||||
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
var name = $"РТК бурение. Отчёт по скважине {well.Caption} куст {well.Cluster}.xlsx";
|
||||
|
||||
return (name, memoryStream);
|
||||
}
|
||||
|
||||
private static void FillProcessMapToWorkbook(XLWorkbook workbook,
|
||||
IEnumerable<WellDrillingProcessMapReportDto> data)
|
||||
{
|
||||
var sheet = workbook.Worksheets.FirstOrDefault();
|
||||
if (sheet is null)
|
||||
return;
|
||||
var dataBySections = data.GroupBy(p => p.IdWellSectionType);
|
||||
FillSheet(sheet, dataBySections);
|
||||
}
|
||||
|
||||
private static void FillSheet(IXLWorksheet sheet,
|
||||
IEnumerable<IGrouping<int, WellDrillingProcessMapReportDto>> dataBySections)
|
||||
{
|
||||
var startRow = headerRowsCount + 1;
|
||||
foreach (var sectionData in dataBySections)
|
||||
{
|
||||
if (sectionData.Any())
|
||||
startRow = FillSection(sheet, sectionData, startRow);
|
||||
}
|
||||
}
|
||||
|
||||
private static int FillSection(IXLWorksheet sheet, IGrouping<int, WellDrillingProcessMapReportDto> sectionData,
|
||||
int row)
|
||||
{
|
||||
var rowStart = row;
|
||||
var sectionName = sectionData.FirstOrDefault()?.WellSectionTypeName
|
||||
?? sectionData.Key.ToString();
|
||||
|
||||
sheet.Range(row, firstColumn, row, lastColumn)
|
||||
.Merge()
|
||||
.FirstCell()
|
||||
.SetVal(sectionName)
|
||||
.Style
|
||||
.Fill.SetBackgroundColor(XLColor.LightGray);
|
||||
row++;
|
||||
foreach (var interval in sectionData)
|
||||
row = FillIntervalData(sheet, interval, row);
|
||||
|
||||
var sectionStyle = sheet.Range(rowStart, firstColumn, row - 1, lastColumn).Style;
|
||||
SetBorders(sectionStyle);
|
||||
return row;
|
||||
}
|
||||
|
||||
private static int FillIntervalData(IXLWorksheet sheet, WellDrillingProcessMapReportDto interval, int row)
|
||||
{
|
||||
const int columnDepth = firstColumn + 1;
|
||||
const int columnDate = firstColumn + 2;
|
||||
const int columnRopTime = firstColumn + 3;
|
||||
const int columnMode = firstColumn + 4;
|
||||
|
||||
sheet.Cell(row, firstColumn)
|
||||
.SetVal(interval.DepthStart, "0.0");
|
||||
|
||||
sheet.Cell(row, columnDepth)
|
||||
.SetVal(interval.DepthEnd, "0.0");
|
||||
|
||||
sheet.Cell(row, columnDate)
|
||||
.SetVal(interval.DateStart);
|
||||
|
||||
sheet.Cell(row, columnRopTime)
|
||||
.SetVal(interval.MechDrillingHours);
|
||||
|
||||
row = FillIntervalModeData(sheet, interval, columnMode, row);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
private static int FillIntervalModeData(IXLWorksheet sheet, WellDrillingProcessMapReportDto modeData,
|
||||
int column, int row)
|
||||
{
|
||||
int columnDeltaDepth = column + 1;
|
||||
int columnPressure = columnDeltaDepth + 1;
|
||||
int columnLoad = columnPressure + 5;
|
||||
int columnTorque = columnLoad + 5;
|
||||
int columnSpeed = columnTorque + 5;
|
||||
int columnUsagePlan = columnSpeed + 5;
|
||||
int columnUsageFact = columnUsagePlan + 1;
|
||||
int columnRop = columnUsageFact + 12;
|
||||
|
||||
sheet.Cell(row, column)
|
||||
.SetVal(modeData.DrillingMode);
|
||||
|
||||
sheet.Cell(row, columnDeltaDepth)
|
||||
.SetVal(modeData.DeltaDepth);
|
||||
|
||||
FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row);
|
||||
FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row);
|
||||
FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row);
|
||||
FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row);
|
||||
|
||||
sheet.Cell(row, columnUsagePlan)
|
||||
.SetVal(modeData.UsagePlan);
|
||||
|
||||
sheet.Cell(row, columnUsageFact)
|
||||
.SetVal(modeData.UsageFact);
|
||||
|
||||
sheet.Cell(row, columnRop)
|
||||
.SetVal(modeData.Rop);
|
||||
|
||||
return row + 1;
|
||||
}
|
||||
|
||||
private static void FillIntervalModeDataParam(IXLWorksheet sheet,
|
||||
WellDrillingProcessMapReportParamsDto dataParam, int column, int row)
|
||||
{
|
||||
const int columnOffsetSpPlan = 0;
|
||||
const int columnOffsetSpFact = 1;
|
||||
const int columnOffsetFact = 2;
|
||||
const int columnOffsetLimit = 3;
|
||||
const int columnOffsetPercent = 4;
|
||||
|
||||
sheet.Cell(row, column + columnOffsetSpPlan)
|
||||
.SetVal(dataParam.SetpointPlan);
|
||||
|
||||
sheet.Cell(row, column + columnOffsetSpFact)
|
||||
.SetVal(dataParam.SetpointFact);
|
||||
|
||||
sheet.Cell(row, column + columnOffsetFact)
|
||||
.SetVal(dataParam.Fact);
|
||||
|
||||
sheet.Cell(row, column + columnOffsetLimit)
|
||||
.SetVal(dataParam.Limit);
|
||||
|
||||
sheet.Cell(row, column + columnOffsetPercent)
|
||||
.SetVal(dataParam.SetpointUsage, format: "0.0");
|
||||
}
|
||||
|
||||
private static void FillIntervalModeDataSpeed(IXLWorksheet sheet,
|
||||
WellDrillingProcessMapReportParamsDto dataParam, int column, int row)
|
||||
{
|
||||
const int columnOffsetSpPlan = 0;
|
||||
const int columnOffsetSpFact = 1;
|
||||
const int columnOffsetFact = 2;
|
||||
const int columnOffsetLimit = 3;
|
||||
const int columnOffsetPercent = 4;
|
||||
|
||||
sheet.Cell(row, column + columnOffsetSpPlan)
|
||||
.SetVal(dataParam.SetpointPlan);
|
||||
|
||||
sheet.Cell(row, column + columnOffsetSpFact)
|
||||
.SetVal(dataParam.SetpointFact);
|
||||
|
||||
sheet.Cell(row, column + columnOffsetFact)
|
||||
.SetVal(dataParam.Fact);
|
||||
|
||||
sheet.Cell(row, column + columnOffsetLimit)
|
||||
.SetVal(dataParam.Limit);
|
||||
|
||||
sheet.Cell(row, column + columnOffsetPercent)
|
||||
.SetVal(dataParam.SetpointUsage, format: "0.0");
|
||||
}
|
||||
|
||||
private static Stream GetExcelTemplateStream()
|
||||
{
|
||||
var stream = Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceStream(
|
||||
"AsbCloudInfrastructure.Services.ProcessMaps.Files.DrillingProcessMapReportTemplate.xlsx");
|
||||
|
||||
return stream!;
|
||||
}
|
||||
|
||||
private static void SetBorders(IXLStyle style)
|
||||
{
|
||||
style.Border.RightBorder = XLBorderStyleValues.Thin;
|
||||
style.Border.LeftBorder = XLBorderStyleValues.Thin;
|
||||
style.Border.TopBorder = XLBorderStyleValues.Thin;
|
||||
style.Border.BottomBorder = XLBorderStyleValues.Thin;
|
||||
style.Border.InsideBorder = XLBorderStyleValues.Thin;
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.ProcessMaps;
|
||||
using AsbCloudApp.Data.ProcessMaps.Report;
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.ProcessMaps.WellDrillingProcessMap;
|
||||
using AsbCloudInfrastructure.Services.ProcessMaps.WellDrillingProcessMap.Report.Data;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ProcessMaps.WellDrillingProcessMap.Report;
|
||||
|
||||
public class WellDrillingProcessMapReportService : IWellDrillingProcessMapReportService
|
||||
{
|
||||
private readonly IWellService wellService;
|
||||
private readonly IWellDrillingProcessMapRepository wellDrillingProcessMapRepository;
|
||||
private readonly ITelemetryDataSaubService telemetryDataSaubService;
|
||||
private readonly IWellOperationRepository wellOperationRepository;
|
||||
|
||||
public WellDrillingProcessMapReportService(IWellService wellService,
|
||||
IWellDrillingProcessMapRepository wellDrillingProcessMapRepository,
|
||||
ITelemetryDataSaubService telemetryDataSaubService,
|
||||
IWellOperationRepository wellOperationRepository)
|
||||
{
|
||||
this.wellService = wellService;
|
||||
this.wellDrillingProcessMapRepository = wellDrillingProcessMapRepository;
|
||||
this.telemetryDataSaubService = telemetryDataSaubService;
|
||||
this.wellOperationRepository = wellOperationRepository;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<WellDrillingProcessMapReportDto>> GetAsync(int idWell,
|
||||
CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважина с Id: {idWell} не найдена");
|
||||
|
||||
if (!well.IdTelemetry.HasValue)
|
||||
throw new ArgumentInvalidException(nameof(idWell), $"Скважина с Id: {idWell} не имеет телеметрии");
|
||||
|
||||
var wellDrillingProcessMaps = await wellDrillingProcessMapRepository.GetByIdWellAsync(idWell, token);
|
||||
|
||||
if (!wellDrillingProcessMaps.Any())
|
||||
return Enumerable.Empty<WellDrillingProcessMapReportDto>();
|
||||
|
||||
var telemetryDataStat =
|
||||
(await telemetryDataSaubService.GetTelemetryDataStatAsync(well.IdTelemetry.Value, token)).ToArray();
|
||||
|
||||
if (!telemetryDataStat.Any())
|
||||
return Enumerable.Empty<WellDrillingProcessMapReportDto>();
|
||||
|
||||
var result = CalcByIntervals(wellDrillingProcessMaps, telemetryDataStat);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private IEnumerable<WellDrillingProcessMapReportDto> CalcByIntervals(
|
||||
IEnumerable<WellDrillingProcessMapDto> wellDrillingProcessMaps,
|
||||
TelemetryDataSaubStatDto[] telemetryDataStat)
|
||||
{
|
||||
var processMapIntervals = CalcDepthIntervals(wellDrillingProcessMaps);
|
||||
|
||||
var result = new List<WellDrillingProcessMapReportDto>(processMapIntervals.Count() * 4);
|
||||
|
||||
var telemetryIndexStart =
|
||||
Array.FindIndex(telemetryDataStat, t => t.WellDepthMin >= processMapIntervals.First().DepthStart);
|
||||
if (telemetryIndexStart < 0)
|
||||
return Enumerable.Empty<WellDrillingProcessMapReportDto>();
|
||||
|
||||
IDictionary<int, string> sectionTypes = wellOperationRepository
|
||||
.GetSectionTypes()
|
||||
.ToDictionary(s => s.Id, s => s.Caption);
|
||||
|
||||
foreach (var interval in processMapIntervals)
|
||||
{
|
||||
var processMapPlanInterval = wellDrillingProcessMaps
|
||||
.Where(p => p.DepthStart <= interval.DepthEnd && p.DepthEnd >= interval.DepthStart);
|
||||
|
||||
if (!processMapPlanInterval.Any())
|
||||
continue;
|
||||
|
||||
var telemetryIndexEnd = Array.FindIndex(telemetryDataStat, telemetryIndexStart,
|
||||
t => t.WellDepthMin >= interval.DepthEnd);
|
||||
if (telemetryIndexEnd < 0)
|
||||
telemetryIndexEnd = telemetryDataStat.Length - 1;
|
||||
var telemetryDataInterval =
|
||||
telemetryDataStat.AsSpan(telemetryIndexStart, telemetryIndexEnd - telemetryIndexStart);
|
||||
|
||||
IEnumerable<WellDrillingProcessMapReportDto> subIntervalsResult =
|
||||
CalcSubIntervals(interval, processMapPlanInterval, telemetryDataInterval, sectionTypes);
|
||||
|
||||
result.AddRange(subIntervalsResult);
|
||||
telemetryIndexStart = telemetryIndexEnd;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<(double DepthStart, double DepthEnd)> CalcDepthIntervals(
|
||||
IEnumerable<WellDrillingProcessMapDto> wellDrillingProcessMaps)
|
||||
{
|
||||
if (!wellDrillingProcessMaps.Any())
|
||||
yield break;
|
||||
|
||||
var intervalStarts = wellDrillingProcessMaps
|
||||
.OrderBy(i => i.DepthStart)
|
||||
.Select(p => p.DepthStart)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
for (var i = 1; i < intervalStarts.Length; i++)
|
||||
yield return (intervalStarts[i - 1], intervalStarts[i]);
|
||||
|
||||
yield return (intervalStarts[^1], wellDrillingProcessMaps.Max(p => p.DepthEnd));
|
||||
}
|
||||
|
||||
private static IEnumerable<WellDrillingProcessMapReportDto> CalcSubIntervals(
|
||||
(double DepthStart, double DepthEnd) interval,
|
||||
IEnumerable<WellDrillingProcessMapDto> wellDrillingProcessMapInterval,
|
||||
Span<TelemetryDataSaubStatDto> telemetryDataInterval,
|
||||
IDictionary<int, string> sectionTypes)
|
||||
{
|
||||
var telemetryDataIntervalLength = telemetryDataInterval.Length;
|
||||
if (telemetryDataInterval.Length == 0)
|
||||
return Enumerable.Empty<WellDrillingProcessMapReportDto>();
|
||||
|
||||
var result = new List<WellDrillingProcessMapReportDto>();
|
||||
var telemetryIndexStart = 0;
|
||||
var subInterval = interval;
|
||||
|
||||
for (var i = telemetryIndexStart + 1; i < telemetryDataIntervalLength; i++)
|
||||
{
|
||||
if (IsDifferent(telemetryDataInterval[telemetryIndexStart], telemetryDataInterval[i]))
|
||||
{
|
||||
subInterval.DepthEnd = telemetryDataInterval[i - 1].WellDepthMax;
|
||||
var telemetryRowSpan = telemetryDataInterval[telemetryIndexStart..(i - 1)];
|
||||
|
||||
if (!telemetryRowSpan.IsEmpty)
|
||||
{
|
||||
var intervalReportRow = CalcSubIntervalReportRow(subInterval, wellDrillingProcessMapInterval,
|
||||
telemetryRowSpan, sectionTypes);
|
||||
result.Add(intervalReportRow);
|
||||
}
|
||||
|
||||
telemetryIndexStart = i;
|
||||
subInterval.DepthStart = subInterval.DepthEnd;
|
||||
}
|
||||
}
|
||||
|
||||
subInterval.DepthEnd = interval.DepthEnd;
|
||||
var intervalReportRowLast = CalcSubIntervalReportRow(subInterval, wellDrillingProcessMapInterval,
|
||||
telemetryDataInterval[telemetryIndexStart..telemetryDataIntervalLength], sectionTypes);
|
||||
result.Add(intervalReportRowLast);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static WellDrillingProcessMapReportDto CalcSubIntervalReportRow(
|
||||
(double DepthStart, double DepthEnd) subInterval,
|
||||
IEnumerable<WellDrillingProcessMapDto> wellDrillingProcessMaps,
|
||||
Span<TelemetryDataSaubStatDto> telemetryRowSpan,
|
||||
IDictionary<int, string> sectionTypes)
|
||||
{
|
||||
var telemetryStat = new TelemetryStat(telemetryRowSpan);
|
||||
var processMapByMode = wellDrillingProcessMaps.FirstOrDefault(p => p.IdMode == telemetryStat.IdMode);
|
||||
var processMapFirst = wellDrillingProcessMaps.First();
|
||||
var idWellSectionType = processMapByMode?.IdWellSectionType ?? processMapFirst.IdWellSectionType;
|
||||
|
||||
var result = new WellDrillingProcessMapReportDto
|
||||
{
|
||||
IdWell = processMapByMode?.IdWell ?? processMapFirst.IdWell,
|
||||
IdWellSectionType = idWellSectionType,
|
||||
WellSectionTypeName = sectionTypes[idWellSectionType],
|
||||
|
||||
DepthStart = subInterval.DepthStart,
|
||||
DepthEnd = subInterval.DepthEnd,
|
||||
DateStart = telemetryStat.DateStart,
|
||||
|
||||
MechDrillingHours = telemetryStat.MechDrillingHours,
|
||||
DrillingMode = telemetryStat.ModeName,
|
||||
|
||||
DeltaDepth = telemetryStat.DeltaDepth,
|
||||
|
||||
PressureDiff = telemetryStat.Pressure.MakeParams(processMapByMode?.Pressure.Plan),
|
||||
AxialLoad = telemetryStat.AxialLoad.MakeParams(processMapByMode?.AxialLoad.Plan),
|
||||
TopDriveTorque = telemetryStat.RotorTorque.MakeParams(processMapByMode?.TopDriveTorque.Plan),
|
||||
SpeedLimit = telemetryStat.BlockSpeed.MakeParams(processMapByMode?.RopPlan),
|
||||
|
||||
Rop = telemetryStat.Rop,
|
||||
UsagePlan = processMapByMode?.UsageSaub ?? telemetryStat.UsagePredictPlan,
|
||||
UsageFact = telemetryStat.UsageSaub,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool IsDifferent(TelemetryDataSaubStatDto intervalStart, TelemetryDataSaubStatDto current)
|
||||
{
|
||||
if (intervalStart.WellDepthMin > current.WellDepthMin)
|
||||
return true;
|
||||
|
||||
if (intervalStart.IdMode != current.IdMode)
|
||||
return true;
|
||||
|
||||
if (Math.Abs(intervalStart.PressureSp - current.PressureSp) > 5d)
|
||||
return true;
|
||||
|
||||
if (Math.Abs(intervalStart.AxialLoadSp - current.AxialLoadSp) > 1d)
|
||||
return true;
|
||||
|
||||
if (Math.Abs(intervalStart.RotorTorqueSp - current.RotorTorqueSp) > 5d)
|
||||
return true;
|
||||
|
||||
var blockSpeedSpDiff = Math.Abs(intervalStart.BlockSpeedSp - current.BlockSpeedSp);
|
||||
if (!(blockSpeedSpDiff > 5d))
|
||||
return false;
|
||||
|
||||
switch (intervalStart.BlockSpeedSp)
|
||||
{
|
||||
case <= 30:
|
||||
case > 30 when blockSpeedSpDiff > 15d:
|
||||
case > 80 when blockSpeedSpDiff > 20d:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user