forked from ddrilling/AsbCloudServer
251 lines
11 KiB
C#
251 lines
11 KiB
C#
using AsbCloudApp.Data;
|
|
using AsbCloudApp.Data.ProcessMaps;
|
|
using AsbCloudApp.Data.SAUB;
|
|
using AsbCloudApp.Data.WITS;
|
|
using AsbCloudApp.IntegrationEvents;
|
|
using AsbCloudApp.IntegrationEvents.Interfaces;
|
|
using AsbCloudApp.Repositories;
|
|
using AsbCloudApp.Requests;
|
|
using AsbCloudApp.Services;
|
|
using AsbCloudInfrastructure.Background;
|
|
using Mapster;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AsbCloudInfrastructure.Services;
|
|
|
|
public class WellInfoService
|
|
{
|
|
public class WorkWellInfoUpdate : Work
|
|
{
|
|
public WorkWellInfoUpdate()
|
|
: base("Well statistics update")
|
|
{
|
|
Timeout = TimeSpan.FromMinutes(30);
|
|
}
|
|
|
|
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token)
|
|
{
|
|
var wellService = services.GetRequiredService<IWellService>();
|
|
var operationsStatService = services.GetRequiredService<IOperationsStatService>();
|
|
var processMapPlanWellDrillingRepository = services.GetRequiredService<IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell>>();
|
|
var subsystemService = services.GetRequiredService<ISubsystemService>();
|
|
var telemetryDataSaubCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
|
|
var messageHub = services.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>();
|
|
|
|
var entries = await wellService.GetAllAsync(token);
|
|
var wells = entries.ToList();
|
|
var activeWells = wells.Where(well => well.IdState == 1);
|
|
|
|
var wellsIds = activeWells.Select(w => w.Id);
|
|
|
|
var processMapPlanWellDrillingRequests = wellsIds.Select(id => new ProcessMapPlanBaseRequestWithWell(id));
|
|
var processMapPlanWellDrillings = new List<ProcessMapPlanDrillingDto>();
|
|
foreach (var processMapPlanWellDrillingRequest in processMapPlanWellDrillingRequests)
|
|
{
|
|
var processMaps = await processMapPlanWellDrillingRepository.Get(processMapPlanWellDrillingRequest, token);
|
|
processMapPlanWellDrillings.AddRange(processMaps);
|
|
}
|
|
|
|
var wellDepthByProcessMap = processMapPlanWellDrillings
|
|
.GroupBy(p => p.IdWell)
|
|
.Select(g => new
|
|
{
|
|
Id = g.Key,
|
|
DepthEnd = g.Max(p => p.DepthEnd)
|
|
});
|
|
|
|
var operationsStat = await operationsStatService.GetWellsStatAsync(wellsIds, token);
|
|
|
|
var subsystemStat = await subsystemService
|
|
.GetStatByActiveWells(wellsIds, token);
|
|
subsystemStat = subsystemStat.ToArray();
|
|
|
|
var count = activeWells.Count();
|
|
var i = 0d;
|
|
WellMapInfo = activeWells.Select(well =>
|
|
{
|
|
var wellMapInfo = well.Adapt<WellMapInfoWithComanies>();
|
|
wellMapInfo.IdState = well.IdState;
|
|
onProgressCallback($"Start updating info by well({well.Id}): {well.Caption}", i++ / count);
|
|
double? currentDepth = null;
|
|
|
|
TelemetryDataSaubDto? lastSaubTelemetry = null;
|
|
|
|
if (well.IdTelemetry.HasValue)
|
|
{
|
|
wellMapInfo.IdTelemetry = well.IdTelemetry.Value;
|
|
lastSaubTelemetry = telemetryDataSaubCache.GetLastOrDefault(well.IdTelemetry.Value);
|
|
if (lastSaubTelemetry is not null)
|
|
{
|
|
currentDepth = lastSaubTelemetry.WellDepth;
|
|
}
|
|
}
|
|
|
|
var wellOperationsStat = operationsStat.FirstOrDefault(s => s.Id == well.Id);
|
|
var wellLastFactSection = wellOperationsStat?.Sections.OrderBy(s => s.Fact?.WellDepthStart).LastOrDefault(s => s.Fact is not null);
|
|
currentDepth ??= wellLastFactSection?.Fact?.WellDepthEnd;
|
|
|
|
var wellProcessMaps = processMapPlanWellDrillings
|
|
.Where(p => p.IdWell == well.Id)
|
|
.OrderBy(p => p.DepthEnd);
|
|
|
|
int? idSection = wellLastFactSection?.Id;
|
|
ProcessMapPlanDrillingDto? processMapPlanWellDrilling = null;
|
|
|
|
if (idSection.HasValue)
|
|
{
|
|
processMapPlanWellDrilling = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
|
|
}
|
|
else if (currentDepth.HasValue)
|
|
{
|
|
processMapPlanWellDrilling = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value);
|
|
}
|
|
|
|
double? planTotalDepth = null;
|
|
planTotalDepth = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd;
|
|
planTotalDepth ??= wellOperationsStat?.Total.Plan?.WellDepthEnd;
|
|
|
|
wellMapInfo.Section = wellLastFactSection?.Caption;
|
|
|
|
wellMapInfo.FirstFactOperationDateStart = wellOperationsStat?.Total.Fact?.Start
|
|
?? wellOperationsStat?.Total.Plan?.Start;
|
|
|
|
wellMapInfo.LastPredictOperationDateEnd = wellOperationsStat?.Total.Plan?.End;
|
|
|
|
wellMapInfo.AxialLoad = new()
|
|
{
|
|
Plan = processMapPlanWellDrilling?.AxialLoadPlan,
|
|
Fact = lastSaubTelemetry?.AxialLoad
|
|
};
|
|
|
|
wellMapInfo.TopDriveSpeed = new()
|
|
{
|
|
Plan = processMapPlanWellDrilling?.TopDriveSpeedPlan,
|
|
Fact = lastSaubTelemetry?.RotorSpeed
|
|
};
|
|
|
|
wellMapInfo.TopDriveTorque = new()
|
|
{
|
|
Plan = processMapPlanWellDrilling?.TopDriveTorquePlan,
|
|
Fact = lastSaubTelemetry?.RotorTorque
|
|
};
|
|
|
|
wellMapInfo.Pressure = new()
|
|
{
|
|
Plan = processMapPlanWellDrilling?.DeltaPressurePlan,
|
|
Fact = lastSaubTelemetry?.Pressure
|
|
};
|
|
|
|
wellMapInfo.PressureSp = lastSaubTelemetry?.PressureSp;
|
|
|
|
wellMapInfo.WellDepth = new()
|
|
{
|
|
Plan = planTotalDepth,
|
|
Fact = currentDepth,
|
|
};
|
|
|
|
wellMapInfo.ROP = new()
|
|
{
|
|
Plan = processMapPlanWellDrilling?.RopPlan,
|
|
Fact = wellOperationsStat?.Total.Fact?.Rop,
|
|
};
|
|
|
|
wellMapInfo.RaceSpeed = new()
|
|
{
|
|
Plan = wellOperationsStat?.Total.Plan?.RouteSpeed,
|
|
Fact = wellOperationsStat?.Total.Fact?.RouteSpeed,
|
|
};
|
|
|
|
var wellSubsystemStat = subsystemStat.FirstOrDefault(s => s.Well.Id == well.Id);
|
|
wellMapInfo.SaubUsage = wellSubsystemStat?.SubsystemAPD?.KUsage ?? 0d;
|
|
wellMapInfo.SpinUsage = wellSubsystemStat?.SubsystemOscillation?.KUsage ?? 0d;
|
|
wellMapInfo.TorqueKUsage = wellSubsystemStat?.SubsystemTorqueMaster?.KUsage ?? 0d;
|
|
wellMapInfo.TvdLagDays = wellOperationsStat?.TvdLagDays;
|
|
wellMapInfo.TvdDrillingDays = wellOperationsStat?.TvdDrillingDays;
|
|
wellMapInfo.IdsCompanies = well.Companies.Select(c => c.Id);
|
|
|
|
return wellMapInfo;
|
|
}).ToArray();
|
|
|
|
var updateWellInfoEventTasks = wellsIds.Select(idWell =>
|
|
messageHub.HandleAsync(new UpdateWellInfoEvent(idWell), token));
|
|
|
|
await Task.WhenAll(updateWellInfoEventTasks);
|
|
}
|
|
}
|
|
|
|
class WellMapInfoWithComanies : WellMapInfoDto
|
|
{
|
|
public int? IdTelemetry { get; set; }
|
|
public IEnumerable<int> IdsCompanies { get; set; } = null!;
|
|
}
|
|
|
|
private readonly ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache;
|
|
private readonly ITelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache;
|
|
private readonly IWitsRecordRepository<Record7Dto> witsRecord7Repository;
|
|
private readonly IWitsRecordRepository<Record1Dto> witsRecord1Repository;
|
|
private readonly IGtrRepository gtrRepository;
|
|
private static IEnumerable<WellMapInfoWithComanies> WellMapInfo = Enumerable.Empty<WellMapInfoWithComanies>();
|
|
|
|
public WellInfoService(
|
|
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache,
|
|
ITelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache,
|
|
IWitsRecordRepository<Record7Dto> witsRecord7Repository,
|
|
IWitsRecordRepository<Record1Dto> witsRecord1Repository,
|
|
IGtrRepository gtrRepository)
|
|
{
|
|
this.telemetryDataSaubCache = telemetryDataSaubCache;
|
|
this.telemetryDataSpinCache = telemetryDataSpinCache;
|
|
|
|
this.witsRecord7Repository = witsRecord7Repository;
|
|
this.witsRecord1Repository = witsRecord1Repository;
|
|
this.gtrRepository = gtrRepository;
|
|
}
|
|
|
|
private WellMapInfoWithTelemetryStat Convert(WellMapInfoWithComanies wellInfo)
|
|
{
|
|
var result = wellInfo.Adapt<WellMapInfoWithTelemetryStat>();
|
|
if (wellInfo.IdTelemetry.HasValue)
|
|
{
|
|
var idTelemetry = wellInfo.IdTelemetry.Value;
|
|
result.LastDataSaub = telemetryDataSaubCache.GetLastOrDefault(idTelemetry);
|
|
result.LastDataSpin = telemetryDataSpinCache.GetLastOrDefault(idTelemetry);
|
|
result.LastDataDdsDate = GetLastOrDefaultDdsTelemetry(idTelemetry);
|
|
result.LastDataGtrDate = gtrRepository.GetLastData(wellInfo.Id)
|
|
.MaxOrDefault(item => item.Date);
|
|
result.LastDataDpcsDate = null;
|
|
result.LastDataDpcsDate = null;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private DateTime? GetLastOrDefaultDdsTelemetry(int idTelemetry)
|
|
{
|
|
var lastDdsRecord1Date = witsRecord1Repository.GetLastOrDefault(idTelemetry)?.DateTime;
|
|
var lastDdsRecord7Date = witsRecord7Repository.GetLastOrDefault(idTelemetry)?.DateTime;
|
|
|
|
if (lastDdsRecord1Date.HasValue && lastDdsRecord7Date.HasValue)
|
|
if (lastDdsRecord1Date.Value > lastDdsRecord7Date.Value)
|
|
return lastDdsRecord1Date.Value;
|
|
else
|
|
return lastDdsRecord7Date.Value;
|
|
|
|
return lastDdsRecord1Date ?? lastDdsRecord7Date;
|
|
}
|
|
|
|
public WellMapInfoWithTelemetryStat? FirstOrDefault(Func<WellMapInfoDto, bool> predicate)
|
|
{
|
|
var first = WellMapInfo.FirstOrDefault(predicate);
|
|
if (first is WellMapInfoWithComanies wellMapInfoWithComanies)
|
|
return Convert(wellMapInfoWithComanies);
|
|
|
|
return null;
|
|
}
|
|
}
|