From 9aa78e9e2cb69f8d003a4ac46d108948ed098375 Mon Sep 17 00:00:00 2001 From: KharchenkoVV Date: Thu, 24 Jun 2021 13:02:31 +0500 Subject: [PATCH] =?UTF-8?q?CS2-24:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D1=80=D0=B0=D1=81=D0=BF=D0=BE=D0=B7=D0=BD?= =?UTF-8?q?=D0=B0=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BF=D0=BE=20=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Services/IAnalyticsService.cs | 2 + AsbCloudApp/Services/ISaubDataCache.cs | 10 ++ AsbCloudDb/Model/AsbCloudDbContext.cs | 39 +++++ AsbCloudDb/Model/DrillingAnalysis.cs | 82 +++++++++ AsbCloudDb/Model/IAsbCloudDbContext.cs | 2 + AsbCloudDb/Model/Operation.cs | 20 +++ AsbCloudDb/Model/Telemetry.cs | 2 + AsbCloudInfrastructure/DependencyInjection.cs | 1 + .../Services/AnalyticsService.cs | 81 +++++++++ .../Services/DataService.cs | 26 ++- .../Services/OperationDetector.cs | 12 ++ .../Services/OperationDetectorsContainer.cs | 163 ++++++++++++++++++ .../Services/SaubEventsCache.cs | 15 ++ .../Controllers/AnalyticsController.cs | 4 +- .../Алгоритм_определения_операций_буровой.ods | Bin 0 -> 28024 bytes .../Алгоритм_определения_операций_буровой.pdf | Bin 0 -> 13192 bytes 16 files changed, 456 insertions(+), 3 deletions(-) create mode 100644 AsbCloudApp/Services/ISaubDataCache.cs create mode 100644 AsbCloudDb/Model/DrillingAnalysis.cs create mode 100644 AsbCloudDb/Model/Operation.cs create mode 100644 AsbCloudInfrastructure/Services/OperationDetector.cs create mode 100644 AsbCloudInfrastructure/Services/OperationDetectorsContainer.cs create mode 100644 AsbCloudInfrastructure/Services/SaubEventsCache.cs create mode 100644 AsbCloudWebApi/Docs/Алгоритм_определения_операций_буровой.ods create mode 100644 AsbCloudWebApi/Docs/Алгоритм_определения_операций_буровой.pdf diff --git a/AsbCloudApp/Services/IAnalyticsService.cs b/AsbCloudApp/Services/IAnalyticsService.cs index e8efb169..dccfd467 100644 --- a/AsbCloudApp/Services/IAnalyticsService.cs +++ b/AsbCloudApp/Services/IAnalyticsService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using AsbCloudApp.Data; +using AsbCloudDb.Model; namespace AsbCloudApp.Services { @@ -13,5 +14,6 @@ namespace AsbCloudApp.Services DateTime begin = default, DateTime end = default); IEnumerable GetOperationsToTime(int wellId, DateTime begin = default, DateTime end = default); + DrillingAnalysis GetDrillingAnalysis(IEnumerable dataSaubBases); } } diff --git a/AsbCloudApp/Services/ISaubDataCache.cs b/AsbCloudApp/Services/ISaubDataCache.cs new file mode 100644 index 00000000..0f01fd49 --- /dev/null +++ b/AsbCloudApp/Services/ISaubDataCache.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using AsbCloudDb.Model; + +namespace AsbCloudApp.Services +{ + public interface ISaubDataCache + { + Dictionary> GetSaubData(); + } +} diff --git a/AsbCloudDb/Model/AsbCloudDbContext.cs b/AsbCloudDb/Model/AsbCloudDbContext.cs index 00b42f46..c762892a 100644 --- a/AsbCloudDb/Model/AsbCloudDbContext.cs +++ b/AsbCloudDb/Model/AsbCloudDbContext.cs @@ -25,6 +25,8 @@ namespace AsbCloudDb.Model public virtual DbSet UserRoles { get; set; } public virtual DbSet Wells { get; set; } public virtual DbSet Reports { get; set; } + public virtual DbSet Operations { get; set; } + public virtual DbSet DrillingAnalysis { get; set; } //public AsbCloudDbContext(string connectionString = "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True") //{ @@ -86,6 +88,20 @@ namespace AsbCloudDb.Model .HasConstraintName("t_telemetry_user_t_telemetry_id_fk"); }); + modelBuilder.Entity(entity => + { + entity.HasOne(d => d.Telemetry) + .WithMany(p => p.Analysis) + .HasForeignKey(d => d.IdTelemetry) + .HasConstraintName("t_analysis_t_telemetry_id_fk"); + + entity.HasOne(d => d.Operation) + .WithMany(p => p.Analysis) + .HasForeignKey(d => d.IdOperation) + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("t_analysis_t_operation_id_fk"); + }); + modelBuilder.Entity(entity => { entity.HasKey(nameof(Event.IdTelemetry), nameof(Event.IdEvent)); @@ -178,6 +194,29 @@ namespace AsbCloudDb.Model new Well{Id = 2, IdCluster = 1, IdCustomer = 1, Caption = "скв 2" }, }); }); + + modelBuilder.Entity(entity => + { + entity.HasData(new List { + new Operation {Id = 1, Name = "Невозможно определить операцию"}, + new Operation {Id = 2, Name = "Роторное бурение" }, + new Operation {Id = 3, Name = "Слайдирование" }, + new Operation {Id = 4, Name = "Подъем с проработкой" }, + new Operation {Id = 5, Name = "Спуск с проработкой" }, + new Operation {Id = 6, Name = "Подъем с промывкой" }, + new Operation {Id = 7, Name = "Спуск с промывкой" }, + new Operation {Id = 8, Name = "Спуск в скважину" }, + new Operation {Id = 9, Name = "Спуск с вращением" }, + new Operation {Id = 10, Name = "Подъем из скважины" }, + new Operation {Id = 11, Name = "Подъем с вращением" }, + new Operation {Id = 12, Name = "Промывка в покое" }, + new Operation {Id = 13, Name = "Промывка с вращением" }, + new Operation {Id = 14, Name = "Удержание в клиньях" }, + new Operation {Id = 15, Name = "Неподвижное состояние" }, + new Operation {Id = 16, Name = "Вращение без циркуляции" }, + new Operation {Id = 17, Name = "На поверхности" } + }); + }); } public IQueryable GetWellsByCustomer(int idCustomer) diff --git a/AsbCloudDb/Model/DrillingAnalysis.cs b/AsbCloudDb/Model/DrillingAnalysis.cs new file mode 100644 index 00000000..8e171981 --- /dev/null +++ b/AsbCloudDb/Model/DrillingAnalysis.cs @@ -0,0 +1,82 @@ +using System; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; + +namespace AsbCloudDb.Model +{ + + [Table("t_analysis"), Comment("События на скважине")] + public class DrillingAnalysis + { + [Key] + [Column("id")] + public int Id { get; set; } + + [Column("id_telemetry")] + public int IdTelemetry { get; set; } + + [Column("date", TypeName = "timestamp with time zone"), Comment("'2021-10-19 18:23:54+05'")] + public DateTime Date { get; set; } + + [Column("id_operation")] + public int? IdOperation { get; set; } + + + [JsonIgnore] + [ForeignKey(nameof(IdTelemetry))] + [InverseProperty(nameof(Model.Telemetry.Analysis))] + public virtual Telemetry Telemetry { get; set; } + + [JsonIgnore] + [ForeignKey(nameof(IdOperation))] + [InverseProperty(nameof(Model.Operation.Analysis))] + public virtual Operation Operation { get; set; } + + [Column("depth_changes"), Comment("Глубина забоя увеличивается")] + public bool IsDepthChanges { get; set; } + + [Column("depth_not_changes"), Comment("Глубина забоя не увеличивается")] + public bool IsDepthNotChanges { get; set; } + + [Column("bit_is_rising"), Comment("Долото поднимается")] + public bool IsBitRising { get; set; } + + [Column("bit_goes_down"), Comment("Глубина спускается")] + public bool IsBitGoesDown { get; set; } + + [Column("bit_stands_still"), Comment("Положение долота не изменяется")] + public bool IsBitStandsStill { get; set; } + + [Column("bit_depth_less_20"), Comment("Положение долота меньше 20м")] + public bool IsBitDepthLess20 { get; set; } + + [Column("block_is_rising"), Comment("Талевый блок поднимается")] + public bool IsBlockRising { get; set; } + + [Column("block_goes_down"), Comment("Талевый блок спускается")] + public bool IsBlockGoesDown { get; set; } + + [Column("block_stands_still"), Comment("Положение блок не изменяется")] + public bool IsBlockStandsStill { get; set; } + + [Column("rotor_speed_less_3"), Comment("Обороты ротора ниже 3")] + public bool IsRotorSpeedLess3 { get; set; } + + [Column("rotor_speed_more_3"), Comment("Обороты ротора выше 3")] + public bool IsRotorSpeedMore3 { get; set; } + + [Column("pressure_less_20"), Comment("Давление менее 20")] + public bool IsPressureLess20 { get; set; } + + [Column("pressure_more_20"), Comment("Давоение более 20")] + public bool IsPressureMore20 { get; set; } + + [Column("hook_weight_not_changes"), Comment("Вес на крюке не меняется")] + public bool IsHookWeightNotChanges { get; set; } + + [Column("hook_weight_less_3"), Comment("Вес на крюке менее 3т")] + public bool IsHookWeightLess3 { get; set; } + } +} diff --git a/AsbCloudDb/Model/IAsbCloudDbContext.cs b/AsbCloudDb/Model/IAsbCloudDbContext.cs index 285df6e9..1341bf61 100644 --- a/AsbCloudDb/Model/IAsbCloudDbContext.cs +++ b/AsbCloudDb/Model/IAsbCloudDbContext.cs @@ -21,6 +21,8 @@ namespace AsbCloudDb.Model DbSet Wells { get; set; } DbSet UserRoles { get; set; } DbSet Reports { get; set; } + DbSet Operations { get; set; } + DbSet DrillingAnalysis { get; set; } int SaveChanges(); int SaveChanges(bool acceptAllChangesOnSuccess); diff --git a/AsbCloudDb/Model/Operation.cs b/AsbCloudDb/Model/Operation.cs new file mode 100644 index 00000000..02a7a78e --- /dev/null +++ b/AsbCloudDb/Model/Operation.cs @@ -0,0 +1,20 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Collections.Generic; + +namespace AsbCloudDb.Model +{ + [Table("t_operation"), Comment("Справочник операций на скважине")] + public class Operation + { + [Key] + [Column("id")] + public int Id { get; set; } + [Column("name"), Comment("Название операции")] + public string Name { get; set; } + + [InverseProperty(nameof(DrillingAnalysis.Operation))] + public virtual ICollection Analysis { get; set; } + } +} diff --git a/AsbCloudDb/Model/Telemetry.cs b/AsbCloudDb/Model/Telemetry.cs index 5c6f7e59..e1bfb43d 100644 --- a/AsbCloudDb/Model/Telemetry.cs +++ b/AsbCloudDb/Model/Telemetry.cs @@ -43,5 +43,7 @@ namespace AsbCloudDb.Model [InverseProperty(nameof(Event.Telemetry))] public virtual ICollection Events { get; set; } + [InverseProperty(nameof(DrillingAnalysis.Telemetry))] + public virtual ICollection Analysis { get; set; } } } diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 63d56782..62c481ba 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -25,6 +25,7 @@ namespace AsbCloudInfrastructure services.AddSingleton(new CacheDb()); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddTransient(); services.AddTransient(); diff --git a/AsbCloudInfrastructure/Services/AnalyticsService.cs b/AsbCloudInfrastructure/Services/AnalyticsService.cs index 9273a14b..5293e987 100644 --- a/AsbCloudInfrastructure/Services/AnalyticsService.cs +++ b/AsbCloudInfrastructure/Services/AnalyticsService.cs @@ -13,12 +13,18 @@ namespace AsbCloudInfrastructure.Services 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) @@ -217,5 +223,80 @@ namespace AsbCloudInfrastructure.Services } }; } + + 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); + } } } diff --git a/AsbCloudInfrastructure/Services/DataService.cs b/AsbCloudInfrastructure/Services/DataService.cs index 9a066f90..d8ecaf59 100644 --- a/AsbCloudInfrastructure/Services/DataService.cs +++ b/AsbCloudInfrastructure/Services/DataService.cs @@ -13,14 +13,20 @@ namespace AsbCloudInfrastructure.Services { private readonly IAsbCloudDbContext db; private readonly ITelemetryService telemetryService; + private readonly IAnalyticsService analyticsService; + private readonly ISaubDataCache saubEventsCache; private readonly IMapper mapper; private readonly CacheTable cacheTelemetry; private readonly CacheTable cacheWells; - public DataService(IAsbCloudDbContext db, ITelemetryService telemetryService, CacheDb cacheDb, MapperConfiguration mapperConfiguration) + public DataService(IAsbCloudDbContext db, ITelemetryService telemetryService, + IAnalyticsService analyticsService, ISaubDataCache saubEventsCache, + CacheDb cacheDb, MapperConfiguration mapperConfiguration) { this.db = db; this.telemetryService = telemetryService; + this.analyticsService = analyticsService; + this.saubEventsCache = saubEventsCache; mapper = mapperConfiguration.CreateMapper(); cacheTelemetry = cacheDb.GetCachedTable((AsbCloudDbContext)db); cacheWells = cacheDb.GetCachedTable((AsbCloudDbContext)db); @@ -92,6 +98,24 @@ namespace AsbCloudInfrastructure.Services var dataSaub = mapper.Map(item); dataSaub.IdTelemetry = telemetryId; db.DataSaubBases.Add(dataSaub); + + if (!saubEventsCache.GetSaubData().ContainsKey(dataSaub.IdTelemetry)) + saubEventsCache.GetSaubData()[dataSaub.IdTelemetry] = new List(); + + var cachedSaubData = saubEventsCache.GetSaubData()[dataSaub.IdTelemetry]; + + cachedSaubData.Add(dataSaub); + + if (cachedSaubData.Count > 1) + { + if (cachedSaubData.Count > 10) + cachedSaubData.RemoveAt(1); + + var drillingAnalysis = analyticsService.GetDrillingAnalysis( + cachedSaubData); + + db.DrillingAnalysis.Add(drillingAnalysis); + } } db.SaveChanges(); diff --git a/AsbCloudInfrastructure/Services/OperationDetector.cs b/AsbCloudInfrastructure/Services/OperationDetector.cs new file mode 100644 index 00000000..0f15c484 --- /dev/null +++ b/AsbCloudInfrastructure/Services/OperationDetector.cs @@ -0,0 +1,12 @@ +using System; +using AsbCloudDb.Model; + +namespace AsbCloudInfrastructure.Services +{ + public class OperationDetector + { + public int Order { get; set; } + public Operation Operation { get; set; } + public Func Detect { get; set; } + } +} diff --git a/AsbCloudInfrastructure/Services/OperationDetectorsContainer.cs b/AsbCloudInfrastructure/Services/OperationDetectorsContainer.cs new file mode 100644 index 00000000..bbec1bf9 --- /dev/null +++ b/AsbCloudInfrastructure/Services/OperationDetectorsContainer.cs @@ -0,0 +1,163 @@ +using System.Collections.Generic; +using System.Linq; +using AsbCloudDb.Model; + +namespace AsbCloudInfrastructure.Services +{ + public class OperationDetectorsContainer + { + public IEnumerable Detectors; + + public OperationDetectorsContainer(IEnumerable operations) + { + Detectors = new List() + { + new OperationDetector + { + Order = 1, + Operation = operations.FirstOrDefault(o => o.Name.Equals("На поверхности")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitDepthLess20 && data.IsHookWeightLess3; + } + }, + new OperationDetector + { + Order = 2, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Удержание в клиньях")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitStandsStill && + data.IsBlockStandsStill && data.IsHookWeightLess3; + } + }, + new OperationDetector + { + Order = 3, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Подъем с проработкой")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitRising && + data.IsBlockRising && data.IsRotorSpeedMore3 && data.IsPressureMore20; + } + }, + new OperationDetector + { + Order = 4, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Спуск с проработкой")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitGoesDown && + data.IsBlockGoesDown && data.IsRotorSpeedMore3 && data.IsPressureMore20; + } + }, + new OperationDetector + { + Order = 5, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Подъем с промывкой")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitRising && + data.IsBlockRising && data.IsRotorSpeedLess3 && data.IsPressureMore20; + } + }, + new OperationDetector + { + Order = 6, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Спуск с промывкой")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitGoesDown && + data.IsBlockGoesDown && data.IsRotorSpeedLess3 && data.IsPressureMore20; + } + }, + new OperationDetector + { + Order = 7, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Спуск в скважину")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitGoesDown && + data.IsBlockGoesDown && data.IsRotorSpeedLess3 && data.IsPressureLess20; + } + }, + new OperationDetector + { + Order = 8, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Спуск с вращением")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitGoesDown && + data.IsBlockGoesDown && data.IsRotorSpeedMore3 && data.IsPressureLess20; + } + }, + new OperationDetector + { + Order = 9, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Подъем из скважины")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitRising && + data.IsBlockRising && data.IsRotorSpeedLess3 && data.IsPressureLess20; + } + }, + new OperationDetector + { + Order = 10, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Подъем с вращением")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitRising && + data.IsBlockRising && data.IsRotorSpeedMore3 && data.IsPressureLess20; + } + }, + new OperationDetector + { + Order = 11, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Промывка в покое")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitStandsStill && + data.IsBlockStandsStill && data.IsRotorSpeedLess3 && data.IsPressureMore20; + } + }, + new OperationDetector + { + Order = 12, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Промывка с вращением")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitStandsStill && + data.IsBlockStandsStill && data.IsRotorSpeedMore3 && data.IsPressureMore20; + } + }, + new OperationDetector + { + Order = 13, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Неподвижное состояние")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitStandsStill && data.IsBlockStandsStill + && data.IsRotorSpeedLess3 && data.IsPressureLess20 && data.IsHookWeightNotChanges; + } + }, + new OperationDetector + { + Order = 14, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Вращение без циркуляции")), + Detect = (data) => + { + return data.IsDepthNotChanges && data.IsBitStandsStill && + data.IsBlockStandsStill && data.IsRotorSpeedMore3 && data.IsPressureLess20; + } + }, + new OperationDetector + { + Order = 15, + Operation = operations.FirstOrDefault(o => o.Name.Equals("Невозможно определить операцию")), + Detect = (data) => true + } + }; + } + } +} diff --git a/AsbCloudInfrastructure/Services/SaubEventsCache.cs b/AsbCloudInfrastructure/Services/SaubEventsCache.cs new file mode 100644 index 00000000..f265e4ce --- /dev/null +++ b/AsbCloudInfrastructure/Services/SaubEventsCache.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using AsbCloudApp.Services; +using AsbCloudDb.Model; + +namespace AsbCloudInfrastructure.Services +{ + public class SaubEventsCache : ISaubDataCache + { + private readonly Dictionary> saubData = + new Dictionary>(); + + public Dictionary> GetSaubData() => + saubData; + } +} diff --git a/AsbCloudWebApi/Controllers/AnalyticsController.cs b/AsbCloudWebApi/Controllers/AnalyticsController.cs index c22eda19..8ffb62c4 100644 --- a/AsbCloudWebApi/Controllers/AnalyticsController.cs +++ b/AsbCloudWebApi/Controllers/AnalyticsController.cs @@ -80,7 +80,7 @@ namespace AsbCloudWebApi.Controllers /// Коллекцию операций на скважине [HttpGet] [Route("{wellId}/operationsSummary")] - [ProducesResponseType(typeof(List), (int)System.Net.HttpStatusCode.OK)] + [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] public IActionResult GetOperationsSummary(int wellId, DateTime begin = default, DateTime end = default) { int? idCustomer = User.GetCustomerId(); @@ -106,7 +106,7 @@ namespace AsbCloudWebApi.Controllers [HttpGet] [Route("{wellId}/operationsToTime")] - [ProducesResponseType(typeof(List), (int)System.Net.HttpStatusCode.OK)] + [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] public IActionResult GetOperationsToTime(int wellId, DateTime begin = default, DateTime end = default) { int? idCustomer = User.GetCustomerId(); diff --git a/AsbCloudWebApi/Docs/Алгоритм_определения_операций_буровой.ods b/AsbCloudWebApi/Docs/Алгоритм_определения_операций_буровой.ods new file mode 100644 index 0000000000000000000000000000000000000000..4779d5f2d1dfa9ed277487f97e029949a3b59e25 GIT binary patch literal 28024 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