2021-07-21 15:29:19 +05:00
|
|
|
|
using AsbCloudApp.Data;
|
2021-06-17 15:12:39 +05:00
|
|
|
|
using AsbCloudApp.Services;
|
|
|
|
|
using AsbCloudDb.Model;
|
2021-07-21 15:29:19 +05:00
|
|
|
|
using AsbCloudInfrastructure.Services.Cache;
|
2021-08-09 15:41:42 +05:00
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
2021-07-21 15:29:19 +05:00
|
|
|
|
using System;
|
2021-06-17 15:12:39 +05:00
|
|
|
|
using System.Collections.Generic;
|
2021-07-21 15:29:19 +05:00
|
|
|
|
using System.Linq;
|
2021-08-11 16:54:42 +05:00
|
|
|
|
using System.Threading;
|
2021-08-11 12:11:21 +05:00
|
|
|
|
using System.Threading.Tasks;
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
namespace AsbCloudInfrastructure.Services.Analysis
|
2021-06-17 15:12:39 +05:00
|
|
|
|
{
|
2021-08-13 15:57:22 +05:00
|
|
|
|
public class TelemetryAnalyticsService : ITelemetryAnalyticsService
|
2021-06-17 15:12:39 +05:00
|
|
|
|
{
|
|
|
|
|
private readonly IAsbCloudDbContext db;
|
|
|
|
|
private readonly ITelemetryService telemetryService;
|
2021-08-16 14:19:43 +05:00
|
|
|
|
private readonly CacheTable<WellOperationCategory> cacheOperations;
|
2021-07-27 13:32:00 +05:00
|
|
|
|
private readonly TelemetryOperationDetectorService operationDetectorService;
|
2021-08-16 14:19:43 +05:00
|
|
|
|
private readonly IEnumerable<WellOperationCategory> operations;
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
private const int countOfRecordsForInterpolation = 12 * 60 * 60;
|
2021-09-30 16:41:00 +05:00
|
|
|
|
|
2021-08-13 15:57:22 +05:00
|
|
|
|
public TelemetryAnalyticsService(IAsbCloudDbContext db, ITelemetryService telemetryService,
|
2021-09-30 16:41:00 +05:00
|
|
|
|
CacheDb cacheDb)
|
2021-06-17 15:12:39 +05:00
|
|
|
|
{
|
|
|
|
|
this.db = db;
|
|
|
|
|
this.telemetryService = telemetryService;
|
2021-08-16 14:19:43 +05:00
|
|
|
|
cacheOperations = cacheDb.GetCachedTable<WellOperationCategory>((AsbCloudDbContext)db);
|
|
|
|
|
operations = cacheOperations.Where();
|
2021-07-27 13:32:00 +05:00
|
|
|
|
operationDetectorService = new TelemetryOperationDetectorService(operations);
|
2021-06-17 15:12:39 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-11 16:54:42 +05:00
|
|
|
|
public async Task<IEnumerable<WellDepthToDayDto>> GetWellDepthToDayAsync(int idWell, CancellationToken token = default)
|
2021-06-17 15:12:39 +05:00
|
|
|
|
{
|
2021-08-09 14:01:57 +05:00
|
|
|
|
var telemetryId = telemetryService.GetIdTelemetryByIdWell(idWell);
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-08-09 14:01:57 +05:00
|
|
|
|
if (telemetryId is null)
|
2021-06-17 15:12:39 +05:00
|
|
|
|
return null;
|
|
|
|
|
|
2021-09-14 17:17:33 +05:00
|
|
|
|
var depthToTimeData = (from d in db.TelemetryDataSaub
|
2021-08-09 14:01:57 +05:00
|
|
|
|
where d.IdTelemetry == telemetryId
|
2021-06-22 09:49:53 +05:00
|
|
|
|
select new
|
2021-06-17 15:12:39 +05:00
|
|
|
|
{
|
2021-06-22 09:49:53 +05:00
|
|
|
|
d.WellDepth,
|
|
|
|
|
d.BitDepth,
|
|
|
|
|
d.Date
|
|
|
|
|
});
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-06-22 09:49:53 +05:00
|
|
|
|
var m = (int)Math.Round(1d * depthToTimeData.Count() / 2048);
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
|
|
|
|
if (m > 1)
|
2021-11-13 18:47:11 +05:00
|
|
|
|
depthToTimeData = depthToTimeData.Where((d, i) => (((d.Date.DayOfYear * 24 + d.Date.Hour) * 60 + d.Date.Minute) * 60 + d.Date.Second) % m == 0);
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-08-11 12:11:21 +05:00
|
|
|
|
return await depthToTimeData.Select(d => new WellDepthToDayDto
|
2021-06-22 09:49:53 +05:00
|
|
|
|
{
|
2021-06-25 15:10:05 +05:00
|
|
|
|
WellDepth = d.WellDepth ?? 0.0,
|
|
|
|
|
BitDepth = d.BitDepth ?? 0.0,
|
2021-06-22 09:49:53 +05:00
|
|
|
|
Date = d.Date
|
2021-08-11 17:26:02 +05:00
|
|
|
|
}).AsNoTracking().ToListAsync(token).ConfigureAwait(false);
|
2021-06-17 15:12:39 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-11 12:11:21 +05:00
|
|
|
|
public async Task<IEnumerable<WellDepthToIntervalDto>> GetWellDepthToIntervalAsync(int idWell,
|
2021-08-11 16:54:42 +05:00
|
|
|
|
int intervalSeconds, int workBeginSeconds, CancellationToken token = default)
|
2021-06-17 15:12:39 +05:00
|
|
|
|
{
|
2021-07-20 11:50:35 +05:00
|
|
|
|
intervalSeconds = intervalSeconds == 0 ? 86400 : intervalSeconds;
|
2021-06-25 15:10:05 +05:00
|
|
|
|
|
2021-08-09 14:01:57 +05:00
|
|
|
|
var telemetryId = telemetryService.GetIdTelemetryByIdWell(idWell);
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-08-09 14:01:57 +05:00
|
|
|
|
if (telemetryId is null)
|
2021-06-17 15:12:39 +05:00
|
|
|
|
return null;
|
|
|
|
|
|
2021-08-09 14:01:57 +05:00
|
|
|
|
var timezoneOffset = telemetryService.GetTimezoneOffsetByTelemetryId((int)telemetryId);
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-08-11 12:11:21 +05:00
|
|
|
|
var drillingPeriodsInfo = await db.GetDepthToIntervalAsync((int)telemetryId, intervalSeconds,
|
2021-08-11 17:26:02 +05:00
|
|
|
|
workBeginSeconds, timezoneOffset, token).ConfigureAwait(false);
|
2021-06-22 09:49:53 +05:00
|
|
|
|
|
|
|
|
|
var wellDepthToIntervalData = drillingPeriodsInfo.Select(d => new WellDepthToIntervalDto
|
|
|
|
|
{
|
2021-06-25 15:10:05 +05:00
|
|
|
|
IntervalStartDate = d.BeginPeriodDate,
|
2021-07-20 11:50:35 +05:00
|
|
|
|
IntervalDepthProgress = (d.MaxDepth - d.MinDepth) ?? 0.0 / intervalSeconds
|
2021-06-22 09:49:53 +05:00
|
|
|
|
}).OrderBy(d => d.IntervalStartDate).ToList();
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-06-22 09:49:53 +05:00
|
|
|
|
return wellDepthToIntervalData;
|
|
|
|
|
}
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-08-11 12:11:21 +05:00
|
|
|
|
public async Task<PaginationContainer<TelemetryOperationDto>> GetOperationsByWellAsync(int idWell,
|
2021-08-09 15:41:42 +05:00
|
|
|
|
IEnumerable<int> categoryIds = default, DateTime begin = default,
|
2021-08-11 16:54:42 +05:00
|
|
|
|
DateTime end = default, int skip = 0, int take = 32, CancellationToken token = default)
|
2021-07-21 16:49:24 +05:00
|
|
|
|
{
|
2021-08-09 14:01:57 +05:00
|
|
|
|
var telemetryId = telemetryService.GetIdTelemetryByIdWell(idWell);
|
2021-07-21 16:49:24 +05:00
|
|
|
|
|
2021-08-09 14:01:57 +05:00
|
|
|
|
if (telemetryId is null)
|
2021-07-21 16:49:24 +05:00
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var operations = from a in db.TelemetryAnalysis.Include(t => t.Operation)
|
2021-08-09 15:41:42 +05:00
|
|
|
|
where a.IdTelemetry == telemetryId
|
2021-08-09 14:01:57 +05:00
|
|
|
|
select a;
|
2021-07-21 16:49:24 +05:00
|
|
|
|
|
|
|
|
|
if ((categoryIds != default) && (categoryIds.Any()))
|
|
|
|
|
operations = operations.Where(o => categoryIds.Contains(o.IdOperation));
|
|
|
|
|
|
2021-07-27 13:32:00 +05:00
|
|
|
|
var result = new PaginationContainer<TelemetryOperationDto>
|
2021-07-21 16:49:24 +05:00
|
|
|
|
{
|
|
|
|
|
Skip = skip,
|
|
|
|
|
Take = take
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
operations = operations.OrderBy(o => o.UnixDate);
|
|
|
|
|
|
|
|
|
|
if (begin != default)
|
|
|
|
|
{
|
|
|
|
|
var unixBegin = (begin - new DateTime(1970, 1, 1)).TotalSeconds;
|
|
|
|
|
operations = operations.Where(o => o.UnixDate >= unixBegin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (end != default)
|
|
|
|
|
{
|
|
|
|
|
var unixEnd = (end - new DateTime(1970, 1, 1)).TotalSeconds;
|
2021-07-21 17:57:59 +05:00
|
|
|
|
operations = operations.Where(m => (m.UnixDate + m.DurationSec) <= unixEnd);
|
2021-07-21 16:49:24 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-11 17:26:02 +05:00
|
|
|
|
result.Count = await operations.CountAsync(token).ConfigureAwait(false);
|
2021-07-21 16:49:24 +05:00
|
|
|
|
|
|
|
|
|
if (skip > 0)
|
|
|
|
|
operations = operations.Skip(skip);
|
|
|
|
|
|
2021-08-11 16:54:42 +05:00
|
|
|
|
var operationsList = await operations.Take(take)
|
|
|
|
|
.AsNoTracking()
|
2021-08-11 17:26:02 +05:00
|
|
|
|
.ToListAsync(token)
|
|
|
|
|
.ConfigureAwait(false);
|
2021-07-21 16:49:24 +05:00
|
|
|
|
|
|
|
|
|
if (operationsList.Count == 0)
|
|
|
|
|
return result;
|
|
|
|
|
|
2021-08-09 15:41:42 +05:00
|
|
|
|
foreach (var operation in operations)
|
2021-07-21 16:49:24 +05:00
|
|
|
|
{
|
2021-07-27 13:32:00 +05:00
|
|
|
|
var operationDto = new TelemetryOperationDto
|
2021-07-21 16:49:24 +05:00
|
|
|
|
{
|
|
|
|
|
Id = operation.Id,
|
|
|
|
|
Name = operation.Operation.Name,
|
|
|
|
|
BeginDate = DateTimeOffset.FromUnixTimeSeconds(operation.UnixDate).DateTime,
|
2021-07-21 17:57:59 +05:00
|
|
|
|
EndDate = DateTimeOffset.FromUnixTimeSeconds(operation.UnixDate + operation.DurationSec).DateTime,
|
2021-07-21 16:49:24 +05:00
|
|
|
|
StartWellDepth = operation.OperationStartDepth ?? 0.0,
|
|
|
|
|
EndWellDepth = operation.OperationEndDepth ?? 0.0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
result.Items.Add(operationDto);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-11 12:11:21 +05:00
|
|
|
|
public async Task<IEnumerable<TelemetryOperationDurationDto>> GetOperationsSummaryAsync(int idWell,
|
2021-08-11 16:54:42 +05:00
|
|
|
|
DateTime begin = default, DateTime end = default, CancellationToken token = default)
|
2021-06-22 09:49:53 +05:00
|
|
|
|
{
|
2021-08-09 14:01:57 +05:00
|
|
|
|
var telemetryId = telemetryService.GetIdTelemetryByIdWell(idWell);
|
2021-06-30 10:16:06 +05:00
|
|
|
|
|
2021-08-09 14:01:57 +05:00
|
|
|
|
if (telemetryId is null)
|
2021-06-30 10:16:06 +05:00
|
|
|
|
return null;
|
|
|
|
|
|
2021-09-10 11:30:24 +05:00
|
|
|
|
var unixBegin = begin == default
|
|
|
|
|
? 0
|
|
|
|
|
: (begin - new DateTime(1970, 1, 1)).TotalSeconds;
|
|
|
|
|
var unixEnd = end == default
|
|
|
|
|
? (DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds
|
|
|
|
|
: (end - new DateTime(1970, 1, 1)).TotalSeconds;
|
2021-07-19 15:31:50 +05:00
|
|
|
|
|
2021-08-11 16:54:42 +05:00
|
|
|
|
return await (from a in db.TelemetryAnalysis
|
2021-08-24 10:59:10 +05:00
|
|
|
|
where a.IdTelemetry == telemetryId &&
|
|
|
|
|
a.UnixDate > unixBegin && a.UnixDate < unixEnd
|
2021-10-08 17:00:30 +05:00
|
|
|
|
join o in db.WellOperationCategories on a.IdOperation equals o.Id
|
2021-08-24 10:59:10 +05:00
|
|
|
|
group a by new { a.IdOperation, o.Name } into g
|
|
|
|
|
select new TelemetryOperationDurationDto
|
|
|
|
|
{
|
|
|
|
|
OperationName = g.Key.Name,
|
|
|
|
|
Duration = g.Where(g => g.DurationSec > 0)
|
|
|
|
|
.Sum(a => a.DurationSec)
|
|
|
|
|
}).AsNoTracking().ToListAsync(token)
|
2021-08-11 17:26:02 +05:00
|
|
|
|
.ConfigureAwait(false);
|
2021-06-22 09:49:53 +05:00
|
|
|
|
}
|
2021-06-17 15:12:39 +05:00
|
|
|
|
|
2021-08-13 12:32:43 +05:00
|
|
|
|
// This method is not finished (only half done). It returns not correct Dtos.
|
2021-08-11 12:11:21 +05:00
|
|
|
|
public async Task<IEnumerable<TelemetryOperationInfoDto>> GetOperationsToIntervalAsync(int idWell,
|
2021-08-11 16:54:42 +05:00
|
|
|
|
int intervalSeconds, int workBeginSeconds, CancellationToken token = default)
|
2021-06-22 09:49:53 +05:00
|
|
|
|
{
|
2021-07-20 11:50:35 +05:00
|
|
|
|
intervalSeconds = intervalSeconds == 0 ? 86400 : intervalSeconds;
|
2021-06-30 10:16:06 +05:00
|
|
|
|
|
2021-08-09 14:01:57 +05:00
|
|
|
|
var telemetryId = telemetryService.GetIdTelemetryByIdWell(idWell);
|
2021-06-30 10:16:06 +05:00
|
|
|
|
|
2021-08-09 14:01:57 +05:00
|
|
|
|
if (telemetryId is null)
|
2021-06-30 10:16:06 +05:00
|
|
|
|
return null;
|
|
|
|
|
|
2021-08-09 14:01:57 +05:00
|
|
|
|
var timezoneOffset = telemetryService.GetTimezoneOffsetByTelemetryId((int)telemetryId);
|
2021-06-30 10:16:06 +05:00
|
|
|
|
|
2021-08-13 12:32:43 +05:00
|
|
|
|
// Get'n'Group all operations only by start date and by name (if there were several operations in interval).
|
|
|
|
|
// Without dividing these operations duration by given interval
|
|
|
|
|
var ops = await (from a in db.TelemetryAnalysis
|
2021-08-24 10:59:10 +05:00
|
|
|
|
where a.IdTelemetry == telemetryId
|
2021-10-08 17:00:30 +05:00
|
|
|
|
join o in db.WellOperationCategories on a.IdOperation equals o.Id
|
2021-08-24 10:59:10 +05:00
|
|
|
|
group a by new
|
|
|
|
|
{
|
|
|
|
|
Interval = Math.Floor((a.UnixDate - workBeginSeconds + timezoneOffset) / intervalSeconds),
|
|
|
|
|
o.Name
|
|
|
|
|
} into g
|
|
|
|
|
select new
|
|
|
|
|
{
|
|
|
|
|
IntervalStart = g.Min(d => d.UnixDate),
|
|
|
|
|
OperationName = g.Key.Name,
|
|
|
|
|
OperationDuration = g.Sum(an => an.DurationSec)
|
|
|
|
|
}).AsNoTracking()
|
2021-08-13 12:32:43 +05:00
|
|
|
|
.OrderBy(op => op.IntervalStart)
|
|
|
|
|
.ToListAsync(token)
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var groupedOperationsList = new List<TelemetryOperationInfoDto>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (operations is not null && operations.Any())
|
|
|
|
|
{
|
|
|
|
|
var operations = ops.Select(o => (o.IntervalStart, o.OperationName, o.OperationDuration));
|
|
|
|
|
|
|
|
|
|
var splittedOperationsByInterval = DivideOperationsByIntervalLength(operations, intervalSeconds); // divides good
|
|
|
|
|
|
|
|
|
|
groupedOperationsList = UniteOperationsInDto(splittedOperationsByInterval, intervalSeconds).ToList(); // unites not good
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return groupedOperationsList;
|
2021-06-17 15:12:39 +05:00
|
|
|
|
}
|
2021-06-24 13:02:31 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
public async Task AnalyzeAndSaveTelemetriesAsync(CancellationToken token = default)
|
2021-07-20 11:24:57 +05:00
|
|
|
|
{
|
2021-11-22 14:04:05 +05:00
|
|
|
|
var allTelemetryIds = await db.Telemetries.Select(t => t.Id).ToListAsync(token).ConfigureAwait(false);
|
2021-07-20 11:24:57 +05:00
|
|
|
|
|
2021-11-22 14:04:05 +05:00
|
|
|
|
foreach (var idTelemetry in allTelemetryIds)
|
2021-07-20 11:24:57 +05:00
|
|
|
|
{
|
2021-10-01 15:44:56 +05:00
|
|
|
|
var analyzeStartDate = await GetLastAnalysisDateAsync(idTelemetry, token).ConfigureAwait(false);
|
|
|
|
|
await AnalyseAndSaveTelemetryAsync(idTelemetry, analyzeStartDate, token).ConfigureAwait(false);
|
|
|
|
|
GC.Collect();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-30 16:41:00 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
private async Task AnalyseAndSaveTelemetryAsync(int idTelemetry, DateTime analyzeStartDate, CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
const int step = 10;
|
|
|
|
|
const int take = step * 2;
|
2021-09-30 16:41:00 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
TelemetryAnalysis currentAnalysis = null;
|
|
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
var dataSaubPart = await GetDataSaubPartOrDefaultAsync(idTelemetry, analyzeStartDate, token).ConfigureAwait(false);
|
|
|
|
|
if (dataSaubPart is null)
|
|
|
|
|
break;
|
2021-09-30 16:41:00 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
var count = dataSaubPart.Count();
|
|
|
|
|
var skip = 0;
|
2021-09-27 11:47:39 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
if (step > count)
|
|
|
|
|
break;
|
2021-09-27 11:47:39 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
analyzeStartDate = dataSaubPart.Last().Date;
|
|
|
|
|
for (; (skip + step) < count; skip += step)
|
|
|
|
|
{
|
|
|
|
|
var dataSaubPartOfPart = dataSaubPart.Skip(skip).Take(take);
|
|
|
|
|
var telemetryAnalysis = GetDrillingAnalysis(dataSaubPartOfPart);
|
2021-09-27 11:47:39 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
if (currentAnalysis is not null)
|
|
|
|
|
{
|
2021-09-30 16:41:00 +05:00
|
|
|
|
if (currentAnalysis.IdOperation == telemetryAnalysis.IdOperation)
|
|
|
|
|
currentAnalysis.DurationSec += telemetryAnalysis.DurationSec;
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-10-01 15:44:56 +05:00
|
|
|
|
currentAnalysis.OperationEndDepth = dataSaubPartOfPart.LastOrDefault()?.WellDepth;
|
2021-09-30 16:41:00 +05:00
|
|
|
|
db.TelemetryAnalysis.Add(currentAnalysis);
|
2021-10-01 15:44:56 +05:00
|
|
|
|
currentAnalysis = null;
|
2021-09-30 16:41:00 +05:00
|
|
|
|
}
|
2021-09-29 12:20:19 +05:00
|
|
|
|
}
|
2021-09-30 16:41:00 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
if (currentAnalysis is null)
|
|
|
|
|
{
|
|
|
|
|
currentAnalysis = telemetryAnalysis;
|
|
|
|
|
currentAnalysis.OperationStartDepth = dataSaubPartOfPart.FirstOrDefault()?.WellDepth;
|
|
|
|
|
}
|
2021-09-27 16:50:56 +05:00
|
|
|
|
}
|
2021-10-01 15:44:56 +05:00
|
|
|
|
|
|
|
|
|
await db.SaveChangesAsync(token).ConfigureAwait(false);
|
|
|
|
|
GC.Collect();
|
2021-07-20 11:24:57 +05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-18 12:03:59 +05:00
|
|
|
|
public async Task<DatesRangeDto> GetOperationsDateRangeAsync(int idWell, bool isUtc,
|
2021-09-10 15:23:36 +05:00
|
|
|
|
CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
var telemetryId = telemetryService.GetIdTelemetryByIdWell(idWell);
|
|
|
|
|
|
|
|
|
|
if (telemetryId is null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var datesRange = await (from d in db.TelemetryAnalysis
|
|
|
|
|
where d.IdTelemetry == telemetryId
|
|
|
|
|
select d.UnixDate).DefaultIfEmpty()
|
|
|
|
|
.GroupBy(g => true)
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.Select(g => new
|
|
|
|
|
{
|
|
|
|
|
From = g.Min(),
|
|
|
|
|
To = g.Max()
|
|
|
|
|
}).OrderBy(gr => gr.From)
|
|
|
|
|
.FirstOrDefaultAsync(token)
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
2021-11-18 12:03:59 +05:00
|
|
|
|
var result = new DatesRangeDto
|
2021-09-10 15:23:36 +05:00
|
|
|
|
{
|
|
|
|
|
From = DateTimeOffset.FromUnixTimeSeconds(datesRange.From).DateTime,
|
|
|
|
|
To = datesRange.To == default
|
|
|
|
|
? DateTime.MaxValue
|
|
|
|
|
: DateTimeOffset.FromUnixTimeSeconds(datesRange.To).DateTime
|
|
|
|
|
};
|
2021-11-18 12:03:59 +05:00
|
|
|
|
|
|
|
|
|
if (isUtc)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
result = await telemetryService.FixDatesRangeByTimeZoneAsync((int)telemetryId, result, token)
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
return result;
|
2021-09-10 15:23:36 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
private async Task<DateTime> GetLastAnalysisDateAsync(int idTelemetry, CancellationToken token = default)
|
2021-09-27 16:50:56 +05:00
|
|
|
|
{
|
2021-10-01 15:44:56 +05:00
|
|
|
|
var lastAnalysisInDb = await (from analysis in db.TelemetryAnalysis
|
2021-09-28 10:17:26 +05:00
|
|
|
|
where analysis.IdTelemetry == idTelemetry
|
2021-09-27 16:50:56 +05:00
|
|
|
|
orderby analysis.UnixDate
|
|
|
|
|
select analysis)
|
2021-10-01 15:44:56 +05:00
|
|
|
|
.LastOrDefaultAsync(token)
|
|
|
|
|
.ConfigureAwait(false);
|
2021-09-30 16:41:00 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
DateTime lastAnalysisDate = default;
|
2021-09-30 16:41:00 +05:00
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
if(lastAnalysisInDb is not null)
|
|
|
|
|
lastAnalysisDate = DateTime.UnixEpoch.AddSeconds(lastAnalysisInDb.DurationSec + lastAnalysisInDb.UnixDate);
|
|
|
|
|
|
|
|
|
|
return lastAnalysisDate;
|
2021-09-30 16:41:00 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
private Task<List<DataSaubAnalyse>> GetDataSaubPartOrDefaultAsync(int idTelemetry, DateTime analyzeStartDate, CancellationToken token) =>
|
|
|
|
|
db.TelemetryDataSaub
|
|
|
|
|
.Where(d =>
|
|
|
|
|
d.IdTelemetry == idTelemetry &&
|
|
|
|
|
d.Date > analyzeStartDate &&
|
|
|
|
|
d.BitDepth != null &&
|
|
|
|
|
d.BlockPosition != null &&
|
|
|
|
|
d.HookWeight != null &&
|
|
|
|
|
d.Pressure != null &&
|
|
|
|
|
d.RotorSpeed != null &&
|
|
|
|
|
d.WellDepth != null
|
|
|
|
|
)
|
|
|
|
|
.OrderBy(d => d.Date)
|
|
|
|
|
.Take(countOfRecordsForInterpolation)
|
|
|
|
|
.Select(d => new DataSaubAnalyse {
|
|
|
|
|
IdTelemetry = d.IdTelemetry,
|
|
|
|
|
Date = d.Date,
|
|
|
|
|
BitDepth = d.BitDepth ?? 0,
|
|
|
|
|
BlockPosition = d.BlockPosition ?? 0,
|
|
|
|
|
HookWeight = d.HookWeight ?? 0,
|
|
|
|
|
Pressure = d.Pressure ?? 0,
|
|
|
|
|
RotorSpeed = d.RotorSpeed ?? 0,
|
|
|
|
|
WellDepth = d.WellDepth ?? 0,
|
|
|
|
|
})
|
|
|
|
|
.ToListAsync(token);
|
2021-09-27 16:50:56 +05:00
|
|
|
|
|
2021-08-13 12:32:43 +05:00
|
|
|
|
private static IEnumerable<(long IntervalStart, string OperationName, int OperationDuration)> DivideOperationsByIntervalLength(
|
|
|
|
|
IEnumerable<(long IntervalStart, string OperationName, int OperationDuration)> operations, int intervalSeconds)
|
|
|
|
|
{
|
|
|
|
|
var splittedOperationsByInterval = new List<(long IntervalStart, string OperationName, int OperationDuration)>();
|
|
|
|
|
|
|
|
|
|
var operationDurationTimeCounter = 0;
|
|
|
|
|
|
2021-09-10 15:23:36 +05:00
|
|
|
|
foreach (var (IntervalStart, OperationName, OperationDuration) in operations)
|
2021-08-13 12:32:43 +05:00
|
|
|
|
{
|
2021-09-10 15:23:36 +05:00
|
|
|
|
if (OperationDuration < (intervalSeconds - operationDurationTimeCounter))
|
2021-08-13 12:32:43 +05:00
|
|
|
|
{
|
2021-09-10 15:23:36 +05:00
|
|
|
|
splittedOperationsByInterval.Add((IntervalStart, OperationName, OperationDuration));
|
|
|
|
|
operationDurationTimeCounter += OperationDuration;
|
2021-08-13 12:32:43 +05:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ // if operation duration overflows current interval it shoud be divided into 2 or more parts for this and next intervals
|
|
|
|
|
var remainingIntervalTime = intervalSeconds - operationDurationTimeCounter;
|
2021-09-10 15:23:36 +05:00
|
|
|
|
splittedOperationsByInterval.Add((IntervalStart, OperationName, remainingIntervalTime)); // first part of long operation
|
2021-08-13 12:32:43 +05:00
|
|
|
|
|
2021-09-10 15:23:36 +05:00
|
|
|
|
var operationDurationAfterDividing = OperationDuration - remainingIntervalTime; // second part of long operation. Can be less or more than interval
|
2021-08-13 12:32:43 +05:00
|
|
|
|
|
|
|
|
|
// If operation duration even after dividing is still more than interval,
|
|
|
|
|
// it should be divided several times to several intervals.
|
|
|
|
|
if (operationDurationAfterDividing > intervalSeconds)
|
|
|
|
|
{
|
|
|
|
|
var counter = 0;
|
2021-09-10 15:23:36 +05:00
|
|
|
|
var updatedIntervalStartTime = IntervalStart + remainingIntervalTime;
|
2021-08-13 12:32:43 +05:00
|
|
|
|
|
|
|
|
|
while (operationDurationAfterDividing > intervalSeconds)
|
|
|
|
|
{
|
2021-09-10 15:23:36 +05:00
|
|
|
|
splittedOperationsByInterval.Add((updatedIntervalStartTime + intervalSeconds * counter, OperationName, intervalSeconds));
|
2021-08-13 12:32:43 +05:00
|
|
|
|
operationDurationAfterDividing -= intervalSeconds;
|
|
|
|
|
counter++;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-10 15:23:36 +05:00
|
|
|
|
splittedOperationsByInterval.Add((updatedIntervalStartTime + operationDurationAfterDividing, OperationName, operationDurationAfterDividing));
|
2021-08-13 12:32:43 +05:00
|
|
|
|
|
|
|
|
|
operationDurationTimeCounter = operationDurationAfterDividing;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-09-10 15:23:36 +05:00
|
|
|
|
splittedOperationsByInterval.Add((IntervalStart, OperationName, operationDurationAfterDividing));
|
2021-08-13 12:32:43 +05:00
|
|
|
|
operationDurationTimeCounter = operationDurationAfterDividing;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return splittedOperationsByInterval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IEnumerable<TelemetryOperationInfoDto> UniteOperationsInDto(
|
|
|
|
|
IEnumerable<(long IntervalStart, string OperationName, int OperationDuration)> operations, int intervalSeconds)
|
|
|
|
|
{
|
|
|
|
|
var groupedOperationsList = new List<TelemetryOperationInfoDto>();
|
|
|
|
|
|
|
|
|
|
var groupedOperationsObj = new TelemetryOperationInfoDto
|
|
|
|
|
{
|
|
|
|
|
IntervalBegin = DateTimeOffset.FromUnixTimeSeconds(operations.First().IntervalStart),
|
|
|
|
|
Operations = new List<TelemetryOperationDetailsDto>()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var intervalEndDate = operations.First().IntervalStart + intervalSeconds;
|
|
|
|
|
|
|
|
|
|
foreach (var op in operations)
|
|
|
|
|
{
|
|
|
|
|
if (op.IntervalStart < intervalEndDate)
|
|
|
|
|
{
|
|
|
|
|
groupedOperationsObj.Operations.Add(new TelemetryOperationDetailsDto
|
|
|
|
|
{
|
|
|
|
|
OperationName = op.OperationName,
|
|
|
|
|
DurationSec = op.OperationDuration
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
groupedOperationsList.Add(groupedOperationsObj);
|
|
|
|
|
|
|
|
|
|
intervalEndDate = op.IntervalStart + intervalSeconds;
|
|
|
|
|
groupedOperationsObj = new TelemetryOperationInfoDto
|
|
|
|
|
{
|
|
|
|
|
IntervalBegin = DateTimeOffset.FromUnixTimeSeconds(op.IntervalStart),
|
|
|
|
|
Operations = new List<TelemetryOperationDetailsDto>()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
groupedOperationsObj.Operations.Add(new TelemetryOperationDetailsDto
|
|
|
|
|
{
|
|
|
|
|
OperationName = op.OperationName,
|
|
|
|
|
DurationSec = op.OperationDuration
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
groupedOperationsList.Add(groupedOperationsObj);
|
|
|
|
|
|
|
|
|
|
return groupedOperationsList;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 15:44:56 +05:00
|
|
|
|
private TelemetryAnalysis GetDrillingAnalysis(IEnumerable<DataSaubAnalyse> dataSaubPartOfPart)
|
2021-06-24 13:02:31 +05:00
|
|
|
|
{
|
2021-10-01 15:44:56 +05:00
|
|
|
|
var dataSaubFirst = dataSaubPartOfPart.First();
|
|
|
|
|
var dataSaubLast = dataSaubPartOfPart.Last();
|
|
|
|
|
|
|
|
|
|
var saubWellDepths = dataSaubPartOfPart.Select(s => (Y: (double)s.WellDepth,
|
|
|
|
|
X: (s.Date - dataSaubFirst.Date).TotalSeconds));
|
|
|
|
|
var saubBitDepths = dataSaubPartOfPart.Select(s => (Y: (double)s.BitDepth,
|
|
|
|
|
X: (s.Date - dataSaubFirst.Date).TotalSeconds));
|
|
|
|
|
var saubBlockPositions = dataSaubPartOfPart.Select(s => (Y: (double)s.BlockPosition,
|
|
|
|
|
X: (s.Date - dataSaubFirst.Date).TotalSeconds));
|
|
|
|
|
var saubRotorSpeeds = dataSaubPartOfPart.Select(s => (Y: (double)s.RotorSpeed,
|
|
|
|
|
X: (s.Date - dataSaubFirst.Date).TotalSeconds));
|
|
|
|
|
var saubPressures = dataSaubPartOfPart.Select(s => (Y: (double)s.Pressure,
|
|
|
|
|
X: (s.Date - dataSaubFirst.Date).TotalSeconds));
|
|
|
|
|
var saubHookWeights = dataSaubPartOfPart.Select(s => (Y: (double)s.HookWeight,
|
|
|
|
|
X: (s.Date - dataSaubFirst.Date).TotalSeconds));
|
2021-06-28 11:35:52 +05:00
|
|
|
|
|
2021-09-30 16:41:00 +05:00
|
|
|
|
var wellDepthLine = new InterpolationLine(saubWellDepths);
|
|
|
|
|
var bitPositionLine = new InterpolationLine(saubBitDepths);
|
|
|
|
|
var blockPositionLine = new InterpolationLine(saubBlockPositions);
|
|
|
|
|
var rotorSpeedLine = new InterpolationLine(saubRotorSpeeds);
|
|
|
|
|
var pressureLine = new InterpolationLine(saubPressures);
|
|
|
|
|
var hookWeightLine = new InterpolationLine(saubHookWeights);
|
2021-06-28 11:35:52 +05:00
|
|
|
|
|
2021-09-30 16:41:00 +05:00
|
|
|
|
var drillingAnalysis = new TelemetryAnalysis
|
2021-06-24 13:02:31 +05:00
|
|
|
|
{
|
2021-10-01 15:44:56 +05:00
|
|
|
|
IdTelemetry = dataSaubFirst.IdTelemetry,
|
|
|
|
|
UnixDate = (long)(dataSaubFirst.Date - DateTime.UnixEpoch).TotalSeconds,
|
|
|
|
|
DurationSec = (int)(dataSaubLast.Date - dataSaubFirst.Date).TotalSeconds,
|
2021-07-20 09:36:40 +05:00
|
|
|
|
OperationStartDepth = null,
|
|
|
|
|
OperationEndDepth = null,
|
2021-09-30 16:41:00 +05:00
|
|
|
|
IsWellDepthDecreasing = wellDepthLine.IsYDecreases(-0.0001),
|
|
|
|
|
IsWellDepthIncreasing = wellDepthLine.IsYIncreases( 0.0001),
|
|
|
|
|
IsBitPositionDecreasing = bitPositionLine.IsYDecreases(-0.0001),
|
|
|
|
|
IsBitPositionIncreasing = bitPositionLine.IsYIncreases(0.0001),
|
|
|
|
|
IsBitPositionLt20 = bitPositionLine.IsAverageYLessThanBound(20),
|
|
|
|
|
IsBlockPositionDecreasing = blockPositionLine.IsYDecreases(-0.0001),
|
|
|
|
|
IsBlockPositionIncreasing = blockPositionLine.IsYIncreases(0.0001),
|
2021-09-30 17:10:12 +05:00
|
|
|
|
IsRotorSpeedLt5 = rotorSpeedLine.IsAverageYLessThanBound(5),
|
|
|
|
|
IsRotorSpeedGt5 = rotorSpeedLine.IsAverageYMoreThanBound(5),
|
2021-09-30 16:41:00 +05:00
|
|
|
|
IsPressureLt20 = pressureLine.IsAverageYLessThanBound(20),
|
|
|
|
|
IsPressureGt20 = pressureLine.IsAverageYMoreThanBound(20),
|
|
|
|
|
IsHookWeightNotChanges = hookWeightLine.IsYNotChanges(0.0001, -0.0001),
|
|
|
|
|
IsHookWeightLt3 = hookWeightLine.IsAverageYLessThanBound(3),
|
2021-10-01 15:44:56 +05:00
|
|
|
|
IdOperation = default,
|
2021-06-24 13:02:31 +05:00
|
|
|
|
};
|
|
|
|
|
|
2021-09-30 16:41:00 +05:00
|
|
|
|
drillingAnalysis.IdOperation =
|
|
|
|
|
operationDetectorService.DetectOperation(drillingAnalysis).Id;
|
2021-06-24 13:02:31 +05:00
|
|
|
|
|
|
|
|
|
return drillingAnalysis;
|
|
|
|
|
}
|
2021-06-17 15:12:39 +05:00
|
|
|
|
}
|
|
|
|
|
}
|