@ -1,245 +1,307 @@
using AsbCloudApp.Data ;
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading ;
using System.Threading.Tasks ;
using AsbCloudApp.Data ;
using AsbCloudApp.Data.DetectedOperation ;
using AsbCloudApp.Data.Subsystems ;
using AsbCloudApp.Exceptions ;
using AsbCloudApp.Requests ;
using AsbCloudApp.Services ;
using AsbCloudDb.Model ;
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading ;
using System.Threading.Tasks ;
using AsbCloudInfrastructure.Services.DetectOperations ;
namespace AsbCloudInfrastructure.Services.Subsystems ;
internal class SubsystemService : ISubsystemService
{
private const int IdSubsystemAPD = 1 ;
private const int IdSubsystemAPDRotor = 11 ;
private const int IdSubsystemAPDSlide = 12 ;
private const int IdSubsystemOscillation = 65536 ;
private const int IdSubsystemAPD = 1 ;
private const int IdSubsystemAPDRotor = 11 ;
private const int IdSubsystemAPDSlide = 12 ;
private const int IdSubsystemOscillation = 65536 ;
private readonly ICrudRepository < SubsystemDto > subsystemRepository ;
private readonly ICrudRepository < SubsystemDto > subsystemRepository ;
private readonly IWellService wellService ;
private readonly IDetectedOperationService detectedOperationService ;
private readonly IWellService wellService ;
private readonly IDetectedOperationService detectedOperationService ;
private readonly IScheduleRepository scheduleRepository ;
private IDictionary < int , SubsystemDto > subsystems = new Dictionary < int , SubsystemDto > ( ) ;
private IDictionary < int , SubsystemDto > subsystems = new Dictionary < int , SubsystemDto > ( ) ;
public SubsystemService ( ICrudRepository < SubsystemDto > subsystemRepository ,
IWellService wellService ,
IDetectedOperationService detectedOperationService )
{
this . wellService = wellService ;
this . subsystemRepository = subsystemRepository ;
this . detectedOperationService = detectedOperationService ;
}
public SubsystemService ( ICrudRepository < SubsystemDto > subsystemRepository ,
IWellService wellService ,
IDetectedOperationService detectedOperationService ,
IScheduleRepository scheduleRepository )
{
this . wellService = wellService ;
this . subsystemRepository = subsystemRepository ;
this . detectedOperationService = detectedOperationService ;
this . scheduleRepository = scheduleRepository ;
}
public async Task < IEnumerable < SubsystemStatDto > > GetStatAsync ( SubsystemRequest request , CancellationToken token )
{
var well = await wellService . GetOrDefaultAsync ( request . IdWell , token )
? ? throw new ArgumentInvalidException ( nameof ( request . IdWell ) , $"Well Id: {request.IdWell} does not exist" ) ;
if ( ! well . IdTelemetry . HasValue )
return Enumerable . Empty < SubsystemStatDto > ( ) ;
var detectedOperationSummaryRequest = new DetectedOperationByWellRequest
// получить расписания бурильщиков по скважинам // ScheduleRepository добавить новый метод
// [
// get telemetryId by idWell // IWellService.GetOrDefaultStatAsync
// получить detectedOperation by telemetry //detectedOperationService.GetOperationsAsync
// сгруппировать по бурильщикам
// [
// рассчитать статистику // CalcStatAsync
// join driller from group
// ]
// join well (cluster, deposit)
// ]
public async Task < IEnumerable < DrillerDetectedOperationStatDto > > GetByWellsAsync ( GetStatRequest request ,
CancellationToken token )
{
var result = new List < DrillerDetectedOperationStatDto > ( ) ;
var schedulePage = await scheduleRepository . GetPageAsync ( request , token ) ;
var wells = await wellService . GetAsync ( new WellRequest { Ids = request . IdsWells } , token ) ;
foreach ( var schedule in schedulePage )
{
IdWell = request . IdWell ,
IdsCategories = WellOperationCategory . MechanicalDrillingSubIds ,
var idWell = schedule . IdWell ;
var well = wells . FirstOrDefault ( w = > w . Id = = idWell ) ! ;
GeDateStart = request . GeDate ,
LeDateEnd = request . LeDate ,
var byWellRequest = new DetectedOperationByWellRequest ( idWell , new DetectedOperationRequest ( ) ) ;
GeDepthStart = request . GeDepth ,
LeDepthEnd = request . LeDepth ,
} ;
var detectedOperations = await detectedOperationService
. GetOperationsAsync ( byWellRequest , token ) ;
var operations = await detectedOperationService . GetOperationsAsync ( detectedOperationSummaryRequest ,
token ) ;
var groupByDriller = detectedOperations
. Where ( operation = > operation . Driller is not null )
. GroupBy ( operation = > operation . Driller ) ;
if ( request . IdDriller . HasValue )
operations = operations . Where ( o = > o . Driller is not null & & o . Driller . Id = = request . IdDriller . Value ) ;
foreach ( var entry in groupByDriller )
{
var drillerOperationsStat = await CalcStatAsync ( entry , token ) ;
var dto = new DrillerDetectedOperationStatDto
{
Statistic = drillerOperationsStat ,
Schedule = schedule ,
Well = well ,
} ;
result . Add ( dto ) ;
}
}
if ( ! operations . Any ( ) )
return Enumerable . Empty < SubsystemStatDto > ( ) ;
return result ;
}
var stat = await CalcStatAsync ( operations , token ) ;
return stat ;
}
public async Task < IEnumerable < SubsystemStatDto > > GetStatAsync ( SubsystemRequest request , CancellationToken token )
{
var well = await wellService . GetOrDefaultAsync ( request . IdWell , token )
? ? throw new ArgumentInvalidException ( nameof ( request . IdWell ) ,
$"Well Id: {request.IdWell} does not exist" ) ;
public async Task < IEnumerable < SubsystemActiveWellStatDto > > GetStatByActiveWells ( IEnumerable < int > wellIds , CancellationToken token )
{
var activeWells = await wellService . GetAsync ( new ( ) { Ids = wellIds , IdState = 1 } , token ) ;
var result = await GetStatAsync ( activeWells , null , null , token ) ;
return result ;
}
private async Task < IEnumerable < SubsystemStatDto > > CalcStatAsync ( IEnumerable < DetectedOperationWithDrillerDto > operations , CancellationToken token )
{
if ( ! subsystems . Any ( ) )
subsystems = ( await subsystemRepository . GetAllAsync ( token ) ) . ToDictionary ( s = > s . Id , s = > s ) ;
if ( ! well . IdTelemetry . HasValue )
return Enumerable . Empty < SubsystemStatDto > ( ) ;
var oscillationStat = CalcOscillationStat ( operations ) ;
var apdStat = CalcApdStat ( operations ) ;
var detectedOperationSummaryRequest = new DetectedOperationByWellRequest
{
IdWell = request . IdWell ,
IdsCategories = WellOperationCategory . MechanicalDrillingSubIds ,
var stat = new List < SubsystemStatDto > { oscillationStat } ;
stat . AddRange ( apdStat ) ;
GeDateStart = request . GeDate ,
LeDateEnd = request . LeDate ,
return stat ;
}
GeDepthStart = request . GeDepth ,
LeDepthEnd = request . LeDepth ,
} ;
private SubsystemStatDto CalcOscillationStat ( IEnumerable < DetectedOperationWithDrillerDto > operations )
{
operations = operations . Where ( o = > o . IdCategory = = WellOperationCategory . IdSlide ) ;
var operations = await detectedOperationService . GetOperationsAsync ( detectedOperationSummaryRequest ,
token ) ;
var ( sumDepthInterval , usedTimeHours , operationCount ) = AggregateOperations ( IdSubsystemOscillation , operations ) ;
if ( request . IdDriller . HasValue )
operations = operations . Where ( o = > o . Driller is not null & & o . Driller . Id = = request . IdDriller . Value ) ;
var oscillationStat = new SubsystemStatDto
{
IdSubsystem = IdSubsystemOscillation ,
SubsystemName = subsystems . TryGetValue ( IdSubsystemOscillation , out var subsystemDto ) ? subsystemDto . Name : "unknown" ,
UsedTimeHours = usedTimeHours ,
SumOperationDepthInterval = operations . Sum ( o = > o . DepthEnd - o . DepthStart ) ,
SumOperationDurationHours = operations . Sum ( o = > o . DurationMinutes / 60 ) ,
SumDepthInterval = sumDepthInterval ,
OperationCount = operationCount ,
} ;
oscillationStat . KUsage = oscillationStat . SumDepthInterval / oscillationStat . SumOperationDepthInterval ;
return oscillationStat ;
}
if ( ! operations . Any ( ) )
return Enumerable . Empty < SubsystemStatDto > ( ) ;
private IEnumerable < SubsystemStatDto > CalcApdStat ( IEnumerable < DetectedOperationWithDrillerDto > operations )
{
var apdRotorAndSlide = operations
. Where ( o = > WellOperationCategory . MechanicalDrillingSubIds . Contains ( o . IdCategory ) )
. GroupBy ( o = > o . IdCategory )
. Select ( group = >
{
var idSubsystem = group . Key switch
{
WellOperationCategory . IdRotor = > IdSubsystemAPDRotor ,
WellOperationCategory . IdSlide = > IdSubsystemAPDSlide ,
_ = > throw new ArgumentException ( $"IdCategory: {group.Key} does not supported in this method" , nameof ( group . Key ) )
} ;
var stat = await CalcStatAsync ( operations , token ) ;
return stat ;
}
var ( sumDepthInterval , usedTimeHours , operationCount ) = AggregateOperations ( idSubsystem , group ) ;
public async Task < IEnumerable < SubsystemActiveWellStatDto > > GetStatByActiveWells ( IEnumerable < int > wellIds ,
CancellationToken token )
{
var activeWells = await wellService . GetAsync ( new ( ) { Ids = wellIds , IdState = 1 } , token ) ;
var result = await GetStatAsync ( activeWells , null , null , token ) ;
return result ;
}
var subsystemStat = new SubsystemStatDto
{
IdSubsystem = idSubsystem ,
SubsystemName = subsystems . TryGetValue ( idSubsystem , out var subsystemDto ) ? subsystemDto . Name : "unknown" ,
UsedTimeHours = usedTimeHours ,
SumOperationDepthInterval = group . Sum ( o = > o . DepthEnd - o . DepthStart ) ,
SumOperationDurationHours = group . Sum ( o = > o . DurationMinutes / 60 ) ,
SumDepthInterval = sumDepthInterval ,
OperationCount = operationCount ,
} ;
private async Task < IEnumerable < SubsystemStatDto > > CalcStatAsync (
IEnumerable < DetectedOperationWithDrillerDto > operations , CancellationToken token )
{
if ( ! subsystems . Any ( ) )
subsystems = ( await subsystemRepository . GetAllAsync ( token ) ) . ToDictionary ( s = > s . Id , s = > s ) ;
subsystemStat . KUsage = subsystemStat . SumDepthInterval / subsystemStat . SumOperationDepthInterval ;
var oscillationStat = CalcOscillationStat ( operations ) ;
var apdStat = CalcApdStat ( operations ) ;
return subsystemStat ;
} ) ;
if ( ! apdRotorAndSlide . Any ( ) )
return Enumerable . Empty < SubsystemStatDto > ( ) ;
var apdSum = new SubsystemStatDto
{
IdSubsystem = IdSubsystemAPD ,
SubsystemName = subsystems . TryGetValue ( IdSubsystemAPD , out var subsystemDto ) ? subsystemDto . Name : "unknown" ,
UsedTimeHours = apdRotorAndSlide . Sum ( part = > part . UsedTimeHours ) ,
SumOperationDepthInterval = apdRotorAndSlide . Sum ( part = > part . SumOperationDepthInterval ) ,
SumOperationDurationHours = apdRotorAndSlide . Sum ( part = > part . SumOperationDurationHours ) ,
SumDepthInterval = apdRotorAndSlide . Sum ( part = > part . SumDepthInterval ) ,
OperationCount = apdRotorAndSlide . Sum ( part = > part . OperationCount ) ,
} ;
apdSum . KUsage = apdSum . SumDepthInterval / apdSum . SumOperationDepthInterval ;
var stat = new List < SubsystemStatDto > { oscillationStat } ;
stat . AddRange ( apdStat ) ;
var apdStat = new List < SubsystemStatDto > { apdSum } ;
apdStat . AddRange ( apdRotorAndSlide ) ;
return stat ;
}
return apdStat ;
}
private SubsystemStatDto CalcOscillationStat ( IEnumerable < DetectedOperationWithDrillerDto > operations )
{
operations = operations . Where ( o = > o . IdCategory = = WellOperationCategory . IdSlide ) ;
private static ( double SumDepthInterval , double UsedTimeHours , int Count ) AggregateOperations ( int idSubsystem ,
IEnumerable < DetectedOperationWithDrillerDto > operations ) = >
idSubsystem switch
{
IdSubsystemAPDRotor = > CalcOperationsByEnableSubsystems ( operations , EnabledSubsystemsFlags . AutoRotor ) ,
IdSubsystemAPDSlide = > CalcOperationsByEnableSubsystems ( operations ,
EnabledSubsystemsFlags . AutoSlide | EnabledSubsystemsFlags . AutoOscillation ) ,
IdSubsystemOscillation = > CalcOperationsByEnableSubsystems ( operations , EnabledSubsystemsFlags . AutoOscillation ) ,
_ = > throw new ArgumentException ( $"IdSubsystem: {idSubsystem} does not supported in this method" , nameof ( idSubsystem ) )
} ;
var ( sumDepthInterval , usedTimeHours , operationCount ) = AggregateOperations ( IdSubsystemOscillation , operations ) ;
private static ( double SumDepthInterval , double UsedTimeHours , int OperationCount ) CalcOperationsByEnableSubsystems (
IEnumerable < DetectedOperationWithDrillerDto > operations ,
EnabledSubsystemsFlags enabledSubsystems )
{
var filtered = operations . Where ( o = > enabledSubsystems . HasEnabledSubsystems ( o . EnabledSubsystems ) ) ;
var oscillationStat = new SubsystemStatDto
{
IdSubsystem = IdSubsystemOscillation ,
SubsystemName = subsystems . TryGetValue ( IdSubsystemOscillation , out var subsystemDto )
? subsystemDto . Name
: "unknown" ,
UsedTimeHours = usedTimeHours ,
SumOperationDepthInterval = operations . Sum ( o = > o . DepthEnd - o . DepthStart ) ,
SumOperationDurationHours = operations . Sum ( o = > o . DurationMinutes / 60 ) ,
SumDepthInterval = sumDepthInterval ,
OperationCount = operationCount ,
} ;
var sumDepthInterval = filtered . Sum ( o = > o . DepthEnd - o . DepthStart ) ;
var usedTimeHours = filtered . Sum ( o = > o . DurationMinutes / 60 ) ;
var operationCount = filtered . Count ( ) ;
oscillationStat . KUsage = oscillationStat . SumDepthInterval / oscillationStat . SumOperationDepthInterval ;
return ( sumDepthInterval , usedTimeHours , operationCount ) ;
}
return oscillationStat ;
}
private async Task < IEnumerable < SubsystemActiveWellStatDto > > GetStatAsync ( IEnumerable < WellDto > wells ,
DateTime ? geDate ,
DateTime ? leDate ,
CancellationToken token )
{
if ( ! wells . Any ( ) )
return Enumerable . Empty < SubsystemActiveWellStatDto > ( ) ;
private IEnumerable < SubsystemStatDto > CalcApdStat ( IEnumerable < DetectedOperationWithDrillerDto > operations )
{
var apdRotorAndSlide = operations
. Where ( o = > WellOperationCategory . MechanicalDrillingSubIds . Contains ( o . IdCategory ) )
. GroupBy ( o = > o . IdCategory )
. Select ( group = >
{
var idSubsystem = group . Key switch
{
WellOperationCategory . IdRotor = > IdSubsystemAPDRotor ,
WellOperationCategory . IdSlide = > IdSubsystemAPDSlide ,
_ = > throw new ArgumentException ( $"IdCategory: {group.Key} does not supported in this method" ,
nameof ( group . Key ) )
} ;
var idsTelemetries = wells
. Where ( w = > w . IdTelemetry is not null )
. Select ( w = > w . IdTelemetry ! . Value )
. Distinct ( ) ;
var ( sumDepthInterval , usedTimeHours , operationCount ) = AggregateOperations ( idSubsystem , group ) ;
var wellsStat = new List < SubsystemActiveWellStatDto > ( ) ;
var subsystemStat = new SubsystemStatDto
{
IdSubsystem = idSubsystem ,
SubsystemName = subsystems . TryGetValue ( idSubsystem , out var subsystemDto )
? subsystemDto . Name
: "unknown" ,
UsedTimeHours = usedTimeHours ,
SumOperationDepthInterval = group . Sum ( o = > o . DepthEnd - o . DepthStart ) ,
SumOperationDurationHours = group . Sum ( o = > o . DurationMinutes / 60 ) ,
SumDepthInterval = sumDepthInterval ,
OperationCount = operationCount ,
} ;
foreach ( var well in wells )
{
var hoursOffset = well . Timezone . Hours ;
subsystemStat . KUsage = subsystemStat . SumDepthInterval / subsystemStat . SumOperationDepthInterval ;
var geDateStartUtc = geDate ? . ToUtcDateTimeOffset ( hoursOffset ) ;
return subsystemStat ;
} ) ;
var leDateUtc = leDate ? . ToUtcDateTimeOffset ( hoursOffset ) ;
if ( ! apdRotorAndSlide . Any ( ) )
return Enumerable . Empty < SubsystemStatDto > ( ) ;
var request = new DetectedOperationByWellRequest
{
IdWell = well . Id ,
IdsCategories = WellOperationCategory . MechanicalDrillingSubIds ,
GeDateStart = geDateStartUtc ,
LeDateEnd = leDateUtc ,
} ;
var apdSum = new SubsystemStatDto
{
IdSubsystem = IdSubsystemAPD ,
SubsystemName =
subsystems . TryGetValue ( IdSubsystemAPD , out var subsystemDto ) ? subsystemDto . Name : "unknown" ,
UsedTimeHours = apdRotorAndSlide . Sum ( part = > part . UsedTimeHours ) ,
SumOperationDepthInterval = apdRotorAndSlide . Sum ( part = > part . SumOperationDepthInterval ) ,
SumOperationDurationHours = apdRotorAndSlide . Sum ( part = > part . SumOperationDurationHours ) ,
SumDepthInterval = apdRotorAndSlide . Sum ( part = > part . SumDepthInterval ) ,
OperationCount = apdRotorAndSlide . Sum ( part = > part . OperationCount ) ,
} ;
var telemetryOperations = await detectedOperationService
. GetOperationsAsync ( request , token ) ;
apdSum . KUsage = apdSum . SumDepthInterval / apdSum . SumOperationDepthInterval ;
var wellStat = new SubsystemActiveWellStatDto { Well = well } ;
var apdStat = new List < SubsystemStatDto > { apdSum } ;
apdStat . AddRange ( apdRotorAndSlide ) ;
if ( ! telemetryOperations . Any ( ) )
continue ;
return apdStat ;
}
var subsystemStat = await CalcStatAsync ( telemetryOperations , token ) ;
private static ( double SumDepthInterval , double UsedTimeHours , int Count ) AggregateOperations ( int idSubsystem ,
IEnumerable < DetectedOperationWithDrillerDto > operations ) = >
idSubsystem switch
{
IdSubsystemAPDRotor = > CalcOperationsByEnableSubsystems ( operations , EnabledSubsystemsFlags . AutoRotor ) ,
IdSubsystemAPDSlide = > CalcOperationsByEnableSubsystems ( operations ,
EnabledSubsystemsFlags . AutoSlide | EnabledSubsystemsFlags . AutoOscillation ) ,
IdSubsystemOscillation = > CalcOperationsByEnableSubsystems ( operations ,
EnabledSubsystemsFlags . AutoOscillation ) ,
_ = > throw new ArgumentException ( $"IdSubsystem: {idSubsystem} does not supported in this method" ,
nameof ( idSubsystem ) )
} ;
if ( ! subsystemStat . Any ( ) )
continue ;
private static ( double SumDepthInterval , double UsedTimeHours , int OperationCount ) CalcOperationsByEnableSubsystems (
IEnumerable < DetectedOperationWithDrillerDto > operations ,
EnabledSubsystemsFlags enabledSubsystems )
{
var filtered = operations . Where ( o = > enabledSubsystems . HasEnabledSubsystems ( o . EnabledSubsystems ) ) ;
wellStat . SubsystemAPD = subsystemStat . FirstOrDefault ( s = > s . IdSubsystem = = IdSubsystemAPD ) ;
wellStat . SubsystemOscillation = subsystemStat . FirstOrDefault ( s = > s . IdSubsystem = = IdSubsystemOscillation ) ;
wellsStat . Add ( wellStat ) ;
}
var sumDepthInterval = filtered . Sum ( o = > o . DepthEnd - o . DepthStart ) ;
var usedTimeHours = filtered . Sum ( o = > o . DurationMinutes / 60 ) ;
var operationCount = filtered . Count ( ) ;
return wellsStat ;
}
return ( sumDepthInterval , usedTimeHours , operationCount ) ;
}
private async Task < IEnumerable < SubsystemActiveWellStatDto > > GetStatAsync ( IEnumerable < WellDto > wells ,
DateTime ? geDate ,
DateTime ? leDate ,
CancellationToken token )
{
if ( ! wells . Any ( ) )
return Enumerable . Empty < SubsystemActiveWellStatDto > ( ) ;
var idsTelemetries = wells
. Where ( w = > w . IdTelemetry is not null )
. Select ( w = > w . IdTelemetry ! . Value )
. Distinct ( ) ;
var wellsStat = new List < SubsystemActiveWellStatDto > ( ) ;
foreach ( var well in wells )
{
var hoursOffset = well . Timezone . Hours ;
var geDateStartUtc = geDate ? . ToUtcDateTimeOffset ( hoursOffset ) ;
var leDateUtc = leDate ? . ToUtcDateTimeOffset ( hoursOffset ) ;
var request = new DetectedOperationByWellRequest
{
IdWell = well . Id ,
IdsCategories = WellOperationCategory . MechanicalDrillingSubIds ,
GeDateStart = geDateStartUtc ,
LeDateEnd = leDateUtc ,
} ;
var telemetryOperations = await detectedOperationService
. GetOperationsAsync ( request , token ) ;
var wellStat = new SubsystemActiveWellStatDto { Well = well } ;
if ( ! telemetryOperations . Any ( ) )
continue ;
var subsystemStat = await CalcStatAsync ( telemetryOperations , token ) ;
if ( ! subsystemStat . Any ( ) )
continue ;
wellStat . SubsystemAPD = subsystemStat . FirstOrDefault ( s = > s . IdSubsystem = = IdSubsystemAPD ) ;
wellStat . SubsystemOscillation = subsystemStat . FirstOrDefault ( s = > s . IdSubsystem = = IdSubsystemOscillation ) ;
wellsStat . Add ( wellStat ) ;
}
return wellsStat ;
}
}