DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/WellOperationsStatService.cs

277 lines
11 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 AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
class OperationParams
{
public OperationParams() { }
public OperationParams(WellOperation operation)
{
Id = operation.Id;
IdWellSectionType = operation.IdWellSectionType;
IdCategory = operation.IdCategory;
WellDepth = operation.WellDepth;
StartDate = operation.StartDate;
DurationHours = operation.DurationHours;
WellDepthReal = operation.WellDepth;
DeltaDepth = 0;
DurationToNextOperationHours = operation.DurationHours;
}
public int Id { get; }
public int IdWellSectionType { get; }
public int IdCategory { get; }
public double WellDepth { get; }
public DateTime StartDate { get; }
public double DurationHours { get; }
public double WellDepthReal { get; set; }
public double DeltaDepth { get; set; }
public double DurationToNextOperationHours { get; set; }
}
class Race
{
public DateTime StartDate { get; set; }
public double StartWellDepth { get; set; }
public DateTime EndDate { get; set; }
public double EndWellDepth { get; set; }
public double DrillingTime { get; set; }
public double NonProductiveHours { get; set; }
public double DeltaDepth => EndWellDepth - StartWellDepth;
public double DeltaHoursTimeNoNpt => (EndDate - StartDate).TotalHours - NonProductiveHours;
public double Speed => DeltaDepth / (DeltaHoursTimeNoNpt + double.Epsilon);
}
class SectionStat
{
public DateTime StartDate { get; set; }
public double StartWellDepth { get; set; }
public DateTime EndDate { get; set; }
public double EndWellDepth { get; set; }
public double AvgRaceSpeed { get; set; }
public double Rop { get; set; }
public double BhaDownSpeed { get; set; }
public double BhaUpSpeed { get; set; }
public double CasingDownSpeed { get; set; }
public int IdSectionType { get; internal set; }
public double Hours => (EndDate - StartDate).TotalHours;
}
public class WellOperationsStatService
{
private readonly IAsbCloudDbContext db;
private readonly CacheTable<WellSectionType> cachedSectionsTypes;
const int idOperationBhaAssembly = 1025;
const int idOperationBhaDisassembly = 1026;
private const int idOperationNonProductiveTime = 1043;
private const int idOperationDrilling = 1001;
private const int idOperationBhaDown = 1046;
private const int idOperationBhaUp = 1047;
private const int IdOperationCasingDown = 1048;
public WellOperationsStatService(IAsbCloudDbContext db, Cache.CacheDb cache)
{
this.db = db;
cachedSectionsTypes = cache.GetCachedTable<WellSectionType>((DbContext)db);
}
public async Task<IEnumerable<WellSectionDto>> GetSectionsByWellIdAsync(int idWell,
CancellationToken token = default)
{
var operationsAll = await db.WellOperations
.Where(o => o.IdWell == idWell)
.OrderBy(o => o.StartDate) // ускорит дальнейшие сортировки
.AsNoTracking()
.ToListAsync(token);
var operationsPlan = operationsAll
.Where(o => o.IdType == 0);
var sectionsPlan = CalcSectionsStats(operationsPlan);
var operationsFact = operationsAll
.Where(o => o.IdType == 1);
var sectionsFact = CalcSectionsStats(operationsFact);
var sectionTypesIds = operationsAll.Select(o => o.IdWellSectionType).Distinct();
var sections = new List<WellSectionDto>(sectionTypesIds.Count());
foreach (var idSectionType in sectionTypesIds)
{
var statPlan = sectionsPlan.FirstOrDefault(s => s.IdSectionType == idSectionType);
var statFact = sectionsFact.FirstOrDefault(s => s.IdSectionType == idSectionType);
WellSectionDto section = MakeWellSectionDto(idSectionType, statPlan, statFact);
sections.Add(section);
}
return sections;
}
private WellSectionDto MakeWellSectionDto(int idSectionType, SectionStat statPlan, SectionStat statFact)
{
return new WellSectionDto
{
Id = idSectionType,
SectionType = cachedSectionsTypes.FirstOrDefault(s => s.Id == idSectionType)?.Caption,
BhaDownSpeedPlan = statPlan?.BhaDownSpeed ?? double.NaN,
BhaUpSpeedPlan = statPlan?.BhaUpSpeed ?? double.NaN,
MechSpeedPlan = statPlan?.Rop ?? double.NaN,
CasingDownSpeedPlan = statPlan?.CasingDownSpeed ?? double.NaN,
RouteSpeedPlan = statPlan?.AvgRaceSpeed ?? double.NaN,
WellDepthPlan = statPlan?.EndWellDepth ?? double.NaN,
DurationPlan = statPlan?.Hours ?? double.NaN,
BhaDownSpeedFact = statFact?.BhaDownSpeed ?? double.NaN,
BhaUpSpeedFact = statFact?.BhaUpSpeed ?? double.NaN,
MechSpeedFact = statFact?.Rop ?? double.NaN,
CasingDownSpeedFact = statFact?.CasingDownSpeed ?? double.NaN,
RouteSpeedFact = statFact?.AvgRaceSpeed ?? double.NaN,
WellDepthFact = statFact?.EndWellDepth ?? double.NaN,
DurationFact = statFact?.Hours ?? double.NaN,
};
}
private static IEnumerable<SectionStat> CalcSectionsStats(IEnumerable<WellOperation> wellOperations)
{
var operations = MakeOperationsExt(wellOperations);
var sectionTypesIds = operations.Select(o => o.IdWellSectionType).Distinct();
var sectionsStats = new List<SectionStat>(sectionTypesIds.Count());
foreach (var idSection in sectionTypesIds)
{
var section = CalcSectionStat(operations, idSection);
sectionsStats.Add(section);
}
return sectionsStats;
}
private static SectionStat CalcSectionStat(IEnumerable<OperationParams> allOperations, int idSectionType)
{
var sectionOperations = allOperations
.Where(o => o.IdWellSectionType == idSectionType)
.OrderBy(o => o.StartDate)
.ThenBy(o => o.WellDepth);
var section = new SectionStat
{
IdSectionType = idSectionType,
StartDate = sectionOperations.First().StartDate,
EndDate = sectionOperations.Max(o => (o.StartDate.AddHours(o.DurationHours))),
StartWellDepth = sectionOperations.Min(o => o.WellDepthReal),
EndWellDepth = sectionOperations.Max(o => o.WellDepthReal),
AvgRaceSpeed = CalcAvgRaceSpeed(sectionOperations),
Rop = CalcROP(sectionOperations),
BhaDownSpeed = CalcSpeedByOperation(sectionOperations, idOperationBhaDown),
BhaUpSpeed = CalcSpeedByOperation(sectionOperations, idOperationBhaUp),
CasingDownSpeed = CalcSpeedByOperation(sectionOperations, IdOperationCasingDown),
};
return section;
}
private static double CalcSpeedByOperation(IEnumerable<OperationParams> operationsProps, int idOperation)
{
var ops = operationsProps.Where(o => o.IdCategory == idOperation);
var maxDepth = 0d;
var dHours = 0d;
foreach (var operation in ops)
{
if (maxDepth > operation.WellDepthReal)
maxDepth = operation.WellDepthReal;
dHours += operation.DurationHours;
}
return maxDepth / (dHours + double.Epsilon);
}
private static double CalcROP(IEnumerable<OperationParams> operationsProps)
{
var drillingOperations = operationsProps.Where(o => o.IdCategory == idOperationDrilling);
var dDepth = 0d;
var dHours = 0d;
foreach (var operation in drillingOperations)
{
dDepth += operation.DeltaDepth;
dHours += operation.DurationHours;
}
return dDepth / (dHours + double.Epsilon);
}
// Метры в час
private static double CalcAvgRaceSpeed(IEnumerable<OperationParams> operations)
{
var races = GetCompleteRaces(operations);
var dDepth = 0d;
var dHours = 0d;
foreach (var race in races)
{
dHours += race.DeltaHoursTimeNoNpt;
dDepth += race.DeltaDepth;
}
return dDepth / (dHours + double.Epsilon);
}
private static IEnumerable<OperationParams> MakeOperationsExt(IEnumerable<WellOperation> operations)
{
var count = operations.Count();
var ops = new List<OperationParams>(count);
var item = operations.ElementAt(0);
var wellDepth = item.WellDepth;
var pre = new OperationParams(item);
var current = new OperationParams(item);
for (int i = 1; i < count; i++)
{
item = operations.ElementAt(i);
current = new OperationParams(item)
{
WellDepthReal = Helper.Max(wellDepth, item.WellDepth) // TODO: учесть операциии с уменьшение глубины ствола.
};
pre.DeltaDepth = current.WellDepthReal - wellDepth;
pre.DurationToNextOperationHours = (current.StartDate - pre.StartDate).TotalHours;
ops.Add(pre);
pre = current;
}
ops.Add(current);
return ops;
}
private static IEnumerable<Race> GetCompleteRaces(IEnumerable<OperationParams> operations)
{
var races = new List<Race>(4);
var iterator = operations.GetEnumerator();
while (iterator.MoveNext())
{
if (iterator.Current.IdCategory == idOperationBhaAssembly)
{
var race = new Race
{
StartDate = iterator.Current.StartDate.AddHours(iterator.Current.DurationHours),
StartWellDepth = iterator.Current.WellDepthReal
};
while (iterator.MoveNext())
{
if (iterator.Current.IdCategory == idOperationNonProductiveTime)
{
race.NonProductiveHours += iterator.Current.DurationHours;
}
if (iterator.Current.IdCategory == idOperationBhaDisassembly)
{
race.EndDate = iterator.Current.StartDate.AddHours(iterator.Current.DurationHours);
race.EndWellDepth = iterator.Current.WellDepthReal;
races.Add(race);
}
}
}
}
return races;
}
}
}