diff --git a/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs b/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs index 2ca5293c..40514429 100644 --- a/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs +++ b/AsbCloudApp/Data/SAUB/TelemetryDataSaubStatDto.cs @@ -47,16 +47,6 @@ namespace AsbCloudApp.Data.SAUB /// public float PressureIdle { get; set; } - /// - /// задание давления для роторного режима - /// - public float PressureSpRotor { get; set; } - - /// - /// задание давления для режима слайда - /// - public float PressureSpSlide { get; set; } - /// /// ограничение макс перепада давления /// @@ -108,13 +98,13 @@ namespace AsbCloudApp.Data.SAUB public float BlockSpeedSp { get; set; } /// - /// Талевый блок. Задание скорости для роторного бурения + /// Режим САУБ /// - public float BlockSpeedSpRotor { get; set; } + public short Mode { get; set; } /// - /// Талевый блок. Задание скорости для режима слайда + /// Текущий критерий бурения /// - public float BlockSpeedSpSlide { get; set; } + public short? IdFeedRegulator { get; set; } } } diff --git a/AsbCloudApp/Repositories/IProcessMapRepository.cs b/AsbCloudApp/Repositories/IProcessMapRepository.cs index c0f347e2..b126e18a 100644 --- a/AsbCloudApp/Repositories/IProcessMapRepository.cs +++ b/AsbCloudApp/Repositories/IProcessMapRepository.cs @@ -11,7 +11,7 @@ namespace AsbCloudApp.Repositories /// /// /// - public interface IProcessMapRepository : IRepositoryWellRelated + public interface IProcessMapPlanRepository : IRepositoryWellRelated { /// /// . diff --git a/AsbCloudApp/Services/IProcessMapReportService.cs b/AsbCloudApp/Services/IProcessMapReportMakerService.cs similarity index 90% rename from AsbCloudApp/Services/IProcessMapReportService.cs rename to AsbCloudApp/Services/IProcessMapReportMakerService.cs index a4bf783b..0fea6d7b 100644 --- a/AsbCloudApp/Services/IProcessMapReportService.cs +++ b/AsbCloudApp/Services/IProcessMapReportMakerService.cs @@ -7,7 +7,7 @@ namespace AsbCloudApp.Services /// /// Сервис формирования РТК. /// - public interface IProcessMapReportService + public interface IProcessMapReportMakerService { /// /// Сформировать. diff --git a/AsbCloudApp/Services/IProcessMapService.cs b/AsbCloudApp/Services/IProcessMapService.cs index 63a611c8..954d899a 100644 --- a/AsbCloudApp/Services/IProcessMapService.cs +++ b/AsbCloudApp/Services/IProcessMapService.cs @@ -8,7 +8,7 @@ namespace AsbCloudApp.Services /// /// Сервис формирования РТК /// - public interface IProcessMapService + public interface IProcessMapReportService { /// /// Получение моделей РТК diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index f74de38e..62fa5d3f 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -107,7 +107,7 @@ namespace AsbCloudInfrastructure services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -133,8 +133,8 @@ namespace AsbCloudInfrastructure services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); - services.AddTransient(); services.AddTransient(); // admin crud services: diff --git a/AsbCloudInfrastructure/Repository/ProcessMapRepository.cs b/AsbCloudInfrastructure/Repository/ProcessMapRepository.cs index dc0539c7..4b6305ca 100644 --- a/AsbCloudInfrastructure/Repository/ProcessMapRepository.cs +++ b/AsbCloudInfrastructure/Repository/ProcessMapRepository.cs @@ -4,10 +4,8 @@ using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; -using DocumentFormat.OpenXml.Spreadsheet; using Mapster; using Microsoft.EntityFrameworkCore; -using Org.BouncyCastle.Asn1.Ocsp; using System; using System.Collections.Generic; using System.Linq; @@ -19,7 +17,7 @@ namespace AsbCloudInfrastructure.Repository { #nullable enable public class ProcessMapRepository : CrudWellRelatedRepositoryBase, - IProcessMapRepository + IProcessMapPlanRepository { private readonly IWellService wellService; diff --git a/AsbCloudInfrastructure/Repository/WellCompositeRepository.cs b/AsbCloudInfrastructure/Repository/WellCompositeRepository.cs index 0ec8d6b9..f57326fa 100644 --- a/AsbCloudInfrastructure/Repository/WellCompositeRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellCompositeRepository.cs @@ -17,9 +17,9 @@ namespace AsbCloudInfrastructure.Repository public class WellCompositeRepository : IWellCompositeRepository { private readonly IAsbCloudDbContext db; - private readonly IProcessMapRepository processMapRepository; + private readonly IProcessMapPlanRepository processMapRepository; - public WellCompositeRepository(IAsbCloudDbContext db, IProcessMapRepository processMapRepository) + public WellCompositeRepository(IAsbCloudDbContext db, IProcessMapPlanRepository processMapRepository) { this.db = db; this.processMapRepository = processMapRepository; diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportMakerService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportMakerService.cs new file mode 100644 index 00000000..8e444a08 --- /dev/null +++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportMakerService.cs @@ -0,0 +1,216 @@ +using AsbCloudApp.Data.ProcessMap; +using AsbCloudApp.Services; +using ClosedXML.Excel; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Services.ProcessMap +{ +#nullable enable + public class ProcessMapReportMakerService : IProcessMapReportMakerService + { + const int firstColumn = 2; + const int lastColumn = 61; + + const int headerRowsCount = 8; + + private readonly IProcessMapReportService processMapService; + + public ProcessMapReportMakerService(IProcessMapReportService processMapService) + { + this.processMapService = processMapService; + } + + public async Task MakeReportAsync(int idWell, CancellationToken token) + { + var stream = GetExcelTemplateStream(); + using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); + + var data = await processMapService.GetProcessMapAsync(idWell, token); + + FillProcessMapToWorkbook(workbook, data); + + MemoryStream memoryStream = new MemoryStream(); + workbook.SaveAs(memoryStream, new SaveOptions { }); + memoryStream.Seek(0, SeekOrigin.Begin); + return memoryStream; + } + + private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable data) + { + var sheet = workbook.Worksheets.FirstOrDefault(); + if (sheet is null) + return; + var dataBySections = data.GroupBy(p => p.IdWellSectionType); + FillSheet(sheet, dataBySections); + } + + private static void FillSheet(IXLWorksheet sheet, IEnumerable> dataBySections) + { + var startRow = headerRowsCount + 1; + foreach (var sectionData in dataBySections) + { + if(sectionData.Any()) + startRow = FillSection(sheet, sectionData, startRow); + } + } + + private static int FillSection(IXLWorksheet sheet, IGrouping sectionData, int row) + { + var rowStart = row; + + var sectionName = sectionData.FirstOrDefault()?.WellSectionTypeName + ?? sectionData.Key.ToString(); + + sheet.Range(row, firstColumn, row, lastColumn) + .Merge() + .FirstCell() + .SetVal(sectionName) + .Style + .Fill.SetBackgroundColor(XLColor.LightGray); + + row++; + + foreach (var interval in sectionData) + row = FillIntervalData(sheet, interval, row); + + var sectionStyle = sheet.Range(rowStart, firstColumn, row - 1, lastColumn).Style; + SetBorders(sectionStyle); + return row; + } + + private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDto interval, int row) + { + const int columnDepth = firstColumn + 1; + const int columnDate = firstColumn + 2; + const int columnRopTime = firstColumn + 3; + const int columnMode = firstColumn + 4; + + int rowRotor = row; + int rowSlide = row + 1; + + sheet.Range(rowRotor, firstColumn, rowSlide, firstColumn) + .Merge(); + + sheet.Range(rowRotor, columnDepth, rowSlide, columnDepth) + .Merge().FirstCell() + .SetVal(interval.DepthStart, "0.0"); + + sheet.Range(rowRotor, columnDate, rowSlide, columnDate) + .Merge().FirstCell() + .SetVal(interval.DateStart); + + sheet.Range(rowRotor, columnRopTime, rowSlide, columnRopTime) + .Merge().FirstCell() + .SetVal(interval.MechDrillingHours); + + //row = FillIntervalModeData(sheet, "Ротор", interval.Rotor, columnMode, row); + //row = FillIntervalModeData(sheet, "Слайд", interval.Slide, columnMode, row); + + return row; + } + + //private static int FillIntervalModeData(IXLWorksheet sheet, string modeName, ProcessMapReportRowDto modeData, int column, int row) + //{ + // int columnDeltaDepth = column + 1; + // int columnPressure = columnDeltaDepth + 1; + // int columnLoad = columnPressure + 5; + // int columnTorque = columnLoad + 5; + // int columnSpeed = columnTorque + 5; + // int columnUsagePlan = columnSpeed + 5; + // int columnUsageFact = columnUsagePlan + 1; + // int columnRop = columnUsageFact + 12; + + // sheet.Cell(row, column) + // .SetVal(modeName); + + // sheet.Cell(row, columnDeltaDepth) + // .SetVal(modeData.DeltaDepth); + + // FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row); + // FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row); + // FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row); + // FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row); + + // sheet.Cell(row, columnUsagePlan) + // .SetVal(100); + + // sheet.Cell(row, columnUsageFact) + // .SetVal(modeData.Usage); + + // sheet.Cell(row, columnRop) + // .SetVal(modeData.Rop); + + // return row + 1; + //} + + private static void FillIntervalModeDataParam(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetSpFact = 1; + const int columnOffsetFact = 2; + const int columnOffsetLimit = 3; + const int columnOffsetPercent = 4; + + sheet.Cell(row, column + columnOffsetSpPlan) + .SetVal(dataParam.SetpointPlan); + + sheet.Cell(row, column + columnOffsetSpFact) + .SetVal(dataParam.SetpointFact); + + sheet.Cell(row, column + columnOffsetFact) + .SetVal(dataParam.Fact); + + sheet.Cell(row, column + columnOffsetLimit) + .SetVal(dataParam.Limit); + + sheet.Cell(row, column + columnOffsetPercent) + .SetVal(dataParam.PercDrillingBySetpoint); + } + + private static void FillIntervalModeDataSpeed(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetSpFact = 1; + const int columnOffsetFact = 2; + const int columnOffsetLimit = 3; + const int columnOffsetPercent = 4; + + sheet.Cell(row, column + columnOffsetSpPlan) + .SetVal(dataParam.SetpointPlan); + + sheet.Cell(row, column + columnOffsetSpFact) + .SetVal(dataParam.SetpointFact); + + sheet.Cell(row, column + columnOffsetFact) + .SetVal(dataParam.Fact); + + sheet.Cell(row, column + columnOffsetLimit) + .SetVal(dataParam.Limit); + + sheet.Cell(row, column + columnOffsetPercent) + .SetVal(dataParam.PercDrillingBySetpoint); + } + + private static Stream GetExcelTemplateStream() + { + var stream = System.Reflection.Assembly.GetExecutingAssembly() + .GetManifestResourceStream("AsbCloudInfrastructure.Services.ProcessMap.ProcessMapReportTemplate.xlsx"); + return stream!; + } + + private static IXLStyle SetBorders(IXLStyle style) + { + style.Border.RightBorder = XLBorderStyleValues.Thin ; + style.Border.LeftBorder = XLBorderStyleValues.Thin; + style.Border.TopBorder = XLBorderStyleValues.Thin ; + style.Border.BottomBorder = XLBorderStyleValues.Thin ; + style.Border.InsideBorder = XLBorderStyleValues.Thin ; + return style; + } + } +#nullable disable +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs index 430da7b4..9cd63e0e 100644 --- a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs +++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs @@ -1,8 +1,15 @@ -using AsbCloudApp.Data.ProcessMap; +using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMap; +using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; using AsbCloudApp.Services; -using ClosedXML.Excel; +using AsbCloudApp.Services.Subsystems; +using AsbCloudDb.Model; +using AsbCloudApp.Data.Subsystems; +using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -10,207 +17,86 @@ using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.ProcessMap { #nullable enable - public class ProcessMapReportService : IProcessMapReportService + public partial class ProcessMapReportService : IProcessMapReportService { - const int firstColumn = 2; - const int lastColumn = 61; + private readonly IWellService wellService; + private readonly IWellOperationRepository wellOperationRepository; + private readonly IProcessMapPlanRepository processMapPlanRepository; + private readonly ITelemetryDataSaubService telemetryDataSaubService; + private readonly ILimitingParameterRepository limitingParameterRepository; + private readonly ISubsystemOperationTimeService subsystemOperationTimeService; - const int headerRowsCount = 8; - - private readonly IProcessMapService processMapService; - - public ProcessMapReportService(IProcessMapService processMapService) + public ProcessMapReportService( + IWellService wellService, + IWellOperationRepository wellOperationService, + IProcessMapPlanRepository processMapPlanRepository, + ITelemetryDataSaubService telemetryDataSaubService, + ILimitingParameterRepository limitingParameterRepository, + ISubsystemOperationTimeService subsystemOperationTimeService) { - this.processMapService = processMapService; + this.wellService = wellService; + this.wellOperationRepository = wellOperationService; + this.processMapPlanRepository = processMapPlanRepository; + this.telemetryDataSaubService = telemetryDataSaubService; + this.limitingParameterRepository = limitingParameterRepository; + this.subsystemOperationTimeService = subsystemOperationTimeService; } - public async Task MakeReportAsync(int idWell, CancellationToken token) + /// + public async Task> GetProcessMapAsync(int idWell, CancellationToken token) { - var stream = GetExcelTemplateStream(); - using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); + var well = wellService.GetOrDefault(idWell) + ?? throw new ArgumentInvalidException("idWell not found", nameof(idWell)); - var data = await processMapService.GetProcessMapAsync(idWell, token); + var idTelemetry = well.IdTelemetry + ?? throw new ArgumentInvalidException("telemetry by well not found", nameof(idWell)); - FillProcessMapToWorkbook(workbook, data); + var processMapPlan = await processMapPlanRepository.GetByIdWellAsync(idWell, token); - MemoryStream memoryStream = new MemoryStream(); - workbook.SaveAs(memoryStream, new SaveOptions { }); - memoryStream.Seek(0, SeekOrigin.Begin); - return memoryStream; + if(!processMapPlan.Any()) + return Enumerable.Empty(); + + var telemetryDataStat = await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token); + + var result = CalcByIntervals(processMapPlan, telemetryDataStat); + + return result; } - private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable data) + private IEnumerable CalcByIntervals(IEnumerable processMapPlan, IEnumerable telemetryDataStat) { - var sheet = workbook.Worksheets.FirstOrDefault(); - if (sheet is null) - return; - var dataBySections = data.GroupBy(p => p.IdWellSectionType); - FillSheet(sheet, dataBySections); - } - - private static void FillSheet(IXLWorksheet sheet, IEnumerable> dataBySections) - { - var startRow = headerRowsCount + 1; - foreach (var sectionData in dataBySections) - { - if(sectionData.Any()) - startRow = FillSection(sheet, sectionData, startRow); - } - } - - private static int FillSection(IXLWorksheet sheet, IGrouping sectionData, int row) - { - var rowStart = row; - - var sectionName = sectionData.FirstOrDefault()?.WellSectionTypeName - ?? sectionData.Key.ToString(); - - sheet.Range(row, firstColumn, row, lastColumn) - .Merge() - .FirstCell() - .SetVal(sectionName) - .Style - .Fill.SetBackgroundColor(XLColor.LightGray); - - row++; - - foreach (var interval in sectionData) - row = FillIntervalData(sheet, interval, row); - - var sectionStyle = sheet.Range(rowStart, firstColumn, row - 1, lastColumn).Style; - SetBorders(sectionStyle); - return row; - } - - private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDto interval, int row) - { - const int columnDepth = firstColumn + 1; - const int columnDate = firstColumn + 2; - const int columnRopTime = firstColumn + 3; - const int columnMode = firstColumn + 4; - - int rowRotor = row; - int rowSlide = row + 1; - - sheet.Range(rowRotor, firstColumn, rowSlide, firstColumn) - .Merge(); - - sheet.Range(rowRotor, columnDepth, rowSlide, columnDepth) - .Merge().FirstCell() - .SetVal(interval.DepthStart, "0.0"); - - sheet.Range(rowRotor, columnDate, rowSlide, columnDate) - .Merge().FirstCell() - .SetVal(interval.DateStart); - - sheet.Range(rowRotor, columnRopTime, rowSlide, columnRopTime) - .Merge().FirstCell() - .SetVal(interval.MechDrillingHours); - - //row = FillIntervalModeData(sheet, "Ротор", interval.Rotor, columnMode, row); - //row = FillIntervalModeData(sheet, "Слайд", interval.Slide, columnMode, row); - - return row; - } - - //private static int FillIntervalModeData(IXLWorksheet sheet, string modeName, ProcessMapReportRowDto modeData, int column, int row) - //{ - // int columnDeltaDepth = column + 1; - // int columnPressure = columnDeltaDepth + 1; - // int columnLoad = columnPressure + 5; - // int columnTorque = columnLoad + 5; - // int columnSpeed = columnTorque + 5; - // int columnUsagePlan = columnSpeed + 5; - // int columnUsageFact = columnUsagePlan + 1; - // int columnRop = columnUsageFact + 12; - - // sheet.Cell(row, column) - // .SetVal(modeName); - - // sheet.Cell(row, columnDeltaDepth) - // .SetVal(modeData.DeltaDepth); - - // FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row); - // FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row); - // FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row); - // FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row); - - // sheet.Cell(row, columnUsagePlan) - // .SetVal(100); - - // sheet.Cell(row, columnUsageFact) - // .SetVal(modeData.Usage); - - // sheet.Cell(row, columnRop) - // .SetVal(modeData.Rop); - - // return row + 1; - //} - - private static void FillIntervalModeDataParam(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) - { - const int columnOffsetSpPlan = 0; - const int columnOffsetSpFact = 1; - const int columnOffsetFact = 2; - const int columnOffsetLimit = 3; - const int columnOffsetPercent = 4; - - sheet.Cell(row, column + columnOffsetSpPlan) - .SetVal(dataParam.SetpointPlan); + var result = new List(processMapPlan.Count() * 4); + var intervals = GetProcessMapIntervals(processMapPlan); - sheet.Cell(row, column + columnOffsetSpFact) - .SetVal(dataParam.SetpointFact); - - sheet.Cell(row, column + columnOffsetFact) - .SetVal(dataParam.Fact); - - sheet.Cell(row, column + columnOffsetLimit) - .SetVal(dataParam.Limit); - - sheet.Cell(row, column + columnOffsetPercent) - .SetVal(dataParam.PercDrillingBySetpoint); + return result; } - private static void FillIntervalModeDataSpeed(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) + private IEnumerable<(double, double)> GetProcessMapIntervals(IEnumerable processMapPlan) { - const int columnOffsetSpPlan = 0; - const int columnOffsetSpFact = 1; - const int columnOffsetFact = 2; - const int columnOffsetLimit = 3; - const int columnOffsetPercent = 4; - - sheet.Cell(row, column + columnOffsetSpPlan) - .SetVal(dataParam.SetpointPlan); - - sheet.Cell(row, column + columnOffsetSpFact) - .SetVal(dataParam.SetpointFact); - - sheet.Cell(row, column + columnOffsetFact) - .SetVal(dataParam.Fact); - - sheet.Cell(row, column + columnOffsetLimit) - .SetVal(dataParam.Limit); - - sheet.Cell(row, column + columnOffsetPercent) - .SetVal(dataParam.PercDrillingBySetpoint); + + return Enumerable.Empty<(double, double)>(); } - private static Stream GetExcelTemplateStream() + private static DateTime GetInterpolatedDate(WellOperationDto operation, double depth) { - var stream = System.Reflection.Assembly.GetExecutingAssembly() - .GetManifestResourceStream("AsbCloudInfrastructure.Services.ProcessMap.ProcessMapReportTemplate.xlsx"); - return stream!; + var ratio = (depth - operation.DepthStart) / (operation.DepthEnd - operation.DepthStart); + var deltaHours = operation.DurationHours * ratio; + var interpolatedDate = operation.DateStart + TimeSpan.FromHours(deltaHours); + return interpolatedDate; } - private static IXLStyle SetBorders(IXLStyle style) + private static IEnumerable<(double min, double max)> SplitByIntervals(double min, double max) { - style.Border.RightBorder = XLBorderStyleValues.Thin ; - style.Border.LeftBorder = XLBorderStyleValues.Thin; - style.Border.TopBorder = XLBorderStyleValues.Thin ; - style.Border.BottomBorder = XLBorderStyleValues.Thin ; - style.Border.InsideBorder = XLBorderStyleValues.Thin ; - return style; + const double step = 100; + var iMin = min; + var iMax = (1 + (int)(min / step)) * step; + for (; iMax < max; iMax += step) + { + yield return (iMin, iMax); + iMin = iMax; + } + yield return (iMin, max); } } #nullable disable -} \ No newline at end of file +} diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs deleted file mode 100644 index 5688e0ff..00000000 --- a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs +++ /dev/null @@ -1,348 +0,0 @@ -using AsbCloudApp.Data; -using AsbCloudApp.Data.ProcessMap; -using AsbCloudApp.Data.SAUB; -using AsbCloudApp.Exceptions; -using AsbCloudApp.Repositories; -using AsbCloudApp.Requests; -using AsbCloudApp.Services; -using AsbCloudApp.Services.Subsystems; -using AsbCloudDb.Model; -using AsbCloudApp.Data.Subsystems; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AsbCloudInfrastructure.Services.Subsystems; - -namespace AsbCloudInfrastructure.Services.ProcessMap -{ -#nullable enable - public partial class ProcessMapService : IProcessMapService - { - private readonly IWellService wellService; - private readonly IWellOperationRepository wellOperationRepository; - private readonly IProcessMapRepository processMapRepository; - private readonly ITelemetryDataSaubService telemetryDataSaubService; - private readonly ILimitingParameterRepository limitingParameterRepository; - private readonly ISubsystemOperationTimeService subsystemOperationTimeService; - - public ProcessMapService( - IWellService wellService, - IWellOperationRepository wellOperationService, - IProcessMapRepository processMapRepository, - ITelemetryDataSaubService telemetryDataSaubService, - ILimitingParameterRepository limitingParameterRepository, - ISubsystemOperationTimeService subsystemOperationTimeService) - { - this.wellService = wellService; - this.wellOperationRepository = wellOperationService; - this.processMapRepository = processMapRepository; - this.telemetryDataSaubService = telemetryDataSaubService; - this.limitingParameterRepository = limitingParameterRepository; - this.subsystemOperationTimeService = subsystemOperationTimeService; - } - - /// - public async Task> GetProcessMapAsync(int idWell, CancellationToken token) - { - var well = wellService.GetOrDefault(idWell) - ?? throw new ArgumentInvalidException("idWell not found", nameof(idWell)); - var idTelemetry = well.IdTelemetry - ?? throw new ArgumentInvalidException("telemetry by well not found", nameof(idWell)); - - var processMap = (await processMapRepository.GetByIdWellAsync(idWell, token))!; - var factDrillingOperations = await GetFactDrillingOperationsAsync(idWell, token); - var telemetryDataStat = await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token); - var limitingParameters = await limitingParameterRepository.GetLimitingParametersAsync(new(), well, token); - var subsystemsOperationTime = await GetOperationTimeAsync(idWell, token); - - var result = factDrillingOperations - .GroupBy(o => o.IdWellSectionType) - .SelectMany(sectionOperations => - { - var sectionProcessMap = processMap.Where(p => p.IdWellSectionType == sectionOperations.Key); - return HandleSection(sectionOperations, sectionProcessMap, telemetryDataStat, limitingParameters, subsystemsOperationTime!); - }) - .ToList(); - - return result; - } - - private Task?> GetOperationTimeAsync(int idWell, CancellationToken token) - { - var request = new SubsystemOperationTimeRequest - { - IdWell = idWell, - IdsSubsystems = new int[] { SubsystemOperationTimeService.IdSubsystemAKB, SubsystemOperationTimeService.IdSubsystemSpin }, - }; - return subsystemOperationTimeService.GetOperationTimeAsync(request, token); - } - - private async Task> GetFactDrillingOperationsAsync(int idWell, CancellationToken token) - { - var operationsRequest = new WellOperationRequest - { - IdWell = idWell, - OperationCategoryIds = WellOperationCategory.MechanicalDrillingSubIds, - OperationType = WellOperation.IdOperationTypeFact, - SortFields = new[] { nameof(WellOperation.DateStart) } - }; - - var allFactDrillingOperations = await wellOperationRepository.GetAsync(operationsRequest, token); - var factDrillingOperations = allFactDrillingOperations.Where(o => o.DepthEnd > o.DepthStart); - return factDrillingOperations; - } - - private static IEnumerable HandleSection( - IEnumerable sectionOperations, - IEnumerable sectionProcessMap, - IEnumerable telemetryDataStat, - IEnumerable limitingParameters, - IEnumerable subsystemsOperationTime) - { - var minDepth = sectionOperations.Min(o => o.DepthStart); - var maxDepth = sectionOperations.Max(o => o.DepthEnd); - - var depthIntervals = SplitByIntervals(minDepth, maxDepth).ToArray(); - var result = new ProcessMapReportDto[depthIntervals.Length]; - - for (var i = 0; i < depthIntervals.Length; i++ ) - result[i] = MakeProcessMapReportDto(depthIntervals[i], sectionOperations, sectionProcessMap, telemetryDataStat, limitingParameters, subsystemsOperationTime); - - return result; - } - - private static ProcessMapReportDto MakeProcessMapReportDto( - (double min, double max) depthInterval, - IEnumerable sectionOperations, - IEnumerable sectionProcessMap, - IEnumerable telemetryDataStat, - IEnumerable limitingParameters, - IEnumerable subsystemsOperationTime) - { - var dto = new ProcessMapReportDto{ - DepthStart = depthInterval.min - }; - - // TODO: trim items by detpth intervals. Use linear interpolation. - var intervalOperations = sectionOperations.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max); - var intervalProcessMap = sectionProcessMap.Where(map => map.DepthEnd >= depthInterval.min && map.DepthStart <= depthInterval.max); - var intervalTelemetryDataStat = CalcIntervalTelemetryDataStat(depthInterval, telemetryDataStat); - var intervalLimitingParametrs = limitingParameters.Where(l => l.DepthEnd >= depthInterval.min && l.DepthStart <= depthInterval.max); - var intervalSubsystemsOperationTime = subsystemsOperationTime.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max); - - var firstIntervalOperation = intervalOperations.FirstOrDefault(); - if (firstIntervalOperation is not null) - { - dto.DateStart = GetInterpolatedDate(firstIntervalOperation, depthInterval.min); - dto.IdWell = firstIntervalOperation.IdWell; - dto.IdWellSectionType = firstIntervalOperation.IdWellSectionType; - dto.WellSectionTypeName = firstIntervalOperation.WellSectionTypeName ?? string.Empty; - dto.MechDrillingHours = CalcHours(depthInterval, intervalOperations); - } - - // TODO: Разделить интервальные коллекции на ротор и слайд. Пока нет готовой методики. - var slideOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdSlide); - var rotorOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdRotor); - - //dto.Slide = CalcDrillModeStat(depthInterval, slideOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime); - //dto.Rotor = CalcDrillModeStat(depthInterval, rotorOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime); - - return dto; - } - - private static TelemetryDataSaubStatDto? CalcIntervalTelemetryDataStat((double min, double max) depthInterval, IEnumerable telemetryDataStat) - { - TelemetryDataSaubStatDto[] data = telemetryDataStat - .Where(d => d.WellDepthMin <= depthInterval.max && d.WellDepthMax >= depthInterval.min) - .ToArray(); - - if (!data.Any()) - return null; - - if (data.Length == 1) - return data.First(); - - var result = new TelemetryDataSaubStatDto - { - WellDepthMin = data.Min(d => d.WellDepthMin), - WellDepthMax = data.Max(d => d.WellDepthMax), - DateMin = data.Min(d => d.DateMin), - DateMax = data.Max(d => d.DateMax), - }; - - var intervalDeltaDepth = result.WellDepthMax - result.WellDepthMin; - - foreach (var item in data) - { - var itemWeight = (item.WellDepthMax - item.WellDepthMin) / intervalDeltaDepth; - - result.Pressure += item.Pressure * itemWeight; - result.PressureSp += item.PressureSp * itemWeight; - result.PressureSpRotor += item.PressureSpSlide * itemWeight; - result.PressureIdle += item.PressureIdle * itemWeight; - result.PressureDelta += item.PressureDelta * itemWeight; - - result.AxialLoad += item.AxialLoad * itemWeight; - result.AxialLoadSp += item.AxialLoadSp * itemWeight; - result.AxialLoadLimitMax += item.AxialLoadLimitMax * itemWeight; - - result.RotorTorque += item.RotorTorque * itemWeight; - result.RotorTorqueSp += item.RotorTorqueSp * itemWeight; - result.RotorTorqueLimitMax += item.RotorTorqueLimitMax * itemWeight; - - result.BlockSpeed += item.BlockSpeed * itemWeight; - result.BlockSpeedSp += item.BlockSpeedSp * itemWeight; - result.BlockSpeedSpRotor += item.BlockSpeedSpRotor * itemWeight; - result.BlockSpeedSpSlide += item.BlockSpeedSpSlide * itemWeight; - } - - return result; - } - - //private static ProcessMapReportRowDto CalcDrillModeStat( - // (double min, double max) depthInterval, - // IEnumerable intervalModeOperations, - // IEnumerable intervalProcessMap, - // TelemetryDataSaubStatDto? telemetryDataStat, - // IEnumerable intervalLimitingParametrs, - // IEnumerable intervalSubsystemsOperationTime) - //{ - // var dto = new ProcessMapReportRowDto(); - // if (intervalModeOperations.Any()) - // { - // var deltaDepth = CalcDeltaDepth(depthInterval, intervalModeOperations); - // dto.DeltaDepth = deltaDepth; - // dto.Rop = deltaDepth / CalcHours(depthInterval, intervalModeOperations); - // }; - - // if (intervalProcessMap.Any()) - // { - // var processMapFirst = intervalProcessMap.First(); - // dto.PressureDiff.SetpointPlan = processMapFirst.Pressure.Plan; - // dto.AxialLoad.SetpointPlan = processMapFirst.AxialLoad.Plan; - // dto.TopDriveTorque.SetpointPlan = processMapFirst.TopDriveTorque.Plan; - // //dto.SpeedLimit.SetpointPlan = null; - // } - - // if (telemetryDataStat is not null) - // { - // dto.PressureDiff.SetpointFact = telemetryDataStat.PressureSp; - // dto.PressureDiff.Fact = telemetryDataStat.PressureDelta; - // dto.PressureDiff.Limit = telemetryDataStat.PressureDeltaLimitMax; - - // dto.AxialLoad.SetpointFact = telemetryDataStat.AxialLoadSp; - // dto.AxialLoad.Fact = telemetryDataStat.AxialLoad; - // dto.AxialLoad.Limit = telemetryDataStat.AxialLoadLimitMax; - - // dto.TopDriveTorque.SetpointFact = telemetryDataStat.RotorTorqueSp; - // dto.TopDriveTorque.Fact = telemetryDataStat.RotorTorque; - // dto.TopDriveTorque.Limit = telemetryDataStat.RotorTorqueLimitMax; - - // dto.SpeedLimit.SetpointFact = telemetryDataStat.BlockSpeedSp; - // dto.SpeedLimit.Fact = telemetryDataStat.BlockSpeed; - // //dto.SpeedLimit.Limit = mull; - // } - - // if(intervalLimitingParametrs.Any()) - // { - // const int idLimParamRop = 1; - // const int idLimParamPressure = 2; - // const int idLimParamAxialLoad = 3; - // const int idLimParamTorque = 4; - - // var intervalLimitingParametrsStat = intervalLimitingParametrs - // .GroupBy(p => p.IdFeedRegulator) - // .Select(g => new - // { - // IdLimParam = g.Key, - // SumDepth = g.Sum(p => p.DepthEnd - p.DepthStart), - // }); - - // var totalDepth = intervalLimitingParametrsStat - // .Sum(s => s.SumDepth); - - // if (totalDepth > 0) - // { - // dto.AxialLoad.PercDrillingSetpoint = intervalLimitingParametrsStat - // .FirstOrDefault(s => s.IdLimParam == idLimParamAxialLoad)?.SumDepth / totalDepth; - - // dto.PressureDiff.PercDrillingSetpoint = intervalLimitingParametrsStat - // .FirstOrDefault(s => s.IdLimParam == idLimParamPressure)?.SumDepth / totalDepth; - - // dto.TopDriveTorque.PercDrillingSetpoint = intervalLimitingParametrsStat - // .FirstOrDefault(s => s.IdLimParam == idLimParamTorque)?.SumDepth / totalDepth; - - // dto.SpeedLimit.PercDrillingSetpoint = intervalLimitingParametrsStat - // .FirstOrDefault(s => s.IdLimParam == idLimParamRop)?.SumDepth / totalDepth; - // } - // } - - // if (intervalSubsystemsOperationTime.Any() && dto.DeltaDepth > 0) - // { - // dto.Usage = intervalSubsystemsOperationTime.Sum(t => t.DepthEnd - t.DepthStart) / dto.DeltaDepth.Value; - // } - - // return dto; - //} - - private static double CalcDeltaDepth((double min, double max) depthInterval, IEnumerable intervalOperations) - { - var ddepth = 0d; - foreach (var operation in intervalOperations) - { - var depthStart = operation.DepthStart > depthInterval.min - ? operation.DepthStart - : depthInterval.min; - - var depthEnd = operation.DepthEnd < depthInterval.max - ? operation.DepthEnd - : depthInterval.max; - - ddepth += (depthEnd - depthEnd); - } - return ddepth; - } - - private static double CalcHours((double min, double max) depthInterval, IEnumerable intervalOperations) - { - var hours = 0d; - foreach (var operation in intervalOperations) - { - var dateStart = operation.DepthStart > depthInterval.min - ? operation.DateStart - : GetInterpolatedDate(operation, depthInterval.min); - - var dateEnd = operation.DepthEnd < depthInterval.max - ? operation.DateStart + TimeSpan.FromHours(operation.DurationHours) - : GetInterpolatedDate(operation, depthInterval.max); - - hours += (dateEnd - dateStart).TotalHours; - } - return hours; - } - - private static DateTime GetInterpolatedDate(WellOperationDto operation, double depth) - { - var ratio = (depth - operation.DepthStart) / (operation.DepthEnd - operation.DepthStart); - var deltaHours = operation.DurationHours * ratio; - var interpolatedDate = operation.DateStart + TimeSpan.FromHours(deltaHours); - return interpolatedDate; - } - - private static IEnumerable<(double min, double max)> SplitByIntervals(double min, double max) - { - const double step = 100; - var iMin = min; - var iMax = (1 + (int)(min / step)) * step; - for (; iMax < max; iMax += step) - { - yield return (iMin, iMax); - iMin = iMax; - } - yield return (iMin, max); - } - } -#nullable disable -} diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index 0d34b80c..6d9a140b 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -42,10 +42,17 @@ namespace AsbCloudInfrastructure.Services.SAUB .Where(t => t.BlockPosition > 0.0001) .Where(t => t.WellDepth > 0.0001) .Where(t => t.WellDepth - t.BitDepth < 0.01) - .GroupBy(t => new { H = t.DateTime.Hour, W = Math.Truncate(t.WellDepth!.Value) }) + .Where(t => t.Mode != null) + .GroupBy(t => new { + t.DateTime.Hour, + WellDepthX10 = Math.Truncate(t.WellDepth!.Value * 10), + t.Mode, + t.IdFeedRegulator}) .Select(g => new TelemetryDataSaubStatDto { Count = g.Count(), + Mode = g.Key.Mode??0, + IdFeedRegulator = g.Key.IdFeedRegulator, DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified), DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified), @@ -55,8 +62,6 @@ namespace AsbCloudInfrastructure.Services.SAUB Pressure = g.Average(t => t.Pressure!.Value), PressureSp = g.Average(t => t.PressureSp!.Value), - PressureSpRotor = g.Average(t => t.PressureSpRotor!.Value), - PressureSpSlide = g.Average(t => t.PressureSpSlide!.Value), PressureIdle = g.Average(t => t.PressureIdle!.Value), PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value), PressureDelta = g.Average(t => t.Pressure!.Value - t.PressureIdle!.Value), @@ -71,8 +76,6 @@ namespace AsbCloudInfrastructure.Services.SAUB BlockSpeed = g.Average(t => t.BlockSpeed!.Value), BlockSpeedSp = g.Average(t => t.BlockSpeedSp!.Value), - BlockSpeedSpRotor = g.Average(t => t.BlockSpeedSpRotor!.Value), - BlockSpeedSpSlide = g.Average(t => t.BlockSpeedSpSlide!.Value), }) .Where(s => s.WellDepthMin != s.WellDepthMax) .Where(s => s.Count > 3) diff --git a/AsbCloudInfrastructure/Services/WellInfoService.cs b/AsbCloudInfrastructure/Services/WellInfoService.cs index 79d59003..998a40f3 100644 --- a/AsbCloudInfrastructure/Services/WellInfoService.cs +++ b/AsbCloudInfrastructure/Services/WellInfoService.cs @@ -44,7 +44,7 @@ namespace AsbCloudInfrastructure.Services var db = serviceProvider.GetRequiredService(); var wellService = serviceProvider.GetRequiredService(); var operationsStatService = serviceProvider.GetRequiredService(); - var processMapRepository = serviceProvider.GetRequiredService(); + var processMapRepository = serviceProvider.GetRequiredService(); var subsystemOperationTimeService = serviceProvider.GetRequiredService(); var activeWells = await wellService.GetAsync(new() {IdState = 1}, token); diff --git a/AsbCloudWebApi/Controllers/ProcessMapController.cs b/AsbCloudWebApi/Controllers/ProcessMapController.cs index 9f5617a2..3613f32c 100644 --- a/AsbCloudWebApi/Controllers/ProcessMapController.cs +++ b/AsbCloudWebApi/Controllers/ProcessMapController.cs @@ -18,17 +18,17 @@ namespace AsbCloudWebApi.Controllers [ApiController] [Route("api/[controller]")] [Authorize] - public class ProcessMapController : CrudWellRelatedController + public class ProcessMapController : CrudWellRelatedController { private readonly ITelemetryService telemetryService; - private readonly IProcessMapReportService processMapReportService; - private readonly IProcessMapService processMapService; + private readonly IProcessMapReportMakerService processMapReportService; + private readonly IProcessMapReportService processMapService; public ProcessMapController( IWellService wellService, - IProcessMapRepository repository, - IProcessMapReportService processMapReportService, - IProcessMapService processMapService, + IProcessMapPlanRepository repository, + IProcessMapReportMakerService processMapReportService, + IProcessMapReportService processMapService, ITelemetryService telemetryService) : base(wellService, repository) { diff --git a/AsbCloudWebApi/Rest/Example.http b/AsbCloudWebApi/Rest/ProcessMap.http similarity index 66% rename from AsbCloudWebApi/Rest/Example.http rename to AsbCloudWebApi/Rest/ProcessMap.http index bd156b32..9a7d487e 100644 --- a/AsbCloudWebApi/Rest/Example.http +++ b/AsbCloudWebApi/Rest/ProcessMap.http @@ -2,34 +2,12 @@ @contentType = application/json @auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2NjI1NDgxNjIsImV4cCI6MTY5NDEwNTc2MiwiaXNzIjoiYSIsImF1ZCI6ImEifQ.OEAlNzxi7Jat6pzDBTAjTbChskc-tdJthJexyWwwUKE +@wellId = 1 + # https://marketplace.visualstudio.com/items?itemName=humao.rest-client ### -GET {{baseUrl}}/api/schedule/test +GET {{baseUrl}}/api/processMap/getDrillProcessMap/{{wellId}} Content-Type: {{contentType}} accept: */* Authorization: {{auth}} - -### -POST {{baseUrl}}/api/schedule/test -Content-Type: {{contentType}} -accept: */* -Authorization: {{auth}} - -{ - "id": 0, - "items": [ - { - "id": 1, - "value": 0.1 - }, - { - "id": 2, - "value": 1. - }, - { - "id": 3, - "value": 2.0 - } - ] -} \ No newline at end of file