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

303 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<Telemetry> cacheTelemetry;
private readonly CacheTable<Operation> cacheOperations;
private readonly IEnumerable<OperationDetector> operationDetectors;
private readonly IEnumerable<Operation> operations;
public AnalyticsService(IAsbCloudDbContext db, ITelemetryService telemetryService, CacheDb cacheDb)
{
this.db = db;
this.telemetryService = telemetryService;
cacheTelemetry = cacheDb.GetCachedTable<Telemetry>((AsbCloudDbContext)db);
cacheOperations = cacheDb.GetCachedTable<Operation>((AsbCloudDbContext)db);
operations = cacheOperations.Select(c => true);
operationDetectors = new OperationDetectorsContainer(operations).Detectors;
}
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,
BitDepth = d.BitDepth,
Date = d.Date
}).ToList();
}
public IEnumerable<WellDepthToIntervalDto> 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<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);
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<double?> 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<double?> 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);
}
}
}