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 telemetry = telemetryService.GetTelemetryByWellId(wellId); if (telemetry is null) return null; var timezoneOffset = telemetryService.GetTimezoneOffsetByTelemetryId(telemetry.Id); var drillingPeriodsInfo = db.GetDepthToInterval(telemetry.Id, intervalHoursTimestamp, workBeginTimestamp, 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) { var telemetry = telemetryService.GetTelemetryByWellId(wellId); if (telemetry is null) return null; var operations = (from a in db.DrillingAnalysis where a.IdTelemetry == telemetry.Id && a.Date > begin && a.Date < end && a.IdOperation != null join o in db.Operations on a.IdOperation equals o.Id group a by new { a.IdOperation, o.Name } into g select new OperationDurationDto { ProcessName = g.Key.Name, Duration = g.Where(g => g.Duration > 0) .Sum(a => a.Duration) }).ToList(); return operations; } public IEnumerable GetOperationsToInterval(int wellId, int intervalHoursTimestamp, int workBeginTimestamp) { intervalHoursTimestamp = intervalHoursTimestamp == 0 ? 86400 : intervalHoursTimestamp; var telemetry = telemetryService.GetTelemetryByWellId(wellId); if (telemetry is null) return null; var timezoneOffset = telemetryService.GetTimezoneOffsetByTelemetryId(telemetry.Id); var operations = (from a in db.DrillingAnalysis where a.IdTelemetry == telemetry.Id && a.IdOperation != null join o in db.Operations on a.IdOperation equals o.Id group a by new { Interval = Math.Floor((a.UnixDate - workBeginTimestamp + timezoneOffset) / intervalHoursTimestamp), OperationId = a.IdOperation, o.Name } into g select new { IntervalStart = g.Min(d => d.Date).Date, OperationName = g.Key.Name, OperationsDuration = g.Sum(an => an.Duration) }).ToList(); var operationsGroupedByInterval = operations.GroupBy(op => op.IntervalStart) .Select(o => new OperationInfoDto { IntervalBegin = o.Key, Operations = o.Select(opr => new OperationDetailsDto { OperationName = opr.OperationName, Duration = opr.OperationsDuration }).ToList() }) .OrderBy(ops => ops.IntervalBegin); return operationsGroupedByInterval; } public DrillingAnalysis GetDrillingAnalysis(IEnumerable dataSaubBases) { var lastSaubDate = dataSaubBases.Last().Date; var saubWellDepths = dataSaubBases.Where(sw => sw.WellDepth is not null) .Select(s => (Value: (double)s.WellDepth, (s.Date - dataSaubBases.First().Date).TotalSeconds)); var saubBitDepths = dataSaubBases.Where(sw => sw.BitDepth is not null) .Select(s => (Value: (double)s.BitDepth, (s.Date - dataSaubBases.First().Date).TotalSeconds)); var saubBlockPositions = dataSaubBases.Where(sw => sw.BlockPosition is not null) .Select(s => (Value: (double)s.BlockPosition, (s.Date - dataSaubBases.First().Date).TotalSeconds)); var saubRotorSpeeds = dataSaubBases.Where(sw => sw.RotorSpeed is not null) .Select(s => (Value: (double)s.RotorSpeed, (s.Date - dataSaubBases.First().Date).TotalSeconds)); var saubPressures = dataSaubBases.Where(sw => sw.Pressure is not null) .Select(s => (Value: (double)s.Pressure, (s.Date - dataSaubBases.First().Date).TotalSeconds)); var saubHookWeights = dataSaubBases.Where(sw => sw.HookWeight is not null) .Select(s => (Value: (double)s.HookWeight, (s.Date - dataSaubBases.First().Date).TotalSeconds)); var wellDepthChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubWellDepths); var bitPositionChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubBitDepths); var blockPositionChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubBlockPositions); var rotorSpeedChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubRotorSpeeds); var pressureChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubPressures); var hookWeightChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubHookWeights); var IsBlockRising = LinearFunctionCalculator.IsValueGoesDown(blockPositionChangingIndex, -0.0001); var IsBlockGoesDown = LinearFunctionCalculator.IsValueGoesUp(blockPositionChangingIndex, 0.0001); var IsBlockStandsStill = LinearFunctionCalculator.IsValueNotChanges(blockPositionChangingIndex, (0.0001, -0.0001)); var drillingAnalysis = new DrillingAnalysis { IdTelemetry = dataSaubBases.First().IdTelemetry, Date = lastSaubDate, UnixDate = (long)(lastSaubDate - new DateTime(1970,1,1,0,0,0)).TotalSeconds, Duration = (int)(dataSaubBases.Last().Date - dataSaubBases.ElementAt(dataSaubBases.Count() - 2).Date).TotalSeconds, IsDepthChanges = LinearFunctionCalculator.IsValueChanges(wellDepthChangingIndex, (0.0001, -0.0001)), IsDepthNotChanges = LinearFunctionCalculator.IsValueNotChanges(wellDepthChangingIndex, (0.0001, -0.0001)), IsBitRising = LinearFunctionCalculator.IsValueGoesDown(bitPositionChangingIndex, -0.0001), IsBitGoesDown = LinearFunctionCalculator.IsValueGoesUp(bitPositionChangingIndex, 0.0001), IsBitStandsStill = LinearFunctionCalculator.IsValueNotChanges(bitPositionChangingIndex, (0.0001, -0.0001)), IsBitDepthLess20 = LinearFunctionCalculator.IsAverageLessThanBound(saubBitDepths, 20), IsBlockRising = LinearFunctionCalculator.IsValueGoesDown(blockPositionChangingIndex, -0.0001), IsBlockGoesDown = LinearFunctionCalculator.IsValueGoesUp(blockPositionChangingIndex, 0.0001), IsBlockStandsStill = LinearFunctionCalculator.IsValueNotChanges(blockPositionChangingIndex, (0.0001, -0.0001)), IsRotorSpeedLess3 = LinearFunctionCalculator.IsAverageLessThanBound(saubRotorSpeeds, 3), IsRotorSpeedMore3 = LinearFunctionCalculator.IsAverageMoreThanBound(saubRotorSpeeds, 3), IsPressureLess20 = LinearFunctionCalculator.IsAverageLessThanBound(saubPressures, 20), IsPressureMore20 = LinearFunctionCalculator.IsAverageMoreThanBound(saubPressures, 20), IsHookWeightNotChanges = LinearFunctionCalculator.IsValueNotChanges(hookWeightChangingIndex, (0.0001, -0.0001)), IsHookWeightLess3 = LinearFunctionCalculator.IsAverageLessThanBound(saubHookWeights, 3), IdOperation = 1 }; drillingAnalysis.IdOperation = operationDetectorService.DetectOperation(drillingAnalysis).Id; return drillingAnalysis; } } }