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 cacheOperations; private readonly OperationDetectorService operationDetectorService; private readonly IEnumerable operations; public AnalyticsService(IAsbCloudDbContext db, ITelemetryService telemetryService, CacheDb cacheDb) { this.db = db; this.telemetryService = telemetryService; cacheOperations = cacheDb.GetCachedTable((AsbCloudDbContext)db); operations = cacheOperations.Select(c => true); operationDetectorService = new OperationDetectorService(operations); } public IEnumerable 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 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 GetOperationsSummary(int wellId, DateTime begin = default, DateTime end = default) { return new List { 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 GetOperationsToTime(int wellId, DateTime begin = default, DateTime end = default) { return new List { new OperationInfoDto { IntervalBegin = new DateTime(2021, 06, 01, 08, 00, 00), IntervalEnd = new DateTime(2021, 06, 02, 08, 00, 00), OperationData = new List { 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 { 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 { 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 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); } } }