DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/WellOperationsStatService.cs
2021-08-24 16:47:10 +05:00

281 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 AsbCloudApp.Services;
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;
Start = operation.StartDate;
DurationHours = operation.DurationHours;
WellDepthReal = operation.WellDepth;
DeltaDepth = 0;
DurationToNextOperationHours = operation.DurationHours;
}
public int IdWellSectionType { get; }
public int IdCategory { get; }
public int Id { get; }
public DateTime Start { get; }
public double WellDepth { 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);
}
public class WellOperationsStatService : IWellOperationsStatService
{
private readonly IAsbCloudDbContext db;
private readonly CacheTable<WellSectionType> cachedSectionsTypes;
private const int idOperationBhaAssembly = 1025;
private 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<StatClusterDto> GetOperationStatByClusterAsync(int idCluster, CancellationToken token = default)
{
var operations = await db.WellOperations
.Include(o => o.Well)
.Where(o => o.Well.IdCluster == idCluster)
.OrderBy(o => o.StartDate)
.AsNoTracking()
.ToListAsync(token);
var wellsIds = operations.Select(o => o.IdWell).Distinct();
var sectionsStats = new List<StatOperationDto>(wellsIds.Count() * 3);
var wellsTotals = new List<StatOperationDto>(wellsIds.Count());
foreach(var idWell in wellsIds)
{
var wellOperations = operations.Where(o => o.IdWell == idWell);
sectionsStats.AddRange(GetWellSectionsStats(wellOperations));
wellsTotals.Add(GetWellStats(wellOperations));
}
var statClusterDto = new StatClusterDto
{
Sections = sectionsStats,
WellsTotals = wellsTotals,
};
return statClusterDto;
}
public async Task<StatWellDto> GetOperationStatByWellAsync(int idWell,
CancellationToken token = default)
{
var operations = await db.WellOperations
.Where(o => o.IdWell == idWell)
.OrderBy(o => o.StartDate) // ускорит дальнейшие сортировки
.AsNoTracking()
.ToListAsync(token);
var statWellDto = new StatWellDto
{
Sections = GetWellSectionsStats(operations),
Total = GetWellStats(operations),
};
return statWellDto;
}
private IEnumerable<StatOperationDto> GetWellSectionsStats(IEnumerable<WellOperation> operations)
{
var sectionTypesIds = operations.Select(o => o.IdWellSectionType).Distinct();
var sections = new List<StatOperationDto>(sectionTypesIds.Count());
var operationsPlan = MakeOperationsExt(operations.Where(o => o.IdType == 0));
var operationsFact = MakeOperationsExt(operations.Where(o => o.IdType == 0));
foreach (var idSectionType in sectionTypesIds)
{
var statPlan = CalcSectionStat(operationsPlan, idSectionType);
var statFact = CalcSectionStat(operationsFact, idSectionType);
StatOperationDto section = MakeWellSectionDto(idSectionType, statPlan, statFact);
sections.Add(section);
}
return sections;
}
private static StatOperationDto GetWellStats(IEnumerable<WellOperation> operations)
{
var operationsPlan = MakeOperationsExt(operations.Where(o => o.IdType == 0));
var operationsFact = MakeOperationsExt(operations.Where(o => o.IdType == 0));
var section = new StatOperationDto
{
Plan = CalcStat(operationsPlan),
Fact = CalcStat(operationsFact),
};
return section;
}
private StatOperationDto MakeWellSectionDto(int idSectionType, StatOperationBase statPlan, StatOperationBase statFact)
{
return new StatOperationDto
{
Id = idSectionType,
Caption = cachedSectionsTypes.FirstOrDefault(s => s.Id == idSectionType)?.Caption,
Plan = statPlan,
Fact = statFact,
};
}
private static StatOperationBase CalcSectionStat(IEnumerable<OperationParams> operations, int idSectionType)
{
var sectionOperations = operations
.Where(o => o.IdWellSectionType == idSectionType)
.OrderBy(o => o.Start)
.ThenBy(o => o.WellDepth);
return CalcStat(sectionOperations);
}
private static StatOperationBase CalcStat(IEnumerable<OperationParams> operations)
{
var section = new StatOperationBase
{
Start = operations.First().Start,
End = operations.Max(o => (o.Start.AddHours(o.DurationHours))),
WellDepthStart = operations.Min(o => o.WellDepthReal),
WellDepthEnd = operations.Max(o => o.WellDepthReal),
RouteSpeed = CalcAvgRaceSpeed(operations),
Rop = CalcROP(operations),
BhaDownSpeed = CalcSpeedByOperation(operations, idOperationBhaDown),
BhaUpSpeed = CalcSpeedByOperation(operations, idOperationBhaUp),
CasingDownSpeed = CalcSpeedByOperation(operations, 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.Start - pre.Start).TotalHours;
ops.Add(pre);
pre = current;
}
ops.Add(current);
return ops;
}
private static IEnumerable<Race> GetCompleteRaces(IEnumerable<OperationParams> operations)
{
var races = new List<Race>();
var iterator = operations.GetEnumerator();
while (iterator.MoveNext())
{
if (iterator.Current.IdCategory == idOperationBhaAssembly)
{
var race = new Race
{
StartDate = iterator.Current.Start.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.Start.AddHours(iterator.Current.DurationHours);
race.EndWellDepth = iterator.Current.WellDepthReal;
races.Add(race);
}
}
}
}
return races;
}
}
}