From f2223adfa9c695ef0d6a2ff697e782e9ec786bb1 Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <markus.quaritsch@tugraz.at> Date: Mon, 5 Aug 2019 16:38:59 +0200 Subject: [PATCH] updating interface for WHR data, adding whr reader, whr lookup map, moving readers into correct folder --- Tools/DeclarationCycleZip/Program.cs | 2 +- VECTO/GUI/EngineForm.vb | 1 + VECTO/GUI/GearboxForm.vb | 4 +- VECTO/GUI/VectoJobForm.vb | 5 +- VECTO/GUI/VectoVTPJobForm.vb | 3 +- VECTO/Input Files/Engine.vb | 8 +- VECTO/Input Files/Gearbox.vb | 990 +++++----- .../InputData/DeclarationInputData.cs | 18 + .../Resources/XMLNames.Designer.cs | 81 + .../VectoCommon/Resources/XMLNames.resx | 27 + .../InputData/FileIO/JSON/JSONEngineData.cs | 4 +- .../XMLDeclarationEngineDataProvider.cs | 97 +- .../XMLEngineeringEngineDataProvider.cs | 2 + .../ComponentData/AccelerationCurveReader.cs | 190 +- .../ComponentData/AuxiliaryDataReader.cs | 144 +- .../CrossWindCorrectionCurveReader.cs | 304 ++-- .../DrivingCycleDataReader.cs | 1596 ++++++++--------- .../FuelConsumptionMapReader.cs | 307 ++-- .../FullLoadCurveReader.cs | 280 +-- .../ComponentData/PTOIdleLossMapReader.cs | 148 +- .../{ => ComponentData}/ShiftPolygonReader.cs | 64 +- .../Reader/ComponentData/WHRPowerReader.cs | 84 + .../Impl/EngineOnlyVectoRunDataFactory.cs | 3 +- .../EngineeringModeVectoRunDataFactory.cs | 2 +- .../Data/Engine/WHRPowerMap.cs | 61 + .../OutputData/XML/AttributeMappings.cs | 210 +-- .../VectoCoreTest/Dummy/EngineFLDTest.cs | 2 +- .../BusAuxiliaries/AuxDemandTest.cs | 2 +- .../EngineOnlyCycle/EngineOnlyCycleTest.cs | 2 +- .../Integration/SimpleDrivingCycles.cs | 2 +- .../Models/Declaration/ShiftPolygonTest.cs | 3 +- .../Models/Simulation/DrivingCycleTests.cs | 2 +- .../Models/Simulation/PwheelModeTests.cs | 2 +- .../DistanceBasedDrivingCycleTest.cs | 5 +- .../VTPCycleValidationTest.cs | 1 + .../DistanceCycleDataTest.cs | 2 +- .../FuelConsumptionMapTest.cs | 81 +- .../VectoCoreTest/Reports/ModDataTest.cs | 2 +- .../Utils/MockEngineDataProvider.cs | 2 + 39 files changed, 2583 insertions(+), 2160 deletions(-) rename VectoCore/VectoCore/InputData/Reader/{ => ComponentData}/DrivingCycleDataReader.cs (97%) rename VectoCore/VectoCore/{Models/SimulationComponent/Data/Engine => InputData/Reader/ComponentData}/FuelConsumptionMapReader.cs (65%) rename VectoCore/VectoCore/InputData/Reader/{ => ComponentData}/FullLoadCurveReader.cs (96%) rename VectoCore/VectoCore/InputData/Reader/{ => ComponentData}/ShiftPolygonReader.cs (98%) create mode 100644 VectoCore/VectoCore/InputData/Reader/ComponentData/WHRPowerReader.cs create mode 100644 VectoCore/VectoCore/Models/SimulationComponent/Data/Engine/WHRPowerMap.cs diff --git a/Tools/DeclarationCycleZip/Program.cs b/Tools/DeclarationCycleZip/Program.cs index 1087511d65..006ce06eed 100644 --- a/Tools/DeclarationCycleZip/Program.cs +++ b/Tools/DeclarationCycleZip/Program.cs @@ -34,7 +34,7 @@ using System.Globalization; using System.IO; using System.Linq; using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.SimulationComponent.Data; using TUGraz.VectoCore.Utils; diff --git a/VECTO/GUI/EngineForm.vb b/VECTO/GUI/EngineForm.vb index 0067aec7f6..d39d9ee746 100644 --- a/VECTO/GUI/EngineForm.vb +++ b/VECTO/GUI/EngineForm.vb @@ -10,6 +10,7 @@ Imports TUGraz.VectoCommon.Models Imports TUGraz.VectoCommon.Utils Imports TUGraz.VectoCore.InputData.FileIO.JSON Imports TUGraz.VectoCore.InputData.Reader +Imports TUGraz.VectoCore.InputData.Reader.ComponentData Imports TUGraz.VectoCore.Models.Declaration Imports TUGraz.VectoCore.Models.SimulationComponent.Data Imports TUGraz.VectoCore.Models.SimulationComponent.Data.Engine diff --git a/VECTO/GUI/GearboxForm.vb b/VECTO/GUI/GearboxForm.vb index 9d38b57f0c..aaef282ea9 100644 --- a/VECTO/GUI/GearboxForm.vb +++ b/VECTO/GUI/GearboxForm.vb @@ -23,16 +23,14 @@ Imports TUGraz.VectoCommon.Utils Imports TUGraz.VectoCore Imports TUGraz.VectoCore.InputData.FileIO.JSON Imports TUGraz.VectoCore.InputData.Impl -Imports TUGraz.VectoCore.InputData.Reader +Imports TUGraz.VectoCore.InputData.Reader.ComponentData Imports TUGraz.VectoCore.Models.Declaration Imports TUGraz.VectoCore.Models.SimulationComponent.Data Imports TUGraz.VectoCore.Models.SimulationComponent.Data.Engine Imports TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox Imports TUGraz.VectoCore.OutputData.FileIO Imports TUGraz.VectoCore.OutputData.XML -Imports TUGraz.VectoCore.OutputData.XML.Engineering Imports TUGraz.VectoCore.OutputData.XML.Engineering.Interfaces -Imports TUGraz.VectoCore.Utils ''' <summary> ''' Gearbox Editor diff --git a/VECTO/GUI/VectoJobForm.vb b/VECTO/GUI/VectoJobForm.vb index 65fe836096..21bd8f91a5 100644 --- a/VECTO/GUI/VectoJobForm.vb +++ b/VECTO/GUI/VectoJobForm.vb @@ -14,17 +14,14 @@ Imports System.Collections.Generic Imports System.Drawing.Imaging Imports System.IO Imports System.Linq -Imports System.Runtime.CompilerServices -Imports System.Text.RegularExpressions Imports System.Windows.Forms.DataVisualization.Charting Imports TUGraz.VECTO.Input_Files Imports TUGraz.VectoCommon.InputData Imports TUGraz.VectoCommon.Models Imports TUGraz.VectoCommon.Utils Imports TUGraz.VectoCore.InputData.FileIO.JSON -Imports TUGraz.VectoCore.InputData.Reader +Imports TUGraz.VectoCore.InputData.Reader.ComponentData Imports TUGraz.VectoCore.Models.Declaration -Imports TUGraz.VectoCore.Models.SimulationComponent.Data Imports TUGraz.VectoCore.Models.SimulationComponent.Data.Engine Imports TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox diff --git a/VECTO/GUI/VectoVTPJobForm.vb b/VECTO/GUI/VectoVTPJobForm.vb index f335f24a5c..b5194ccf68 100644 --- a/VECTO/GUI/VectoVTPJobForm.vb +++ b/VECTO/GUI/VectoVTPJobForm.vb @@ -23,8 +23,7 @@ Imports TUGraz.VectoCommon.Utils Imports TUGraz.VectoCore Imports TUGraz.VectoCore.InputData.FileIO.JSON Imports TUGraz.VectoCore.InputData.FileIO.XML -Imports TUGraz.VectoCore.InputData.FileIO.XML.Declaration -Imports TUGraz.VectoCore.InputData.Reader +Imports TUGraz.VectoCore.InputData.Reader.ComponentData Imports TUGraz.VectoCore.Models.Declaration Imports TUGraz.VectoCore.Models.SimulationComponent.Data.Engine diff --git a/VECTO/Input Files/Engine.vb b/VECTO/Input Files/Engine.vb index 935663d719..cbe9c27ff9 100644 --- a/VECTO/Input Files/Engine.vb +++ b/VECTO/Input Files/Engine.vb @@ -403,7 +403,13 @@ Public Class Engine End Get End Property - Public ReadOnly Property RatedPowerDeclared As Watt Implements IEngineDeclarationInputData.RatedPowerDeclared + Public ReadOnly Property WasteHeatRecoveryData As IWHRData Implements IEngineModeDeclarationInputData.WasteHeatRecoveryData + Get + Return nothing + End Get + End Property + + Public ReadOnly Property RatedPowerDeclared As Watt Implements IEngineDeclarationInputData.RatedPowerDeclared Get Return ratedPowerInput End Get diff --git a/VECTO/Input Files/Gearbox.vb b/VECTO/Input Files/Gearbox.vb index b162f7826e..d0b43249bf 100644 --- a/VECTO/Input Files/Gearbox.vb +++ b/VECTO/Input Files/Gearbox.vb @@ -12,15 +12,13 @@ Imports System.Collections.Generic Imports System.ComponentModel.DataAnnotations Imports System.IO Imports System.Linq -Imports System.Runtime.CompilerServices -Imports Newtonsoft.Json.Linq Imports TUGraz.VECTO.Input_Files Imports TUGraz.VectoCommon.InputData Imports TUGraz.VectoCommon.Models Imports TUGraz.VectoCommon.Utils Imports TUGraz.VectoCore.InputData.FileIO.JSON Imports TUGraz.VectoCore.InputData.Impl -Imports TUGraz.VectoCore.InputData.Reader +Imports TUGraz.VectoCore.InputData.Reader.ComponentData Imports TUGraz.VectoCore.InputData.Reader.DataObjectAdapter Imports TUGraz.VectoCore.Models.Declaration Imports TUGraz.VectoCore.Models.SimulationComponent.Data @@ -29,499 +27,499 @@ Imports TUGraz.VectoCore.Utils <CustomValidation(GetType(Gearbox), "ValidateGearbox")> Public Class Gearbox - Implements IGearboxEngineeringInputData, IGearboxDeclarationInputData, IAxleGearInputData, - ITorqueConverterEngineeringInputData, ITorqueConverterDeclarationInputData, IGearshiftEngineeringInputData + Implements IGearboxEngineeringInputData, IGearboxDeclarationInputData, IAxleGearInputData, + ITorqueConverterEngineeringInputData, ITorqueConverterDeclarationInputData, IGearshiftEngineeringInputData - Private _myPath As String - Private _filePath As String - - Public ModelName As String - Public GbxInertia As Double - Public TracIntrSi As Double - - Public GearRatios As List(Of Double) - Public GearLossmaps As List(Of SubPath) - - 'Gear shift polygons - Public GearshiftFiles As List(Of SubPath) - - Public MaxTorque As List(Of String) - Public MaxSpeed As List(Of String) - - Public TorqueResv As Double - 'Public SkipGears As Boolean - Public ShiftTime As Double - Public TorqueResvStart As Double - Public StartSpeed As Double - Public StartAcc As Double - 'Public ShiftInside As Boolean - - Public Type As GearboxType - - 'Torque Converter Input - Public TorqueConverterReferenceRpm As Double - Private ReadOnly _torqueConverterFile As New SubPath - Public TorqueConverterInertia As Double - Public TorqueConverterShiftPolygonFile As String - Public TCLUpshiftMinAcceleration As Double - Public TCCUpshiftMinAcceleration As Double - - Public UpshiftMinAcceleration As Double - Public DownshiftAfterUpshift As Double - Public UpshiftAfterDownshift As Double - Public TorqueConverterMaxSpeed As Double - - Public PSShiftTime As Double - - - Public Sub New() - _myPath = "" - _filePath = "" - SetDefault() - End Sub - - Private Sub SetDefault() - - ModelName = "" - GbxInertia = 0 - TracIntrSi = 0 - - GearRatios = New List(Of Double) - GearLossmaps = New List(Of SubPath) - GearshiftFiles = New List(Of SubPath) - MaxTorque = New List(Of String) - MaxSpeed = New List(Of String) - - TorqueResv = 0 - 'SkipGears = False - ShiftTime = 0 - TorqueResvStart = 0 - StartSpeed = 0 - StartAcc = 0 - 'ShiftInside = False - - Type = GearboxType.MT - - TorqueConverterReferenceRpm = 0 - _torqueConverterFile.Clear() - - TorqueConverterInertia = 0 - End Sub - - Public Function SaveFile() As Boolean - - Dim validationResults As IList(Of ValidationResult) = - Validate(If(Cfg.DeclMode, ExecutionMode.Declaration, ExecutionMode.Engineering), Type, False) - - If validationResults.Count > 0 Then - Dim messages As IEnumerable(Of String) = - validationResults.Select(Function(r) r.ErrorMessage + String.Join(", ", r.MemberNames.Distinct())) - MsgBox("Invalid input." + Environment.NewLine + String.Join("; ", messages), MsgBoxStyle.OkOnly, - "Failed to save gearbox") - Return False - End If - - Try - Dim writer As JSONFileWriter = JSONFileWriter.Instance - writer.SaveGearbox(Me, Me, Me, Me, _filePath) - Catch ex As Exception - MsgBox("failed to write Gearbox file: " + ex.Message) - Return False - End Try - Return True - End Function - - - Public Property FilePath() As String - Get - Return _filePath - End Get - Set(ByVal value As String) - _filePath = value - If _filePath = "" Then - _myPath = "" - Else - _myPath = Path.GetDirectoryName(_filePath) & "\" - End If - End Set - End Property - - Public Property GearLossMap(ByVal gearNr As Integer, Optional ByVal original As Boolean = False) As String - Get - If original Then - Return GearLossmaps(gearNr).OriginalPath - Else - Return GearLossmaps(gearNr).FullPath - End If - End Get - Set(ByVal value As String) - GearLossmaps(gearNr).Init(_myPath, value) - End Set - End Property - - Public Property ShiftPolygonFile(ByVal gearNr As Integer, Optional ByVal original As Boolean = False) As String - Get - If original Then - Return GearshiftFiles(gearNr).OriginalPath - Else - Return GearshiftFiles(gearNr).FullPath - End If - End Get - Set(value As String) - GearshiftFiles(gearNr).Init(_myPath, value) - End Set - End Property - - Public Property TorqueConverterFile(Optional ByVal original As Boolean = False) As String - Get - If original Then - Return _torqueConverterFile.OriginalPath - Else - Return _torqueConverterFile.FullPath - End If - End Get - Set(value As String) - _torqueConverterFile.Init(_myPath, value) - End Set - End Property - - - ' ReSharper disable once UnusedMember.Global -- used by Validation - Public Shared Function ValidateGearbox(gearbox As Gearbox, validationContext As ValidationContext) As ValidationResult - Dim modeService As VectoValidationModeServiceContainer = - TryCast(validationContext.GetService(GetType(VectoValidationModeServiceContainer)), - VectoValidationModeServiceContainer) - Dim mode As ExecutionMode = If(modeService Is Nothing, ExecutionMode.Declaration, modeService.Mode) - Dim emsCycle As Boolean = (modeService IsNot Nothing) AndAlso modeService.IsEMSCycle - - Dim axlegearData As AxleGearData - Dim gearboxData As GearboxData - - Try - 'Dim vectoJob As VectoJob = New VectoJob() With {.FilePath = VectoJobForm.VECTOfile} - Dim vectoFile As String = VectoJobForm.VectoFile - Dim inputData As IEngineeringInputDataProvider = - TryCast(JSONInputDataFactory.ReadComponentData(vectoFile), - IEngineeringInputDataProvider) - 'Dim vehicle As IVehicleEngineeringInputData = inputData.VehicleInputData - Dim engine As CombustionEngineData - Dim vehiclecategory As VehicleCategory - Dim rdyn As Meter = 0.5.SI(Of Meter)() - Try - vehiclecategory = inputData.JobInputData.Vehicle.VehicleCategory - Catch ex As Exception - vehiclecategory = vehiclecategory.RigidTruck - End Try - If mode = ExecutionMode.Declaration Then - Dim doa As DeclarationDataAdapter = New DeclarationDataAdapter() - - Try - engine = doa.CreateEngineData(inputData.JobInputData.Vehicle, inputData.JobInputData.Vehicle.Components.EngineInputData.EngineModes.First(), New Mission() With {.MissionType = MissionType.LongHaul}) - Catch - engine = GetDefaultEngine(gearbox.Gears) - End Try - - axlegearData = doa.CreateAxleGearData(gearbox) - gearboxData = doa.CreateGearboxData(gearbox, engine, axlegearData.AxleGear.Ratio, rdyn, vehiclecategory, gearbox) - Else - Dim doa As EngineeringDataAdapter = New EngineeringDataAdapter() - Try - engine = doa.CreateEngineData(inputData.JobInputData.Vehicle, inputData.JobInputData.Vehicle.Components.EngineInputData.EngineModes.First()) - Catch - engine = GetDefaultEngine(gearbox.Gears) - End Try - - axlegearData = doa.CreateAxleGearData(gearbox) - gearboxData = doa.CreateGearboxData(gearbox, engine, gearbox, axlegearData.AxleGear.Ratio, rdyn, vehiclecategory, gearbox) - End If - - Dim result As IList(Of ValidationResult) = - gearboxData.Validate(If(Cfg.DeclMode, ExecutionMode.Declaration, ExecutionMode.Engineering), gearbox.Type, emsCycle) - If result.Any() Then - Return _ - New ValidationResult("Gearbox Configuration is invalid. ", - result.Select(Function(r) r.ErrorMessage + String.Join(Environment.NewLine, r.MemberNames)).ToList()) - End If - - result = axlegearData.Validate(If(Cfg.DeclMode, ExecutionMode.Declaration, ExecutionMode.Engineering), gearbox.Type, - emsCycle) - If result.Any() Then - Return _ - New ValidationResult("Axlegear Configuration is invalid. ", - result.Select(Function(r) r.ErrorMessage + String.Join(Environment.NewLine, r.MemberNames)).ToList()) - End If - - Return ValidationResult.Success - - Catch ex As Exception - Return New ValidationResult(ex.Message) - End Try - End Function - - Private Shared Function GetDefaultEngine(gears As IList(Of ITransmissionInputData)) As CombustionEngineData - Dim fldData As MemoryStream = New MemoryStream() - Dim writer As StreamWriter = New StreamWriter(fldData) - writer.WriteLine("engine speed, full load torque, motoring torque") - writer.WriteLine(" 500, 2000, -500") - writer.WriteLine("2500, 2000, -500") - writer.WriteLine("3000, 0, -500") - writer.Flush() - fldData.Seek(0, SeekOrigin.Begin) - Dim retVal As CombustionEngineData = New CombustionEngineData() With { - .IdleSpeed = 600.RPMtoRad() - } - - Dim fldCurve As EngineFullLoadCurve = FullLoadCurveReader.Create(VectoCSVFile.ReadStream(fldData)) - Dim fullLoadCurves As Dictionary(Of UInteger, EngineFullLoadCurve) = - New Dictionary(Of UInteger, EngineFullLoadCurve)() - fullLoadCurves(0) = fldCurve - fullLoadCurves(0).EngineData = retVal - For i As Integer = 0 To gears.Count - 1 - fullLoadCurves(CType(i + 1, UInteger)) = AbstractSimulationDataAdapter.IntersectFullLoadCurves(fullLoadCurves(0), - gears(i).MaxTorque) - Next - retVal.FullLoadCurves = fullLoadCurves - Return retVal - End Function - - - Public ReadOnly Property DataSource As DataSource Implements IComponentInputData.DataSource - Get - Dim retVal As DataSource = New DataSource() - retVal.SourceType = DataSourceType.JSONFile - retVal.SourceFile = FilePath - Return retVal - End Get - End Property - - Public ReadOnly Property SavedInDeclarationMode As Boolean Implements IComponentInputData.SavedInDeclarationMode - Get - Return Cfg.DeclMode - End Get - End Property - - Public ReadOnly Property Manufacturer As String Implements IComponentInputData.Manufacturer - Get - ' Just for the interface. Value is not available in GUI yet. - Return TUGraz.VectoCore.Configuration.Constants.NOT_AVailABLE - End Get - End Property - - - Public ReadOnly Property [Date] As String Implements IComponentInputData.[Date] - Get - Return Now.ToUniversalTime().ToString("o") - End Get - End Property - - Public ReadOnly Property CertificationMethod As CertificationMethod Implements IComponentInputData.CertificationMethod - Get - Return CertificationMethod.NotCertified - End Get - End Property - - Public ReadOnly Property CertificationNumber As String Implements IComponentInputData.CertificationNumber - Get - ' Just for the interface. Value is not available in GUI yet. - Return TUGraz.VectoCore.Configuration.Constants.NOT_AVailABLE - End Get - End Property - - Public ReadOnly Property DigestValue As DigestData Implements IComponentInputData.DigestValue - Get - Return Nothing - End Get - End Property - - Public ReadOnly Property Model As String Implements IComponentInputData.Model - Get - Return ModelName - End Get - End Property - - Public ReadOnly Property IGearboxDeclarationInputData_Type As GearboxType Implements IGearboxDeclarationInputData.Type - Get - Return Type - End Get - End Property - - Public ReadOnly Property Gears As IList(Of ITransmissionInputData) Implements IGearboxDeclarationInputData.Gears - Get - Dim ls As IList(Of ITransmissionInputData) = New List(Of ITransmissionInputData) - Dim i As Integer - For i = 1 To GearRatios.Count - 1 - Dim gearDict As New TransmissionInputData With { - .Ratio = GearRatios(i), - .Gear = i - } - If File.Exists(GearshiftFiles(i).FullPath) Then - gearDict.ShiftPolygon = VectoCSVFile.Read(GearshiftFiles(i).FullPath) - End If - If Not String.IsNullOrWhiteSpace(MaxTorque(i)) AndAlso IsNumeric(MaxTorque(i)) Then - gearDict.MaxTorque = MaxTorque(i).ToDouble().SI(Of NewtonMeter)() - End If - If Not String.IsNullOrWhiteSpace(MaxSpeed(i)) AndAlso IsNumeric(MaxSpeed(i)) Then - gearDict.MaxInputSpeed = MaxSpeed(i).ToDouble().RPMtoRad() - End If - If IsNumeric(GearLossMap(i, True)) Then - gearDict.Efficiency = GearLossMap(i, True).ToDouble() - Else - gearDict.LossMap = VectoCSVFile.Read(GearLossmaps(i).FullPath) - End If - - ls.Add(gearDict) - Next - Return ls - End Get - End Property - - Public ReadOnly Property ReferenceRPM As PerSecond Implements ITorqueConverterEngineeringInputData.ReferenceRPM - Get - Return TorqueConverterReferenceRpm.RPMtoRad() - End Get - End Property - - Public ReadOnly Property ITorqueConverterEngineeringInputData_Inertia As KilogramSquareMeter _ - Implements ITorqueConverterEngineeringInputData.Inertia - Get - Return TorqueConverterInertia.SI(Of KilogramSquareMeter)() - End Get - End Property - - Public ReadOnly Property Inertia As KilogramSquareMeter Implements IGearboxEngineeringInputData.Inertia - Get - Return GbxInertia.SI(Of KilogramSquareMeter)() - End Get - End Property - - Public ReadOnly Property ShiftPolygon As TableData Implements ITorqueConverterEngineeringInputData.ShiftPolygon - Get - If Not File.Exists(Path.Combine(_myPath, TorqueConverterShiftPolygonFile)) Then Return Nothing - Return VectoCSVFile.Read(Path.Combine(_myPath, TorqueConverterShiftPolygonFile)) - End Get - End Property - - Public ReadOnly Property MaxInputSpeed As PerSecond Implements ITorqueConverterEngineeringInputData.MaxInputSpeed - Get - Return TorqueConverterMaxSpeed.RPMtoRad() - End Get - End Property - - Public ReadOnly Property CLUpshiftMinAcceleration As MeterPerSquareSecond _ - Implements IGearshiftEngineeringInputData.CLUpshiftMinAcceleration - Get - Return TCLUpshiftMinAcceleration.SI(Of MeterPerSquareSecond)() - End Get - End Property - - Public ReadOnly Property CCUpshiftMinAcceleration As MeterPerSquareSecond _ - Implements IGearshiftEngineeringInputData.CCUpshiftMinAcceleration - Get - Return TCCUpshiftMinAcceleration.SI(Of MeterPerSquareSecond)() - End Get - End Property - - - Public ReadOnly Property TractionInterruption As Second Implements IGearboxEngineeringInputData.TractionInterruption - Get - Return TracIntrSi.SI(Of Second)() - End Get - End Property - - - Public ReadOnly Property TorqueReserve As Double Implements IGearshiftEngineeringInputData.TorqueReserve - Get - Return TorqueResv / 100 - End Get - End Property - - Public ReadOnly Property StartAcceleration As MeterPerSquareSecond _ - Implements IGearshiftEngineeringInputData.StartAcceleration - Get - Return StartAcc.SI(Of MeterPerSquareSecond)() - End Get - End Property - - Public ReadOnly Property StartTorqueReserve As Double Implements IGearshiftEngineeringInputData.StartTorqueReserve - Get - Return TorqueResvStart / 100 - End Get - End Property - - Public ReadOnly Property DownshiftAferUpshiftDelay As Second _ - Implements IGearshiftEngineeringInputData.DownshiftAfterUpshiftDelay - Get - Return DownshiftAfterUpshift.SI(Of Second)() - End Get - End Property - - Public ReadOnly Property UpshiftAfterDownshiftDelay As Second _ - Implements IGearshiftEngineeringInputData.UpshiftAfterDownshiftDelay - Get - Return UpshiftAfterDownshift.SI(Of Second)() - End Get - End Property - - Public ReadOnly Property PowershiftShiftTime As Second Implements IGearboxEngineeringInputData.PowershiftShiftTime - Get - Return PSShiftTime.SI(Of Second)() - End Get - End Property - - - Public ReadOnly Property IGearboxEngineeringInputData_UpshiftMinAcceleration As MeterPerSquareSecond _ - Implements IGearshiftEngineeringInputData.UpshiftMinAcceleration - Get - Return UpshiftMinAcceleration.SI(Of MeterPerSquareSecond)() - End Get - End Property - - - Public ReadOnly Property IGearboxEngineeringInputData_StartSpeed As MeterPerSecond _ - Implements IGearshiftEngineeringInputData.StartSpeed - Get - Return StartSpeed.SI(Of MeterPerSecond)() - End Get - End Property - - Public ReadOnly Property MinTimeBetweenGearshift As Second _ - Implements IGearshiftEngineeringInputData.MinTimeBetweenGearshift - Get - Return ShiftTime.SI(Of Second)() - End Get - End Property - - Public ReadOnly Property TCData As TableData Implements ITorqueConverterDeclarationInputData.TCData - Get - If Not File.Exists(_torqueConverterFile.FullPath) Then Return Nothing - Return VectoCSVFile.Read(_torqueConverterFile.FullPath) - End Get - End Property - - - Public ReadOnly Property Ratio As Double Implements IAxleGearInputData.Ratio - Get - Return GearRatios(0) - End Get - End Property - - Public ReadOnly Property LossMap As TableData Implements IAxleGearInputData.LossMap - Get - If Not File.Exists(GearLossmaps(0).FullPath) Then Return Nothing - Return VectoCSVFile.Read(GearLossmaps(0).FullPath) - End Get - End Property - - Public ReadOnly Property Efficiency As Double Implements IAxleGearInputData.Efficiency - Get - Return GearLossMap(0, True).ToDouble(0) - End Get - End Property - - Public ReadOnly Property LineType As AxleLineType Implements IAxleGearInputData.LineType - Get - Return AxleLineType.SinglePortalAxle - End Get - End Property + Private _myPath As String + Private _filePath As String + + Public ModelName As String + Public GbxInertia As Double + Public TracIntrSi As Double + + Public GearRatios As List(Of Double) + Public GearLossmaps As List(Of SubPath) + + 'Gear shift polygons + Public GearshiftFiles As List(Of SubPath) + + Public MaxTorque As List(Of String) + Public MaxSpeed As List(Of String) + + Public TorqueResv As Double + 'Public SkipGears As Boolean + Public ShiftTime As Double + Public TorqueResvStart As Double + Public StartSpeed As Double + Public StartAcc As Double + 'Public ShiftInside As Boolean + + Public Type As GearboxType + + 'Torque Converter Input + Public TorqueConverterReferenceRpm As Double + Private ReadOnly _torqueConverterFile As New SubPath + Public TorqueConverterInertia As Double + Public TorqueConverterShiftPolygonFile As String + Public TCLUpshiftMinAcceleration As Double + Public TCCUpshiftMinAcceleration As Double + + Public UpshiftMinAcceleration As Double + Public DownshiftAfterUpshift As Double + Public UpshiftAfterDownshift As Double + Public TorqueConverterMaxSpeed As Double + + Public PSShiftTime As Double + + + Public Sub New() + _myPath = "" + _filePath = "" + SetDefault() + End Sub + + Private Sub SetDefault() + + ModelName = "" + GbxInertia = 0 + TracIntrSi = 0 + + GearRatios = New List(Of Double) + GearLossmaps = New List(Of SubPath) + GearshiftFiles = New List(Of SubPath) + MaxTorque = New List(Of String) + MaxSpeed = New List(Of String) + + TorqueResv = 0 + 'SkipGears = False + ShiftTime = 0 + TorqueResvStart = 0 + StartSpeed = 0 + StartAcc = 0 + 'ShiftInside = False + + Type = GearboxType.MT + + TorqueConverterReferenceRpm = 0 + _torqueConverterFile.Clear() + + TorqueConverterInertia = 0 + End Sub + + Public Function SaveFile() As Boolean + + Dim validationResults As IList(Of ValidationResult) = + Validate(If(Cfg.DeclMode, ExecutionMode.Declaration, ExecutionMode.Engineering), Type, False) + + If validationResults.Count > 0 Then + Dim messages As IEnumerable(Of String) = + validationResults.Select(Function(r) r.ErrorMessage + String.Join(", ", r.MemberNames.Distinct())) + MsgBox("Invalid input." + Environment.NewLine + String.Join("; ", messages), MsgBoxStyle.OkOnly, + "Failed to save gearbox") + Return False + End If + + Try + Dim writer As JSONFileWriter = JSONFileWriter.Instance + writer.SaveGearbox(Me, Me, Me, Me, _filePath) + Catch ex As Exception + MsgBox("failed to write Gearbox file: " + ex.Message) + Return False + End Try + Return True + End Function + + + Public Property FilePath() As String + Get + Return _filePath + End Get + Set(ByVal value As String) + _filePath = value + If _filePath = "" Then + _myPath = "" + Else + _myPath = Path.GetDirectoryName(_filePath) & "\" + End If + End Set + End Property + + Public Property GearLossMap(ByVal gearNr As Integer, Optional ByVal original As Boolean = False) As String + Get + If original Then + Return GearLossmaps(gearNr).OriginalPath + Else + Return GearLossmaps(gearNr).FullPath + End If + End Get + Set(ByVal value As String) + GearLossmaps(gearNr).Init(_myPath, value) + End Set + End Property + + Public Property ShiftPolygonFile(ByVal gearNr As Integer, Optional ByVal original As Boolean = False) As String + Get + If original Then + Return GearshiftFiles(gearNr).OriginalPath + Else + Return GearshiftFiles(gearNr).FullPath + End If + End Get + Set(value As String) + GearshiftFiles(gearNr).Init(_myPath, value) + End Set + End Property + + Public Property TorqueConverterFile(Optional ByVal original As Boolean = False) As String + Get + If original Then + Return _torqueConverterFile.OriginalPath + Else + Return _torqueConverterFile.FullPath + End If + End Get + Set(value As String) + _torqueConverterFile.Init(_myPath, value) + End Set + End Property + + + ' ReSharper disable once UnusedMember.Global -- used by Validation + Public Shared Function ValidateGearbox(gearbox As Gearbox, validationContext As ValidationContext) As ValidationResult + Dim modeService As VectoValidationModeServiceContainer = + TryCast(validationContext.GetService(GetType(VectoValidationModeServiceContainer)), + VectoValidationModeServiceContainer) + Dim mode As ExecutionMode = If(modeService Is Nothing, ExecutionMode.Declaration, modeService.Mode) + Dim emsCycle As Boolean = (modeService IsNot Nothing) AndAlso modeService.IsEMSCycle + + Dim axlegearData As AxleGearData + Dim gearboxData As GearboxData + + Try + 'Dim vectoJob As VectoJob = New VectoJob() With {.FilePath = VectoJobForm.VECTOfile} + Dim vectoFile As String = VectoJobForm.VectoFile + Dim inputData As IEngineeringInputDataProvider = + TryCast(JSONInputDataFactory.ReadComponentData(vectoFile), + IEngineeringInputDataProvider) + 'Dim vehicle As IVehicleEngineeringInputData = inputData.VehicleInputData + Dim engine As CombustionEngineData + Dim vehiclecategory As VehicleCategory + Dim rdyn As Meter = 0.5.SI(Of Meter)() + Try + vehiclecategory = inputData.JobInputData.Vehicle.VehicleCategory + Catch ex As Exception + vehiclecategory = vehiclecategory.RigidTruck + End Try + If mode = ExecutionMode.Declaration Then + Dim doa As DeclarationDataAdapter = New DeclarationDataAdapter() + + Try + engine = doa.CreateEngineData(inputData.JobInputData.Vehicle, inputData.JobInputData.Vehicle.Components.EngineInputData.EngineModes.First(), New Mission() With {.MissionType = MissionType.LongHaul}) + Catch + engine = GetDefaultEngine(gearbox.Gears) + End Try + + axlegearData = doa.CreateAxleGearData(gearbox) + gearboxData = doa.CreateGearboxData(gearbox, engine, axlegearData.AxleGear.Ratio, rdyn, vehiclecategory, gearbox) + Else + Dim doa As EngineeringDataAdapter = New EngineeringDataAdapter() + Try + engine = doa.CreateEngineData(inputData.JobInputData.Vehicle, inputData.JobInputData.Vehicle.Components.EngineInputData.EngineModes.First()) + Catch + engine = GetDefaultEngine(gearbox.Gears) + End Try + + axlegearData = doa.CreateAxleGearData(gearbox) + gearboxData = doa.CreateGearboxData(gearbox, engine, gearbox, axlegearData.AxleGear.Ratio, rdyn, vehiclecategory, gearbox) + End If + + Dim result As IList(Of ValidationResult) = + gearboxData.Validate(If(Cfg.DeclMode, ExecutionMode.Declaration, ExecutionMode.Engineering), gearbox.Type, emsCycle) + If result.Any() Then + Return _ + New ValidationResult("Gearbox Configuration is invalid. ", + result.Select(Function(r) r.ErrorMessage + String.Join(Environment.NewLine, r.MemberNames)).ToList()) + End If + + result = axlegearData.Validate(If(Cfg.DeclMode, ExecutionMode.Declaration, ExecutionMode.Engineering), gearbox.Type, + emsCycle) + If result.Any() Then + Return _ + New ValidationResult("Axlegear Configuration is invalid. ", + result.Select(Function(r) r.ErrorMessage + String.Join(Environment.NewLine, r.MemberNames)).ToList()) + End If + + Return ValidationResult.Success + + Catch ex As Exception + Return New ValidationResult(ex.Message) + End Try + End Function + + Private Shared Function GetDefaultEngine(gears As IList(Of ITransmissionInputData)) As CombustionEngineData + Dim fldData As MemoryStream = New MemoryStream() + Dim writer As StreamWriter = New StreamWriter(fldData) + writer.WriteLine("engine speed, full load torque, motoring torque") + writer.WriteLine(" 500, 2000, -500") + writer.WriteLine("2500, 2000, -500") + writer.WriteLine("3000, 0, -500") + writer.Flush() + fldData.Seek(0, SeekOrigin.Begin) + Dim retVal As CombustionEngineData = New CombustionEngineData() With { + .IdleSpeed = 600.RPMtoRad() + } + + Dim fldCurve As EngineFullLoadCurve = FullLoadCurveReader.Create(VectoCSVFile.ReadStream(fldData)) + Dim fullLoadCurves As Dictionary(Of UInteger, EngineFullLoadCurve) = + New Dictionary(Of UInteger, EngineFullLoadCurve)() + fullLoadCurves(0) = fldCurve + fullLoadCurves(0).EngineData = retVal + For i As Integer = 0 To gears.Count - 1 + fullLoadCurves(CType(i + 1, UInteger)) = AbstractSimulationDataAdapter.IntersectFullLoadCurves(fullLoadCurves(0), + gears(i).MaxTorque) + Next + retVal.FullLoadCurves = fullLoadCurves + Return retVal + End Function + + + Public ReadOnly Property DataSource As DataSource Implements IComponentInputData.DataSource + Get + Dim retVal As DataSource = New DataSource() + retVal.SourceType = DataSourceType.JSONFile + retVal.SourceFile = FilePath + Return retVal + End Get + End Property + + Public ReadOnly Property SavedInDeclarationMode As Boolean Implements IComponentInputData.SavedInDeclarationMode + Get + Return Cfg.DeclMode + End Get + End Property + + Public ReadOnly Property Manufacturer As String Implements IComponentInputData.Manufacturer + Get + ' Just for the interface. Value is not available in GUI yet. + Return TUGraz.VectoCore.Configuration.Constants.NOT_AVailABLE + End Get + End Property + + + Public ReadOnly Property [Date] As String Implements IComponentInputData.[Date] + Get + Return Now.ToUniversalTime().ToString("o") + End Get + End Property + + Public ReadOnly Property CertificationMethod As CertificationMethod Implements IComponentInputData.CertificationMethod + Get + Return CertificationMethod.NotCertified + End Get + End Property + + Public ReadOnly Property CertificationNumber As String Implements IComponentInputData.CertificationNumber + Get + ' Just for the interface. Value is not available in GUI yet. + Return TUGraz.VectoCore.Configuration.Constants.NOT_AVailABLE + End Get + End Property + + Public ReadOnly Property DigestValue As DigestData Implements IComponentInputData.DigestValue + Get + Return Nothing + End Get + End Property + + Public ReadOnly Property Model As String Implements IComponentInputData.Model + Get + Return ModelName + End Get + End Property + + Public ReadOnly Property IGearboxDeclarationInputData_Type As GearboxType Implements IGearboxDeclarationInputData.Type + Get + Return Type + End Get + End Property + + Public ReadOnly Property Gears As IList(Of ITransmissionInputData) Implements IGearboxDeclarationInputData.Gears + Get + Dim ls As IList(Of ITransmissionInputData) = New List(Of ITransmissionInputData) + Dim i As Integer + For i = 1 To GearRatios.Count - 1 + Dim gearDict As New TransmissionInputData With { + .Ratio = GearRatios(i), + .Gear = i + } + If File.Exists(GearshiftFiles(i).FullPath) Then + gearDict.ShiftPolygon = VectoCSVFile.Read(GearshiftFiles(i).FullPath) + End If + If Not String.IsNullOrWhiteSpace(MaxTorque(i)) AndAlso IsNumeric(MaxTorque(i)) Then + gearDict.MaxTorque = MaxTorque(i).ToDouble().SI(Of NewtonMeter)() + End If + If Not String.IsNullOrWhiteSpace(MaxSpeed(i)) AndAlso IsNumeric(MaxSpeed(i)) Then + gearDict.MaxInputSpeed = MaxSpeed(i).ToDouble().RPMtoRad() + End If + If IsNumeric(GearLossMap(i, True)) Then + gearDict.Efficiency = GearLossMap(i, True).ToDouble() + Else + gearDict.LossMap = VectoCSVFile.Read(GearLossmaps(i).FullPath) + End If + + ls.Add(gearDict) + Next + Return ls + End Get + End Property + + Public ReadOnly Property ReferenceRPM As PerSecond Implements ITorqueConverterEngineeringInputData.ReferenceRPM + Get + Return TorqueConverterReferenceRpm.RPMtoRad() + End Get + End Property + + Public ReadOnly Property ITorqueConverterEngineeringInputData_Inertia As KilogramSquareMeter _ + Implements ITorqueConverterEngineeringInputData.Inertia + Get + Return TorqueConverterInertia.SI(Of KilogramSquareMeter)() + End Get + End Property + + Public ReadOnly Property Inertia As KilogramSquareMeter Implements IGearboxEngineeringInputData.Inertia + Get + Return GbxInertia.SI(Of KilogramSquareMeter)() + End Get + End Property + + Public ReadOnly Property ShiftPolygon As TableData Implements ITorqueConverterEngineeringInputData.ShiftPolygon + Get + If Not File.Exists(Path.Combine(_myPath, TorqueConverterShiftPolygonFile)) Then Return Nothing + Return VectoCSVFile.Read(Path.Combine(_myPath, TorqueConverterShiftPolygonFile)) + End Get + End Property + + Public ReadOnly Property MaxInputSpeed As PerSecond Implements ITorqueConverterEngineeringInputData.MaxInputSpeed + Get + Return TorqueConverterMaxSpeed.RPMtoRad() + End Get + End Property + + Public ReadOnly Property CLUpshiftMinAcceleration As MeterPerSquareSecond _ + Implements IGearshiftEngineeringInputData.CLUpshiftMinAcceleration + Get + Return TCLUpshiftMinAcceleration.SI(Of MeterPerSquareSecond)() + End Get + End Property + + Public ReadOnly Property CCUpshiftMinAcceleration As MeterPerSquareSecond _ + Implements IGearshiftEngineeringInputData.CCUpshiftMinAcceleration + Get + Return TCCUpshiftMinAcceleration.SI(Of MeterPerSquareSecond)() + End Get + End Property + + + Public ReadOnly Property TractionInterruption As Second Implements IGearboxEngineeringInputData.TractionInterruption + Get + Return TracIntrSi.SI(Of Second)() + End Get + End Property + + + Public ReadOnly Property TorqueReserve As Double Implements IGearshiftEngineeringInputData.TorqueReserve + Get + Return TorqueResv / 100 + End Get + End Property + + Public ReadOnly Property StartAcceleration As MeterPerSquareSecond _ + Implements IGearshiftEngineeringInputData.StartAcceleration + Get + Return StartAcc.SI(Of MeterPerSquareSecond)() + End Get + End Property + + Public ReadOnly Property StartTorqueReserve As Double Implements IGearshiftEngineeringInputData.StartTorqueReserve + Get + Return TorqueResvStart / 100 + End Get + End Property + + Public ReadOnly Property DownshiftAferUpshiftDelay As Second _ + Implements IGearshiftEngineeringInputData.DownshiftAfterUpshiftDelay + Get + Return DownshiftAfterUpshift.SI(Of Second)() + End Get + End Property + + Public ReadOnly Property UpshiftAfterDownshiftDelay As Second _ + Implements IGearshiftEngineeringInputData.UpshiftAfterDownshiftDelay + Get + Return UpshiftAfterDownshift.SI(Of Second)() + End Get + End Property + + Public ReadOnly Property PowershiftShiftTime As Second Implements IGearboxEngineeringInputData.PowershiftShiftTime + Get + Return PSShiftTime.SI(Of Second)() + End Get + End Property + + + Public ReadOnly Property IGearboxEngineeringInputData_UpshiftMinAcceleration As MeterPerSquareSecond _ + Implements IGearshiftEngineeringInputData.UpshiftMinAcceleration + Get + Return UpshiftMinAcceleration.SI(Of MeterPerSquareSecond)() + End Get + End Property + + + Public ReadOnly Property IGearboxEngineeringInputData_StartSpeed As MeterPerSecond _ + Implements IGearshiftEngineeringInputData.StartSpeed + Get + Return StartSpeed.SI(Of MeterPerSecond)() + End Get + End Property + + Public ReadOnly Property MinTimeBetweenGearshift As Second _ + Implements IGearshiftEngineeringInputData.MinTimeBetweenGearshift + Get + Return ShiftTime.SI(Of Second)() + End Get + End Property + + Public ReadOnly Property TCData As TableData Implements ITorqueConverterDeclarationInputData.TCData + Get + If Not File.Exists(_torqueConverterFile.FullPath) Then Return Nothing + Return VectoCSVFile.Read(_torqueConverterFile.FullPath) + End Get + End Property + + + Public ReadOnly Property Ratio As Double Implements IAxleGearInputData.Ratio + Get + Return GearRatios(0) + End Get + End Property + + Public ReadOnly Property LossMap As TableData Implements IAxleGearInputData.LossMap + Get + If Not File.Exists(GearLossmaps(0).FullPath) Then Return Nothing + Return VectoCSVFile.Read(GearLossmaps(0).FullPath) + End Get + End Property + + Public ReadOnly Property Efficiency As Double Implements IAxleGearInputData.Efficiency + Get + Return GearLossMap(0, True).ToDouble(0) + End Get + End Property + + Public ReadOnly Property LineType As AxleLineType Implements IAxleGearInputData.LineType + Get + Return AxleLineType.SinglePortalAxle + End Get + End Property End Class diff --git a/VectoCommon/VectoCommon/InputData/DeclarationInputData.cs b/VectoCommon/VectoCommon/InputData/DeclarationInputData.cs index 905396fd4e..9e42e515e5 100644 --- a/VectoCommon/VectoCommon/InputData/DeclarationInputData.cs +++ b/VectoCommon/VectoCommon/InputData/DeclarationInputData.cs @@ -512,6 +512,24 @@ namespace TUGraz.VectoCommon.InputData IList<IEngineFuelDelcarationInputData> Fuels { get; } + IWHRData WasteHeatRecoveryData { get; } + + } + + public interface IWHRData + { + double UrbanCorrectionFactor { get; } + + double RuralCorrectionFactor { get; } + + double MotorwayCorrectionFactor { get; } + + double BFColdHot { get; } + + double CFRegPer { get; } + + TableData GeneratedElectricPower { get; } + } public interface IEngineFuelDelcarationInputData diff --git a/VectoCommon/VectoCommon/Resources/XMLNames.Designer.cs b/VectoCommon/VectoCommon/Resources/XMLNames.Designer.cs index ae747f4ad1..70741f6c65 100644 --- a/VectoCommon/VectoCommon/Resources/XMLNames.Designer.cs +++ b/VectoCommon/VectoCommon/Resources/XMLNames.Designer.cs @@ -1041,6 +1041,33 @@ namespace TUGraz.VectoCommon.Resources { } } + /// <summary> + /// Looks up a localized string similar to electricPower. + /// </summary> + public static string Engine_FuelConsumptionMap_WHRElPower_Attr { + get { + return ResourceManager.GetString("Engine_FuelConsumptionMap_WHRElPower_Attr", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Mode. + /// </summary> + public static string Engine_FuelModes { + get { + return ResourceManager.GetString("Engine_FuelModes", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Fuel. + /// </summary> + public static string Engine_FuelModes_Fuel { + get { + return ResourceManager.GetString("Engine_FuelModes_Fuel", resourceCulture); + } + } + /// <summary> /// Looks up a localized string similar to FuelType. /// </summary> @@ -1131,6 +1158,60 @@ namespace TUGraz.VectoCommon.Resources { } } + /// <summary> + /// Looks up a localized string similar to WHRCorrectionFactors. + /// </summary> + public static string Engine_WHRCorrectionFactors { + get { + return ResourceManager.GetString("Engine_WHRCorrectionFactors", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to BFColdHot. + /// </summary> + public static string Engine_WHRCorrectionFactors_BFColdHot { + get { + return ResourceManager.GetString("Engine_WHRCorrectionFactors_BFColdHot", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to CFRegPer. + /// </summary> + public static string Engine_WHRCorrectionFactors_CFRegPer { + get { + return ResourceManager.GetString("Engine_WHRCorrectionFactors_CFRegPer", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Motorway. + /// </summary> + public static string Engine_WHRCorrectionFactors_Motorway { + get { + return ResourceManager.GetString("Engine_WHRCorrectionFactors_Motorway", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Rural. + /// </summary> + public static string Engine_WHRCorrectionFactors_Rural { + get { + return ResourceManager.GetString("Engine_WHRCorrectionFactors_Rural", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Urban. + /// </summary> + public static string Engine_WHRCorrectionFactors_Urban { + get { + return ResourceManager.GetString("Engine_WHRCorrectionFactors_Urban", resourceCulture); + } + } + /// <summary> /// Looks up a localized string similar to WHTCEngineering. /// </summary> diff --git a/VectoCommon/VectoCommon/Resources/XMLNames.resx b/VectoCommon/VectoCommon/Resources/XMLNames.resx index 47d5519e91..2ac518ece7 100644 --- a/VectoCommon/VectoCommon/Resources/XMLNames.resx +++ b/VectoCommon/VectoCommon/Resources/XMLNames.resx @@ -1074,4 +1074,31 @@ <data name="Report_Engine_FuelMode" xml:space="preserve"> <value>Mode</value> </data> + <data name="Engine_FuelConsumptionMap_WHRElPower_Attr" xml:space="preserve"> + <value>electricPower</value> + </data> + <data name="Engine_WHRCorrectionFactors" xml:space="preserve"> + <value>WHRCorrectionFactors</value> + </data> + <data name="Engine_FuelModes" xml:space="preserve"> + <value>Mode</value> + </data> + <data name="Engine_FuelModes_Fuel" xml:space="preserve"> + <value>Fuel</value> + </data> + <data name="Engine_WHRCorrectionFactors_Urban" xml:space="preserve"> + <value>Urban</value> + </data> + <data name="Engine_WHRCorrectionFactors_Rural" xml:space="preserve"> + <value>Rural</value> + </data> + <data name="Engine_WHRCorrectionFactors_Motorway" xml:space="preserve"> + <value>Motorway</value> + </data> + <data name="Engine_WHRCorrectionFactors_BFColdHot" xml:space="preserve"> + <value>BFColdHot</value> + </data> + <data name="Engine_WHRCorrectionFactors_CFRegPer" xml:space="preserve"> + <value>CFRegPer</value> + </data> </root> \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONEngineData.cs b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONEngineData.cs index 1a1a08ad9c..449b69722d 100644 --- a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONEngineData.cs +++ b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONEngineData.cs @@ -159,7 +159,9 @@ namespace TUGraz.VectoCore.InputData.FileIO.JSON } } - public IList<IEngineFuelDelcarationInputData> Fuels { get { return new IEngineFuelDelcarationInputData[] { this }; } } + public virtual IList<IEngineFuelDelcarationInputData> Fuels { get { return new IEngineFuelDelcarationInputData[] { this }; } } + + public virtual IWHRData WasteHeatRecoveryData { get { return null; } } public virtual Watt RatedPowerDeclared { diff --git a/VectoCore/VectoCore/InputData/FileIO/XML/Declaration/DataProvider/XMLDeclarationEngineDataProvider.cs b/VectoCore/VectoCore/InputData/FileIO/XML/Declaration/DataProvider/XMLDeclarationEngineDataProvider.cs index df2da08ad2..78f24a51b5 100644 --- a/VectoCore/VectoCore/InputData/FileIO/XML/Declaration/DataProvider/XMLDeclarationEngineDataProvider.cs +++ b/VectoCore/VectoCore/InputData/FileIO/XML/Declaration/DataProvider/XMLDeclarationEngineDataProvider.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Xml; using System.Xml.Linq; using TUGraz.IVT.VectoXML; +using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCommon.InputData; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Resources; @@ -56,16 +57,16 @@ namespace TUGraz.VectoCore.InputData.FileIO.XML.Declaration.DataProvider { get { return _engineModes ?? - (_engineModes = new List<IEngineModeDeclarationInputData>() { new XMLSingleFuelEngine(BaseNode) }); + (_engineModes = new List<IEngineModeDeclarationInputData>() { new XMLSingleFuelEngineMode(BaseNode) }); } } - public class XMLSingleFuelEngine : AbstractXMLType, IEngineModeDeclarationInputData + public class XMLSingleFuelEngineMode : AbstractXMLType, IEngineModeDeclarationInputData { - protected IList<IEngineFuelDelcarationInputData> _fuels; + protected IList<IEngineFuelDelcarationInputData> FuelsList; - public XMLSingleFuelEngine(XmlNode baseNode) : base(baseNode) + public XMLSingleFuelEngineMode(XmlNode baseNode) : base(baseNode) { } @@ -85,11 +86,12 @@ namespace TUGraz.VectoCore.InputData.FileIO.XML.Declaration.DataProvider public virtual IList<IEngineFuelDelcarationInputData> Fuels { get { - return _fuels ?? (_fuels = new List<IEngineFuelDelcarationInputData>() { new XMLSingleFuelEngineFuel(BaseNode) }); + return FuelsList ?? (FuelsList = new List<IEngineFuelDelcarationInputData>() { new XMLSingleFuelEngineFuel(BaseNode) }); } } + public virtual IWHRData WasteHeatRecoveryData { get { return null; } } } public class XMLSingleFuelEngineFuel : AbstractXMLType, IEngineFuelDelcarationInputData @@ -236,28 +238,75 @@ namespace TUGraz.VectoCore.InputData.FileIO.XML.Declaration.DataProvider public override IList<IEngineModeDeclarationInputData> EngineModes { get { - return _engineModes ?? (_engineModes = GetNodes("Mode") + return _engineModes ?? (_engineModes = GetNodes(XMLNames.Engine_FuelModes) .Cast<XmlNode>().Select(x => new XMLDualFuelEngineMode(x)).Cast<IEngineModeDeclarationInputData>().ToList()); } } #endregion - public class XMLDualFuelEngineMode : XMLSingleFuelEngine + public class XMLDualFuelEngineMode : XMLSingleFuelEngineMode { + protected IWHRData WHRData; + public XMLDualFuelEngineMode(XmlNode baseNode) : base(baseNode) { } - #region Overrides of XMLSingleFuelEngine + #region Overrides of XMLSingleFuelEngineMode public override IList<IEngineFuelDelcarationInputData> Fuels { get { - return _fuels ?? (_fuels = GetNodes("Fuel").Cast<XmlNode>().Select(x => new XMLDualFuelEngineFuel(x)) + return FuelsList ?? (FuelsList = GetNodes(XMLNames.Engine_FuelModes_Fuel).Cast<XmlNode>().Select(x => new XMLDualFuelEngineFuel(x)) .Cast<IEngineFuelDelcarationInputData>().ToList()); } } + public override IWHRData WasteHeatRecoveryData + { + get { return WHRData ?? (WHRData = ReadWHRData()); } + } + #endregion + + protected virtual IWHRData ReadWHRData() + { + var correctionFactorNodes = GetNodes(new[] { XMLNames.Engine_FuelModes_Fuel, XMLNames.Engine_WHRCorrectionFactors }); + if (correctionFactorNodes.Count == 0) { + return new XMLWHRData(); + } + if (correctionFactorNodes.Count > 1) { + throw new VectoException("WHRData can only be defined for one fuel!"); + } + + if (GetNodes(new[] { XMLNames.Engine_FuelModes_Fuel, XMLNames.Engine_FuelConsumptionMap, XMLNames.Engine_FuelConsumptionMap_Entry }) + .Cast<XmlNode>().All(x => x.Attributes?[XMLNames.Engine_FuelConsumptionMap_WHRElPower_Attr] == null)) { + return new XMLWHRData(); + } + + var fuelNodes = GetNodes(XMLNames.Engine_FuelModes_Fuel); + XmlNode whrFuelNode = null; + if (fuelNodes.Count > 1) { + for (var i = 0; i < fuelNodes.Count; i++) { + var fuel = fuelNodes[i]; + if (GetNodes("Entry", fuel).Cast<XmlNode>().Any(x => x.Attributes?[XMLNames.Engine_FuelConsumptionMap_WHRElPower_Attr] != null)) { + if (whrFuelNode != null) { + throw new VectoException("WHRData can only be defined for one fuel!"); + } + + whrFuelNode = fuel; + } + } + } else { + whrFuelNode = fuelNodes[0]; + } + + if (correctionFactorNodes[0].ParentNode != whrFuelNode) { + throw new VectoException("Correction Factors and WHR-Map have to be defined for the same fuel!"); + } + + return new XMLWHRData(whrFuelNode); + } + } public class XMLDualFuelEngineFuel : XMLSingleFuelEngineFuel @@ -273,5 +322,35 @@ namespace TUGraz.VectoCore.InputData.FileIO.XML.Declaration.DataProvider #endregion } + + public class XMLWHRData : AbstractXMLType, IWHRData + { + protected TableData WHRPower; + + public XMLWHRData(XmlNode whrFuelNode) : base(whrFuelNode) + { + } + + public XMLWHRData() :base(null) + { + } + + #region Implementation of IWHRData + + public double UrbanCorrectionFactor { get { return GetDouble(new[] { XMLNames.Engine_WHRCorrectionFactors, XMLNames.Engine_WHRCorrectionFactors_Urban}, 1); } } + public double RuralCorrectionFactor { get { return GetDouble(new[] { XMLNames.Engine_WHRCorrectionFactors, XMLNames.Engine_WHRCorrectionFactors_Rural}, 1); } } + public double MotorwayCorrectionFactor { get { return GetDouble(new[] { XMLNames.Engine_WHRCorrectionFactors, XMLNames.Engine_WHRCorrectionFactors_Motorway}, 1); } } + public double BFColdHot { get { return GetDouble(new[] { XMLNames.Engine_WHRCorrectionFactors, XMLNames.Engine_WHRCorrectionFactors_BFColdHot}, 1); } } + public double CFRegPer { get { return GetDouble(new[] { XMLNames.Engine_WHRCorrectionFactors, XMLNames.Engine_WHRCorrectionFactors_CFRegPer}, 1); } } + + public TableData GeneratedElectricPower + { + get { return WHRPower ?? (WHRPower = ReadTableData(XMLNames.Engine_FuelConsumptionMap, XMLNames.Engine_FuelConsumptionMap_Entry, AttributeMappings.WHRPowerMapMapping)); } + } + + #endregion + } } + + } diff --git a/VectoCore/VectoCore/InputData/FileIO/XML/Engineering/DataProvider/XMLEngineeringEngineDataProvider.cs b/VectoCore/VectoCore/InputData/FileIO/XML/Engineering/DataProvider/XMLEngineeringEngineDataProvider.cs index 9948d3e4f8..b99b975fdc 100644 --- a/VectoCore/VectoCore/InputData/FileIO/XML/Engineering/DataProvider/XMLEngineeringEngineDataProvider.cs +++ b/VectoCore/VectoCore/InputData/FileIO/XML/Engineering/DataProvider/XMLEngineeringEngineDataProvider.cs @@ -150,6 +150,8 @@ namespace TUGraz.VectoCore.InputData.FileIO.XML.Engineering.DataProvider get { return new[] { this }.Cast<IEngineFuelDelcarationInputData>().ToList(); } } + public virtual IWHRData WasteHeatRecoveryData { get { return null; } } + public virtual Watt RatedPowerDeclared { get { diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/AccelerationCurveReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/AccelerationCurveReader.cs index 85d47543fb..3ffb483361 100644 --- a/VectoCore/VectoCore/InputData/Reader/ComponentData/AccelerationCurveReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/AccelerationCurveReader.cs @@ -29,99 +29,99 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.InputData.Reader.ComponentData -{ - public static class AccelerationCurveReader - { - public static AccelerationCurveData ReadFromStream(Stream stream) - { - var data = VectoCSVFile.ReadStream(stream); - return Create(data); - } - - public static AccelerationCurveData ReadFromFile(string fileName) - { - try { - var data = VectoCSVFile.Read(fileName); - return Create(data); - } catch (Exception ex) { - throw new VectoException("ERROR while reading AccelerationCurve File: " + ex.Message); - } - } - - internal static AccelerationCurveData Create(DataTable data) - { - if (data.Columns.Count != 3) { - throw new VectoException("Acceleration Limiting File must consist of 3 columns."); - } - - if (data.Rows.Count < 2) { - throw new VectoException("Acceleration Limiting File must consist of at least two entries."); - } - - if (HeaderIsValid(data.Columns)) { - return CreateFromColumnNames(data); - } - LoggingObject.Logger<AccelerationCurveData>() - .Warn("Acceleration Curve: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: {3}", - Fields.Velocity, Fields.Acceleration, - Fields.Deceleration, - string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); - return CreateFromColumnIndizes(data); - } - - private static AccelerationCurveData CreateFromColumnIndizes(DataTable data) - { - return new AccelerationCurveData(data.Rows.Cast<DataRow>() - .Select(r => new KeyValuePair<MeterPerSecond, AccelerationCurveData.AccelerationEntry>( - r.ParseDouble(0).KMPHtoMeterPerSecond(), - new AccelerationCurveData.AccelerationEntry { - Acceleration = r.ParseDouble(1).SI<MeterPerSquareSecond>(), - Deceleration = r.ParseDouble(2).SI<MeterPerSquareSecond>() - })) - .OrderBy(x => x.Key) - .ToList()); - } - - private static AccelerationCurveData CreateFromColumnNames(DataTable data) - { - return new AccelerationCurveData( - data.Rows.Cast<DataRow>() - .Select(r => new KeyValuePair<MeterPerSecond, AccelerationCurveData.AccelerationEntry>( - r.ParseDouble(Fields.Velocity).KMPHtoMeterPerSecond(), - new AccelerationCurveData.AccelerationEntry { - Acceleration = r.ParseDouble(Fields.Acceleration).SI<MeterPerSquareSecond>(), - Deceleration = r.ParseDouble(Fields.Deceleration).SI<MeterPerSquareSecond>() - })) - .OrderBy(x => x.Key) - .ToList()); - } - - private static bool HeaderIsValid(DataColumnCollection columns) - { - return columns.Contains(Fields.Velocity) && - columns.Contains(Fields.Acceleration) && - columns.Contains(Fields.Deceleration); - } - - public static class Fields - { - public const string Velocity = "v"; - - public const string Acceleration = "acc"; - - public const string Deceleration = "dec"; - } - } +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData +{ + public static class AccelerationCurveReader + { + public static AccelerationCurveData ReadFromStream(Stream stream) + { + var data = VectoCSVFile.ReadStream(stream); + return Create(data); + } + + public static AccelerationCurveData ReadFromFile(string fileName) + { + try { + var data = VectoCSVFile.Read(fileName); + return Create(data); + } catch (Exception ex) { + throw new VectoException("ERROR while reading AccelerationCurve File: " + ex.Message); + } + } + + internal static AccelerationCurveData Create(DataTable data) + { + if (data.Columns.Count != 3) { + throw new VectoException("Acceleration Limiting File must consist of 3 columns."); + } + + if (data.Rows.Count < 2) { + throw new VectoException("Acceleration Limiting File must consist of at least two entries."); + } + + if (HeaderIsValid(data.Columns)) { + return CreateFromColumnNames(data); + } + LoggingObject.Logger<AccelerationCurveData>() + .Warn("Acceleration Curve: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: {3}", + Fields.Velocity, Fields.Acceleration, + Fields.Deceleration, + string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + return CreateFromColumnIndizes(data); + } + + private static AccelerationCurveData CreateFromColumnIndizes(DataTable data) + { + return new AccelerationCurveData(data.Rows.Cast<DataRow>() + .Select(r => new KeyValuePair<MeterPerSecond, AccelerationCurveData.AccelerationEntry>( + r.ParseDouble(0).KMPHtoMeterPerSecond(), + new AccelerationCurveData.AccelerationEntry { + Acceleration = r.ParseDouble(1).SI<MeterPerSquareSecond>(), + Deceleration = r.ParseDouble(2).SI<MeterPerSquareSecond>() + })) + .OrderBy(x => x.Key) + .ToList()); + } + + private static AccelerationCurveData CreateFromColumnNames(DataTable data) + { + return new AccelerationCurveData( + data.Rows.Cast<DataRow>() + .Select(r => new KeyValuePair<MeterPerSecond, AccelerationCurveData.AccelerationEntry>( + r.ParseDouble(Fields.Velocity).KMPHtoMeterPerSecond(), + new AccelerationCurveData.AccelerationEntry { + Acceleration = r.ParseDouble(Fields.Acceleration).SI<MeterPerSquareSecond>(), + Deceleration = r.ParseDouble(Fields.Deceleration).SI<MeterPerSquareSecond>() + })) + .OrderBy(x => x.Key) + .ToList()); + } + + private static bool HeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(Fields.Velocity) && + columns.Contains(Fields.Acceleration) && + columns.Contains(Fields.Deceleration); + } + + public static class Fields + { + public const string Velocity = "v"; + + public const string Acceleration = "acc"; + + public const string Deceleration = "dec"; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/AuxiliaryDataReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/AuxiliaryDataReader.cs index 979108a218..480bdbea93 100644 --- a/VectoCore/VectoCore/InputData/Reader/ComponentData/AuxiliaryDataReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/AuxiliaryDataReader.cs @@ -29,76 +29,76 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Data; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.InputData.Reader.ComponentData -{ - /// <summary> - /// Reads the auxiliary demand map. - /// </summary> - public static class AuxiliaryDataReader - { - /// <summary> - /// Factory method. - /// </summary> - /// <param name="data"></param> - /// <returns></returns> - public static AuxiliaryData Create(IAuxiliaryEngineeringInputData data) - { - var map = ReadAuxMap(data.ID, data.DemandMap); - return new AuxiliaryData(data.ID, data.TransmissionRatio, data.EfficiencyToEngine, data.EfficiencyToSupply, map); - } - - private static DelaunayMap ReadAuxMap(string id, DataTable table) - { - var map = new DelaunayMap(id); - if (HeaderIsValid(table.Columns)) { - FillFromColumnNames(table, map); - } else { - FillFromColumnIndizes(table, map); - } - - map.Triangulate(); - return map; - } - - private static void FillFromColumnIndizes(DataTable table, DelaunayMap map) - { - for (var i = 0; i < table.Rows.Count; i++) { - var row = table.Rows[i]; - map.AddPoint(row.ParseDouble(0).RPMtoRad().Value(), row.ParseDouble(2), row.ParseDouble(1)); - } - } - - private static void FillFromColumnNames(DataTable table, DelaunayMap map) - { - for (var i = 0; i < table.Rows.Count; i++) { - var row = table.Rows[i]; - map.AddPoint(row.ParseDouble(Fields.AuxSpeed).RPMtoRad().Value(), row.ParseDouble(Fields.SupplyPower), - row.ParseDouble(Fields.MechPower)); - } - } - - public static bool HeaderIsValid(DataColumnCollection columns) - { - return columns.Contains(Fields.AuxSpeed) && columns.Contains(Fields.MechPower) && - columns.Contains(Fields.SupplyPower); - } - - internal static class Fields - { - /// <summary>[1/min]</summary> - public const string AuxSpeed = "Auxiliary speed"; - - /// <summary>[kW]</summary> - public const string MechPower = "Mechanical power"; - - /// <summary>[kW]</summary> - public const string SupplyPower = "Supply power"; - } - } +using System.Data; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData +{ + /// <summary> + /// Reads the auxiliary demand map. + /// </summary> + public static class AuxiliaryDataReader + { + /// <summary> + /// Factory method. + /// </summary> + /// <param name="data"></param> + /// <returns></returns> + public static AuxiliaryData Create(IAuxiliaryEngineeringInputData data) + { + var map = ReadAuxMap(data.ID, data.DemandMap); + return new AuxiliaryData(data.ID, data.TransmissionRatio, data.EfficiencyToEngine, data.EfficiencyToSupply, map); + } + + private static DelaunayMap ReadAuxMap(string id, DataTable table) + { + var map = new DelaunayMap(id); + if (HeaderIsValid(table.Columns)) { + FillFromColumnNames(table, map); + } else { + FillFromColumnIndizes(table, map); + } + + map.Triangulate(); + return map; + } + + private static void FillFromColumnIndizes(DataTable table, DelaunayMap map) + { + for (var i = 0; i < table.Rows.Count; i++) { + var row = table.Rows[i]; + map.AddPoint(row.ParseDouble(0).RPMtoRad().Value(), row.ParseDouble(2), row.ParseDouble(1)); + } + } + + private static void FillFromColumnNames(DataTable table, DelaunayMap map) + { + for (var i = 0; i < table.Rows.Count; i++) { + var row = table.Rows[i]; + map.AddPoint(row.ParseDouble(Fields.AuxSpeed).RPMtoRad().Value(), row.ParseDouble(Fields.SupplyPower), + row.ParseDouble(Fields.MechPower)); + } + } + + public static bool HeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(Fields.AuxSpeed) && columns.Contains(Fields.MechPower) && + columns.Contains(Fields.SupplyPower); + } + + internal static class Fields + { + /// <summary>[1/min]</summary> + public const string AuxSpeed = "Auxiliary speed"; + + /// <summary>[kW]</summary> + public const string MechPower = "Mechanical power"; + + /// <summary>[kW]</summary> + public const string SupplyPower = "Supply power"; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/CrossWindCorrectionCurveReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/CrossWindCorrectionCurveReader.cs index 3a8932e76c..3766144203 100644 --- a/VectoCore/VectoCore/InputData/Reader/ComponentData/CrossWindCorrectionCurveReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/CrossWindCorrectionCurveReader.cs @@ -29,156 +29,156 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.IO; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.InputData.Reader.ComponentData -{ - public static class CrossWindCorrectionCurveReader - { - public static List<CrossWindCorrectionEntry> GetNoCorrectionCurve(SquareMeter aerodynamicDragArea) - { - return new[] { - new CrossWindCorrectionEntry { - Velocity = 0.KMPHtoMeterPerSecond(), - EffectiveCrossSectionArea = aerodynamicDragArea - }, - new CrossWindCorrectionEntry { - Velocity = 300.KMPHtoMeterPerSecond(), - EffectiveCrossSectionArea = aerodynamicDragArea - } - }.ToList(); - } - - public static List<CrossWindCorrectionEntry> ReadSpeedDependentCorrectionCurveFromStream(Stream inputData, - SquareMeter aerodynamicDragArea) - { - var data = VectoCSVFile.ReadStream(inputData); - return ParseSpeedDependent(data, aerodynamicDragArea); - } - - public static List<CrossWindCorrectionEntry> ReadSpeedDependentCorrectionCurve(DataTable data, - SquareMeter aerodynamicDragArea) - { - return ParseSpeedDependent(data, aerodynamicDragArea); - } - - public static List<AirDragBetaEntry> ReadCdxABetaTable(DataTable betaTable) - { - if (betaTable.Columns.Count != 2) { - throw new VectoException("VAir/Beta Crosswind Correction must consist of 2 columns"); - } - if (betaTable.Rows.Count < 2) { - throw new VectoException("VAir/Beta Crosswind Correction must consist of at least 2 rows"); - } - if (HeaderIsValid(betaTable.Columns)) { - return ParseCdxABetaFromColumnNames(betaTable); - } - LogManager.GetLogger(typeof(CrossWindCorrectionCurveReader).FullName) - .Warn("VAir/Beta Crosswind Correction header Line is not valid"); - return ParseCdxABetaFromColumnIndices(betaTable); - } - - private static List<CrossWindCorrectionEntry> ParseSpeedDependent(DataTable data, SquareMeter aerodynamicDragArea) - { - if (data.Columns.Count != 2) { - throw new VectoException("Crosswind correction file must consist of 2 columns."); - } - if (data.Rows.Count < 2) { - throw new VectoException("Crosswind correction file must consist of at least 2 rows"); - } - - if (SpeedDependentHeaderIsValid(data.Columns)) { - return ParseSpeedDependentFromColumnNames(data, aerodynamicDragArea); - } - LogManager.GetLogger(typeof(CrossWindCorrectionCurveReader).FullName).Warn( - "Crosswind correction file: Header line is not valid. Expected: '{0}, {1}', Got: '{2}'. Falling back to column index.", - FieldsSpeedDependent.Velocity, FieldsSpeedDependent.Cd, - string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName).Reverse())); - return ParseSpeedDependentFromColumnIndizes(data, aerodynamicDragArea); - } - - private static List<CrossWindCorrectionEntry> ParseSpeedDependentFromColumnIndizes(DataTable data, - SquareMeter aerodynamicDragArea) - { - return (from DataRow row in data.Rows - select new CrossWindCorrectionEntry { - Velocity = row.ParseDouble(0).KMPHtoMeterPerSecond(), - EffectiveCrossSectionArea = row.ParseDouble(1) * aerodynamicDragArea - }).ToList(); - } - - private static List<CrossWindCorrectionEntry> ParseSpeedDependentFromColumnNames(DataTable data, - SquareMeter aerodynamicDragArea) - { - return (from DataRow row in data.Rows - select new CrossWindCorrectionEntry { - Velocity = row.ParseDouble(FieldsSpeedDependent.Velocity).KMPHtoMeterPerSecond(), - EffectiveCrossSectionArea = row.ParseDouble(FieldsSpeedDependent.Cd) * aerodynamicDragArea - }).ToList(); - } - - private static bool SpeedDependentHeaderIsValid(DataColumnCollection columns) - { - return columns.Contains(FieldsSpeedDependent.Velocity) && columns.Contains(FieldsSpeedDependent.Cd); - } - - private static List<AirDragBetaEntry> ParseCdxABetaFromColumnIndices(DataTable betaTable) - { - return (from DataRow row in betaTable.Rows - select - new AirDragBetaEntry { - Beta = row.ParseDouble(0), - DeltaCdA = row.ParseDouble(1).SI<SquareMeter>() - }).ToList(); - } - - private static List<AirDragBetaEntry> ParseCdxABetaFromColumnNames(DataTable betaTable) - { - return (from DataRow row in betaTable.Rows - select - new AirDragBetaEntry { - Beta = row.ParseDouble(FieldsCdxABeta.Beta), - DeltaCdA = row.ParseDouble(FieldsCdxABeta.DeltaCdxA).SI<SquareMeter>() - }).ToList(); - } - - private static bool HeaderIsValid(DataColumnCollection columns) - { - return columns.Contains(FieldsCdxABeta.Beta) && columns.Contains(FieldsCdxABeta.DeltaCdxA); - } - - public static class FieldsCdxABeta - { - public const string Beta = "beta"; - public const string DeltaCdxA = "delta CdA"; - } - - public static class FieldsSpeedDependent - { - public const string Velocity = "v_veh"; - public const string Cd = "Cd"; - } - - [DebuggerDisplay("beta: {Beta}, deltaCdxA: {DeltaCdA}")] - public class AirDragBetaEntry - { - public double Beta; - public SquareMeter DeltaCdA; - } - - [DebuggerDisplay("v: {Velocity}, CdxA: {EffectiveCrossSectionArea}")] - public class CrossWindCorrectionEntry - { - public SquareMeter EffectiveCrossSectionArea; - public MeterPerSecond Velocity; - } - } +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.IO; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData +{ + public static class CrossWindCorrectionCurveReader + { + public static List<CrossWindCorrectionEntry> GetNoCorrectionCurve(SquareMeter aerodynamicDragArea) + { + return new[] { + new CrossWindCorrectionEntry { + Velocity = 0.KMPHtoMeterPerSecond(), + EffectiveCrossSectionArea = aerodynamicDragArea + }, + new CrossWindCorrectionEntry { + Velocity = 300.KMPHtoMeterPerSecond(), + EffectiveCrossSectionArea = aerodynamicDragArea + } + }.ToList(); + } + + public static List<CrossWindCorrectionEntry> ReadSpeedDependentCorrectionCurveFromStream(Stream inputData, + SquareMeter aerodynamicDragArea) + { + var data = VectoCSVFile.ReadStream(inputData); + return ParseSpeedDependent(data, aerodynamicDragArea); + } + + public static List<CrossWindCorrectionEntry> ReadSpeedDependentCorrectionCurve(DataTable data, + SquareMeter aerodynamicDragArea) + { + return ParseSpeedDependent(data, aerodynamicDragArea); + } + + public static List<AirDragBetaEntry> ReadCdxABetaTable(DataTable betaTable) + { + if (betaTable.Columns.Count != 2) { + throw new VectoException("VAir/Beta Crosswind Correction must consist of 2 columns"); + } + if (betaTable.Rows.Count < 2) { + throw new VectoException("VAir/Beta Crosswind Correction must consist of at least 2 rows"); + } + if (HeaderIsValid(betaTable.Columns)) { + return ParseCdxABetaFromColumnNames(betaTable); + } + LogManager.GetLogger(typeof(CrossWindCorrectionCurveReader).FullName) + .Warn("VAir/Beta Crosswind Correction header Line is not valid"); + return ParseCdxABetaFromColumnIndices(betaTable); + } + + private static List<CrossWindCorrectionEntry> ParseSpeedDependent(DataTable data, SquareMeter aerodynamicDragArea) + { + if (data.Columns.Count != 2) { + throw new VectoException("Crosswind correction file must consist of 2 columns."); + } + if (data.Rows.Count < 2) { + throw new VectoException("Crosswind correction file must consist of at least 2 rows"); + } + + if (SpeedDependentHeaderIsValid(data.Columns)) { + return ParseSpeedDependentFromColumnNames(data, aerodynamicDragArea); + } + LogManager.GetLogger(typeof(CrossWindCorrectionCurveReader).FullName).Warn( + "Crosswind correction file: Header line is not valid. Expected: '{0}, {1}', Got: '{2}'. Falling back to column index.", + FieldsSpeedDependent.Velocity, FieldsSpeedDependent.Cd, + string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName).Reverse())); + return ParseSpeedDependentFromColumnIndizes(data, aerodynamicDragArea); + } + + private static List<CrossWindCorrectionEntry> ParseSpeedDependentFromColumnIndizes(DataTable data, + SquareMeter aerodynamicDragArea) + { + return (from DataRow row in data.Rows + select new CrossWindCorrectionEntry { + Velocity = row.ParseDouble(0).KMPHtoMeterPerSecond(), + EffectiveCrossSectionArea = row.ParseDouble(1) * aerodynamicDragArea + }).ToList(); + } + + private static List<CrossWindCorrectionEntry> ParseSpeedDependentFromColumnNames(DataTable data, + SquareMeter aerodynamicDragArea) + { + return (from DataRow row in data.Rows + select new CrossWindCorrectionEntry { + Velocity = row.ParseDouble(FieldsSpeedDependent.Velocity).KMPHtoMeterPerSecond(), + EffectiveCrossSectionArea = row.ParseDouble(FieldsSpeedDependent.Cd) * aerodynamicDragArea + }).ToList(); + } + + private static bool SpeedDependentHeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(FieldsSpeedDependent.Velocity) && columns.Contains(FieldsSpeedDependent.Cd); + } + + private static List<AirDragBetaEntry> ParseCdxABetaFromColumnIndices(DataTable betaTable) + { + return (from DataRow row in betaTable.Rows + select + new AirDragBetaEntry { + Beta = row.ParseDouble(0), + DeltaCdA = row.ParseDouble(1).SI<SquareMeter>() + }).ToList(); + } + + private static List<AirDragBetaEntry> ParseCdxABetaFromColumnNames(DataTable betaTable) + { + return (from DataRow row in betaTable.Rows + select + new AirDragBetaEntry { + Beta = row.ParseDouble(FieldsCdxABeta.Beta), + DeltaCdA = row.ParseDouble(FieldsCdxABeta.DeltaCdxA).SI<SquareMeter>() + }).ToList(); + } + + private static bool HeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(FieldsCdxABeta.Beta) && columns.Contains(FieldsCdxABeta.DeltaCdxA); + } + + public static class FieldsCdxABeta + { + public const string Beta = "beta"; + public const string DeltaCdxA = "delta CdA"; + } + + public static class FieldsSpeedDependent + { + public const string Velocity = "v_veh"; + public const string Cd = "Cd"; + } + + [DebuggerDisplay("beta: {Beta}, deltaCdxA: {DeltaCdA}")] + public class AirDragBetaEntry + { + public double Beta; + public SquareMeter DeltaCdA; + } + + [DebuggerDisplay("v: {Velocity}, CdxA: {EffectiveCrossSectionArea}")] + public class CrossWindCorrectionEntry + { + public SquareMeter EffectiveCrossSectionArea; + public MeterPerSecond Velocity; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/DrivingCycleDataReader.cs similarity index 97% rename from VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs rename to VectoCore/VectoCore/InputData/Reader/ComponentData/DrivingCycleDataReader.cs index d76d3222b8..a67b9bd23d 100644 --- a/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/DrivingCycleDataReader.cs @@ -1,799 +1,799 @@ -/* -* This file is part of VECTO. -* -* Copyright © 2012-2019 European Union -* -* Developed by Graz University of Technology, -* Institute of Internal Combustion Engines and Thermodynamics, -* Institute of Technical Informatics -* -* VECTO is licensed under the EUPL, Version 1.1 or - as soon they will be approved -* by the European Commission - subsequent versions of the EUPL (the "Licence"); -* You may not use VECTO except in compliance with the Licence. -* You may obtain a copy of the Licence at: -* -* https://joinup.ec.europa.eu/community/eupl/og_page/eupl -* -* Unless required by applicable law or agreed to in writing, VECTO -* distributed under the Licence is distributed on an "AS IS" basis, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the Licence for the specific language governing permissions and -* limitations under the Licence. -* -* Authors: -* Stefan Hausberger, hausberger@ivt.tugraz.at, IVT, Graz University of Technology -* Christian Kreiner, christian.kreiner@tugraz.at, ITI, Graz University of Technology -* Michael Krisper, michael.krisper@tugraz.at, ITI, Graz University of Technology -* Raphael Luz, luz@ivt.tugraz.at, IVT, Graz University of Technology -* Markus Quaritsch, markus.quaritsch@tugraz.at, IVT, Graz University of Technology -* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology -*/ - -using System; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.InputData.Reader -{ - public static class DrivingCycleDataReader - { - /// <summary> - /// Detects the appropriate cycle type for a cycle in a DataTable. - /// </summary> - /// <param name="cycleData">The cycle data.</param> - /// <returns></returns> - /// <exception cref="VectoException">CycleFile Format is unknown.</exception> - public static CycleType DetectCycleType(DataTable cycleData) - { - var cols = cycleData.Columns; - - if (PTOCycleDataParser.ValidateHeader(cols, false)) { - return CycleType.PTO; - } - - if (PWheelCycleDataParser.ValidateHeader(cols, false)) { - return CycleType.PWheel; - } - if (MeasuredSpeedGearDataParser.ValidateHeader(cols, false)) { - return CycleType.MeasuredSpeedGear; - } - if (MeasuredSpeedDataParser.ValidateHeader(cols, false)) { - return CycleType.MeasuredSpeed; - } - if (EngineOnlyCycleDataParser.ValidateHeader(cols, false)) { - return CycleType.EngineOnly; - } - if (DistanceBasedCycleDataParser.ValidateHeader(cols, false)) { - return CycleType.DistanceBased; - } - if (VTPCycleDataParser.ValidateHeader(cols, false)) { - return CycleType.VTP; - } - throw new VectoException("CycleFile format is unknown."); - } - - private static ICycleDataParser GetDataParser(CycleType type) - { - switch (type) { - case CycleType.EngineOnly: - return new EngineOnlyCycleDataParser(); - case CycleType.DistanceBased: - return new DistanceBasedCycleDataParser(); - case CycleType.PWheel: - return new PWheelCycleDataParser(); - case CycleType.MeasuredSpeedGear: - return new MeasuredSpeedGearDataParser(); - case CycleType.MeasuredSpeed: - return new MeasuredSpeedDataParser(); - case CycleType.PTO: - return new PTOCycleDataParser(); - case CycleType.VTP: - return new VTPCycleDataParser(); - - default: - throw new ArgumentOutOfRangeException("Cycle Type", type.ToString()); - } - } - - /// <summary> - /// Reads a cycle from a file. - /// </summary> - /// <param name="fileName">Name of the file.</param> - /// <param name="type">The type.</param> - /// <param name="crossWindRequired"></param> - /// <returns></returns> - /// <exception cref="VectoException">ERROR while reading DrivingCycle File: + ex.Message</exception> - public static DrivingCycleData ReadFromFile(string fileName, CycleType type, bool crossWindRequired) - { - try { - var stream = File.OpenRead(fileName); - return ReadFromStream(stream, type, Path.GetFileNameWithoutExtension(fileName), crossWindRequired); - } catch (Exception ex) { - throw new VectoException("ERROR while opening DrivingCycle File: " + ex.Message, ex); - } - } - - /// <summary> - /// Reads the cycle from a stream. - /// </summary> - /// <param name="stream">The stream.</param> - /// <param name="type">The type.</param> - /// <param name="crossWindRequired"></param> - /// <param name="name">the name of the cycle</param> - /// <returns></returns> - public static DrivingCycleData ReadFromStream(Stream stream, CycleType type, string name, bool crossWindRequired) - { - try { - return ReadFromDataTable(VectoCSVFile.ReadStream(stream), type, name, crossWindRequired); - } catch (Exception ex) { - throw new VectoException("ERROR while reading DrivingCycle Stream: " + ex.Message, ex); - } - } - - /// <summary> - /// Creates a cycle from a DataTable with automatic determination of Cycle Type. - /// </summary> - /// <param name="data">The cycle data.</param> - /// <param name="name">The name.</param> - /// <param name="crossWindRequired"></param> - /// <returns></returns> - public static DrivingCycleData ReadFromDataTable(DataTable data, string name, bool crossWindRequired) - { - if (data == null) { - LogManager.GetLogger(typeof(DrivingCycleDataReader).FullName) - .Warn("Invalid data for DrivingCycle -- dataTable is null"); - throw new VectoException("Invalid data for DrivingCycle -- dataTable is null"); - } - return ReadFromDataTable(data, DetectCycleType(data), name, crossWindRequired); - } - - /// <summary> - /// Creates a cycle from a DataTable - /// </summary> - /// <param name="data">The cycle data.</param> - /// <param name="type">The type.</param> - /// <param name="name">The name.</param> - /// <param name="crossWindRequired"></param> - /// <returns></returns> - private static DrivingCycleData ReadFromDataTable(DataTable data, CycleType type, string name, bool crossWindRequired) - { - if (data == null) { - LogManager.GetLogger(typeof(DrivingCycleDataReader).FullName) - .Warn("Invalid data for DrivingCycle -- dataTable is null"); - throw new VectoException("Invalid data for DrivingCycle -- dataTable is null"); - } - var entries = GetDataParser(type).Parse(data, crossWindRequired).ToList(); - - if (type == CycleType.DistanceBased) { - entries = FilterDrivingCycleEntries(entries); - } - if (type == CycleType.MeasuredSpeed || type == CycleType.MeasuredSpeedGear) { - entries = ComputeAltitudeTimeBased(entries); - } - var cycle = new DrivingCycleData { - Entries = entries, - CycleType = type, - Name = name - }; - return cycle; - } - - private static List<DrivingCycleData.DrivingCycleEntry> ComputeAltitudeTimeBased( - List<DrivingCycleData.DrivingCycleEntry> entries) - { - var current = entries.First(); - current.Altitude = 0.SI<Meter>(); - var altitude = current.Altitude; - var lastTime = entries.First().Time; - foreach (var drivingCycleEntry in entries) { - altitude += drivingCycleEntry.VehicleTargetSpeed * (drivingCycleEntry.Time - lastTime) * - drivingCycleEntry.RoadGradient; - drivingCycleEntry.Altitude = altitude; - lastTime = drivingCycleEntry.Time; - } - return entries; - } - - private static List<DrivingCycleData.DrivingCycleEntry> FilterDrivingCycleEntries( - List<DrivingCycleData.DrivingCycleEntry> entries) - { - var filtered = new List<DrivingCycleData.DrivingCycleEntry>(); - var current = entries.First(); - current.Altitude = 0.SI<Meter>(); - filtered.Add(current); - var distance = current.Distance; - var altitude = current.Altitude; - for (var i = 0; i < entries.Count; i++) { - var entry = entries[i]; - if (i == 0 && entry.VehicleTargetSpeed.IsEqual(0) && entry.StoppingTime.IsEqual(0)) { - entry.StoppingTime = 1.SI<Second>(); - } - if (!entry.StoppingTime.IsEqual(0) && !entry.VehicleTargetSpeed.IsEqual(0)) { - throw new VectoException( - "Error in DrivingCycle: stop time specified but target-speed > 0! Distance: {0}, stop-time: {1}, target speed: {2}", - entry.Distance, entry.StoppingTime, entry.VehicleTargetSpeed); - } - if (entry.Distance < distance) { - throw new VectoException( - "Error in DrivingCycle: distance entry is smaller than last distance! last distance: {0}, current distance: {1} ", - distance, entry.Distance); - } - if (i > 0) { - altitude += (entry.Distance - distance) * entries[i - 1].RoadGradientPercent / 100.0; - } - entry.Altitude = altitude; - // if something changes in the cycle, add it to the filtered cycle but always add last entry - if (!CycleEntriesAreEqual(current, entry) || i == entries.Count - 1) { - entry.Altitude = altitude; - filtered.Add(entry); - current = entry; - } - if (entry.VehicleTargetSpeed.IsEqual(0)) { - // vehicle stops. duplicate current distance entry with 0 waiting time - var tmp = new DrivingCycleData.DrivingCycleEntry(entry) { - StoppingTime = 0.SI<Second>(), - PTOActive = false, - RoadGradient = entry.RoadGradient, - VehicleTargetSpeed = i < entries.Count - 1 ? entries[i + 1].VehicleTargetSpeed : 0.SI<MeterPerSecond>() - }; - filtered.Add(tmp); - current = tmp; - } - - distance = entry.Distance; - } - LogManager.GetLogger(typeof(DrivingCycleDataReader).FullName) - .Info("Data loaded. Number of Entries: {0}, filtered Entries: {1}", entries.Count, filtered.Count); - entries = filtered; - - AdjustDistanceAfterStop(entries); - - return entries; - } - - private static void AdjustDistanceAfterStop(List<DrivingCycleData.DrivingCycleEntry> entries) - { - using (var currentIt = entries.GetEnumerator()) { - using (var nextIt = entries.GetEnumerator()) { - nextIt.MoveNext(); - while (currentIt.MoveNext() && nextIt.MoveNext()) { - if (currentIt.Current != null && !currentIt.Current.StoppingTime.IsEqual(0)) { - if (nextIt.Current != null) { - nextIt.Current.Distance = currentIt.Current.Distance; - } - } - } - } - } - } - - private static bool CycleEntriesAreEqual(DrivingCycleData.DrivingCycleEntry first, - DrivingCycleData.DrivingCycleEntry second) - { - if (first.Distance.IsEqual(second.Distance)) { - return true; - } - - if (first.VehicleTargetSpeed != second.VehicleTargetSpeed) { - return false; - } - - if (!first.RoadGradient.IsEqual(second.RoadGradient, Constants.SimulationSettings.DrivingCycleRoadGradientTolerance)) { - return false; - } - - if (!(first.StoppingTime.IsEqual(0) && second.StoppingTime.IsEqual(0))) { - return false; - } - - if (first.AdditionalAuxPowerDemand != second.AdditionalAuxPowerDemand) { - return false; - } - - if (first.AuxiliarySupplyPower.Count != second.AuxiliarySupplyPower.Count) { - return false; - } - - if (!first.AuxiliarySupplyPower.SequenceEqual(second.AuxiliarySupplyPower)) { - return false; - } - - if (first.AirSpeedRelativeToVehicle != null && second.AirSpeedRelativeToVehicle != null && - !first.AirSpeedRelativeToVehicle.IsEqual(second.AirSpeedRelativeToVehicle)) { - return false; - } - - if (!first.WindYawAngle.IsEqual(second.WindYawAngle)) { - return false; - } - - return true; - } - - public static class Fields - { - public const string PTOTorque = "PTO Torque"; - public const string EngineSpeedFull = "Engine speed"; - public const string PWheel = "Pwheel"; - public const string Distance = "s"; - public const string Time = "t"; - public const string VehicleSpeed = "v"; - public const string RoadGradient = "grad"; - public const string StoppingTime = "stop"; - public const string EngineSpeed = "n"; - public const string EngineSpeedSuffix = "n_eng"; - public const string FanSpeed = "n_fan"; - public const string WheelTorqueLeft = "tq_left"; - public const string WheelTorqueRight = "tq_right"; - public const string WheelSpeedLeft = "n_wh_left"; - public const string WheelSpeedRight = "n_wh_right"; - public const string FuelConsumption = "fc"; - public const string Gear = "gear"; - public const string AdditionalAuxPowerDemand = "Padd"; - public const string AirSpeedRelativeToVehicle = "vair_res"; - public const string WindYawAngle = "vair_beta"; - public const string EnginePower = "Pe"; - public const string EngineTorque = "Me"; - public const string TorqueConverterActive = "tc_active"; - public const string PTOActive = "PTO"; - } - - #region DataParser - - private interface ICycleDataParser - { - /// <summary> - /// Parses a datatable to a list of drivingcycleentries for the current implementation. - /// </summary> - /// <param name="table"></param> - /// <param name="crossWindRequired"></param> - /// <returns></returns> - IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired); - } - - private abstract class AbstractCycleDataParser : LoggingObject, ICycleDataParser - { - protected static bool CheckColumns(DataColumnCollection header, IEnumerable<string> allowedCols, - IEnumerable<string> requiredCols, bool throwExceptions, bool allowAux) - { - var headerStr = header.Cast<DataColumn>().Select(col => col.ColumnName.ToLowerInvariant()).ToArray(); - - var diff = headerStr.GroupBy(c => c).Where(g => g.Count() > 2).SelectMany(g => g).ToList(); - if (diff.Any()) { - if (throwExceptions) { - throw new VectoException("Column(s) defined more than once: " + string.Join(", ", diff.OrderBy(x => x))); - } - return false; - } - - if (allowAux) { - headerStr = headerStr.Where(c => !c.ToUpper().StartsWith(Constants.Auxiliaries.Prefix)).ToArray(); - } - - diff = headerStr.Except(allowedCols.Select(x => x.ToLowerInvariant())).ToList(); - if (diff.Any()) { - if (throwExceptions) { - throw new VectoException("Column(s) not allowed: " + string.Join(", ", diff)); - } - return false; - } - - diff = requiredCols.Select(x => x.ToLowerInvariant()).Except(headerStr).ToList(); - if (diff.Any()) { - if (throwExceptions) { - throw new VectoException("Column(s) required: " + string.Join(", ", diff)); - } - return false; - } - return true; - } - - protected static bool CheckComboColumns(DataColumnCollection header, string[] cols, bool throwExceptions) - { - var colCount = header.Cast<DataColumn>() - .Select(col => col.ColumnName.ToLowerInvariant()) - .Intersect(cols.Select(x => x.ToLowerInvariant())).Count(); - - if (colCount != 0 && colCount != cols.Length) { - if (throwExceptions) { - throw new VectoException("Either all columns have to be defined or none of them: {0}", string.Join(", ", cols)); - } - return false; - } - - return true; - } - - public abstract IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired); - } - - private class DistanceBasedCycleDataParser : AbstractCycleDataParser - { - public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) - { - ValidateHeader(table.Columns); - - return table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { - Distance = row.ParseDouble(Fields.Distance).SI<Meter>(), - VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(), - RoadGradient = VectoMath.InclinationToAngle(row.ParseDoubleOrGetDefault(Fields.RoadGradient) / 100.0), - StoppingTime = row.ParseDouble(Fields.StoppingTime).SI<Second>(), - AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), - AngularVelocity = row.ParseDoubleOrGetDefault(Fields.EngineSpeed).RPMtoRad(), - Gear = (uint)row.ParseDoubleOrGetDefault(Fields.Gear), - AirSpeedRelativeToVehicle = - crossWindRequired ? row.ParseDouble(Fields.AirSpeedRelativeToVehicle).KMPHtoMeterPerSecond() : null, - WindYawAngle = crossWindRequired ? row.ParseDoubleOrGetDefault(Fields.WindYawAngle) : 0, - AuxiliarySupplyPower = row.GetAuxiliaries(), - PTOActive = table.Columns.Contains(Fields.PTOActive) && row.Field<string>(Fields.PTOActive) == "1" - }); - } - - public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) - { - var requiredCols = new[] { - Fields.Distance, - Fields.VehicleSpeed, - Fields.StoppingTime - }; - - var allowedCols = new[] { - Fields.Distance, - Fields.VehicleSpeed, - Fields.StoppingTime, - Fields.AdditionalAuxPowerDemand, - Fields.RoadGradient, - Fields.AirSpeedRelativeToVehicle, - Fields.WindYawAngle, - Fields.PTOActive - }; - - const bool allowAux = true; - - return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux) && - CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions); - } - } - - /// <summary> - /// Parser for EngineOnly Cycles. - /// </summary> - // <t>, <n>, (<Pe>|<Me>)[, <Padd>] - private class EngineOnlyCycleDataParser : AbstractCycleDataParser - { - public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) - { - ValidateHeader(table.Columns); - - var absTime = 0; - foreach (DataRow row in table.Rows) { - var entry = new DrivingCycleData.DrivingCycleEntry { - Time = row.ParseDoubleOrGetDefault(Fields.Time, absTime).SI<Second>(), - AngularVelocity = row.ParseDoubleOrGetDefault(Fields.EngineSpeed).RPMtoRad(), - AdditionalAuxPowerDemand = - row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), - AuxiliarySupplyPower = row.GetAuxiliaries() - }; - - if (row.Table.Columns.Contains(Fields.EngineTorque)) { - if (row.Field<string>(Fields.EngineTorque).Equals("<DRAG>")) { - entry.Drag = true; - } else { - entry.Torque = row.ParseDouble(Fields.EngineTorque).SI<NewtonMeter>(); - } - } else { - if (row.Field<string>(Fields.EnginePower).Equals("<DRAG>")) { - entry.Drag = true; - } else { - entry.Torque = row.ParseDouble(Fields.EnginePower).SI(Unit.SI.Kilo.Watt).Cast<Watt>() / entry.AngularVelocity; - } - } - absTime += 1; - - yield return entry; - } - } - - public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) - { - var requiredCols = new[] { - //Fields.Time not needed --> if missing 1 second resolution is assumed - Fields.EngineSpeed - }; - - var allowedCols = new[] { - Fields.Time, - Fields.EngineSpeed, - Fields.EngineTorque, - Fields.EnginePower, - Fields.AdditionalAuxPowerDemand - }; - - const bool allowAux = false; - - if (!CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux)) { - return false; - } - - var containsNone = !header.Contains(Fields.EngineTorque) && !header.Contains(Fields.EnginePower); - if (containsNone) { - if (throwExceptions) { - throw new VectoException("Column(s) missing: Either column '{0}' or column '{1}' must be defined.", - Fields.EngineTorque, Fields.EnginePower); - } - return false; - } - - var containsBoth = header.Contains(Fields.EngineTorque) && header.Contains(Fields.EnginePower); - if (containsBoth) { - LogManager.GetLogger(typeof(EngineOnlyCycleDataParser).FullName) - .Warn("Found column '{0}' and column '{1}': Only column '{0}' will be used.", - Fields.EngineTorque, Fields.EnginePower); - } - return true; - } - } - - /// <summary> - /// Parser for PWheel (SiCo) Mode. - /// </summary> - // <t>, <Pwheel>, <Gear>, <n>, <Padd> - private class PWheelCycleDataParser : AbstractCycleDataParser - { - public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) - { - ValidateHeader(table.Columns); - - var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { - Time = row.ParseDouble(Fields.Time).SI<Second>(), - PWheel = row.ParseDouble(Fields.PWheel).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), - Gear = (uint)row.ParseDouble(Fields.Gear), - AngularVelocity = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), - AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), - }).ToArray(); - - return entries; - } - - public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) - { - var requiredCols = new[] { - Fields.Time, - Fields.PWheel, - Fields.Gear, - Fields.EngineSpeed - }; - var allowedCols = new[] { - Fields.Time, - Fields.PWheel, - Fields.Gear, - Fields.EngineSpeed, - Fields.AdditionalAuxPowerDemand - }; - - return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux: false); - } - } - - /// <summary> - /// Parser for Measured Speed Mode Option 1. - /// </summary> - // <t>, <v>[, <grad>, <Padd>, <vair_res>, <vair_beta>, Aux_...] - private class MeasuredSpeedDataParser : AbstractCycleDataParser - { - public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) - { - ValidateHeader(table.Columns); - - var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { - Time = row.ParseDouble(Fields.Time).SI<Second>(), - VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(), - RoadGradient = VectoMath.InclinationToAngle(row.ParseDoubleOrGetDefault(Fields.RoadGradient) / 100.0), - AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), - AirSpeedRelativeToVehicle = - crossWindRequired ? row.ParseDouble(Fields.AirSpeedRelativeToVehicle).KMPHtoMeterPerSecond() : null, - WindYawAngle = crossWindRequired ? row.ParseDouble(Fields.WindYawAngle) : 0, - AuxiliarySupplyPower = row.GetAuxiliaries() - }).ToArray(); - - return entries; - } - - public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) - { - var requiredCols = new[] { - Fields.Time, - Fields.VehicleSpeed - }; - - var allowedCols = new[] { - Fields.Time, - Fields.VehicleSpeed, - Fields.AdditionalAuxPowerDemand, - Fields.RoadGradient, - Fields.AirSpeedRelativeToVehicle, - Fields.WindYawAngle - }; - - const bool allowAux = true; - - return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux) && - CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions); - } - } - - /// <summary> - /// Parser for Measured Speed Mode Option 2. - /// </summary> - // <t>, <v>, <n>, <gear>[, <tc_active>, <grad>, <Padd>, <vair_res>, <vair_beta>, Aux_...] - private class MeasuredSpeedGearDataParser : AbstractCycleDataParser - { - public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) - { - ValidateHeader(table.Columns); - - var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { - Time = row.ParseDouble(Fields.Time).SI<Second>(), - VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(), - RoadGradient = VectoMath.InclinationToAngle(row.ParseDoubleOrGetDefault(Fields.RoadGradient) / 100.0), - AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), - AngularVelocity = row.ParseDoubleOrGetDefault(Fields.EngineSpeed).RPMtoRad(), - Gear = (uint)row.ParseDouble(Fields.Gear), - TorqueConverterActive = table.Columns.Contains(Fields.TorqueConverterActive) - ? row.ParseBoolean(Fields.TorqueConverterActive) - : (bool?)null, - AirSpeedRelativeToVehicle = crossWindRequired - ? row.ParseDouble(Fields.AirSpeedRelativeToVehicle).KMPHtoMeterPerSecond() - : null, - WindYawAngle = crossWindRequired ? row.ParseDoubleOrGetDefault(Fields.WindYawAngle) : 0, - AuxiliarySupplyPower = row.GetAuxiliaries() - }).ToArray(); - - return entries; - } - - public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) - { - var requiredCols = new[] { - Fields.Time, - Fields.VehicleSpeed, - Fields.Gear - }; - var allowedCols = new[] { - Fields.Time, - Fields.VehicleSpeed, - Fields.EngineSpeed, - Fields.Gear, - Fields.TorqueConverterActive, - Fields.AdditionalAuxPowerDemand, - Fields.RoadGradient, - Fields.AirSpeedRelativeToVehicle, - Fields.WindYawAngle - }; - - const bool allowAux = true; - - return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux) && - CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions); - } - } - - /// <summary> - /// Parser for PTO Cycles. - /// </summary> - // <t> [s], <Engine Speed> [rpm], <PTO Torque> [Nm] - private class PTOCycleDataParser : AbstractCycleDataParser - { - public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) - { - ValidateHeader(table.Columns); - - var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { - Time = row.ParseDouble(Fields.Time).SI<Second>(), - AngularVelocity = row.ParseDouble(Fields.EngineSpeedFull).RPMtoRad(), - Torque = row.ParseDouble(Fields.PTOTorque).SI<NewtonMeter>() - }).ToArray(); - - return entries; - } - - public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) - { - var requiredCols = new[] { - Fields.Time, - Fields.EngineSpeedFull, - Fields.PTOTorque - }; - var allowedCols = new[] { - Fields.Time, - Fields.EngineSpeedFull, - Fields.PTOTorque - }; - - const bool allowAux = false; - - return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux); - } - } - - /// <summary> - /// Parser for PTO Cycles. - /// </summary> - // <t>,<v> [km/h],<Pwheel> [kW],<n_eng> [rpm],<n_fan> [rpm], <Padd> [kW] - private class VTPCycleDataParser : AbstractCycleDataParser - { - public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) - { - ValidateHeader(table.Columns); - - var entries = table.Rows.Cast<DataRow>().Select(row => { - var tqLeft = row.ParseDouble(Fields.WheelTorqueLeft).SI<NewtonMeter>(); - var tqRight = row.ParseDouble(Fields.WheelTorqueRight).SI<NewtonMeter>(); - var speedLeft = row.ParseDouble(Fields.WheelSpeedLeft).RPMtoRad(); - var speedRight = row.ParseDouble(Fields.WheelSpeedRight).RPMtoRad(); - return new DrivingCycleData.DrivingCycleEntry { - Time = row.ParseDouble(Fields.Time).SI<Second>(), - VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(), - AdditionalAuxPowerDemand = - row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), - EngineSpeed = row.ParseDouble(Fields.EngineSpeedSuffix).RPMtoRad(), - FanSpeed = row.ParseDouble(Fields.FanSpeed).RPMtoRad(), - Gear = (uint)row.ParseDoubleOrGetDefault(Fields.Gear), - Fuelconsumption = row.ParseDoubleOrGetDefault(Fields.FuelConsumption).SI(Unit.SI.Gramm.Per.Hour).Cast<KilogramPerSecond>(), - TorqueConverterActive = row.ParseBooleanOrGetDefault(Fields.TorqueConverterActive), - TorqueWheelLeft = tqLeft, - TorqueWheelRight = tqRight, - WheelSpeedLeft = speedLeft, - WheelSpeedRight = speedRight - }; - }).ToArray(); - - return entries; - } - - public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) - { - var requiredCols = new[] { - Fields.Time, - Fields.VehicleSpeed, - Fields.EngineSpeedSuffix, - Fields.FanSpeed, - Fields.WheelSpeedLeft, - Fields.WheelSpeedRight, - Fields.WheelTorqueLeft, - Fields.WheelTorqueRight, - }; - - var allowedCols = new[] { - Fields.Time, - Fields.VehicleSpeed, - Fields.EngineSpeedSuffix, - Fields.FanSpeed, - Fields.WheelSpeedLeft, - Fields.WheelSpeedRight, - Fields.WheelTorqueLeft, - Fields.WheelTorqueRight, - Fields.Gear, - Fields.TorqueConverterActive, - Fields.FuelConsumption - }; - - const bool allowAux = true; - - return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux) && - CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions); - } - } - - } - - #endregion +/* +* This file is part of VECTO. +* +* Copyright © 2012-2019 European Union +* +* Developed by Graz University of Technology, +* Institute of Internal Combustion Engines and Thermodynamics, +* Institute of Technical Informatics +* +* VECTO is licensed under the EUPL, Version 1.1 or - as soon they will be approved +* by the European Commission - subsequent versions of the EUPL (the "Licence"); +* You may not use VECTO except in compliance with the Licence. +* You may obtain a copy of the Licence at: +* +* https://joinup.ec.europa.eu/community/eupl/og_page/eupl +* +* Unless required by applicable law or agreed to in writing, VECTO +* distributed under the Licence is distributed on an "AS IS" basis, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the Licence for the specific language governing permissions and +* limitations under the Licence. +* +* Authors: +* Stefan Hausberger, hausberger@ivt.tugraz.at, IVT, Graz University of Technology +* Christian Kreiner, christian.kreiner@tugraz.at, ITI, Graz University of Technology +* Michael Krisper, michael.krisper@tugraz.at, ITI, Graz University of Technology +* Raphael Luz, luz@ivt.tugraz.at, IVT, Graz University of Technology +* Markus Quaritsch, markus.quaritsch@tugraz.at, IVT, Graz University of Technology +* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology +*/ + +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData +{ + public static class DrivingCycleDataReader + { + /// <summary> + /// Detects the appropriate cycle type for a cycle in a DataTable. + /// </summary> + /// <param name="cycleData">The cycle data.</param> + /// <returns></returns> + /// <exception cref="VectoException">CycleFile Format is unknown.</exception> + public static CycleType DetectCycleType(DataTable cycleData) + { + var cols = cycleData.Columns; + + if (PTOCycleDataParser.ValidateHeader(cols, false)) { + return CycleType.PTO; + } + + if (PWheelCycleDataParser.ValidateHeader(cols, false)) { + return CycleType.PWheel; + } + if (MeasuredSpeedGearDataParser.ValidateHeader(cols, false)) { + return CycleType.MeasuredSpeedGear; + } + if (MeasuredSpeedDataParser.ValidateHeader(cols, false)) { + return CycleType.MeasuredSpeed; + } + if (EngineOnlyCycleDataParser.ValidateHeader(cols, false)) { + return CycleType.EngineOnly; + } + if (DistanceBasedCycleDataParser.ValidateHeader(cols, false)) { + return CycleType.DistanceBased; + } + if (VTPCycleDataParser.ValidateHeader(cols, false)) { + return CycleType.VTP; + } + throw new VectoException("CycleFile format is unknown."); + } + + private static ICycleDataParser GetDataParser(CycleType type) + { + switch (type) { + case CycleType.EngineOnly: + return new EngineOnlyCycleDataParser(); + case CycleType.DistanceBased: + return new DistanceBasedCycleDataParser(); + case CycleType.PWheel: + return new PWheelCycleDataParser(); + case CycleType.MeasuredSpeedGear: + return new MeasuredSpeedGearDataParser(); + case CycleType.MeasuredSpeed: + return new MeasuredSpeedDataParser(); + case CycleType.PTO: + return new PTOCycleDataParser(); + case CycleType.VTP: + return new VTPCycleDataParser(); + + default: + throw new ArgumentOutOfRangeException("Cycle Type", type.ToString()); + } + } + + /// <summary> + /// Reads a cycle from a file. + /// </summary> + /// <param name="fileName">Name of the file.</param> + /// <param name="type">The type.</param> + /// <param name="crossWindRequired"></param> + /// <returns></returns> + /// <exception cref="VectoException">ERROR while reading DrivingCycle File: + ex.Message</exception> + public static DrivingCycleData ReadFromFile(string fileName, CycleType type, bool crossWindRequired) + { + try { + var stream = File.OpenRead(fileName); + return ReadFromStream(stream, type, Path.GetFileNameWithoutExtension(fileName), crossWindRequired); + } catch (Exception ex) { + throw new VectoException("ERROR while opening DrivingCycle File: " + ex.Message, ex); + } + } + + /// <summary> + /// Reads the cycle from a stream. + /// </summary> + /// <param name="stream">The stream.</param> + /// <param name="type">The type.</param> + /// <param name="crossWindRequired"></param> + /// <param name="name">the name of the cycle</param> + /// <returns></returns> + public static DrivingCycleData ReadFromStream(Stream stream, CycleType type, string name, bool crossWindRequired) + { + try { + return ReadFromDataTable(VectoCSVFile.ReadStream(stream), type, name, crossWindRequired); + } catch (Exception ex) { + throw new VectoException("ERROR while reading DrivingCycle Stream: " + ex.Message, ex); + } + } + + /// <summary> + /// Creates a cycle from a DataTable with automatic determination of Cycle Type. + /// </summary> + /// <param name="data">The cycle data.</param> + /// <param name="name">The name.</param> + /// <param name="crossWindRequired"></param> + /// <returns></returns> + public static DrivingCycleData ReadFromDataTable(DataTable data, string name, bool crossWindRequired) + { + if (data == null) { + LogManager.GetLogger(typeof(DrivingCycleDataReader).FullName) + .Warn("Invalid data for DrivingCycle -- dataTable is null"); + throw new VectoException("Invalid data for DrivingCycle -- dataTable is null"); + } + return ReadFromDataTable(data, DetectCycleType(data), name, crossWindRequired); + } + + /// <summary> + /// Creates a cycle from a DataTable + /// </summary> + /// <param name="data">The cycle data.</param> + /// <param name="type">The type.</param> + /// <param name="name">The name.</param> + /// <param name="crossWindRequired"></param> + /// <returns></returns> + private static DrivingCycleData ReadFromDataTable(DataTable data, CycleType type, string name, bool crossWindRequired) + { + if (data == null) { + LogManager.GetLogger(typeof(DrivingCycleDataReader).FullName) + .Warn("Invalid data for DrivingCycle -- dataTable is null"); + throw new VectoException("Invalid data for DrivingCycle -- dataTable is null"); + } + var entries = GetDataParser(type).Parse(data, crossWindRequired).ToList(); + + if (type == CycleType.DistanceBased) { + entries = FilterDrivingCycleEntries(entries); + } + if (type == CycleType.MeasuredSpeed || type == CycleType.MeasuredSpeedGear) { + entries = ComputeAltitudeTimeBased(entries); + } + var cycle = new DrivingCycleData { + Entries = entries, + CycleType = type, + Name = name + }; + return cycle; + } + + private static List<DrivingCycleData.DrivingCycleEntry> ComputeAltitudeTimeBased( + List<DrivingCycleData.DrivingCycleEntry> entries) + { + var current = entries.First(); + current.Altitude = 0.SI<Meter>(); + var altitude = current.Altitude; + var lastTime = entries.First().Time; + foreach (var drivingCycleEntry in entries) { + altitude += drivingCycleEntry.VehicleTargetSpeed * (drivingCycleEntry.Time - lastTime) * + drivingCycleEntry.RoadGradient; + drivingCycleEntry.Altitude = altitude; + lastTime = drivingCycleEntry.Time; + } + return entries; + } + + private static List<DrivingCycleData.DrivingCycleEntry> FilterDrivingCycleEntries( + List<DrivingCycleData.DrivingCycleEntry> entries) + { + var filtered = new List<DrivingCycleData.DrivingCycleEntry>(); + var current = entries.First(); + current.Altitude = 0.SI<Meter>(); + filtered.Add(current); + var distance = current.Distance; + var altitude = current.Altitude; + for (var i = 0; i < entries.Count; i++) { + var entry = entries[i]; + if (i == 0 && entry.VehicleTargetSpeed.IsEqual(0) && entry.StoppingTime.IsEqual(0)) { + entry.StoppingTime = 1.SI<Second>(); + } + if (!entry.StoppingTime.IsEqual(0) && !entry.VehicleTargetSpeed.IsEqual(0)) { + throw new VectoException( + "Error in DrivingCycle: stop time specified but target-speed > 0! Distance: {0}, stop-time: {1}, target speed: {2}", + entry.Distance, entry.StoppingTime, entry.VehicleTargetSpeed); + } + if (entry.Distance < distance) { + throw new VectoException( + "Error in DrivingCycle: distance entry is smaller than last distance! last distance: {0}, current distance: {1} ", + distance, entry.Distance); + } + if (i > 0) { + altitude += (entry.Distance - distance) * entries[i - 1].RoadGradientPercent / 100.0; + } + entry.Altitude = altitude; + // if something changes in the cycle, add it to the filtered cycle but always add last entry + if (!CycleEntriesAreEqual(current, entry) || i == entries.Count - 1) { + entry.Altitude = altitude; + filtered.Add(entry); + current = entry; + } + if (entry.VehicleTargetSpeed.IsEqual(0)) { + // vehicle stops. duplicate current distance entry with 0 waiting time + var tmp = new DrivingCycleData.DrivingCycleEntry(entry) { + StoppingTime = 0.SI<Second>(), + PTOActive = false, + RoadGradient = entry.RoadGradient, + VehicleTargetSpeed = i < entries.Count - 1 ? entries[i + 1].VehicleTargetSpeed : 0.SI<MeterPerSecond>() + }; + filtered.Add(tmp); + current = tmp; + } + + distance = entry.Distance; + } + LogManager.GetLogger(typeof(DrivingCycleDataReader).FullName) + .Info("Data loaded. Number of Entries: {0}, filtered Entries: {1}", entries.Count, filtered.Count); + entries = filtered; + + AdjustDistanceAfterStop(entries); + + return entries; + } + + private static void AdjustDistanceAfterStop(List<DrivingCycleData.DrivingCycleEntry> entries) + { + using (var currentIt = entries.GetEnumerator()) { + using (var nextIt = entries.GetEnumerator()) { + nextIt.MoveNext(); + while (currentIt.MoveNext() && nextIt.MoveNext()) { + if (currentIt.Current != null && !currentIt.Current.StoppingTime.IsEqual(0)) { + if (nextIt.Current != null) { + nextIt.Current.Distance = currentIt.Current.Distance; + } + } + } + } + } + } + + private static bool CycleEntriesAreEqual(DrivingCycleData.DrivingCycleEntry first, + DrivingCycleData.DrivingCycleEntry second) + { + if (first.Distance.IsEqual(second.Distance)) { + return true; + } + + if (first.VehicleTargetSpeed != second.VehicleTargetSpeed) { + return false; + } + + if (!first.RoadGradient.IsEqual(second.RoadGradient, Constants.SimulationSettings.DrivingCycleRoadGradientTolerance)) { + return false; + } + + if (!(first.StoppingTime.IsEqual(0) && second.StoppingTime.IsEqual(0))) { + return false; + } + + if (first.AdditionalAuxPowerDemand != second.AdditionalAuxPowerDemand) { + return false; + } + + if (first.AuxiliarySupplyPower.Count != second.AuxiliarySupplyPower.Count) { + return false; + } + + if (!first.AuxiliarySupplyPower.SequenceEqual(second.AuxiliarySupplyPower)) { + return false; + } + + if (first.AirSpeedRelativeToVehicle != null && second.AirSpeedRelativeToVehicle != null && + !first.AirSpeedRelativeToVehicle.IsEqual(second.AirSpeedRelativeToVehicle)) { + return false; + } + + if (!first.WindYawAngle.IsEqual(second.WindYawAngle)) { + return false; + } + + return true; + } + + public static class Fields + { + public const string PTOTorque = "PTO Torque"; + public const string EngineSpeedFull = "Engine speed"; + public const string PWheel = "Pwheel"; + public const string Distance = "s"; + public const string Time = "t"; + public const string VehicleSpeed = "v"; + public const string RoadGradient = "grad"; + public const string StoppingTime = "stop"; + public const string EngineSpeed = "n"; + public const string EngineSpeedSuffix = "n_eng"; + public const string FanSpeed = "n_fan"; + public const string WheelTorqueLeft = "tq_left"; + public const string WheelTorqueRight = "tq_right"; + public const string WheelSpeedLeft = "n_wh_left"; + public const string WheelSpeedRight = "n_wh_right"; + public const string FuelConsumption = "fc"; + public const string Gear = "gear"; + public const string AdditionalAuxPowerDemand = "Padd"; + public const string AirSpeedRelativeToVehicle = "vair_res"; + public const string WindYawAngle = "vair_beta"; + public const string EnginePower = "Pe"; + public const string EngineTorque = "Me"; + public const string TorqueConverterActive = "tc_active"; + public const string PTOActive = "PTO"; + } + + #region DataParser + + private interface ICycleDataParser + { + /// <summary> + /// Parses a datatable to a list of drivingcycleentries for the current implementation. + /// </summary> + /// <param name="table"></param> + /// <param name="crossWindRequired"></param> + /// <returns></returns> + IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired); + } + + private abstract class AbstractCycleDataParser : LoggingObject, ICycleDataParser + { + protected static bool CheckColumns(DataColumnCollection header, IEnumerable<string> allowedCols, + IEnumerable<string> requiredCols, bool throwExceptions, bool allowAux) + { + var headerStr = header.Cast<DataColumn>().Select(col => col.ColumnName.ToLowerInvariant()).ToArray(); + + var diff = headerStr.GroupBy(c => c).Where(g => g.Count() > 2).SelectMany(g => g).ToList(); + if (diff.Any()) { + if (throwExceptions) { + throw new VectoException("Column(s) defined more than once: " + string.Join(", ", diff.OrderBy(x => x))); + } + return false; + } + + if (allowAux) { + headerStr = headerStr.Where(c => !c.ToUpper().StartsWith(Constants.Auxiliaries.Prefix)).ToArray(); + } + + diff = headerStr.Except(allowedCols.Select(x => x.ToLowerInvariant())).ToList(); + if (diff.Any()) { + if (throwExceptions) { + throw new VectoException("Column(s) not allowed: " + string.Join(", ", diff)); + } + return false; + } + + diff = requiredCols.Select(x => x.ToLowerInvariant()).Except(headerStr).ToList(); + if (diff.Any()) { + if (throwExceptions) { + throw new VectoException("Column(s) required: " + string.Join(", ", diff)); + } + return false; + } + return true; + } + + protected static bool CheckComboColumns(DataColumnCollection header, string[] cols, bool throwExceptions) + { + var colCount = header.Cast<DataColumn>() + .Select(col => col.ColumnName.ToLowerInvariant()) + .Intersect(cols.Select(x => x.ToLowerInvariant())).Count(); + + if (colCount != 0 && colCount != cols.Length) { + if (throwExceptions) { + throw new VectoException("Either all columns have to be defined or none of them: {0}", string.Join(", ", cols)); + } + return false; + } + + return true; + } + + public abstract IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired); + } + + private class DistanceBasedCycleDataParser : AbstractCycleDataParser + { + public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) + { + ValidateHeader(table.Columns); + + return table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { + Distance = row.ParseDouble(Fields.Distance).SI<Meter>(), + VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(), + RoadGradient = VectoMath.InclinationToAngle(row.ParseDoubleOrGetDefault(Fields.RoadGradient) / 100.0), + StoppingTime = row.ParseDouble(Fields.StoppingTime).SI<Second>(), + AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), + AngularVelocity = row.ParseDoubleOrGetDefault(Fields.EngineSpeed).RPMtoRad(), + Gear = (uint)row.ParseDoubleOrGetDefault(Fields.Gear), + AirSpeedRelativeToVehicle = + crossWindRequired ? row.ParseDouble(Fields.AirSpeedRelativeToVehicle).KMPHtoMeterPerSecond() : null, + WindYawAngle = crossWindRequired ? row.ParseDoubleOrGetDefault(Fields.WindYawAngle) : 0, + AuxiliarySupplyPower = row.GetAuxiliaries(), + PTOActive = table.Columns.Contains(Fields.PTOActive) && row.Field<string>(Fields.PTOActive) == "1" + }); + } + + public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) + { + var requiredCols = new[] { + Fields.Distance, + Fields.VehicleSpeed, + Fields.StoppingTime + }; + + var allowedCols = new[] { + Fields.Distance, + Fields.VehicleSpeed, + Fields.StoppingTime, + Fields.AdditionalAuxPowerDemand, + Fields.RoadGradient, + Fields.AirSpeedRelativeToVehicle, + Fields.WindYawAngle, + Fields.PTOActive + }; + + const bool allowAux = true; + + return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux) && + CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions); + } + } + + /// <summary> + /// Parser for EngineOnly Cycles. + /// </summary> + // <t>, <n>, (<Pe>|<Me>)[, <Padd>] + private class EngineOnlyCycleDataParser : AbstractCycleDataParser + { + public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) + { + ValidateHeader(table.Columns); + + var absTime = 0; + foreach (DataRow row in table.Rows) { + var entry = new DrivingCycleData.DrivingCycleEntry { + Time = row.ParseDoubleOrGetDefault(Fields.Time, absTime).SI<Second>(), + AngularVelocity = row.ParseDoubleOrGetDefault(Fields.EngineSpeed).RPMtoRad(), + AdditionalAuxPowerDemand = + row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), + AuxiliarySupplyPower = row.GetAuxiliaries() + }; + + if (row.Table.Columns.Contains(Fields.EngineTorque)) { + if (row.Field<string>(Fields.EngineTorque).Equals("<DRAG>")) { + entry.Drag = true; + } else { + entry.Torque = row.ParseDouble(Fields.EngineTorque).SI<NewtonMeter>(); + } + } else { + if (row.Field<string>(Fields.EnginePower).Equals("<DRAG>")) { + entry.Drag = true; + } else { + entry.Torque = row.ParseDouble(Fields.EnginePower).SI(Unit.SI.Kilo.Watt).Cast<Watt>() / entry.AngularVelocity; + } + } + absTime += 1; + + yield return entry; + } + } + + public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) + { + var requiredCols = new[] { + //Fields.Time not needed --> if missing 1 second resolution is assumed + Fields.EngineSpeed + }; + + var allowedCols = new[] { + Fields.Time, + Fields.EngineSpeed, + Fields.EngineTorque, + Fields.EnginePower, + Fields.AdditionalAuxPowerDemand + }; + + const bool allowAux = false; + + if (!CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux)) { + return false; + } + + var containsNone = !header.Contains(Fields.EngineTorque) && !header.Contains(Fields.EnginePower); + if (containsNone) { + if (throwExceptions) { + throw new VectoException("Column(s) missing: Either column '{0}' or column '{1}' must be defined.", + Fields.EngineTorque, Fields.EnginePower); + } + return false; + } + + var containsBoth = header.Contains(Fields.EngineTorque) && header.Contains(Fields.EnginePower); + if (containsBoth) { + LogManager.GetLogger(typeof(EngineOnlyCycleDataParser).FullName) + .Warn("Found column '{0}' and column '{1}': Only column '{0}' will be used.", + Fields.EngineTorque, Fields.EnginePower); + } + return true; + } + } + + /// <summary> + /// Parser for PWheel (SiCo) Mode. + /// </summary> + // <t>, <Pwheel>, <Gear>, <n>, <Padd> + private class PWheelCycleDataParser : AbstractCycleDataParser + { + public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) + { + ValidateHeader(table.Columns); + + var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { + Time = row.ParseDouble(Fields.Time).SI<Second>(), + PWheel = row.ParseDouble(Fields.PWheel).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), + Gear = (uint)row.ParseDouble(Fields.Gear), + AngularVelocity = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), + AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), + }).ToArray(); + + return entries; + } + + public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) + { + var requiredCols = new[] { + Fields.Time, + Fields.PWheel, + Fields.Gear, + Fields.EngineSpeed + }; + var allowedCols = new[] { + Fields.Time, + Fields.PWheel, + Fields.Gear, + Fields.EngineSpeed, + Fields.AdditionalAuxPowerDemand + }; + + return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux: false); + } + } + + /// <summary> + /// Parser for Measured Speed Mode Option 1. + /// </summary> + // <t>, <v>[, <grad>, <Padd>, <vair_res>, <vair_beta>, Aux_...] + private class MeasuredSpeedDataParser : AbstractCycleDataParser + { + public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) + { + ValidateHeader(table.Columns); + + var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { + Time = row.ParseDouble(Fields.Time).SI<Second>(), + VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(), + RoadGradient = VectoMath.InclinationToAngle(row.ParseDoubleOrGetDefault(Fields.RoadGradient) / 100.0), + AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), + AirSpeedRelativeToVehicle = + crossWindRequired ? row.ParseDouble(Fields.AirSpeedRelativeToVehicle).KMPHtoMeterPerSecond() : null, + WindYawAngle = crossWindRequired ? row.ParseDouble(Fields.WindYawAngle) : 0, + AuxiliarySupplyPower = row.GetAuxiliaries() + }).ToArray(); + + return entries; + } + + public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) + { + var requiredCols = new[] { + Fields.Time, + Fields.VehicleSpeed + }; + + var allowedCols = new[] { + Fields.Time, + Fields.VehicleSpeed, + Fields.AdditionalAuxPowerDemand, + Fields.RoadGradient, + Fields.AirSpeedRelativeToVehicle, + Fields.WindYawAngle + }; + + const bool allowAux = true; + + return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux) && + CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions); + } + } + + /// <summary> + /// Parser for Measured Speed Mode Option 2. + /// </summary> + // <t>, <v>, <n>, <gear>[, <tc_active>, <grad>, <Padd>, <vair_res>, <vair_beta>, Aux_...] + private class MeasuredSpeedGearDataParser : AbstractCycleDataParser + { + public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) + { + ValidateHeader(table.Columns); + + var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { + Time = row.ParseDouble(Fields.Time).SI<Second>(), + VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(), + RoadGradient = VectoMath.InclinationToAngle(row.ParseDoubleOrGetDefault(Fields.RoadGradient) / 100.0), + AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), + AngularVelocity = row.ParseDoubleOrGetDefault(Fields.EngineSpeed).RPMtoRad(), + Gear = (uint)row.ParseDouble(Fields.Gear), + TorqueConverterActive = table.Columns.Contains(Fields.TorqueConverterActive) + ? row.ParseBoolean(Fields.TorqueConverterActive) + : (bool?)null, + AirSpeedRelativeToVehicle = crossWindRequired + ? row.ParseDouble(Fields.AirSpeedRelativeToVehicle).KMPHtoMeterPerSecond() + : null, + WindYawAngle = crossWindRequired ? row.ParseDoubleOrGetDefault(Fields.WindYawAngle) : 0, + AuxiliarySupplyPower = row.GetAuxiliaries() + }).ToArray(); + + return entries; + } + + public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) + { + var requiredCols = new[] { + Fields.Time, + Fields.VehicleSpeed, + Fields.Gear + }; + var allowedCols = new[] { + Fields.Time, + Fields.VehicleSpeed, + Fields.EngineSpeed, + Fields.Gear, + Fields.TorqueConverterActive, + Fields.AdditionalAuxPowerDemand, + Fields.RoadGradient, + Fields.AirSpeedRelativeToVehicle, + Fields.WindYawAngle + }; + + const bool allowAux = true; + + return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux) && + CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions); + } + } + + /// <summary> + /// Parser for PTO Cycles. + /// </summary> + // <t> [s], <Engine Speed> [rpm], <PTO Torque> [Nm] + private class PTOCycleDataParser : AbstractCycleDataParser + { + public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) + { + ValidateHeader(table.Columns); + + var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry { + Time = row.ParseDouble(Fields.Time).SI<Second>(), + AngularVelocity = row.ParseDouble(Fields.EngineSpeedFull).RPMtoRad(), + Torque = row.ParseDouble(Fields.PTOTorque).SI<NewtonMeter>() + }).ToArray(); + + return entries; + } + + public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) + { + var requiredCols = new[] { + Fields.Time, + Fields.EngineSpeedFull, + Fields.PTOTorque + }; + var allowedCols = new[] { + Fields.Time, + Fields.EngineSpeedFull, + Fields.PTOTorque + }; + + const bool allowAux = false; + + return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux); + } + } + + /// <summary> + /// Parser for PTO Cycles. + /// </summary> + // <t>,<v> [km/h],<Pwheel> [kW],<n_eng> [rpm],<n_fan> [rpm], <Padd> [kW] + private class VTPCycleDataParser : AbstractCycleDataParser + { + public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired) + { + ValidateHeader(table.Columns); + + var entries = table.Rows.Cast<DataRow>().Select(row => { + var tqLeft = row.ParseDouble(Fields.WheelTorqueLeft).SI<NewtonMeter>(); + var tqRight = row.ParseDouble(Fields.WheelTorqueRight).SI<NewtonMeter>(); + var speedLeft = row.ParseDouble(Fields.WheelSpeedLeft).RPMtoRad(); + var speedRight = row.ParseDouble(Fields.WheelSpeedRight).RPMtoRad(); + return new DrivingCycleData.DrivingCycleEntry { + Time = row.ParseDouble(Fields.Time).SI<Second>(), + VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(), + AdditionalAuxPowerDemand = + row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI(Unit.SI.Kilo.Watt).Cast<Watt>(), + EngineSpeed = row.ParseDouble(Fields.EngineSpeedSuffix).RPMtoRad(), + FanSpeed = row.ParseDouble(Fields.FanSpeed).RPMtoRad(), + Gear = (uint)row.ParseDoubleOrGetDefault(Fields.Gear), + Fuelconsumption = row.ParseDoubleOrGetDefault(Fields.FuelConsumption).SI(Unit.SI.Gramm.Per.Hour).Cast<KilogramPerSecond>(), + TorqueConverterActive = row.ParseBooleanOrGetDefault(Fields.TorqueConverterActive), + TorqueWheelLeft = tqLeft, + TorqueWheelRight = tqRight, + WheelSpeedLeft = speedLeft, + WheelSpeedRight = speedRight + }; + }).ToArray(); + + return entries; + } + + public static bool ValidateHeader(DataColumnCollection header, bool throwExceptions = true) + { + var requiredCols = new[] { + Fields.Time, + Fields.VehicleSpeed, + Fields.EngineSpeedSuffix, + Fields.FanSpeed, + Fields.WheelSpeedLeft, + Fields.WheelSpeedRight, + Fields.WheelTorqueLeft, + Fields.WheelTorqueRight, + }; + + var allowedCols = new[] { + Fields.Time, + Fields.VehicleSpeed, + Fields.EngineSpeedSuffix, + Fields.FanSpeed, + Fields.WheelSpeedLeft, + Fields.WheelSpeedRight, + Fields.WheelTorqueLeft, + Fields.WheelTorqueRight, + Fields.Gear, + Fields.TorqueConverterActive, + Fields.FuelConsumption + }; + + const bool allowAux = true; + + return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux) && + CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions); + } + } + + } + + #endregion } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMapReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/FuelConsumptionMapReader.cs similarity index 65% rename from VectoCore/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMapReader.cs rename to VectoCore/VectoCore/InputData/Reader/ComponentData/FuelConsumptionMapReader.cs index 7a13f43060..8d1e4e3de7 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMapReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/FuelConsumptionMapReader.cs @@ -1,122 +1,187 @@ -/* -* This file is part of VECTO. -* -* Copyright © 2012-2019 European Union -* -* Developed by Graz University of Technology, -* Institute of Internal Combustion Engines and Thermodynamics, -* Institute of Technical Informatics -* -* VECTO is licensed under the EUPL, Version 1.1 or - as soon they will be approved -* by the European Commission - subsequent versions of the EUPL (the "Licence"); -* You may not use VECTO except in compliance with the Licence. -* You may obtain a copy of the Licence at: -* -* https://joinup.ec.europa.eu/community/eupl/og_page/eupl -* -* Unless required by applicable law or agreed to in writing, VECTO -* distributed under the Licence is distributed on an "AS IS" basis, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the Licence for the specific language governing permissions and -* limitations under the Licence. -* -* Authors: -* Stefan Hausberger, hausberger@ivt.tugraz.at, IVT, Graz University of Technology -* Christian Kreiner, christian.kreiner@tugraz.at, ITI, Graz University of Technology -* Michael Krisper, michael.krisper@tugraz.at, ITI, Graz University of Technology -* Raphael Luz, luz@ivt.tugraz.at, IVT, Graz University of Technology -* Markus Quaritsch, markus.quaritsch@tugraz.at, IVT, Graz University of Technology -* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology -*/ - -using System; -using System.Data; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine -{ - public static class FuelConsumptionMapReader - { - public static FuelConsumptionMap ReadFromFile(string fileName) - { - try { - var data = VectoCSVFile.Read(fileName); - return Create(data); - } catch (Exception e) { - throw new VectoException(string.Format("File {0}: {1}", fileName, e.Message), e); - } - } - - public static FuelConsumptionMap Create(DataTable data) - { - var headerValid = HeaderIsValid(data.Columns); - if (!headerValid) { - LoggingObject.Logger<FuelConsumptionMap>().Warn( - "FuelConsumptionMap: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: {3}", - Fields.EngineSpeed, Fields.Torque, Fields.FuelConsumption, - string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); - } - var delaunayMap = new DelaunayMap("FuelConsumptionMap"); - - foreach (DataRow row in data.Rows) { - try { - var entry = headerValid ? CreateFromColumNames(row) : CreateFromColumnIndizes(row); - delaunayMap.AddPoint(entry.Torque.Value(), - (headerValid ? row.ParseDouble(Fields.EngineSpeed) : row.ParseDouble(0)).RPMtoRad().Value(), - entry.FuelConsumption.Value()); - } catch (Exception e) { - throw new VectoException(string.Format("FuelConsumptionMap - Line {0}: {1}", data.Rows.IndexOf(row), e.Message), e); - } - } - - delaunayMap.Triangulate(); - return new FuelConsumptionMap(delaunayMap); - } - - private static bool HeaderIsValid(DataColumnCollection columns) - { - return columns.Contains(Fields.EngineSpeed) && columns.Contains(Fields.Torque) && - columns.Contains(Fields.FuelConsumption); - } - - private static FuelConsumptionMap.Entry CreateFromColumnIndizes(DataRow row) - { - return new FuelConsumptionMap.Entry( - engineSpeed: row.ParseDouble(0).RPMtoRad(), - torque: row.ParseDouble(1).SI<NewtonMeter>(), - fuelConsumption: row.ParseDouble(2).SI(Unit.SI.Gramm.Per.Hour).Cast<KilogramPerSecond>() - ); - } - - private static FuelConsumptionMap.Entry CreateFromColumNames(DataRow row) - { - return new FuelConsumptionMap.Entry( - engineSpeed: row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), - torque: row.SI<NewtonMeter>(Fields.Torque), - fuelConsumption: row.ParseDouble(Fields.FuelConsumption).SI(Unit.SI.Gramm.Per.Hour).Cast<KilogramPerSecond>() - ); - } - - public static class Fields - { - /// <summary> - /// [rpm] - /// </summary> - public const string EngineSpeed = "engine speed"; - - /// <summary> - /// [Nm] - /// </summary> - public const string Torque = "torque"; - - /// <summary> - /// [g/h] - /// </summary> - public const string FuelConsumption = "fuel consumption"; - } - } +/* +* This file is part of VECTO. +* +* Copyright © 2012-2019 European Union +* +* Developed by Graz University of Technology, +* Institute of Internal Combustion Engines and Thermodynamics, +* Institute of Technical Informatics +* +* VECTO is licensed under the EUPL, Version 1.1 or - as soon they will be approved +* by the European Commission - subsequent versions of the EUPL (the "Licence"); +* You may not use VECTO except in compliance with the Licence. +* You may obtain a copy of the Licence at: +* +* https://joinup.ec.europa.eu/community/eupl/og_page/eupl +* +* Unless required by applicable law or agreed to in writing, VECTO +* distributed under the Licence is distributed on an "AS IS" basis, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the Licence for the specific language governing permissions and +* limitations under the Licence. +* +* Authors: +* Stefan Hausberger, hausberger@ivt.tugraz.at, IVT, Graz University of Technology +* Christian Kreiner, christian.kreiner@tugraz.at, ITI, Graz University of Technology +* Michael Krisper, michael.krisper@tugraz.at, ITI, Graz University of Technology +* Raphael Luz, luz@ivt.tugraz.at, IVT, Graz University of Technology +* Markus Quaritsch, markus.quaritsch@tugraz.at, IVT, Graz University of Technology +* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology +*/ + +using System; +using System.Data; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData +{ + public static class WHRPowerReader + { + public static WHRPowerMap ReadFromFile(string fileName) + { + try { + var data = VectoCSVFile.Read(fileName); + return Create(data); + } catch (Exception e) { + throw new VectoException(string.Format("File {0}: {1}", fileName, e.Message), e); + } + } + + public static WHRPowerMap Create(DataTable data) + { + var headerValid = HeaderIsValid(data.Columns); + if (!headerValid) { + LoggingObject.Logger<FuelConsumptionMap>().Warn( + "FuelConsumptionMap: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: {3}", + Fields.EngineSpeed, Fields.Torque, Fields.ElectricPower, + string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + } + var delaunayMap = new DelaunayMap("FuelConsumptionMap"); + + + foreach (DataRow row in data.Rows) { + try { + var entry = headerValid ? CreateFromColumNames(row) : CreateFromColumnIndizes(row); + delaunayMap.AddPoint(entry.Torque.Value(), + (headerValid ? row.ParseDouble(Fields.EngineSpeed) : row.ParseDouble(0)).RPMtoRad().Value(), + entry.FuelConsumption.Value()); + } catch (Exception e) { + throw new VectoException(string.Format("FuelConsumptionMap - Line {0}: {1}", data.Rows.IndexOf(row), e.Message), e); + } + } + + delaunayMap.Triangulate(); + return new WHRPowerMap(delaunayMap); + } + + private static bool HeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(Fields.EngineSpeed) && columns.Contains(Fields.Torque) && + columns.Contains(Fields.ElectricPower); + } + + public static class Fields + { + /// <summary> + /// [rpm] + /// </summary> + public const string EngineSpeed = "engine speed"; + + /// <summary> + /// [Nm] + /// </summary> + public const string Torque = "torque"; + + /// <summary> + /// [g/h] + /// </summary> + public const string ElectricPower = "whr power"; + } + } + + public static class FuelConsumptionMapReader + { + public static FuelConsumptionMap ReadFromFile(string fileName) + { + try { + var data = VectoCSVFile.Read(fileName); + return Create(data); + } catch (Exception e) { + throw new VectoException(string.Format("File {0}: {1}", fileName, e.Message), e); + } + } + + public static FuelConsumptionMap Create(DataTable data) + { + var headerValid = HeaderIsValid(data.Columns); + if (!headerValid) { + LoggingObject.Logger<FuelConsumptionMap>().Warn( + "FuelConsumptionMap: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: {3}", + Fields.EngineSpeed, Fields.Torque, Fields.FuelConsumption, + string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + } + var delaunayMap = new DelaunayMap("FuelConsumptionMap"); + + foreach (DataRow row in data.Rows) { + try { + var entry = headerValid ? CreateFromColumNames(row) : CreateFromColumnIndizes(row); + delaunayMap.AddPoint(entry.Torque.Value(), + (headerValid ? row.ParseDouble(Fields.EngineSpeed) : row.ParseDouble(0)).RPMtoRad().Value(), + entry.FuelConsumption.Value()); + } catch (Exception e) { + throw new VectoException(string.Format("FuelConsumptionMap - Line {0}: {1}", data.Rows.IndexOf(row), e.Message), e); + } + } + + delaunayMap.Triangulate(); + return new FuelConsumptionMap(delaunayMap); + } + + private static bool HeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(Fields.EngineSpeed) && columns.Contains(Fields.Torque) && + columns.Contains(Fields.FuelConsumption); + } + + private static FuelConsumptionMap.Entry CreateFromColumnIndizes(DataRow row) + { + return new FuelConsumptionMap.Entry( + engineSpeed: row.ParseDouble(0).RPMtoRad(), + torque: row.ParseDouble(1).SI<NewtonMeter>(), + fuelConsumption: row.ParseDouble(2).SI(Unit.SI.Gramm.Per.Hour).Cast<KilogramPerSecond>() + ); + } + + private static FuelConsumptionMap.Entry CreateFromColumNames(DataRow row) + { + return new FuelConsumptionMap.Entry( + engineSpeed: row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), + torque: row.SI<NewtonMeter>(Fields.Torque), + fuelConsumption: row.ParseDouble(Fields.FuelConsumption).SI(Unit.SI.Gramm.Per.Hour).Cast<KilogramPerSecond>() + ); + } + + public static class Fields + { + /// <summary> + /// [rpm] + /// </summary> + public const string EngineSpeed = "engine speed"; + + /// <summary> + /// [Nm] + /// </summary> + public const string Torque = "torque"; + + /// <summary> + /// [g/h] + /// </summary> + public const string FuelConsumption = "fuel consumption"; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/FullLoadCurveReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/FullLoadCurveReader.cs similarity index 96% rename from VectoCore/VectoCore/InputData/Reader/FullLoadCurveReader.cs rename to VectoCore/VectoCore/InputData/Reader/ComponentData/FullLoadCurveReader.cs index e0b5b5b5bc..9f6550bb27 100644 --- a/VectoCore/VectoCore/InputData/Reader/FullLoadCurveReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/FullLoadCurveReader.cs @@ -1,141 +1,141 @@ -/* -* This file is part of VECTO. -* -* Copyright © 2012-2019 European Union -* -* Developed by Graz University of Technology, -* Institute of Internal Combustion Engines and Thermodynamics, -* Institute of Technical Informatics -* -* VECTO is licensed under the EUPL, Version 1.1 or - as soon they will be approved -* by the European Commission - subsequent versions of the EUPL (the "Licence"); -* You may not use VECTO except in compliance with the Licence. -* You may obtain a copy of the Licence at: -* -* https://joinup.ec.europa.eu/community/eupl/og_page/eupl -* -* Unless required by applicable law or agreed to in writing, VECTO -* distributed under the Licence is distributed on an "AS IS" basis, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the Licence for the specific language governing permissions and -* limitations under the Licence. -* -* Authors: -* Stefan Hausberger, hausberger@ivt.tugraz.at, IVT, Graz University of Technology -* Christian Kreiner, christian.kreiner@tugraz.at, ITI, Graz University of Technology -* Michael Krisper, michael.krisper@tugraz.at, ITI, Graz University of Technology -* Raphael Luz, luz@ivt.tugraz.at, IVT, Graz University of Technology -* Markus Quaritsch, markus.quaritsch@tugraz.at, IVT, Graz University of Technology -* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology -*/ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.InputData.Reader -{ - public static class FullLoadCurveReader - { - public static EngineFullLoadCurve ReadFromFile(string fileName, bool declarationMode = false) - { - try { - var data = VectoCSVFile.Read(fileName); - return Create(data, declarationMode); - } catch (Exception ex) { - throw new VectoException("ERROR while reading FullLoadCurve File: " + ex.Message, ex); - } - } - - public static EngineFullLoadCurve Create(DataTable data, bool declarationMode = false) - { - if (data.Columns.Count < 3) { - throw new VectoException("Engine FullLoadCurve Data File must consist of at least 3 columns."); - } - - if (data.Rows.Count < 2) { - throw new VectoException( - "FullLoadCurve must consist of at least two lines with numeric values (below file header)"); - } - - List<EngineFullLoadCurve.FullLoadCurveEntry> entriesFld; - if (HeaderIsValid(data.Columns)) { - entriesFld = CreateFromColumnNames(data); - } else { - LoggingObject.Logger<EngineFullLoadCurve>().Warn( - "FullLoadCurve: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: '{3}'. Falling back to column index.", - Fields.EngineSpeed, Fields.TorqueFullLoad, - Fields.TorqueDrag, string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); - - entriesFld = CreateFromColumnIndizes(data); - } - - LookupData<PerSecond, PT1.PT1Result> tmp; - if (declarationMode) { - tmp = new PT1(); - } else { - tmp = data.Columns.Count > 3 ? new PT1(data) : new PT1(); - } - entriesFld.Sort((entry1, entry2) => entry1.EngineSpeed.Value().CompareTo(entry2.EngineSpeed.Value())); - var duplicates = entriesFld.Select(x => x.EngineSpeed.AsRPM).GroupBy(x => x).Where(g => g.Count() > 1) - .Select(g => g.Key).ToList(); - if (duplicates.Count > 0) { - throw new VectoException( - "Error reading full-load curve: multiple entries for engine speeds {0}", string.Join(", ", duplicates)); - } - return new EngineFullLoadCurve(entriesFld, tmp); - } - - private static bool HeaderIsValid(DataColumnCollection columns) - { - return columns.Contains(Fields.EngineSpeed) - && columns.Contains(Fields.TorqueFullLoad) - && columns.Contains(Fields.TorqueDrag); - } - - private static List<EngineFullLoadCurve.FullLoadCurveEntry> CreateFromColumnNames(DataTable data) - { - return (from DataRow row in data.Rows - select new EngineFullLoadCurve.FullLoadCurveEntry { - EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), - TorqueFullLoad = row.ParseDouble(Fields.TorqueFullLoad).SI<NewtonMeter>(), - TorqueDrag = row.ParseDouble(Fields.TorqueDrag).SI<NewtonMeter>() - }).ToList(); - } - - private static List<EngineFullLoadCurve.FullLoadCurveEntry> CreateFromColumnIndizes(DataTable data) - { - return (from DataRow row in data.Rows - select new EngineFullLoadCurve.FullLoadCurveEntry { - EngineSpeed = row.ParseDouble(0).RPMtoRad(), - TorqueFullLoad = row.ParseDouble(1).SI<NewtonMeter>(), - TorqueDrag = row.ParseDouble(2).SI<NewtonMeter>() - }).ToList(); - } - - public static class Fields - { - /// <summary> - /// [rpm] engine speed - /// </summary> - public const string EngineSpeed = "engine speed"; - - /// <summary> - /// [Nm] full load torque - /// </summary> - public const string TorqueFullLoad = "full load torque"; - - /// <summary> - /// [Nm] motoring torque - /// </summary> - public const string TorqueDrag = "motoring torque"; - } - } +/* +* This file is part of VECTO. +* +* Copyright © 2012-2019 European Union +* +* Developed by Graz University of Technology, +* Institute of Internal Combustion Engines and Thermodynamics, +* Institute of Technical Informatics +* +* VECTO is licensed under the EUPL, Version 1.1 or - as soon they will be approved +* by the European Commission - subsequent versions of the EUPL (the "Licence"); +* You may not use VECTO except in compliance with the Licence. +* You may obtain a copy of the Licence at: +* +* https://joinup.ec.europa.eu/community/eupl/og_page/eupl +* +* Unless required by applicable law or agreed to in writing, VECTO +* distributed under the Licence is distributed on an "AS IS" basis, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the Licence for the specific language governing permissions and +* limitations under the Licence. +* +* Authors: +* Stefan Hausberger, hausberger@ivt.tugraz.at, IVT, Graz University of Technology +* Christian Kreiner, christian.kreiner@tugraz.at, ITI, Graz University of Technology +* Michael Krisper, michael.krisper@tugraz.at, ITI, Graz University of Technology +* Raphael Luz, luz@ivt.tugraz.at, IVT, Graz University of Technology +* Markus Quaritsch, markus.quaritsch@tugraz.at, IVT, Graz University of Technology +* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology +*/ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData +{ + public static class FullLoadCurveReader + { + public static EngineFullLoadCurve ReadFromFile(string fileName, bool declarationMode = false) + { + try { + var data = VectoCSVFile.Read(fileName); + return Create(data, declarationMode); + } catch (Exception ex) { + throw new VectoException("ERROR while reading FullLoadCurve File: " + ex.Message, ex); + } + } + + public static EngineFullLoadCurve Create(DataTable data, bool declarationMode = false) + { + if (data.Columns.Count < 3) { + throw new VectoException("Engine FullLoadCurve Data File must consist of at least 3 columns."); + } + + if (data.Rows.Count < 2) { + throw new VectoException( + "FullLoadCurve must consist of at least two lines with numeric values (below file header)"); + } + + List<EngineFullLoadCurve.FullLoadCurveEntry> entriesFld; + if (HeaderIsValid(data.Columns)) { + entriesFld = CreateFromColumnNames(data); + } else { + LoggingObject.Logger<EngineFullLoadCurve>().Warn( + "FullLoadCurve: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: '{3}'. Falling back to column index.", + Fields.EngineSpeed, Fields.TorqueFullLoad, + Fields.TorqueDrag, string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + + entriesFld = CreateFromColumnIndizes(data); + } + + LookupData<PerSecond, PT1.PT1Result> tmp; + if (declarationMode) { + tmp = new PT1(); + } else { + tmp = data.Columns.Count > 3 ? new PT1(data) : new PT1(); + } + entriesFld.Sort((entry1, entry2) => entry1.EngineSpeed.Value().CompareTo(entry2.EngineSpeed.Value())); + var duplicates = entriesFld.Select(x => x.EngineSpeed.AsRPM).GroupBy(x => x).Where(g => g.Count() > 1) + .Select(g => g.Key).ToList(); + if (duplicates.Count > 0) { + throw new VectoException( + "Error reading full-load curve: multiple entries for engine speeds {0}", string.Join(", ", duplicates)); + } + return new EngineFullLoadCurve(entriesFld, tmp); + } + + private static bool HeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(Fields.EngineSpeed) + && columns.Contains(Fields.TorqueFullLoad) + && columns.Contains(Fields.TorqueDrag); + } + + private static List<EngineFullLoadCurve.FullLoadCurveEntry> CreateFromColumnNames(DataTable data) + { + return (from DataRow row in data.Rows + select new EngineFullLoadCurve.FullLoadCurveEntry { + EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), + TorqueFullLoad = row.ParseDouble(Fields.TorqueFullLoad).SI<NewtonMeter>(), + TorqueDrag = row.ParseDouble(Fields.TorqueDrag).SI<NewtonMeter>() + }).ToList(); + } + + private static List<EngineFullLoadCurve.FullLoadCurveEntry> CreateFromColumnIndizes(DataTable data) + { + return (from DataRow row in data.Rows + select new EngineFullLoadCurve.FullLoadCurveEntry { + EngineSpeed = row.ParseDouble(0).RPMtoRad(), + TorqueFullLoad = row.ParseDouble(1).SI<NewtonMeter>(), + TorqueDrag = row.ParseDouble(2).SI<NewtonMeter>() + }).ToList(); + } + + public static class Fields + { + /// <summary> + /// [rpm] engine speed + /// </summary> + public const string EngineSpeed = "engine speed"; + + /// <summary> + /// [Nm] full load torque + /// </summary> + public const string TorqueFullLoad = "full load torque"; + + /// <summary> + /// [Nm] motoring torque + /// </summary> + public const string TorqueDrag = "motoring torque"; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/PTOIdleLossMapReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/PTOIdleLossMapReader.cs index d6351dce21..074d41cad9 100644 --- a/VectoCore/VectoCore/InputData/Reader/ComponentData/PTOIdleLossMapReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/PTOIdleLossMapReader.cs @@ -29,78 +29,78 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Data; -using System.IO; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.InputData.Reader.ComponentData -{ - public static class PTOIdleLossMapReader - { - - public static PTOLossMap ReadFromStream(Stream stream) - { - try { - return Create(VectoCSVFile.ReadStream(stream)); - } catch (Exception ex) { - throw new VectoException("ERROR while loading PTO Idle LossMap: " + ex.Message); - } - } - - /// <summary> - /// Create the pto idle loss map from an appropriate datatable. (2 columns: Engine Speed, PTO Torque) - /// </summary> - public static PTOLossMap Create(DataTable data) - { - if (data.Columns.Count != 2) { - throw new VectoException("PTO Idle LossMap Data File must consist of 2 columns: {0}, {1}", Fields.EngineSpeed, - Fields.PTOTorque); - } - - if (data.Rows.Count < 2) { - throw new VectoException("PTO Idle LossMap must contain at least 2 entries."); - } - - if (!(data.Columns.Contains(Fields.EngineSpeed) && data.Columns.Contains(Fields.PTOTorque))) { - data.Columns[0].ColumnName = Fields.EngineSpeed; - data.Columns[1].ColumnName = Fields.PTOTorque; - LoggingObject.Logger<RetarderLossMap>().Warn( - "PTO Idle LossMap: Header Line is not valid. Expected: '{0}, {1}', Got: '{2}'. Falling back to column index.", - Fields.EngineSpeed, Fields.PTOTorque, string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); - } - - return new PTOLossMap(data.Rows.Cast<DataRow>() - .Select(row => new PTOLossMap.Entry { - EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), - PTOTorque = row.ParseDouble(Fields.PTOTorque).SI<NewtonMeter>() - }).OrderBy(e => e.EngineSpeed).ToArray()); - } - - public static class Fields - { - /// <summary> - /// [rpm] - /// </summary> - public const string EngineSpeed = "Engine speed"; - - /// <summary> - /// [Nm] - /// </summary> - public const string PTOTorque = "PTO Torque"; - } - - public static PTOLossMap GetZeroLossMap() - { - return new PTOLossMap(new[] { - new PTOLossMap.Entry { EngineSpeed = 0.RPMtoRad(), PTOTorque = 0.SI<NewtonMeter>() }, - new PTOLossMap.Entry { EngineSpeed = 10000.RPMtoRad(), PTOTorque = 0.SI<NewtonMeter>() }, - }); - } - } +using System; +using System.Data; +using System.IO; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData +{ + public static class PTOIdleLossMapReader + { + + public static PTOLossMap ReadFromStream(Stream stream) + { + try { + return Create(VectoCSVFile.ReadStream(stream)); + } catch (Exception ex) { + throw new VectoException("ERROR while loading PTO Idle LossMap: " + ex.Message); + } + } + + /// <summary> + /// Create the pto idle loss map from an appropriate datatable. (2 columns: Engine Speed, PTO Torque) + /// </summary> + public static PTOLossMap Create(DataTable data) + { + if (data.Columns.Count != 2) { + throw new VectoException("PTO Idle LossMap Data File must consist of 2 columns: {0}, {1}", Fields.EngineSpeed, + Fields.PTOTorque); + } + + if (data.Rows.Count < 2) { + throw new VectoException("PTO Idle LossMap must contain at least 2 entries."); + } + + if (!(data.Columns.Contains(Fields.EngineSpeed) && data.Columns.Contains(Fields.PTOTorque))) { + data.Columns[0].ColumnName = Fields.EngineSpeed; + data.Columns[1].ColumnName = Fields.PTOTorque; + LoggingObject.Logger<RetarderLossMap>().Warn( + "PTO Idle LossMap: Header Line is not valid. Expected: '{0}, {1}', Got: '{2}'. Falling back to column index.", + Fields.EngineSpeed, Fields.PTOTorque, string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + } + + return new PTOLossMap(data.Rows.Cast<DataRow>() + .Select(row => new PTOLossMap.Entry { + EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), + PTOTorque = row.ParseDouble(Fields.PTOTorque).SI<NewtonMeter>() + }).OrderBy(e => e.EngineSpeed).ToArray()); + } + + public static class Fields + { + /// <summary> + /// [rpm] + /// </summary> + public const string EngineSpeed = "Engine speed"; + + /// <summary> + /// [Nm] + /// </summary> + public const string PTOTorque = "PTO Torque"; + } + + public static PTOLossMap GetZeroLossMap() + { + return new PTOLossMap(new[] { + new PTOLossMap.Entry { EngineSpeed = 0.RPMtoRad(), PTOTorque = 0.SI<NewtonMeter>() }, + new PTOLossMap.Entry { EngineSpeed = 10000.RPMtoRad(), PTOTorque = 0.SI<NewtonMeter>() }, + }); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/ShiftPolygonReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/ShiftPolygonReader.cs similarity index 98% rename from VectoCore/VectoCore/InputData/Reader/ShiftPolygonReader.cs rename to VectoCore/VectoCore/InputData/Reader/ComponentData/ShiftPolygonReader.cs index f94fbfb3a9..63c2d71751 100644 --- a/VectoCore/VectoCore/InputData/Reader/ShiftPolygonReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/ShiftPolygonReader.cs @@ -1,34 +1,34 @@ -/* -* This file is part of VECTO. -* -* Copyright © 2012-2019 European Union -* -* Developed by Graz University of Technology, -* Institute of Internal Combustion Engines and Thermodynamics, -* Institute of Technical Informatics -* -* VECTO is licensed under the EUPL, Version 1.1 or - as soon they will be approved -* by the European Commission - subsequent versions of the EUPL (the "Licence"); -* You may not use VECTO except in compliance with the Licence. -* You may obtain a copy of the Licence at: -* -* https://joinup.ec.europa.eu/community/eupl/og_page/eupl -* -* Unless required by applicable law or agreed to in writing, VECTO -* distributed under the Licence is distributed on an "AS IS" basis, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the Licence for the specific language governing permissions and -* limitations under the Licence. -* -* Authors: -* Stefan Hausberger, hausberger@ivt.tugraz.at, IVT, Graz University of Technology -* Christian Kreiner, christian.kreiner@tugraz.at, ITI, Graz University of Technology -* Michael Krisper, michael.krisper@tugraz.at, ITI, Graz University of Technology -* Raphael Luz, luz@ivt.tugraz.at, IVT, Graz University of Technology -* Markus Quaritsch, markus.quaritsch@tugraz.at, IVT, Graz University of Technology -* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology -*/ - +/* +* This file is part of VECTO. +* +* Copyright © 2012-2019 European Union +* +* Developed by Graz University of Technology, +* Institute of Internal Combustion Engines and Thermodynamics, +* Institute of Technical Informatics +* +* VECTO is licensed under the EUPL, Version 1.1 or - as soon they will be approved +* by the European Commission - subsequent versions of the EUPL (the "Licence"); +* You may not use VECTO except in compliance with the Licence. +* You may obtain a copy of the Licence at: +* +* https://joinup.ec.europa.eu/community/eupl/og_page/eupl +* +* Unless required by applicable law or agreed to in writing, VECTO +* distributed under the Licence is distributed on an "AS IS" basis, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the Licence for the specific language governing permissions and +* limitations under the Licence. +* +* Authors: +* Stefan Hausberger, hausberger@ivt.tugraz.at, IVT, Graz University of Technology +* Christian Kreiner, christian.kreiner@tugraz.at, ITI, Graz University of Technology +* Michael Krisper, michael.krisper@tugraz.at, ITI, Graz University of Technology +* Raphael Luz, luz@ivt.tugraz.at, IVT, Graz University of Technology +* Markus Quaritsch, markus.quaritsch@tugraz.at, IVT, Graz University of Technology +* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology +*/ + using System; using System.Collections.Generic; using System.Data; @@ -39,7 +39,7 @@ using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; using TUGraz.VectoCore.Utils; -namespace TUGraz.VectoCore.InputData.Reader +namespace TUGraz.VectoCore.InputData.Reader.ComponentData { public static class ShiftPolygonReader { diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/WHRPowerReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/WHRPowerReader.cs new file mode 100644 index 0000000000..9a1c8f3b23 --- /dev/null +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/WHRPowerReader.cs @@ -0,0 +1,84 @@ +using System; +using System.Data; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData { + public static class WHRPowerReader + { + public static WHRPowerMap ReadFromFile(string fileName) + { + try { + var data = VectoCSVFile.Read(fileName); + return Create(data); + } catch (Exception e) { + throw new VectoException(string.Format("File {0}: {1}", fileName, e.Message), e); + } + } + + public static WHRPowerMap Create(DataTable data) + { + var headerValid = HeaderIsValid(data.Columns); + if (!headerValid) { + LoggingObject.Logger<FuelConsumptionMap>().Warn( + "FuelConsumptionMap: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: {3}", + Fields.EngineSpeed, Fields.Torque, Fields.ElectricPower, + string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + } + var delaunayMap = new DelaunayMap("FuelConsumptionMap"); + + if (!headerValid) { + data.Columns[0].ColumnName = Fields.EngineSpeed; + data.Columns[1].ColumnName = Fields.Torque; + // column with idx==2 is fuel consumption in csv files + data.Columns[3].ColumnName = Fields.ElectricPower; + } + + foreach (DataRow row in data.Rows) { + try { + var entry = new WHRPowerMap.Entry ( + engineSpeed: row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), + torque: row.ParseDouble(Fields.Torque).SI<NewtonMeter>(), + electricPower:row.ParseDouble(Fields.ElectricPower).SI<Watt>() + ); + delaunayMap.AddPoint(entry.Torque.Value(), + (headerValid ? row.ParseDouble(Fields.EngineSpeed) : row.ParseDouble(0)).RPMtoRad().Value(), + entry.ElectricPower.Value()); + } catch (Exception e) { + throw new VectoException(string.Format("WHR Map - Line {0}: {1}", data.Rows.IndexOf(row), e.Message), e); + } + } + + delaunayMap.Triangulate(); + return new WHRPowerMap(delaunayMap); + } + + private static bool HeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(Fields.EngineSpeed) && columns.Contains(Fields.Torque) && + columns.Contains(Fields.ElectricPower); + } + + public static class Fields + { + /// <summary> + /// [rpm] + /// </summary> + public const string EngineSpeed = "engine speed"; + + /// <summary> + /// [Nm] + /// </summary> + public const string Torque = "torque"; + + /// <summary> + /// [g/h] + /// </summary> + public const string ElectricPower = "whr power"; + } + } +} \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/Impl/EngineOnlyVectoRunDataFactory.cs b/VectoCore/VectoCore/InputData/Reader/Impl/EngineOnlyVectoRunDataFactory.cs index fbbfbf7715..1bc78f2ecc 100644 --- a/VectoCore/VectoCore/InputData/Reader/Impl/EngineOnlyVectoRunDataFactory.cs +++ b/VectoCore/VectoCore/InputData/Reader/Impl/EngineOnlyVectoRunDataFactory.cs @@ -30,12 +30,11 @@ */ using System.Collections.Generic; -using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCommon.InputData; using TUGraz.VectoCommon.Models; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data; namespace TUGraz.VectoCore.InputData.Reader.Impl { diff --git a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs index 0fb3381dd4..aeb35bc788 100644 --- a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs +++ b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs @@ -30,10 +30,10 @@ */ using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; using TUGraz.VectoCommon.InputData; using TUGraz.VectoCommon.Models; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.SimulationComponent.Data; diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Engine/WHRPowerMap.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Engine/WHRPowerMap.cs new file mode 100644 index 0000000000..9d998b5d8a --- /dev/null +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Engine/WHRPowerMap.cs @@ -0,0 +1,61 @@ +using System.ComponentModel.DataAnnotations; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData +{ + public class WHRPowerMap + { + protected readonly DelaunayMap WHRMap; + + public WHRPowerMap(DelaunayMap whrMap) + { + WHRMap = whrMap; + } + + public class Entry + { + [Required, SIRange(0, 5000 * Constants.RPMToRad)] public readonly PerSecond EngineSpeed; + [Required] public readonly NewtonMeter Torque; + [Required, SIRange(0, double.MaxValue)] public readonly Watt ElectricPower; + + public Entry(PerSecond engineSpeed, NewtonMeter torque, Watt electricPower) + { + EngineSpeed = engineSpeed; + Torque = torque; + ElectricPower = electricPower; + } + } + + public WHRPowerResult GetWHRPower(NewtonMeter torque, PerSecond engineSpeed, bool allowExtrapolation) + { + var result = new WHRPowerResult(); + // delaunay map needs is initialised with rpm, therefore the angularVelocity has to be converted. + var value = WHRMap.Interpolate(torque, engineSpeed); + if (value.HasValue) { + result.ElectricPower = value.Value.SI(Unit.SI.Kilo.Gramm.Per.Second).Cast<Watt>(); + return result; + } + + if (allowExtrapolation) { + result.ElectricPower = + WHRMap.Extrapolate(torque, engineSpeed).SI(Unit.SI.Kilo.Gramm.Per.Second).Cast<Watt>(); + result.Extrapolated = true; + return result; + } + + throw new VectoException("WHR Map: Interpolation failed. torque: {0}, n: {1}", torque.Value(), + engineSpeed.AsRPM); + } + } + + public class WHRPowerResult + { + public Watt ElectricPower; + public bool Extrapolated; + + } +} \ No newline at end of file diff --git a/VectoCore/VectoCore/OutputData/XML/AttributeMappings.cs b/VectoCore/VectoCore/OutputData/XML/AttributeMappings.cs index d222966f77..a8ca35ccb2 100644 --- a/VectoCore/VectoCore/OutputData/XML/AttributeMappings.cs +++ b/VectoCore/VectoCore/OutputData/XML/AttributeMappings.cs @@ -29,106 +29,112 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Collections.Generic; -using TUGraz.VectoCommon.Resources; -using TUGraz.VectoCore.InputData.Reader; -using TUGraz.VectoCore.InputData.Reader.ComponentData; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; - -namespace TUGraz.IVT.VectoXML -{ - internal static class AttributeMappings - { - public static readonly Dictionary<string, string> FuelConsumptionMapMapping = new Dictionary<string, string> { - { FuelConsumptionMapReader.Fields.EngineSpeed, XMLNames.Engine_FuelConsumptionMap_EngineSpeed_Attr }, - { FuelConsumptionMapReader.Fields.Torque, XMLNames.Engine_FuelConsumptionMap_Torque_Attr }, - { FuelConsumptionMapReader.Fields.FuelConsumption, XMLNames.Engine_FuelConsumptionMap_FuelConsumption_Attr } - }; - - public static readonly Dictionary<string, string> EngineFullLoadCurveMapping = new Dictionary<string, string> { - { FullLoadCurveReader.Fields.EngineSpeed, XMLNames.Engine_EngineFullLoadCurve_EngineSpeed_Attr }, - { FullLoadCurveReader.Fields.TorqueFullLoad, XMLNames.Engine_FullLoadCurve_MaxTorque_Attr }, - { FullLoadCurveReader.Fields.TorqueDrag, XMLNames.Engine_FullLoadCurve_DragTorque_Attr }, - { "PT1", "PT1" } - }; - - public static readonly Dictionary<string, string> ShiftPolygonMapping = new Dictionary<string, string> { - { ShiftPolygonReader.Fields.Torque, XMLNames.Gear_ShiftPolygon_EngineTorque_Attr }, - { ShiftPolygonReader.Fields.AngularSpeedDown, XMLNames.Gear_ShiftPolygonMapping_DownshiftSpeed_Attr }, - { ShiftPolygonReader.Fields.AngularSpeedUp, XMLNames.Gear_ShiftPolygonMapping_UpshiftSpeed_Attr } - }; - - public static readonly Dictionary<string, string> AuxMapMapping = new Dictionary<string, string>() { - { AuxiliaryDataReader.Fields.AuxSpeed, XMLNames.Aux_AuxMap_AuxiliarySpeed_Attr }, - { AuxiliaryDataReader.Fields.MechPower, XMLNames.Aux_AuxMap_MechanicalPower_Attr }, - { AuxiliaryDataReader.Fields.SupplyPower, XMLNames.Auxr_AuxMapMapping_SupplyPower_Attr } - }; - - public static readonly Dictionary<string, string> RetarderLossmapMapping = new Dictionary<string, string> { - { RetarderLossMapReader.Fields.RetarderSpeed, XMLNames.Retarder_RetarderLossmap_RetarderSpeed_Attr }, - { RetarderLossMapReader.Fields.TorqueLoss, XMLNames.Retarder_RetarderLossmap_TorqueLoss_Attr } - }; - - public static readonly Dictionary<string, string> TorqueConverterDataMapping = new Dictionary<string, string>() { - { TorqueConverterDataReader.Fields.SpeedRatio, XMLNames.TorqueConverterData_SpeedRatio_Attr }, - { TorqueConverterDataReader.Fields.TorqueRatio, XMLNames.TorqueConverterData_TorqueRatio_Attr }, - { TorqueConverterDataReader.Fields.CharacteristicTorque, XMLNames.TorqueConverterDataMapping_InputTorqueRef_Attr } - }; - - public static readonly Dictionary<string, string> TransmissionLossmapMapping = new Dictionary<string, string>() { - { TransmissionLossMapReader.Fields.InputSpeed, XMLNames.TransmissionLossmap_InputSpeed_Attr }, - { TransmissionLossMapReader.Fields.InputTorque, XMLNames.TransmissionLossmap_InputTorque_Attr }, - { TransmissionLossMapReader.Fields.TorqeLoss, XMLNames.TransmissionLossmap_TorqueLoss_Attr } - }; - - public static readonly Dictionary<string, string> DriverAccelerationCurveMapping = new Dictionary<string, string>() { - { AccelerationCurveReader.Fields.Velocity, XMLNames.Vehicle_CrosswindCorrectionMap_VehicleSpeed_Attr }, - { AccelerationCurveReader.Fields.Acceleration, XMLNames.Vehicle_AccelerationCurve_MaxAcceleration_Attr }, - { AccelerationCurveReader.Fields.Deceleration, XMLNames.Vehicle_AccelerationCurve_MaxDeceleration_Attr } - }; - - public static readonly Dictionary<string, string> CoastingDFTargetSpeedLookupMapping = - new Dictionary<string, string>() { - { - LACDecisionFactor.LACDecisionFactorVTarget.Fields.TargetVelocity, - XMLNames.Driver_CoastingDFTargetSpeedLookupMapping_TargetVelocity_Attr - }, { - LACDecisionFactor.LACDecisionFactorVTarget.Fields.DecisionFactor, - XMLNames.Driver_CoastingDFTargetSpeedLookupMapping_DecisionFactor_Attr - } - }; - - public static readonly Dictionary<string, string> CoastingDFVelocityDropLookupMapping = - new Dictionary<string, string>() { - { - LACDecisionFactor.LACDecisionFactorVdrop.Fields.VelocityDrop, - XMLNames.Driver_CoastingDFVelocityDropLookupMapping_VelocityDrop_Attr - }, { - LACDecisionFactor.LACDecisionFactorVdrop.Fields.DecisionFactor, - XMLNames.Driver_CoastingDFVelocityDropLookupMapping_DecisionFactorDrop_Attr - } - }; - - public static readonly Dictionary<string, string> CrossWindCorrectionMapping = new Dictionary<string, string>() { - { - CrossWindCorrectionCurveReader.FieldsSpeedDependent.Velocity, - XMLNames.Vehicle_CrosswindCorrectionMap_VehicleSpeed_Attr - }, - { CrossWindCorrectionCurveReader.FieldsSpeedDependent.Cd, XMLNames.Vehicle_CrosswindCorrectionMap_CdScalingFactor }, - { CrossWindCorrectionCurveReader.FieldsCdxABeta.Beta, XMLNames.Vehicle_CrosswindCorrectionMap_Beta }, - { CrossWindCorrectionCurveReader.FieldsCdxABeta.DeltaCdxA, XMLNames.Vehicle_CrosswindCorrectionMap_DeltaCdxA }, - }; - - public static readonly Dictionary<string, string> PTOLossMap = new Dictionary<string, string> { - { PTOIdleLossMapReader.Fields.EngineSpeed, XMLNames.Vehicle_PTOIdleLossMap_EngineSpeed_Attr }, - { PTOIdleLossMapReader.Fields.PTOTorque, XMLNames.Vehicle_PTOIdleLossMap_TorqueLoss_Attr }, - }; - - public static readonly Dictionary<string, string> PTOCycleMap = new Dictionary<string, string>() { - { DrivingCycleDataReader.Fields.Time, XMLNames.Vehicle_PTOCycle_Time_Attr }, - { DrivingCycleDataReader.Fields.EngineSpeed, XMLNames.Vehicle_PTOCycle_EngineSpeed_Attr }, - { DrivingCycleDataReader.Fields.PTOTorque, XMLNames.Vehicle_PTOCycle_Torque_Attr }, - }; - } +using System.Collections.Generic; +using TUGraz.VectoCommon.Resources; +using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; + +namespace TUGraz.IVT.VectoXML +{ + internal static class AttributeMappings + { + public static readonly Dictionary<string, string> FuelConsumptionMapMapping = new Dictionary<string, string> { + { FuelConsumptionMapReader.Fields.EngineSpeed, XMLNames.Engine_FuelConsumptionMap_EngineSpeed_Attr }, + { FuelConsumptionMapReader.Fields.Torque, XMLNames.Engine_FuelConsumptionMap_Torque_Attr }, + { FuelConsumptionMapReader.Fields.FuelConsumption, XMLNames.Engine_FuelConsumptionMap_FuelConsumption_Attr } + }; + + public static readonly Dictionary<string, string> WHRPowerMapMapping = new Dictionary<string, string> { + { WHRPowerReader.Fields.EngineSpeed, XMLNames.Engine_FuelConsumptionMap_EngineSpeed_Attr }, + { WHRPowerReader.Fields.Torque, XMLNames.Engine_FuelConsumptionMap_Torque_Attr }, + { WHRPowerReader.Fields.ElectricPower, XMLNames.Engine_FuelConsumptionMap_WHRElPower_Attr } + }; + + public static readonly Dictionary<string, string> EngineFullLoadCurveMapping = new Dictionary<string, string> { + { FullLoadCurveReader.Fields.EngineSpeed, XMLNames.Engine_EngineFullLoadCurve_EngineSpeed_Attr }, + { FullLoadCurveReader.Fields.TorqueFullLoad, XMLNames.Engine_FullLoadCurve_MaxTorque_Attr }, + { FullLoadCurveReader.Fields.TorqueDrag, XMLNames.Engine_FullLoadCurve_DragTorque_Attr }, + { "PT1", "PT1" } + }; + + public static readonly Dictionary<string, string> ShiftPolygonMapping = new Dictionary<string, string> { + { ShiftPolygonReader.Fields.Torque, XMLNames.Gear_ShiftPolygon_EngineTorque_Attr }, + { ShiftPolygonReader.Fields.AngularSpeedDown, XMLNames.Gear_ShiftPolygonMapping_DownshiftSpeed_Attr }, + { ShiftPolygonReader.Fields.AngularSpeedUp, XMLNames.Gear_ShiftPolygonMapping_UpshiftSpeed_Attr } + }; + + public static readonly Dictionary<string, string> AuxMapMapping = new Dictionary<string, string>() { + { AuxiliaryDataReader.Fields.AuxSpeed, XMLNames.Aux_AuxMap_AuxiliarySpeed_Attr }, + { AuxiliaryDataReader.Fields.MechPower, XMLNames.Aux_AuxMap_MechanicalPower_Attr }, + { AuxiliaryDataReader.Fields.SupplyPower, XMLNames.Auxr_AuxMapMapping_SupplyPower_Attr } + }; + + public static readonly Dictionary<string, string> RetarderLossmapMapping = new Dictionary<string, string> { + { RetarderLossMapReader.Fields.RetarderSpeed, XMLNames.Retarder_RetarderLossmap_RetarderSpeed_Attr }, + { RetarderLossMapReader.Fields.TorqueLoss, XMLNames.Retarder_RetarderLossmap_TorqueLoss_Attr } + }; + + public static readonly Dictionary<string, string> TorqueConverterDataMapping = new Dictionary<string, string>() { + { TorqueConverterDataReader.Fields.SpeedRatio, XMLNames.TorqueConverterData_SpeedRatio_Attr }, + { TorqueConverterDataReader.Fields.TorqueRatio, XMLNames.TorqueConverterData_TorqueRatio_Attr }, + { TorqueConverterDataReader.Fields.CharacteristicTorque, XMLNames.TorqueConverterDataMapping_InputTorqueRef_Attr } + }; + + public static readonly Dictionary<string, string> TransmissionLossmapMapping = new Dictionary<string, string>() { + { TransmissionLossMapReader.Fields.InputSpeed, XMLNames.TransmissionLossmap_InputSpeed_Attr }, + { TransmissionLossMapReader.Fields.InputTorque, XMLNames.TransmissionLossmap_InputTorque_Attr }, + { TransmissionLossMapReader.Fields.TorqeLoss, XMLNames.TransmissionLossmap_TorqueLoss_Attr } + }; + + public static readonly Dictionary<string, string> DriverAccelerationCurveMapping = new Dictionary<string, string>() { + { AccelerationCurveReader.Fields.Velocity, XMLNames.Vehicle_CrosswindCorrectionMap_VehicleSpeed_Attr }, + { AccelerationCurveReader.Fields.Acceleration, XMLNames.Vehicle_AccelerationCurve_MaxAcceleration_Attr }, + { AccelerationCurveReader.Fields.Deceleration, XMLNames.Vehicle_AccelerationCurve_MaxDeceleration_Attr } + }; + + public static readonly Dictionary<string, string> CoastingDFTargetSpeedLookupMapping = + new Dictionary<string, string>() { + { + LACDecisionFactor.LACDecisionFactorVTarget.Fields.TargetVelocity, + XMLNames.Driver_CoastingDFTargetSpeedLookupMapping_TargetVelocity_Attr + }, { + LACDecisionFactor.LACDecisionFactorVTarget.Fields.DecisionFactor, + XMLNames.Driver_CoastingDFTargetSpeedLookupMapping_DecisionFactor_Attr + } + }; + + public static readonly Dictionary<string, string> CoastingDFVelocityDropLookupMapping = + new Dictionary<string, string>() { + { + LACDecisionFactor.LACDecisionFactorVdrop.Fields.VelocityDrop, + XMLNames.Driver_CoastingDFVelocityDropLookupMapping_VelocityDrop_Attr + }, { + LACDecisionFactor.LACDecisionFactorVdrop.Fields.DecisionFactor, + XMLNames.Driver_CoastingDFVelocityDropLookupMapping_DecisionFactorDrop_Attr + } + }; + + public static readonly Dictionary<string, string> CrossWindCorrectionMapping = new Dictionary<string, string>() { + { + CrossWindCorrectionCurveReader.FieldsSpeedDependent.Velocity, + XMLNames.Vehicle_CrosswindCorrectionMap_VehicleSpeed_Attr + }, + { CrossWindCorrectionCurveReader.FieldsSpeedDependent.Cd, XMLNames.Vehicle_CrosswindCorrectionMap_CdScalingFactor }, + { CrossWindCorrectionCurveReader.FieldsCdxABeta.Beta, XMLNames.Vehicle_CrosswindCorrectionMap_Beta }, + { CrossWindCorrectionCurveReader.FieldsCdxABeta.DeltaCdxA, XMLNames.Vehicle_CrosswindCorrectionMap_DeltaCdxA }, + }; + + public static readonly Dictionary<string, string> PTOLossMap = new Dictionary<string, string> { + { PTOIdleLossMapReader.Fields.EngineSpeed, XMLNames.Vehicle_PTOIdleLossMap_EngineSpeed_Attr }, + { PTOIdleLossMapReader.Fields.PTOTorque, XMLNames.Vehicle_PTOIdleLossMap_TorqueLoss_Attr }, + }; + + public static readonly Dictionary<string, string> PTOCycleMap = new Dictionary<string, string>() { + { DrivingCycleDataReader.Fields.Time, XMLNames.Vehicle_PTOCycle_Time_Attr }, + { DrivingCycleDataReader.Fields.EngineSpeed, XMLNames.Vehicle_PTOCycle_EngineSpeed_Attr }, + { DrivingCycleDataReader.Fields.PTOTorque, XMLNames.Vehicle_PTOCycle_Torque_Attr }, + }; + } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Dummy/EngineFLDTest.cs b/VectoCore/VectoCoreTest/Dummy/EngineFLDTest.cs index 42108fb3ed..64bedf88c5 100644 --- a/VectoCore/VectoCoreTest/Dummy/EngineFLDTest.cs +++ b/VectoCore/VectoCoreTest/Dummy/EngineFLDTest.cs @@ -33,8 +33,8 @@ using System; using System.Diagnostics; using System.IO; using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.InputData.Reader; using NUnit.Framework; +using TUGraz.VectoCore.InputData.Reader.ComponentData; namespace TUGraz.VectoCore.Tests.Dummy { diff --git a/VectoCore/VectoCoreTest/Integration/BusAuxiliaries/AuxDemandTest.cs b/VectoCore/VectoCoreTest/Integration/BusAuxiliaries/AuxDemandTest.cs index 5050d645cc..92913bfb50 100644 --- a/VectoCore/VectoCoreTest/Integration/BusAuxiliaries/AuxDemandTest.cs +++ b/VectoCore/VectoCoreTest/Integration/BusAuxiliaries/AuxDemandTest.cs @@ -33,7 +33,6 @@ using System.Collections.Generic; using NUnit.Framework; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.InputData.Reader; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.Simulation.DataBus; using TUGraz.VectoCore.Models.Simulation.Impl; @@ -42,6 +41,7 @@ using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; using TUGraz.VectoCore.Models.SimulationComponent.Impl; using TUGraz.VectoCore.Tests.Utils; using System.IO; +using TUGraz.VectoCore.InputData.Reader.ComponentData; namespace TUGraz.VectoCore.Tests.Integration.BusAuxiliaries { diff --git a/VectoCore/VectoCoreTest/Integration/EngineOnlyCycle/EngineOnlyCycleTest.cs b/VectoCore/VectoCoreTest/Integration/EngineOnlyCycle/EngineOnlyCycleTest.cs index cfabc0c1a8..890210a065 100644 --- a/VectoCore/VectoCoreTest/Integration/EngineOnlyCycle/EngineOnlyCycleTest.cs +++ b/VectoCore/VectoCoreTest/Integration/EngineOnlyCycle/EngineOnlyCycleTest.cs @@ -35,7 +35,7 @@ using NUnit.Framework; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.Simulation.Data; diff --git a/VectoCore/VectoCoreTest/Integration/SimpleDrivingCycles.cs b/VectoCore/VectoCoreTest/Integration/SimpleDrivingCycles.cs index e2563340d1..e473262876 100644 --- a/VectoCore/VectoCoreTest/Integration/SimpleDrivingCycles.cs +++ b/VectoCore/VectoCoreTest/Integration/SimpleDrivingCycles.cs @@ -31,7 +31,7 @@ using System.Diagnostics.CodeAnalysis; using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.SimulationComponent.Data; using TUGraz.VectoCore.Tests.Utils; diff --git a/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs b/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs index a7bdea401c..1b83d356fd 100644 --- a/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs +++ b/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs @@ -40,8 +40,7 @@ using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.InputData.FileIO.JSON; using TUGraz.VectoCore.InputData.FileIO.XML; -using TUGraz.VectoCore.InputData.FileIO.XML.Declaration; -using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.SimulationComponent.Data; diff --git a/VectoCore/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs b/VectoCore/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs index 908703b4a5..24c4e69236 100644 --- a/VectoCore/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs +++ b/VectoCore/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs @@ -34,7 +34,7 @@ using NUnit.Framework; using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Simulation.Impl; using TUGraz.VectoCore.Models.SimulationComponent.Data; diff --git a/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs b/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs index 4d436cc724..371f44ac54 100644 --- a/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs +++ b/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs @@ -36,7 +36,6 @@ using System.Linq; using System.Collections.Generic; using TUGraz.VectoCore.OutputData; using TUGraz.VectoCore.Tests.Utils; -using TUGraz.VectoCore.InputData.Reader; using TUGraz.VectoCore.OutputData.FileIO; using TUGraz.VectoCore.InputData.FileIO.JSON; using TUGraz.VectoCore.Models.Simulation.Impl; @@ -48,6 +47,7 @@ using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; using TUGraz.VectoCore.Models.SimulationComponent.Impl; using NUnit.Framework; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.Declaration; namespace TUGraz.VectoCore.Tests.Models.Simulation diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponent/DistanceBasedDrivingCycleTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponent/DistanceBasedDrivingCycleTest.cs index fcf787829e..2eea155463 100644 --- a/VectoCore/VectoCoreTest/Models/SimulationComponent/DistanceBasedDrivingCycleTest.cs +++ b/VectoCore/VectoCoreTest/Models/SimulationComponent/DistanceBasedDrivingCycleTest.cs @@ -36,14 +36,11 @@ using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.InputData.FileIO.JSON; -using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Simulation.Impl; using TUGraz.VectoCore.Models.SimulationComponent.Data; using TUGraz.VectoCore.Models.SimulationComponent.Impl; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.OutputData.FileIO; using TUGraz.VectoCore.Tests.Integration; using TUGraz.VectoCore.Tests.Utils; diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponent/VTPCycleValidationTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponent/VTPCycleValidationTest.cs index aac7d72921..f153a1ec34 100644 --- a/VectoCore/VectoCoreTest/Models/SimulationComponent/VTPCycleValidationTest.cs +++ b/VectoCore/VectoCoreTest/Models/SimulationComponent/VTPCycleValidationTest.cs @@ -39,6 +39,7 @@ using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.Configuration; using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.Simulation.Impl; diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponentData/DistanceCycleDataTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponentData/DistanceCycleDataTest.cs index c4d86c085b..95cfd2cdf6 100644 --- a/VectoCore/VectoCoreTest/Models/SimulationComponentData/DistanceCycleDataTest.cs +++ b/VectoCore/VectoCoreTest/Models/SimulationComponentData/DistanceCycleDataTest.cs @@ -32,7 +32,7 @@ using NUnit.Framework; using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.InputData.Reader; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.SimulationComponent.Data; using TUGraz.VectoCore.Tests.Integration; using TUGraz.VectoCore.Tests.Utils; diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponentData/FuelConsumptionMapTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponentData/FuelConsumptionMapTest.cs index 6de2f99f6b..957b76d820 100644 --- a/VectoCore/VectoCoreTest/Models/SimulationComponentData/FuelConsumptionMapTest.cs +++ b/VectoCore/VectoCoreTest/Models/SimulationComponentData/FuelConsumptionMapTest.cs @@ -29,45 +29,46 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; -using NUnit.Framework; - -namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData -{ - [TestFixture] - public class FuelConsumptionMapTest - { - private const double Tolerance = 0.0001; - - [TestCase] - public void TestFuelConsumption_FixedPoints() - { - var map = FuelConsumptionMapReader.ReadFromFile(@"TestData\Components\24t Coach.vmap"); - var lines = File.ReadAllLines(@"TestData\Components\24t Coach.vmap").Skip(1).ToArray(); - AssertMapValuesEqual(lines, map); - } - - [TestCase] - public void TestFuelConsumption_InterpolatedPoints() - { - var map = FuelConsumptionMapReader.ReadFromFile(@"TestData\Components\24t Coach.vmap"); - var lines = File.ReadAllLines(@"TestData\Components\24t CoachInterpolated.vmap").Skip(1).ToArray(); - AssertMapValuesEqual(lines, map); - } - - private static void AssertMapValuesEqual(IReadOnlyList<string> lines, FuelConsumptionMap map) - { +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using NUnit.Framework; +using TUGraz.VectoCore.InputData.Reader.ComponentData; + +namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData +{ + [TestFixture] + public class FuelConsumptionMapTest + { + private const double Tolerance = 0.0001; + + [TestCase] + public void TestFuelConsumption_FixedPoints() + { + var map = FuelConsumptionMapReader.ReadFromFile(@"TestData\Components\24t Coach.vmap"); + var lines = File.ReadAllLines(@"TestData\Components\24t Coach.vmap").Skip(1).ToArray(); + AssertMapValuesEqual(lines, map); + } + + [TestCase] + public void TestFuelConsumption_InterpolatedPoints() + { + var map = FuelConsumptionMapReader.ReadFromFile(@"TestData\Components\24t Coach.vmap"); + var lines = File.ReadAllLines(@"TestData\Components\24t CoachInterpolated.vmap").Skip(1).ToArray(); + AssertMapValuesEqual(lines, map); + } + + private static void AssertMapValuesEqual(IReadOnlyList<string> lines, FuelConsumptionMap map) + { for (var i = 1; i < lines.Count; i++) { - var entry = lines[i].Split(',').Select(x => double.Parse(x, CultureInfo.InvariantCulture)).ToArray(); - - Assert.AreEqual(entry[2].SI(Unit.SI.Gramm.Per.Hour).Value(), - map.GetFuelConsumption(entry[1].SI<NewtonMeter>(), entry[0].RPMtoRad(), true).Value.Value(), Tolerance); - } - } - } + var entry = lines[i].Split(',').Select(x => double.Parse(x, CultureInfo.InvariantCulture)).ToArray(); + + Assert.AreEqual(entry[2].SI(Unit.SI.Gramm.Per.Hour).Value(), + map.GetFuelConsumption(entry[1].SI<NewtonMeter>(), entry[0].RPMtoRad(), true).Value.Value(), Tolerance); + } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Reports/ModDataTest.cs b/VectoCore/VectoCoreTest/Reports/ModDataTest.cs index d938e21737..465a206490 100644 --- a/VectoCore/VectoCoreTest/Reports/ModDataTest.cs +++ b/VectoCore/VectoCoreTest/Reports/ModDataTest.cs @@ -50,7 +50,7 @@ using TUGraz.VectoCore.Tests.Utils; using System.IO; using Ninject; using TUGraz.VectoCore.InputData.FileIO.XML; -using TUGraz.VectoCore.InputData.FileIO.XML.Declaration; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Tests.Models.Simulation; diff --git a/VectoCore/VectoCoreTest/Utils/MockEngineDataProvider.cs b/VectoCore/VectoCoreTest/Utils/MockEngineDataProvider.cs index 895fc7be42..6489e8ab38 100644 --- a/VectoCore/VectoCoreTest/Utils/MockEngineDataProvider.cs +++ b/VectoCore/VectoCoreTest/Utils/MockEngineDataProvider.cs @@ -68,6 +68,8 @@ namespace TUGraz.VectoCore.Tests.Utils get { return new[] { this }.Cast<IEngineFuelDelcarationInputData>().ToList(); } } + public IWHRData WasteHeatRecoveryData { get; } + public Watt RatedPowerDeclared { get; set; } public PerSecond RatedSpeedDeclared { get; set; } public NewtonMeter MaxTorqueDeclared { get; set; } -- GitLab