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

311 lines
15 KiB
C#
Raw Normal View History

using System;
using System.Linq;
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.Cache;
using AsbCloudDb.Model;
using System.Collections.Generic;
namespace AsbCloudInfrastructure.Services
{
public class AnalyticsService : IAnalyticsService
{
private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService;
private readonly CacheTable<Operation> cacheOperations;
private readonly OperationDetectorService operationDetectorService;
private readonly IEnumerable<Operation> operations;
public AnalyticsService(IAsbCloudDbContext db, ITelemetryService telemetryService, CacheDb cacheDb)
{
this.db = db;
this.telemetryService = telemetryService;
cacheOperations = cacheDb.GetCachedTable<Operation>((AsbCloudDbContext)db);
operations = cacheOperations.Select(c => true);
operationDetectorService = new OperationDetectorService(operations);
}
public IEnumerable<WellDepthToDayDto> GetWellDepthToDay(int wellId)
{
var telemetry = telemetryService.GetTelemetryByWellId(wellId);
if (telemetry is null)
return null;
var depthToTimeData = (from d in db.DataSaubBases
where d.IdTelemetry == telemetry.Id
select new
{
d.Id,
d.WellDepth,
d.BitDepth,
d.Date
});
var m = (int)Math.Round(1d * depthToTimeData.Count() / 2048);
if (m > 1)
depthToTimeData = depthToTimeData.Where(d => d.Id % m == 0);
return depthToTimeData.Select(d => new WellDepthToDayDto
{
WellDepth = d.WellDepth ?? 0.0,
BitDepth = d.BitDepth ?? 0.0,
Date = d.Date
}).ToList();
}
public IEnumerable<WellDepthToIntervalDto> GetWellDepthToInterval(int wellId,
int intervalHoursTimestamp, int workBeginTimestamp)
{
intervalHoursTimestamp = intervalHoursTimestamp == 0 ? 86400 : intervalHoursTimestamp;
var intervalTime = new TimeSpan(0, 0, intervalHoursTimestamp);
var workDayBeginTime = new TimeSpan(0, 0, workBeginTimestamp);
var telemetry = telemetryService.GetTelemetryByWellId(wellId);
if (telemetry is null)
return null;
var timezoneOffset = telemetryService.GetTimezoneOffsetByTelemetryId(telemetry.Id);
var drillingPeriodsInfo = db.GetDepthToInterval(telemetry.Id, (int)intervalTime.TotalSeconds,
(int)workDayBeginTime.TotalSeconds, timezoneOffset);
var wellDepthToIntervalData = drillingPeriodsInfo.Select(d => new WellDepthToIntervalDto
{
IntervalStartDate = d.BeginPeriodDate,
IntervalDepthProgress = (d.MaxDepth - d.MinDepth) ?? 0.0 / intervalHoursTimestamp
}).OrderBy(d => d.IntervalStartDate).ToList();
return wellDepthToIntervalData;
}
public IEnumerable<OperationPercentageDto> GetOperationsSummary(int wellId,
DateTime begin = default, DateTime end = default)
{
return new List<OperationPercentageDto>
{
new OperationPercentageDto { ProcessName = "Роторное бурение", Percentage = 19.7 },
new OperationPercentageDto { ProcessName = "Подъем с проработкой", Percentage = 6.2 },
new OperationPercentageDto { ProcessName = "Спуск с проработкой", Percentage = 9.4 },
new OperationPercentageDto { ProcessName = "Подъем с промывкой", Percentage = 18.4 },
new OperationPercentageDto { ProcessName = "Неподвижное состояние", Percentage = 12.1 },
new OperationPercentageDto { ProcessName = "Вращение без циркуляции", Percentage = 7.4 },
new OperationPercentageDto { ProcessName = "Спуск в скважину", Percentage = 16.7 },
new OperationPercentageDto { ProcessName = "На поверхности", Percentage = 10.1 }
};
}
public IEnumerable<OperationInfoDto> GetOperationsToTime(int wellId,
DateTime begin = default, DateTime end = default)
{
return new List<OperationInfoDto>
{
new OperationInfoDto
{
IntervalBegin = new DateTime(2021, 06, 01, 08, 00, 00),
IntervalEnd = new DateTime(2021, 06, 02, 08, 00, 00),
OperationData = new List<OperationDetailsDto>
{
new OperationDetailsDto
{
OperationName = "Роторное бурение",
OperationStartTime = new DateTime(2021, 06, 01, 10, 00, 00),
DurationHours = 1.2
},
new OperationDetailsDto
{
OperationName = "Подъем с проработкой",
OperationStartTime = new DateTime(2021, 06, 01, 11, 00, 00),
DurationHours = 3.2
},
new OperationDetailsDto
{
OperationName = "Роторное бурение",
OperationStartTime = new DateTime(2021, 06, 01, 12, 00, 00),
DurationHours = 1.5
},
new OperationDetailsDto
{
OperationName = "Неподвижное состояние",
OperationStartTime = new DateTime(2021, 06, 01, 13, 00, 00),
DurationHours = 0.2
},
new OperationDetailsDto
{
OperationName = "Роторное бурение",
OperationStartTime = new DateTime(2021, 06, 01, 14, 00, 00),
DurationHours = 3.2
}
}
},
new OperationInfoDto
{
IntervalBegin = new DateTime(2021, 06, 02, 08, 00, 00),
IntervalEnd = new DateTime(2021, 06, 03, 08, 00, 00),
OperationData = new List<OperationDetailsDto>
{
new OperationDetailsDto
{
OperationName = "На поверхности",
OperationStartTime = new DateTime(2021, 06, 13, 10, 01, 00),
DurationHours = 2.2
},
new OperationDetailsDto
{
OperationName = "Спуск в скважину",
OperationStartTime = new DateTime(2021, 06, 13, 11, 10, 00),
DurationHours = 0.4
},
new OperationDetailsDto
{
OperationName = "На поверхности",
OperationStartTime = new DateTime(2021, 06, 13, 12, 20, 00),
DurationHours = 2.5
},
new OperationDetailsDto
{
OperationName = "Вращение без циркуляции",
OperationStartTime = new DateTime(2021, 06, 13, 13, 00, 00),
DurationHours = 1.2
},
new OperationDetailsDto
{
OperationName = "Роторное бурение",
OperationStartTime = new DateTime(2021, 06, 13, 14, 00, 00),
DurationHours = 5.2
}
}
},
new OperationInfoDto
{
IntervalBegin = new DateTime(2021, 06, 03, 08, 00, 00),
IntervalEnd = new DateTime(2021, 06, 04, 08, 00, 00),
OperationData = new List<OperationDetailsDto>
{
new OperationDetailsDto
{
OperationName = "Подъем с проработкой",
OperationStartTime = new DateTime(2021, 06, 12, 10, 00, 00),
DurationHours = 3.2
},
new OperationDetailsDto
{
OperationName = "Спуск с проработкой",
OperationStartTime = new DateTime(2021, 06, 12, 11, 00, 00),
DurationHours = 1.4
},
new OperationDetailsDto
{
OperationName = "Подъем с проработкой",
OperationStartTime = new DateTime(2021, 06, 12, 12, 00, 00),
DurationHours = 0.5
},
new OperationDetailsDto
{
OperationName = "На поверхности",
OperationStartTime = new DateTime(2021, 06, 12, 13, 00, 00),
DurationHours = 3.2
},
new OperationDetailsDto
{
OperationName = "Роторное бурение",
OperationStartTime = new DateTime(2021, 06, 13, 14, 00, 00),
DurationHours = 1.2
}
}
}
};
}
public DrillingAnalysis GetDrillingAnalysis(IEnumerable<DataSaubBase> dataSaubBases)
{
var saubWellDepths = dataSaubBases.Select(s => (s.WellDepth,
TotalSeconds: (s.Date -
new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000));
var saubBitDepths = dataSaubBases.Select(s => (s.BitDepth,
TotalSeconds: (s.Date -
new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000));
var saubBlockPositions = dataSaubBases.Select(s => (s.BlockPosition,
TotalSeconds: (s.Date -
new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000));
var saubRotorSpeeds = dataSaubBases.Select(s => (s.RotorSpeed,
TotalSeconds: (s.Date -
new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000));
var saubPressures = dataSaubBases.Select(s => (s.Pressure,
TotalSeconds: (s.Date -
new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000));
var saubHookWeights = dataSaubBases.Select(s => (s.HookWeight,
TotalSeconds: (s.Date -
new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000));
var wellDepthChangingIndex = GetAForLinearFormula(saubWellDepths);
var bitPositionChangingIndex = GetAForLinearFormula(saubBitDepths);
var blockPositionChangingIndex = GetAForLinearFormula(saubBlockPositions);
var rotorSpeedChangingIndex = GetAForLinearFormula(saubRotorSpeeds);
var pressureChangingIndex = GetAForLinearFormula(saubPressures);
var hookWeightChangingIndex = GetAForLinearFormula(saubHookWeights);
var drillingAnalysis = new DrillingAnalysis
{
IdTelemetry = dataSaubBases.First().IdTelemetry,
Date = dataSaubBases.Last().Date,
IsDepthChanges = wellDepthChangingIndex >= 0.0001 || wellDepthChangingIndex <= -0.0001,
IsDepthNotChanges = wellDepthChangingIndex < 0.0001 && wellDepthChangingIndex > -0.0001,
IsBitRising = bitPositionChangingIndex >= 0.0001,
IsBitGoesDown = bitPositionChangingIndex <= -0.0001,
IsBitStandsStill = bitPositionChangingIndex < 0.0001 && bitPositionChangingIndex > -0.0001,
IsBitDepthLess20 = (saubBitDepths.Sum(s => s.BitDepth) / saubBitDepths.Count()) < 20.0,
IsBlockRising = blockPositionChangingIndex >= 0.0001,
IsBlockGoesDown = blockPositionChangingIndex <= -0.0001,
IsBlockStandsStill = blockPositionChangingIndex < 0.001 && blockPositionChangingIndex > -0.0001,
IsRotorSpeedLess3 = (saubRotorSpeeds.Sum(s => s.RotorSpeed) / saubRotorSpeeds.Count()) < 3,
IsRotorSpeedMore3 = (saubRotorSpeeds.Sum(s => s.RotorSpeed) / saubRotorSpeeds.Count()) >= 3,
IsPressureLess20 = (saubPressures.Sum(s => s.Pressure) / saubPressures.Count()) < 20.0,
IsPressureMore20 = (saubPressures.Sum(s => s.Pressure) / saubPressures.Count()) >= 20.0,
IsHookWeightNotChanges = hookWeightChangingIndex < 0.0001 && hookWeightChangingIndex > 0.0001,
IsHookWeightLess3 = (saubHookWeights.Sum(s => s.HookWeight) / saubHookWeights.Count()) < 3.0,
IdOperation = 1
};
drillingAnalysis.IdOperation = operationDetectorService.DetectOperation(drillingAnalysis).Id;
return drillingAnalysis;
}
private static double GetAForLinearFormula(IEnumerable<(double?, double)> rawData)
{
var (xSum, ySum, xySum, x2Sum) = GetFormulaVariables(rawData);
return (xSum * ySum - rawData.Count() * xySum) /
(xSum * xSum - rawData.Count() * x2Sum);
}
private static double GetBForLinearFormula(IEnumerable<(double?, double)> rawData)
{
var (xSum, ySum, xySum, x2Sum) = GetFormulaVariables(rawData);
return (xSum * xySum - x2Sum * ySum) /
(xSum * xSum - rawData.Count() * x2Sum);
}
private static (double xSum, double ySum, double xySum, double x2Sum) GetFormulaVariables(
IEnumerable<(double? value, double timestamp)> rawData)
{
var data = rawData.Select((d) => new
{
X = d.timestamp,
Y = d.value ?? 0.0
});
var xSum = data.Sum(d => d.X);
var ySum = data.Sum(d => d.Y);
var xySum = data.Sum(d => d.X * d.Y);
var x2Sum = data.Sum(d => d.X * d.X);
return (xSum, ySum, xySum, x2Sum);
}
}
}