forked from ddrilling/AsbCloudServer
303 lines
14 KiB
C#
303 lines
14 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|