2021-08-24 10:59:10 +05:00
|
|
|
|
using AsbCloudApp.Data;
|
2021-08-24 16:47:10 +05:00
|
|
|
|
using AsbCloudApp.Services;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
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;
|
|
|
|
|
|
2021-08-24 16:47:10 +05:00
|
|
|
|
Start = operation.StartDate;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
|
2021-08-25 15:17:24 +05:00
|
|
|
|
WellDepth = operation.WellDepth;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
DeltaDepth = 0;
|
2021-08-25 15:17:24 +05:00
|
|
|
|
DurationHours = operation.DurationHours;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
}
|
|
|
|
|
public int IdWellSectionType { get; }
|
|
|
|
|
public int IdCategory { get; }
|
2021-08-24 16:47:10 +05:00
|
|
|
|
public int Id { get; }
|
|
|
|
|
public DateTime Start { get; }
|
2021-08-25 15:17:24 +05:00
|
|
|
|
public double WellDepth { get; set; }
|
2021-08-24 10:59:10 +05:00
|
|
|
|
public double DeltaDepth { get; set; }
|
2021-08-25 15:17:24 +05:00
|
|
|
|
public double DurationHours { get; set; }
|
2021-08-24 10:59:10 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-24 16:47:10 +05:00
|
|
|
|
public class WellOperationsStatService : IWellOperationsStatService
|
2021-08-24 10:59:10 +05:00
|
|
|
|
{
|
|
|
|
|
private readonly IAsbCloudDbContext db;
|
2021-08-25 11:13:56 +05:00
|
|
|
|
private readonly IWellService wellService;
|
2021-08-25 17:58:35 +05:00
|
|
|
|
private readonly CacheTable<WellSectionType> cacheSectionsTypes;
|
|
|
|
|
private readonly CacheTable<Well> cacheWell;
|
|
|
|
|
private readonly CacheTable<WellType> cacheWellType;
|
2021-08-25 11:13:56 +05:00
|
|
|
|
private readonly CacheTable<Cluster> cacheCluster;
|
2021-08-24 16:47:10 +05:00
|
|
|
|
private const int idOperationBhaAssembly = 1025;
|
|
|
|
|
private const int idOperationBhaDisassembly = 1026;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
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;
|
|
|
|
|
|
2021-08-25 11:13:56 +05:00
|
|
|
|
public WellOperationsStatService(IAsbCloudDbContext db, CacheDb cache, IWellService wellService)
|
2021-08-24 10:59:10 +05:00
|
|
|
|
{
|
|
|
|
|
this.db = db;
|
2021-08-25 11:13:56 +05:00
|
|
|
|
this.wellService = wellService;
|
2021-08-25 17:58:35 +05:00
|
|
|
|
cacheSectionsTypes = cache.GetCachedTable<WellSectionType>((DbContext)db);
|
|
|
|
|
cacheWell = cache.GetCachedTable<Well>((DbContext)db);
|
|
|
|
|
cacheWellType = cache.GetCachedTable<WellType>((DbContext)db);
|
2021-08-25 11:13:56 +05:00
|
|
|
|
cacheCluster = cache.GetCachedTable<Cluster>((DbContext)db);
|
2021-08-24 10:59:10 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-25 11:30:50 +05:00
|
|
|
|
public async Task<StatClusterDto> GetStatClusterAsync(int idCluster, CancellationToken token = default)
|
2021-08-24 16:47:10 +05:00
|
|
|
|
{
|
|
|
|
|
var operations = await db.WellOperations
|
|
|
|
|
.Where(o => o.Well.IdCluster == idCluster)
|
|
|
|
|
.OrderBy(o => o.StartDate)
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.ToListAsync(token);
|
|
|
|
|
|
2021-08-25 11:13:56 +05:00
|
|
|
|
var cluster = await cacheCluster.FirstOrDefaultAsync(c => c.Id == idCluster, token);
|
|
|
|
|
|
2021-08-24 16:47:10 +05:00
|
|
|
|
var wellsIds = operations.Select(o => o.IdWell).Distinct();
|
|
|
|
|
|
2021-08-25 11:13:56 +05:00
|
|
|
|
var statsWells = new List<StatWellDto>(wellsIds.Count());
|
|
|
|
|
|
|
|
|
|
foreach (var idWell in wellsIds)
|
2021-08-24 16:47:10 +05:00
|
|
|
|
{
|
2021-08-25 11:13:56 +05:00
|
|
|
|
var statWellDto = await CalcStatWell(operations, idWell, token);
|
|
|
|
|
statsWells.Add(statWellDto);
|
2021-08-24 16:47:10 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var statClusterDto = new StatClusterDto
|
|
|
|
|
{
|
2021-08-25 11:13:56 +05:00
|
|
|
|
Id = idCluster,
|
|
|
|
|
Caption = cluster.Caption,
|
|
|
|
|
StatsWells = statsWells,
|
2021-08-24 16:47:10 +05:00
|
|
|
|
};
|
|
|
|
|
return statClusterDto;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-25 11:30:50 +05:00
|
|
|
|
public async Task<StatWellDto> GetStatWellAsync(int idWell,
|
2021-08-24 10:59:10 +05:00
|
|
|
|
CancellationToken token = default)
|
|
|
|
|
{
|
2021-08-24 16:47:10 +05:00
|
|
|
|
var operations = await db.WellOperations
|
2021-08-24 10:59:10 +05:00
|
|
|
|
.Where(o => o.IdWell == idWell)
|
|
|
|
|
.OrderBy(o => o.StartDate) // ускорит дальнейшие сортировки
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.ToListAsync(token);
|
|
|
|
|
|
2021-08-25 11:13:56 +05:00
|
|
|
|
var statWellDto = await CalcStatWell(operations, idWell, token);
|
|
|
|
|
return statWellDto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<StatWellDto> CalcStatWell(IEnumerable<WellOperation> operations, int idWell,
|
|
|
|
|
CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
var wellOperations = operations
|
|
|
|
|
.Where(o => o.IdWell == idWell);
|
|
|
|
|
|
2021-08-25 17:58:35 +05:00
|
|
|
|
var well = await cacheWell.FirstOrDefaultAsync(w => w.Id == idWell, token);
|
|
|
|
|
var wellType = await cacheWellType.FirstOrDefaultAsync(t => t.Id == well.IdWellType, token);
|
2021-08-25 11:13:56 +05:00
|
|
|
|
|
2021-08-24 16:47:10 +05:00
|
|
|
|
var statWellDto = new StatWellDto
|
|
|
|
|
{
|
2021-08-25 11:13:56 +05:00
|
|
|
|
Id = idWell,
|
|
|
|
|
Caption = well.Caption,
|
2021-08-25 17:58:35 +05:00
|
|
|
|
WellType = wellType?.Caption,
|
2021-08-25 11:13:56 +05:00
|
|
|
|
Companies = await wellService.GetCompaniesAsync(idWell, token),
|
|
|
|
|
Sections = CalcSectionsStats(operations),
|
|
|
|
|
Total = GetStat(operations),
|
2021-08-24 16:47:10 +05:00
|
|
|
|
};
|
|
|
|
|
return statWellDto;
|
|
|
|
|
}
|
2021-08-24 10:59:10 +05:00
|
|
|
|
|
2021-08-25 11:13:56 +05:00
|
|
|
|
private IEnumerable<StatSectionDto> CalcSectionsStats(IEnumerable<WellOperation> operations)
|
2021-08-24 16:47:10 +05:00
|
|
|
|
{
|
2021-08-25 11:13:56 +05:00
|
|
|
|
var sectionTypeIds = operations
|
|
|
|
|
.Select(o => o.IdWellSectionType)
|
|
|
|
|
.Distinct();
|
|
|
|
|
|
2021-08-25 17:58:35 +05:00
|
|
|
|
var sectionTypes = cacheSectionsTypes
|
2021-08-25 11:13:56 +05:00
|
|
|
|
.Where(s => sectionTypeIds.Contains(s.Id))
|
|
|
|
|
.ToDictionary(s => s.Id);
|
|
|
|
|
|
|
|
|
|
var sections = new List<StatSectionDto>(sectionTypes.Count);
|
2021-08-24 16:47:10 +05:00
|
|
|
|
var operationsPlan = MakeOperationsExt(operations.Where(o => o.IdType == 0));
|
|
|
|
|
var operationsFact = MakeOperationsExt(operations.Where(o => o.IdType == 0));
|
2021-08-24 10:59:10 +05:00
|
|
|
|
|
2021-08-25 11:13:56 +05:00
|
|
|
|
foreach ((var id, var sectionType) in sectionTypes)
|
2021-08-24 10:59:10 +05:00
|
|
|
|
{
|
2021-08-25 11:13:56 +05:00
|
|
|
|
StatSectionDto section = new StatSectionDto
|
|
|
|
|
{
|
|
|
|
|
Id = id,
|
2021-08-25 15:17:24 +05:00
|
|
|
|
Caption = sectionType.Caption,
|
2021-08-25 11:13:56 +05:00
|
|
|
|
Plan = CalcSectionStat(operationsPlan, id),
|
|
|
|
|
Fact = CalcSectionStat(operationsFact, id),
|
|
|
|
|
};
|
2021-08-24 10:59:10 +05:00
|
|
|
|
sections.Add(section);
|
|
|
|
|
}
|
|
|
|
|
return sections;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-25 11:13:56 +05:00
|
|
|
|
private static PlanFactBase<StatOperationsDto> GetStat(IEnumerable<WellOperation> operations)
|
2021-08-24 10:59:10 +05:00
|
|
|
|
{
|
2021-08-24 16:47:10 +05:00
|
|
|
|
var operationsPlan = MakeOperationsExt(operations.Where(o => o.IdType == 0));
|
|
|
|
|
var operationsFact = MakeOperationsExt(operations.Where(o => o.IdType == 0));
|
2021-08-25 11:13:56 +05:00
|
|
|
|
var section = new PlanFactBase<StatOperationsDto>
|
2021-08-24 10:59:10 +05:00
|
|
|
|
{
|
2021-08-24 16:47:10 +05:00
|
|
|
|
Plan = CalcStat(operationsPlan),
|
|
|
|
|
Fact = CalcStat(operationsFact),
|
2021-08-24 10:59:10 +05:00
|
|
|
|
};
|
2021-08-24 16:47:10 +05:00
|
|
|
|
return section;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-25 11:13:56 +05:00
|
|
|
|
private static StatOperationsDto CalcSectionStat(IEnumerable<OperationParams> operations, int idSectionType)
|
2021-08-24 10:59:10 +05:00
|
|
|
|
{
|
2021-08-24 16:47:10 +05:00
|
|
|
|
var sectionOperations = operations
|
2021-08-24 10:59:10 +05:00
|
|
|
|
.Where(o => o.IdWellSectionType == idSectionType)
|
2021-08-24 16:47:10 +05:00
|
|
|
|
.OrderBy(o => o.Start)
|
2021-08-24 10:59:10 +05:00
|
|
|
|
.ThenBy(o => o.WellDepth);
|
2021-08-24 16:47:10 +05:00
|
|
|
|
return CalcStat(sectionOperations);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-25 11:13:56 +05:00
|
|
|
|
private static StatOperationsDto CalcStat(IEnumerable<OperationParams> operations)
|
2021-08-24 16:47:10 +05:00
|
|
|
|
{
|
2021-08-25 11:13:56 +05:00
|
|
|
|
var section = new StatOperationsDto
|
2021-08-24 10:59:10 +05:00
|
|
|
|
{
|
2021-08-24 16:47:10 +05:00
|
|
|
|
Start = operations.First().Start,
|
|
|
|
|
End = operations.Max(o => (o.Start.AddHours(o.DurationHours))),
|
2021-08-25 15:17:24 +05:00
|
|
|
|
WellDepthStart = operations.Min(o => o.WellDepth),
|
|
|
|
|
WellDepthEnd = operations.Max(o => o.WellDepth),
|
2021-08-24 16:47:10 +05:00
|
|
|
|
RouteSpeed = CalcAvgRaceSpeed(operations),
|
|
|
|
|
Rop = CalcROP(operations),
|
|
|
|
|
BhaDownSpeed = CalcSpeedByOperation(operations, idOperationBhaDown),
|
|
|
|
|
BhaUpSpeed = CalcSpeedByOperation(operations, idOperationBhaUp),
|
|
|
|
|
CasingDownSpeed = CalcSpeedByOperation(operations, IdOperationCasingDown),
|
2021-08-24 10:59:10 +05:00
|
|
|
|
};
|
|
|
|
|
return section;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-25 17:58:35 +05:00
|
|
|
|
// this will be deleted
|
2021-08-24 10:59:10 +05:00
|
|
|
|
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)
|
|
|
|
|
{
|
2021-08-25 17:58:35 +05:00
|
|
|
|
if (maxDepth < operation.WellDepth)
|
2021-08-25 15:17:24 +05:00
|
|
|
|
maxDepth = operation.WellDepth;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
dHours += operation.DurationHours;
|
|
|
|
|
}
|
|
|
|
|
return maxDepth / (dHours + double.Epsilon);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-25 17:58:35 +05:00
|
|
|
|
//private static double CalcBhaDownSpeed(IEnumerable<OperationParams> operationsProps)
|
|
|
|
|
//{
|
|
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
2021-08-24 10:59:10 +05:00
|
|
|
|
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)
|
|
|
|
|
{
|
2021-08-25 11:41:09 +05:00
|
|
|
|
var sortedOperations = operations.OrderBy(o => o.StartDate);
|
2021-08-24 10:59:10 +05:00
|
|
|
|
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);
|
2021-08-25 17:58:35 +05:00
|
|
|
|
current = new OperationParams(item){ WellDepth = Helper.Max(wellDepth, item.WellDepth) };
|
2021-08-25 15:17:24 +05:00
|
|
|
|
pre.DeltaDepth = current.WellDepth - wellDepth;
|
2021-08-25 17:58:35 +05:00
|
|
|
|
wellDepth = current.WellDepth;
|
2021-08-25 15:17:24 +05:00
|
|
|
|
pre.DurationHours = (current.Start - pre.Start).TotalHours;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
ops.Add(pre);
|
|
|
|
|
pre = current;
|
|
|
|
|
}
|
|
|
|
|
ops.Add(current);
|
|
|
|
|
return ops;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IEnumerable<Race> GetCompleteRaces(IEnumerable<OperationParams> operations)
|
|
|
|
|
{
|
2021-08-24 16:47:10 +05:00
|
|
|
|
var races = new List<Race>();
|
2021-08-25 17:58:35 +05:00
|
|
|
|
var iterator = operations
|
|
|
|
|
.OrderBy(o => o.Start)
|
|
|
|
|
.GetEnumerator();
|
2021-08-24 10:59:10 +05:00
|
|
|
|
while (iterator.MoveNext())
|
|
|
|
|
{
|
|
|
|
|
if (iterator.Current.IdCategory == idOperationBhaAssembly)
|
|
|
|
|
{
|
|
|
|
|
var race = new Race
|
|
|
|
|
{
|
2021-08-24 16:47:10 +05:00
|
|
|
|
StartDate = iterator.Current.Start.AddHours(iterator.Current.DurationHours),
|
2021-08-25 15:17:24 +05:00
|
|
|
|
StartWellDepth = iterator.Current.WellDepth
|
2021-08-24 10:59:10 +05:00
|
|
|
|
};
|
|
|
|
|
while (iterator.MoveNext())
|
|
|
|
|
{
|
|
|
|
|
if (iterator.Current.IdCategory == idOperationNonProductiveTime)
|
|
|
|
|
{
|
|
|
|
|
race.NonProductiveHours += iterator.Current.DurationHours;
|
|
|
|
|
}
|
|
|
|
|
if (iterator.Current.IdCategory == idOperationBhaDisassembly)
|
|
|
|
|
{
|
2021-08-25 17:58:35 +05:00
|
|
|
|
race.EndDate = iterator.Current.Start;
|
2021-08-25 15:17:24 +05:00
|
|
|
|
race.EndWellDepth = iterator.Current.WellDepth;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
races.Add(race);
|
2021-08-25 17:58:35 +05:00
|
|
|
|
break;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return races;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|