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