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 cacheTelemetry; private readonly CacheTable cacheOperations; private readonly IEnumerable operationDetectors; private readonly IEnumerable operations; public AnalyticsService(IAsbCloudDbContext db, ITelemetryService telemetryService, CacheDb cacheDb) { this.db = db; this.telemetryService = telemetryService; cacheTelemetry = cacheDb.GetCachedTable((AsbCloudDbContext)db); cacheOperations = cacheDb.GetCachedTable((AsbCloudDbContext)db); operations = cacheOperations.Select(c => true); operationDetectors = new OperationDetectorsContainer(operations).Detectors; } 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, BitDepth = d.BitDepth, Date = d.Date }).ToList(); } public IEnumerable GetWellDepthToInterval(int wellId, int intervalHours = 24, int intervalMinutes = 0, int workBeginHour = 8, int workBeginMinutes = 0) { var intervalTime = new TimeSpan(intervalHours, intervalMinutes, 0) == default ? new TimeSpan(24, 0, 0) : new TimeSpan(intervalHours, intervalMinutes, 0); var workDayBeginTime = new TimeSpan(workBeginHour, workBeginMinutes, 0) == default ? new TimeSpan(8, 0, 0) : new TimeSpan(intervalHours, intervalMinutes, 0); ; var telemetry = telemetryService.GetTelemetryByWellId(wellId); if (telemetry is null) return null; var timezoneOffset = cacheTelemetry.FirstOrDefault(t => t.Id == telemetry.Id).Info.TimeZoneOffsetTotalHours; var drillingPeriodsInfo = db.GetDepthToInterval(telemetry.Id, (int)intervalTime.TotalSeconds, (int)workDayBeginTime.TotalSeconds, timezoneOffset); var wellDepthToIntervalData = drillingPeriodsInfo.Select(d => new WellDepthToIntervalDto { IntervalStartDate = d.Item3, IntervalDepthProgress = (d.Item2 - d.Item1) ?? 0.0 / intervalHours }).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); var saubBitDepths = dataSaubBases.Select(s => s.BitDepth); var saubBlockPositions = dataSaubBases.Select(s => s.BlockPosition); var saubRotorSpeeds = dataSaubBases.Select(s => s.RotorSpeed); var saubPressures = dataSaubBases.Select(s => s.Pressure); var saubHookWeights = dataSaubBases.Select(s => s.HookWeight); 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 >= 1.0 || wellDepthChangingIndex <= -1.0, IsDepthNotChanges = wellDepthChangingIndex < 1.0 && wellDepthChangingIndex > -1.0, IsBitRising = bitPositionChangingIndex <= -1.0, IsBitGoesDown = bitPositionChangingIndex >= 1.0, IsBitStandsStill = bitPositionChangingIndex < 1.0 && bitPositionChangingIndex > -1.0, IsBitDepthLess20 = (saubBitDepths.Sum() / saubBitDepths.Count()) < 20.0, IsBlockRising = blockPositionChangingIndex <= -1.0, IsBlockGoesDown = blockPositionChangingIndex >= 1.0, IsBlockStandsStill = blockPositionChangingIndex < 1.0 && blockPositionChangingIndex > -1.0, IsRotorSpeedLess3 = (saubRotorSpeeds.Sum() / saubRotorSpeeds.Count()) < 3.0, IsRotorSpeedMore3 = (saubRotorSpeeds.Sum() / saubRotorSpeeds.Count()) >= 3.0, IsPressureLess20 = (saubPressures.Sum() / saubPressures.Count()) < 20.0, IsPressureMore20 = (saubPressures.Sum() / saubPressures.Count()) >= 20.0, IsHookWeightNotChanges = hookWeightChangingIndex < 1.0 && hookWeightChangingIndex > 1.0, IsHookWeightLess3 = (saubHookWeights.Sum() / saubHookWeights.Count()) < 3.0, IdOperation = 1 }; drillingAnalysis.IdOperation = GetOperation(drillingAnalysis).Id; return drillingAnalysis; } private Operation GetOperation(DrillingAnalysis data) { var operation = operationDetectors.OrderBy(d => d.Order).First(o => o.Detect(data)).Operation ?? new Operation { Id = 1, Name = "Невозможно определить операцию" }; return operations.FirstOrDefault(o => o.Name.Equals(operation.Name)); } private static double GetAForLinearFormula(IEnumerable rawData) { var (xSum, ySum, xySum, x2Sum) = GetFormulaVariables(rawData); return (xSum * ySum - rawData.Count() * xySum) / (xSum * xSum - rawData.Count() * x2Sum); } private static (int xSum, double ySum, double xySum, int x2Sum) GetFormulaVariables( IEnumerable rawData) { var data = rawData.Select((d, i) => new { X = i, Y = d ?? 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); } } }