From ce80e54ba99a2d3c84d568a64d6fecb2475bc9ab Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Wed, 22 Jul 2015 15:17:14 +0200
Subject: [PATCH] adapt file-I/O to read new input files for gearbox, engine.
 fix engine-only simulation runs / time-based run

---
 .../FileIO/DeclarationFile/EngineFileDecl.cs  |    5 +-
 .../FileIO/DeclarationFile/GearboxFileDecl.cs |    3 +-
 .../FileIO/EngineeringFile/EngineFileEng.cs   |    2 +-
 .../FileIO/EngineeringFile/GearboxFileEng.cs  |    2 +-
 .../AbstractSimulationDataAdapter.cs          |    4 +-
 .../DeclarationDataAdapter.cs                 |   35 +-
 .../EngineeringDataAdapter.cs                 |   24 +-
 .../DeclarationModeSimulationDataReader.cs    |    8 +-
 .../EngineeringModeSimulationDataReader.cs    |    8 +-
 .../Models/Declaration/DeclarationData.cs     |    5 +-
 .../Models/Simulation/Impl/DistanceRun.cs     |    8 +-
 .../Simulation/Impl/PowertrainBuilder.cs      |    8 +-
 .../Simulation/Impl/SimulatorFactory.cs       |    9 +-
 VectoCore/Models/Simulation/Impl/TimeRun.cs   |   30 +
 VectoCore/Models/Simulation/Impl/VectoRun.cs  |    4 +-
 .../Simulation/Impl/VehicleContainer.cs       |    4 +-
 .../Data/CombustionEngineData.cs              |   43 +-
 ...ullLoadCurve.cs => EngineFullLoadCurve.cs} | 1004 ++++++++---------
 .../Data/GearFullLoadCurve.cs                 |   10 +
 .../Data/Gearbox/GearData.cs                  |   19 +-
 .../Models/SimulationComponent/Impl/Clutch.cs |    2 +-
 .../Impl/CombustionEngine.cs                  |   36 +-
 .../Impl/TimeBasedDrivingCycle.cs             |    9 +-
 VectoCore/VectoCore.csproj                    |    4 +-
 .../Models/Simulation/DrivingCycleTests.cs    |    2 +-
 .../CombustionEngineTest.cs                   |    6 +-
 .../FullLoadCurveTest.cs                      |   20 +-
 .../Components/12t Delivery Truck.veng        |   23 +-
 .../Components/12t Delivery Truck.vgbx        |   26 +-
 .../TestData/Components/24t Coach.veng        |   15 +-
 .../TestData/Components/24t Coach.vgbx        |   32 +-
 31 files changed, 727 insertions(+), 683 deletions(-)
 create mode 100644 VectoCore/Models/Simulation/Impl/TimeRun.cs
 rename VectoCore/Models/SimulationComponent/Data/Engine/{FullLoadCurve.cs => EngineFullLoadCurve.cs} (94%)
 create mode 100644 VectoCore/Models/SimulationComponent/Data/GearFullLoadCurve.cs

diff --git a/VectoCore/FileIO/DeclarationFile/EngineFileDecl.cs b/VectoCore/FileIO/DeclarationFile/EngineFileDecl.cs
index ebf5920a64..baa80e0352 100644
--- a/VectoCore/FileIO/DeclarationFile/EngineFileDecl.cs
+++ b/VectoCore/FileIO/DeclarationFile/EngineFileDecl.cs
@@ -34,7 +34,7 @@ namespace TUGraz.VectoCore.FileIO.DeclarationFile
 	///  }
 	/// }
 	/// </code>
-	internal class EngineFileV2Declaration : VectoEngineFile
+	internal class EngineFileV3Declaration : VectoEngineFile
 	{
 		[JsonProperty(Required = Required.Always)] public JsonDataHeader Header;
 		[JsonProperty(Required = Required.Always)] public DataBodyDecl Body;
@@ -60,7 +60,8 @@ namespace TUGraz.VectoCore.FileIO.DeclarationFile
 			/// </summary>
 			[JsonProperty("IdlingSpeed", Required = Required.Always)] public double IdleSpeed;
 
-			[JsonProperty(Required = Required.Always)] public IList<DataFullLoadCurve> FullLoadCurves;
+			//[JsonProperty(Required = Required.Always)] public IList<DataFullLoadCurve> FullLoadCurves;
+			[JsonProperty(Required = Required.Always)] public string FullLoadCurve;
 
 			/// <summary>
 			///     The Fuel Consumption Map is used to calculate the base Fuel Consumption (FC) value.
diff --git a/VectoCore/FileIO/DeclarationFile/GearboxFileDecl.cs b/VectoCore/FileIO/DeclarationFile/GearboxFileDecl.cs
index a4d7021cdc..146419ff95 100644
--- a/VectoCore/FileIO/DeclarationFile/GearboxFileDecl.cs
+++ b/VectoCore/FileIO/DeclarationFile/GearboxFileDecl.cs
@@ -30,7 +30,7 @@ namespace TUGraz.VectoCore.FileIO.DeclarationFile
 	///		...
 	///		]
 	/// }
-	public class GearboxFileV4Declaration : VectoGearboxFile
+	public class GearboxFileV5Declaration : VectoGearboxFile
 	{
 		[JsonProperty(Required = Required.Always)] public JsonDataHeader Header;
 		[JsonProperty(Required = Required.Always)] public DataBodyDecl Body;
@@ -53,6 +53,7 @@ namespace TUGraz.VectoCore.FileIO.DeclarationFile
 		{
 			[JsonProperty(Required = Required.Always)] public double Ratio;
 			[JsonProperty(Required = Required.Always)] public string LossMap;
+			[JsonProperty] public string FullLoadCurve;
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/FileIO/EngineeringFile/EngineFileEng.cs b/VectoCore/FileIO/EngineeringFile/EngineFileEng.cs
index 78e9288358..4d4771b06a 100644
--- a/VectoCore/FileIO/EngineeringFile/EngineFileEng.cs
+++ b/VectoCore/FileIO/EngineeringFile/EngineFileEng.cs
@@ -3,7 +3,7 @@ using TUGraz.VectoCore.FileIO.DeclarationFile;
 
 namespace TUGraz.VectoCore.FileIO.EngineeringFile
 {
-	internal class EngineFileV2Engineering : EngineFileV2Declaration
+	internal class EngineFileV3Engineering : EngineFileV3Declaration
 	{
 		[JsonProperty(Required = Required.Always)] public new DataBodyEng Body;
 
diff --git a/VectoCore/FileIO/EngineeringFile/GearboxFileEng.cs b/VectoCore/FileIO/EngineeringFile/GearboxFileEng.cs
index 17d164efb2..ad0c4847e4 100644
--- a/VectoCore/FileIO/EngineeringFile/GearboxFileEng.cs
+++ b/VectoCore/FileIO/EngineeringFile/GearboxFileEng.cs
@@ -48,7 +48,7 @@ namespace TUGraz.VectoCore.FileIO.EngineeringFile
 	///		...
 	///		]
 	/// }
-	public class GearboxFileV4Engineering : GearboxFileV4Declaration
+	public class GearboxFileV5Engineering : GearboxFileV5Declaration
 	{
 		[JsonProperty(Required = Required.Always)] public new DataBodyEng Body;
 
diff --git a/VectoCore/FileIO/Reader/DataObjectAdaper/AbstractSimulationDataAdapter.cs b/VectoCore/FileIO/Reader/DataObjectAdaper/AbstractSimulationDataAdapter.cs
index deb799e312..b970b1c3a1 100644
--- a/VectoCore/FileIO/Reader/DataObjectAdaper/AbstractSimulationDataAdapter.cs
+++ b/VectoCore/FileIO/Reader/DataObjectAdaper/AbstractSimulationDataAdapter.cs
@@ -51,7 +51,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 			return retVal;
 		}
 
-		internal CombustionEngineData SetCommonCombustionEngineData(EngineFileV2Declaration.DataBodyDecl data, string basePath)
+		internal CombustionEngineData SetCommonCombustionEngineData(EngineFileV3Declaration.DataBodyDecl data, string basePath)
 		{
 			var retVal = new CombustionEngineData() {
 				SavedInDeclarationMode = data.SavedInDeclarationMode,
@@ -66,7 +66,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 			return retVal;
 		}
 
-		internal GearboxData SetCommonGearboxData(GearboxFileV4Declaration.DataBodyDecl data)
+		internal GearboxData SetCommonGearboxData(GearboxFileV5Declaration.DataBodyDecl data)
 		{
 			return new GearboxData() {
 				SavedInDeclarationMode = data.SavedInDeclarationMode,
diff --git a/VectoCore/FileIO/Reader/DataObjectAdaper/DeclarationDataAdapter.cs b/VectoCore/FileIO/Reader/DataObjectAdaper/DeclarationDataAdapter.cs
index c33723ecf6..5c62e1c806 100644
--- a/VectoCore/FileIO/Reader/DataObjectAdaper/DeclarationDataAdapter.cs
+++ b/VectoCore/FileIO/Reader/DataObjectAdaper/DeclarationDataAdapter.cs
@@ -36,7 +36,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 
 		public override CombustionEngineData CreateEngineData(VectoEngineFile engine)
 		{
-			var fileV2Decl = engine as EngineFileV2Declaration;
+			var fileV2Decl = engine as EngineFileV3Declaration;
 			if (fileV2Decl != null) {
 				return CreateEngineData(fileV2Decl);
 			}
@@ -45,7 +45,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 
 		public override GearboxData CreateGearboxData(VectoGearboxFile gearbox, CombustionEngineData engine)
 		{
-			var fileV5Decl = gearbox as GearboxFileV4Declaration;
+			var fileV5Decl = gearbox as GearboxFileV5Declaration;
 			if (fileV5Decl != null) {
 				return CreateGearboxData(fileV5Decl, engine);
 			}
@@ -143,18 +143,17 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 			return retVal;
 		}
 
-		internal CombustionEngineData CreateEngineData(EngineFileV2Declaration engine)
+		internal CombustionEngineData CreateEngineData(EngineFileV3Declaration engine)
 		{
 			var retVal = SetCommonCombustionEngineData(engine.Body, engine.BasePath);
 			retVal.Inertia = DeclarationData.Engine.EngineInertia(retVal.Displacement);
-			foreach (var entry in engine.Body.FullLoadCurves) {
-				retVal.AddFullLoadCurve(entry.Gears, FullLoadCurve.ReadFromFile(Path.Combine(engine.BasePath, entry.Path), true));
-			}
+			retVal.FullLoadCurve = EngineFullLoadCurve.ReadFromFile(Path.Combine(engine.BasePath, engine.Body.FullLoadCurve),
+				true);
 
 			return retVal;
 		}
 
-		internal GearboxData CreateGearboxData(GearboxFileV4Declaration gearbox, CombustionEngineData engine)
+		internal GearboxData CreateGearboxData(GearboxFileV5Declaration gearbox, CombustionEngineData engine)
 		{
 			var retVal = SetCommonGearboxData(gearbox.Body);
 
@@ -181,17 +180,29 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 			for (uint i = 0; i < gearbox.Body.Gears.Count; i++) {
 				var gearSettings = gearbox.Body.Gears[(int)i];
 				var lossMapPath = Path.Combine(gearbox.BasePath, gearSettings.LossMap);
-				TransmissionLossMap lossMap = TransmissionLossMap.ReadFromFile(lossMapPath, gearSettings.Ratio);
+				var lossMap = TransmissionLossMap.ReadFromFile(lossMapPath, gearSettings.Ratio);
 
 
 				if (i == 0) {
-					retVal.AxleGearData = new GearData(lossMap, null, gearSettings.Ratio, false);
+					retVal.AxleGearData = new GearData() {
+						LossMap = lossMap,
+						Ratio = gearSettings.Ratio,
+						TorqueConverterActive = false
+					};
 				} else {
-					var shiftPolygon = DeclarationData.Gearbox.ComputeShiftPolygon(engine, i);
-					retVal._gearData.Add(i, new GearData(lossMap, shiftPolygon, gearSettings.Ratio, false));
+					var fullLoad = !String.IsNullOrEmpty(gearSettings.FullLoadCurve) && gearSettings.FullLoadCurve.Equals("<NOFILE>")
+						? GearFullLoadCurve.ReadFromFile(Path.Combine(gearbox.BasePath, gearSettings.FullLoadCurve))
+						: null;
+					var shiftPolygon = DeclarationData.Gearbox.ComputeShiftPolygon(fullLoad, engine);
+
+					retVal._gearData.Add(i, new GearData() {
+						LossMap = lossMap,
+						ShiftPolygon = shiftPolygon,
+						Ratio = gearSettings.Ratio,
+						TorqueConverterActive = false
+					});
 				}
 			}
-
 			return retVal;
 		}
 	}
diff --git a/VectoCore/FileIO/Reader/DataObjectAdaper/EngineeringDataAdapter.cs b/VectoCore/FileIO/Reader/DataObjectAdaper/EngineeringDataAdapter.cs
index 01880224d1..002aed5ccf 100644
--- a/VectoCore/FileIO/Reader/DataObjectAdaper/EngineeringDataAdapter.cs
+++ b/VectoCore/FileIO/Reader/DataObjectAdaper/EngineeringDataAdapter.cs
@@ -31,7 +31,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 
 		public override CombustionEngineData CreateEngineData(VectoEngineFile engine)
 		{
-			var fileV2Eng = engine as EngineFileV2Engineering;
+			var fileV2Eng = engine as EngineFileV3Engineering;
 			if (fileV2Eng != null) {
 				return CreateEngineData(fileV2Eng);
 			}
@@ -40,7 +40,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 
 		public override GearboxData CreateGearboxData(VectoGearboxFile gearbox, CombustionEngineData engine)
 		{
-			var fileV5Eng = gearbox as GearboxFileV4Engineering;
+			var fileV5Eng = gearbox as GearboxFileV5Engineering;
 			if (fileV5Eng != null) {
 				return CreateGearboxData(fileV5Eng);
 			}
@@ -125,13 +125,12 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 		/// </summary>
 		/// <param name="engine">Engin-Data file (Engineering mode)</param>
 		/// <returns></returns>
-		internal CombustionEngineData CreateEngineData(EngineFileV2Engineering engine)
+		internal CombustionEngineData CreateEngineData(EngineFileV3Engineering engine)
 		{
 			var retVal = SetCommonCombustionEngineData(engine.Body, engine.BasePath);
 			retVal.Inertia = engine.Body.Inertia.SI<KilogramSquareMeter>();
-			foreach (var entry in engine.Body.FullLoadCurves) {
-				retVal.AddFullLoadCurve(entry.Gears, FullLoadCurve.ReadFromFile(Path.Combine(engine.BasePath, entry.Path), false));
-			}
+			retVal.FullLoadCurve = EngineFullLoadCurve.ReadFromFile(Path.Combine(engine.BasePath, engine.Body.FullLoadCurve),
+				false);
 
 			return retVal;
 		}
@@ -143,7 +142,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 		/// </summary>
 		/// <param name="gearbox"></param>
 		/// <returns></returns>
-		internal GearboxData CreateGearboxData(GearboxFileV4Engineering gearbox)
+		internal GearboxData CreateGearboxData(GearboxFileV5Engineering gearbox)
 		{
 			var retVal = SetCommonGearboxData(gearbox.Body);
 
@@ -169,8 +168,17 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper
 				var shiftPolygon = !String.IsNullOrEmpty(gearSettings.ShiftPolygon)
 					? ShiftPolygon.ReadFromFile(Path.Combine(gearbox.BasePath, gearSettings.ShiftPolygon))
 					: null;
+				var fullLoad = !String.IsNullOrEmpty(gearSettings.FullLoadCurve) && !gearSettings.FullLoadCurve.Equals("<NOFILE>")
+					? GearFullLoadCurve.ReadFromFile(Path.Combine(gearbox.BasePath, gearSettings.FullLoadCurve))
+					: null;
 
-				var gear = new GearData(lossMap, shiftPolygon, gearSettings.Ratio, gearSettings.TCactive);
+				var gear = new GearData() {
+					LossMap = lossMap,
+					ShiftPolygon = shiftPolygon,
+					FullLoadCurve = fullLoad,
+					Ratio = gearSettings.Ratio,
+					TorqueConverterActive = gearSettings.TCactive
+				};
 				if (i == 0) {
 					retVal.AxleGearData = gear;
 				} else {
diff --git a/VectoCore/FileIO/Reader/Impl/DeclarationModeSimulationDataReader.cs b/VectoCore/FileIO/Reader/Impl/DeclarationModeSimulationDataReader.cs
index 75cb4047c5..eb996b81e9 100644
--- a/VectoCore/FileIO/Reader/Impl/DeclarationModeSimulationDataReader.cs
+++ b/VectoCore/FileIO/Reader/Impl/DeclarationModeSimulationDataReader.cs
@@ -115,8 +115,8 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl
 			CheckForDeclarationMode(fileInfo, "Engine");
 
 			switch (fileInfo.Version) {
-				case 2:
-					Engine = JsonConvert.DeserializeObject<EngineFileV2Declaration>(json);
+				case 3:
+					Engine = JsonConvert.DeserializeObject<EngineFileV3Declaration>(json);
 					Engine.BasePath = Path.GetDirectoryName(file);
 					break;
 				default:
@@ -131,8 +131,8 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl
 			CheckForDeclarationMode(fileInfo, "Gearbox");
 
 			switch (fileInfo.Version) {
-				case 4:
-					Gearbox = JsonConvert.DeserializeObject<GearboxFileV4Declaration>(json);
+				case 5:
+					Gearbox = JsonConvert.DeserializeObject<GearboxFileV5Declaration>(json);
 					Gearbox.BasePath = Path.GetDirectoryName(file);
 					break;
 				default:
diff --git a/VectoCore/FileIO/Reader/Impl/EngineeringModeSimulationDataReader.cs b/VectoCore/FileIO/Reader/Impl/EngineeringModeSimulationDataReader.cs
index bcbd0c2a3f..a9a53668d1 100644
--- a/VectoCore/FileIO/Reader/Impl/EngineeringModeSimulationDataReader.cs
+++ b/VectoCore/FileIO/Reader/Impl/EngineeringModeSimulationDataReader.cs
@@ -196,8 +196,8 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl
 			CheckForEngineeringMode(fileInfo, "Engine");
 
 			switch (fileInfo.Version) {
-				case 2:
-					var tmp = JsonConvert.DeserializeObject<EngineFileV2Engineering>(json);
+				case 3:
+					var tmp = JsonConvert.DeserializeObject<EngineFileV3Engineering>(json);
 					tmp.BasePath = Path.GetDirectoryName(file) + Path.DirectorySeparatorChar;
 					return tmp;
 				default:
@@ -217,8 +217,8 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl
 			CheckForEngineeringMode(fileInfo, "Gearbox");
 
 			switch (fileInfo.Version) {
-				case 4:
-					var tmp = JsonConvert.DeserializeObject<GearboxFileV4Engineering>(json);
+				case 5:
+					var tmp = JsonConvert.DeserializeObject<GearboxFileV5Engineering>(json);
 					tmp.BasePath = Path.GetDirectoryName(file) + Path.DirectorySeparatorChar;
 					return tmp;
 				default:
diff --git a/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/Models/Declaration/DeclarationData.cs
index df50040d6e..045ef0dc62 100644
--- a/VectoCore/Models/Declaration/DeclarationData.cs
+++ b/VectoCore/Models/Declaration/DeclarationData.cs
@@ -210,9 +210,10 @@ namespace TUGraz.VectoCore.Models.Declaration
 				return false;
 			}
 
-			internal static ShiftPolygon ComputeShiftPolygon(CombustionEngineData engine, uint gear)
+			internal static ShiftPolygon ComputeShiftPolygon(GearFullLoadCurve gear, CombustionEngineData engine)
 			{
-				var fullLoadCurve = engine.GetFullLoadCurve(gear);
+				// TODO: How to compute shift-polygons exactly? (merge with engine full load?)
+				var fullLoadCurve = engine.FullLoadCurve;
 				var idleSpeed = engine.IdleSpeed;
 
 				var maxTorque = fullLoadCurve.MaxLoadTorque;
diff --git a/VectoCore/Models/Simulation/Impl/DistanceRun.cs b/VectoCore/Models/Simulation/Impl/DistanceRun.cs
index ca3294473e..5c832fdf8b 100644
--- a/VectoCore/Models/Simulation/Impl/DistanceRun.cs
+++ b/VectoCore/Models/Simulation/Impl/DistanceRun.cs
@@ -10,10 +10,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 	{
 		public DistanceRun(IVehicleContainer container) : base(container) {}
 
-		protected override Connector.Ports.IResponse DoSimulationStep()
+		protected override IResponse DoSimulationStep()
 		{
-			//_dt = TimeSpan.FromSeconds(1) - TimeSpan.FromMilliseconds(_dt.Milliseconds);
-
 			// estimate distance to be traveled within the next TargetTimeInterval
 			var ds = (Container.VehicleSpeed() * Constants.SimulationSettings.TargetTimeInterval).Cast<Meter>();
 
@@ -21,7 +19,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				ds = Constants.SimulationSettings.DriveOffDistance;
 			}
 
-			var response = CyclePort.Request((Second)AbsTime, ds);
+			var response = CyclePort.Request(AbsTime, ds);
 
 			//while (response is ResponseFailTimeInterval) {
 			//	_dt = (response as ResponseFailTimeInterval).DeltaT;
@@ -32,7 +30,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				return response;
 			}
 
-			AbsTime = (AbsTime + response.SimulationInterval / 2);
+			AbsTime = AbsTime + response.SimulationInterval;
 			dt = response.SimulationInterval;
 			return response;
 		}
diff --git a/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
index f96a671e3f..81d1ebb5ad 100644
--- a/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
+++ b/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
@@ -36,8 +36,12 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			if (_engineOnly) {
 				cycle = new TimeBasedDrivingCycle(_container, data.Cycle);
 			} else {
-				//todo: make distinction between time based and distance based driving cycle!
-				cycle = new DistanceBasedDrivingCycle(_container, data.Cycle);
+				if (data.IsEngineOnly) {
+					cycle = new TimeBasedDrivingCycle(_container, data.Cycle);
+				} else {
+					//todo: make distinction between time based and distance based driving cycle!
+					cycle = new DistanceBasedDrivingCycle(_container, data.Cycle);
+				}
 			}
 			// connect cycle --> driver --> vehicle --> wheels --> axleGear --> gearBox --> retarder --> clutch
 			dynamic tmp = AddComponent(cycle, new Driver(_container, data.DriverData));
diff --git a/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs b/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs
index 66fd5f7484..de622da14f 100644
--- a/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs
+++ b/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs
@@ -78,7 +78,14 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				var sumWriterDecorator = DecorateSumWriter(data.IsEngineOnly, SumWriter, data.JobFileName, jobName, data.Cycle.Name);
 				var builder = new PowertrainBuilder(modWriter, sumWriterDecorator, DataReader.IsEngineOnly);
 
-				yield return new DistanceRun(builder.Build(data));
+				VectoRun run;
+				if (data.IsEngineOnly) {
+					run = new TimeRun(builder.Build(data));
+				} else {
+					run = new DistanceRun(builder.Build(data));
+				}
+
+				yield return run;
 			}
 		}
 
diff --git a/VectoCore/Models/Simulation/Impl/TimeRun.cs b/VectoCore/Models/Simulation/Impl/TimeRun.cs
new file mode 100644
index 0000000000..2404ffaa42
--- /dev/null
+++ b/VectoCore/Models/Simulation/Impl/TimeRun.cs
@@ -0,0 +1,30 @@
+using TUGraz.VectoCore.Models.Connector.Ports;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
+using TUGraz.VectoCore.Utils;
+
+namespace TUGraz.VectoCore.Models.Simulation.Impl
+{
+	public class TimeRun : VectoRun
+	{
+		public TimeRun(IVehicleContainer container) : base(container) {}
+
+		protected override IResponse DoSimulationStep()
+		{
+			var dt = 1.SI<Second>();
+
+			var response = CyclePort.Request(AbsTime, dt);
+
+			if (response is ResponseCycleFinished) {
+				return response;
+			}
+
+			AbsTime = AbsTime + dt;
+			return response;
+		}
+
+		protected override IResponse Initialize()
+		{
+			throw new System.NotImplementedException();
+		}
+	}
+}
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/VectoRun.cs b/VectoCore/Models/Simulation/Impl/VectoRun.cs
index 354c2d296b..ee2931f023 100644
--- a/VectoCore/Models/Simulation/Impl/VectoRun.cs
+++ b/VectoCore/Models/Simulation/Impl/VectoRun.cs
@@ -45,7 +45,9 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 
 			do {
 				response = DoSimulationStep();
-				Container.CommitSimulationStep(AbsTime, dt);
+				if (response.ResponseType == ResponseType.Success) {
+					Container.CommitSimulationStep(AbsTime, dt);
+				}
 
 				// set _dt to difference to next full second.
 				AbsTime += dt;
diff --git a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
index 0a2ea160d7..5127646e19 100644
--- a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
+++ b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
@@ -120,8 +120,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			}
 
 			if (_dataWriter != null) {
-				_dataWriter[ModalResultField.time] = time;
-				_dataWriter[ModalResultField.simulationInterval] = simulationInterval;
+				_dataWriter[ModalResultField.time] = time.Value();
+				_dataWriter[ModalResultField.simulationInterval] = simulationInterval.Value();
 				_dataWriter.CommitSimulationStep();
 			}
 		}
diff --git a/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs b/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs
index dab60bec06..63a2453586 100644
--- a/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs
+++ b/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs
@@ -15,10 +15,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 {
 	public class CombustionEngineData : SimulationComponentData
 	{
-		private readonly Dictionary<Range, FullLoadCurve> _fullLoadCurves =
-			new Dictionary<Range, FullLoadCurve>();
-
-
 		public string ModelName { get; internal set; }
 
 
@@ -56,30 +52,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 		public FuelConsumptionMap ConsumptionMap { get; internal set; }
 
 
-		public FullLoadCurve GetFullLoadCurve(uint gear)
-		{
-			var curve = _fullLoadCurves.FirstOrDefault(kv => kv.Key.Contains(gear));
-			if (curve.Key == null) {
-				throw new KeyNotFoundException(string.Format("GearData '{0}' was not found in the FullLoadCurves.", gear));
-			}
-
-			return curve.Value;
-		}
-
-		internal void AddFullLoadCurve(string gears, FullLoadCurve fullLoadCurve)
-		{
-			var range = new Range(gears);
-			if (!_fullLoadCurves.ContainsKey(range)) {
-				fullLoadCurve.EngineData = this;
-				_fullLoadCurves.Add(range, fullLoadCurve);
-			} else {
-				throw new VectoException(String.Format("FullLoadCurve for gears {0} already specified!", gears));
-			}
-		}
+		public EngineFullLoadCurve FullLoadCurve { get; internal set; }
 
 		protected bool Equals(CombustionEngineData other)
 		{
-			return Equals(_fullLoadCurves, other._fullLoadCurves) && string.Equals(ModelName, other.ModelName) &&
+			return Equals(FullLoadCurve, other.FullLoadCurve) && string.Equals(ModelName, other.ModelName) &&
 					Equals(Displacement, other.Displacement) && Equals(IdleSpeed, other.IdleSpeed) && Equals(Inertia, other.Inertia) &&
 					Equals(WHTCUrban, other.WHTCUrban) && Equals(WHTCRural, other.WHTCRural) &&
 					Equals(WHTCMotorway, other.WHTCMotorway) && Equals(ConsumptionMap, other.ConsumptionMap);
@@ -96,13 +73,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 			if (obj.GetType() != this.GetType()) {
 				return false;
 			}
-			return Equals((CombustionEngineData) obj);
+			return Equals((CombustionEngineData)obj);
 		}
 
 		public override int GetHashCode()
 		{
 			unchecked {
-				var hashCode = (_fullLoadCurves != null ? _fullLoadCurves.GetHashCode() : 0);
+				var hashCode = (FullLoadCurve != null ? FullLoadCurve.GetHashCode() : 0);
 				hashCode = (hashCode * 397) ^ (ModelName != null ? ModelName.GetHashCode() : 0);
 				hashCode = (hashCode * 397) ^ (Displacement != null ? Displacement.GetHashCode() : 0);
 				hashCode = (hashCode * 397) ^ (IdleSpeed != null ? IdleSpeed.GetHashCode() : 0);
@@ -120,18 +97,18 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 		{
 			public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
 			{
-				return sourceType == typeof (string) || base.CanConvertFrom(context, sourceType);
+				return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
 			}
 
 			public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 			{
-				return value.GetType() == typeof (string)
-					? new Range((string) value)
+				return value.GetType() == typeof(string)
+					? new Range((string)value)
 					: base.ConvertFrom(context, culture, value);
 			}
 		}
 
-		[TypeConverter(typeof (RangeConverter))]
+		[TypeConverter(typeof(RangeConverter))]
 		private class Range
 		{
 			private readonly uint _end;
@@ -174,13 +151,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 				if (obj.GetType() != GetType()) {
 					return false;
 				}
-				return Equals((Range) obj);
+				return Equals((Range)obj);
 			}
 
 			public override int GetHashCode()
 			{
 				unchecked {
-					return (int) ((_start * 397) ^ _end);
+					return (int)((_start * 397) ^ _end);
 				}
 			}
 
diff --git a/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs
similarity index 94%
rename from VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs
rename to VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs
index 6f5e4a7e23..b729e81aa5 100644
--- a/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs
+++ b/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs
@@ -1,503 +1,503 @@
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Diagnostics.Contracts;
-using System.Linq;
-using Common.Logging;
-using Newtonsoft.Json;
-using TUGraz.VectoCore.Exceptions;
-using TUGraz.VectoCore.Models.Declaration;
-using TUGraz.VectoCore.Models.SimulationComponent.Data;
-using TUGraz.VectoCore.Utils;
-
-namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
-{
-	/// <summary>
-	/// Represents the Full load curve.
-	/// </summary>
-	public class FullLoadCurve : SimulationComponentData
-	{
-		private List<FullLoadCurveEntry> _fullLoadEntries;
-		private LookupData<PerSecond, Second> _pt1Data;
-
-		private Watt _maxPower;
-
-		private PerSecond _ratedSpeed;
-		private PerSecond _preferredSpeed;
-		private PerSecond _engineSpeedLo; // 55% of Pmax
-		private PerSecond _engineSpeedHi; // 70% of Pmax
-		private PerSecond _n95hSpeed; // 95% of Pmax
-
-		public static FullLoadCurve ReadFromFile(string fileName, bool declarationMode = false)
-		{
-			var data = VectoCSVFile.Read(fileName);
-
-			//todo Contract.Requires<VectoException>(data.Columns.Count != 4, "FullLoadCurve Data File must consist of 4 columns.");
-			if (data.Columns.Count < 3) {
-				throw new VectoException("FullLoadCurve Data File must consist of at least 3 columns.");
-			}
-
-			//todo Contract.Requires<VectoException>(data.Rows.Count < 2, "FullLoadCurve must consist of at least two lines with numeric values (below file header)");
-			if (data.Rows.Count < 2) {
-				throw new VectoException(
-					"FullLoadCurve must consist of at least two lines with numeric values (below file header)");
-			}
-
-			List<FullLoadCurveEntry> entriesFld;
-			if (HeaderIsValid(data.Columns)) {
-				entriesFld = CreateFromColumnNames(data);
-			} else {
-				var log = LogManager.GetLogger<FullLoadCurve>();
-				log.WarnFormat(
-					"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).Reverse()));
-
-				entriesFld = CreateFromColumnIndizes(data);
-			}
-
-			LookupData<PerSecond, Second> tmp;
-			if (declarationMode) {
-				tmp = new PT1();
-			} else {
-				tmp = PT1Curve.ReadFromFile(fileName);
-			}
-
-			return new FullLoadCurve { _fullLoadEntries = entriesFld, _pt1Data = tmp };
-		}
-
-		private static bool HeaderIsValid(DataColumnCollection columns)
-		{
-			Contract.Requires(columns != null);
-			return columns.Contains(Fields.EngineSpeed)
-					&& columns.Contains(Fields.TorqueDrag)
-					&& columns.Contains(Fields.TorqueFullLoad);
-			//&& columns.Contains(Fields.PT1);
-		}
-
-		private static List<FullLoadCurveEntry> CreateFromColumnNames(DataTable data)
-		{
-			Contract.Requires(data != null);
-			return (from DataRow row in data.Rows
-				select new FullLoadCurveEntry {
-					EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(),
-					TorqueFullLoad = row.ParseDouble(Fields.TorqueFullLoad).SI<NewtonMeter>(),
-					TorqueDrag = row.ParseDouble(Fields.TorqueDrag).SI<NewtonMeter>(),
-					//PT1 = row.ParseDouble(Fields.PT1).SI<Second>()
-				}).ToList();
-		}
-
-		private static List<FullLoadCurveEntry> CreateFromColumnIndizes(DataTable data)
-		{
-			Contract.Requires(data != null);
-			return (from DataRow row in data.Rows
-				select new FullLoadCurveEntry {
-					EngineSpeed = row.ParseDouble(0).RPMtoRad(),
-					TorqueFullLoad = row.ParseDouble(1).SI<NewtonMeter>(),
-					TorqueDrag = row.ParseDouble(2).SI<NewtonMeter>(),
-					//PT1 = row.ParseDouble(3).SI<Second>()
-				}).ToList();
-		}
-
-		public CombustionEngineData EngineData { get; internal set; }
-
-		/// <summary>
-		///     [rad/s] => [Nm]
-		/// </summary>
-		/// <param name="angularVelocity">[rad/s]</param>
-		/// <returns>[Nm]</returns>
-		public NewtonMeter FullLoadStationaryTorque(PerSecond angularVelocity)
-		{
-			var idx = FindIndex(angularVelocity);
-			return VectoMath.Interpolate(_fullLoadEntries[idx - 1].EngineSpeed, _fullLoadEntries[idx].EngineSpeed,
-				_fullLoadEntries[idx - 1].TorqueFullLoad, _fullLoadEntries[idx].TorqueFullLoad,
-				angularVelocity);
-		}
-
-		/// <summary>
-		///     [rad/s] => [W]
-		/// </summary>
-		/// <param name="angularVelocity">[rad/s]</param>
-		/// <returns>[W]</returns>
-		public Watt FullLoadStationaryPower(PerSecond angularVelocity)
-		{
-			return Formulas.TorqueToPower(FullLoadStationaryTorque(angularVelocity), angularVelocity);
-		}
-
-		/// <summary>
-		///     [rad/s] => [Nm]
-		/// </summary>
-		/// <param name="angularVelocity">[rad/s]</param>
-		/// <returns>[Nm]</returns>
-		public NewtonMeter DragLoadStationaryTorque(PerSecond angularVelocity)
-		{
-			var idx = FindIndex(angularVelocity);
-			return VectoMath.Interpolate(_fullLoadEntries[idx - 1].EngineSpeed, _fullLoadEntries[idx].EngineSpeed,
-				_fullLoadEntries[idx - 1].TorqueDrag, _fullLoadEntries[idx].TorqueDrag,
-				angularVelocity);
-		}
-
-		/// <summary>
-		///     [rad/s] => [W].
-		/// </summary>
-		/// <param name="angularVelocity">[rad/s]</param>
-		/// <returns>[W]</returns>
-		public Watt DragLoadStationaryPower(PerSecond angularVelocity)
-		{
-			Contract.Requires(angularVelocity.HasEqualUnit(new SI().Radian.Per.Second));
-			Contract.Ensures(Contract.Result<SI>().HasEqualUnit(new SI().Watt));
-
-			return Formulas.TorqueToPower(DragLoadStationaryTorque(angularVelocity), angularVelocity);
-		}
-
-		/// <summary>
-		///     [rad/s] => [s]
-		/// </summary>
-		/// <param name="angularVelocity">[rad/s]</param>
-		/// <returns>[s]</returns>
-		public Second PT1(PerSecond angularVelocity)
-		{
-			return _pt1Data.Lookup(angularVelocity);
-		}
-
-
-		/// <summary>
-		///		Get the engine's rated speed from the given full-load curve (i.e. engine speed with max. power)
-		/// </summary>
-		/// <returns>[1/s]</returns>
-		public PerSecond RatedSpeed
-		{
-			get
-			{
-				if (_ratedSpeed == null) {
-					ComputeRatedSpeed();
-				}
-				return _ratedSpeed;
-			}
-		}
-
-		public Watt MaxPower
-		{
-			get
-			{
-				if (_maxPower == null) {
-					ComputeRatedSpeed();
-				}
-				return _maxPower;
-			}
-		}
-
-		/// <summary>
-		///		Get the engine's preferred speed from the given full-load curve (i.e. Speed at 51% torque/speed-integral between idling and N95h.)
-		/// </summary>
-		public PerSecond PreferredSpeed
-		{
-			get
-			{
-				if (_preferredSpeed == null) {
-					ComputePreferredSpeed();
-				}
-				return _preferredSpeed;
-			}
-		}
-
-		public PerSecond N95hSpeed
-		{
-			get { return _n95hSpeed ?? (_n95hSpeed = FindEngineSpeedForPower(0.95 * MaxPower).Last()); }
-		}
-
-
-		public PerSecond LoSpeed
-		{
-			get { return _engineSpeedLo ?? (_engineSpeedLo = FindEngineSpeedForPower(0.55 * MaxPower).First()); }
-		}
-
-		public PerSecond HiSpeed
-		{
-			get { return _engineSpeedHi ?? (_engineSpeedHi = FindEngineSpeedForPower(0.7 * MaxPower).Last()); }
-		}
-
-
-		public NewtonMeter MaxLoadTorque
-		{
-			get { return _fullLoadEntries.Max(x => x.TorqueFullLoad); }
-		}
-
-		public NewtonMeter MaxDragTorque
-		{
-			get { return _fullLoadEntries.Min(x => x.TorqueDrag); }
-		}
-
-		/// <summary>
-		///		Compute the engine's rated speed from the given full-load curve (i.e. engine speed with max. power)
-		/// </summary>
-		/// <returns>[1/s]</returns>
-		private void ComputeRatedSpeed()
-		{
-			var max = new Tuple<PerSecond, Watt>(0.SI<PerSecond>(), 0.SI<Watt>());
-			for (var idx = 1; idx < _fullLoadEntries.Count; idx++) {
-				var currentMax = FindMaxPower(_fullLoadEntries[idx - 1], _fullLoadEntries[idx]);
-				if (currentMax.Item2 > max.Item2) {
-					max = currentMax;
-				}
-			}
-
-			_ratedSpeed = max.Item1;
-			_maxPower = max.Item2;
-		}
-
-
-		private void ComputePreferredSpeed()
-		{
-			var maxArea = ComputeArea(EngineData.IdleSpeed, N95hSpeed);
-
-			var area = 0.0;
-			var idx = 0;
-			while (++idx < _fullLoadEntries.Count) {
-				var additionalArea = ComputeArea(_fullLoadEntries[idx - 1].EngineSpeed, _fullLoadEntries[idx].EngineSpeed);
-				if (area + additionalArea > 0.51 * maxArea) {
-					var deltaArea = 0.51 * maxArea - area;
-					_preferredSpeed = ComputeEngineSpeedForSegmentArea(_fullLoadEntries[idx - 1], _fullLoadEntries[idx], deltaArea);
-					return;
-				}
-				area += additionalArea;
-			}
-			Log.WarnFormat("Could not compute preferred speed, check FullLoadCurve! N95h: {0}, maxArea: {1}", N95hSpeed, maxArea);
-		}
-
-		private PerSecond ComputeEngineSpeedForSegmentArea(FullLoadCurveEntry p1, FullLoadCurveEntry p2, double area)
-		{
-			var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed);
-			var d = p2.TorqueFullLoad - k * p2.EngineSpeed;
-
-			if (k.IsEqual(0.0)) {
-				// rectangle
-				// area = M * n
-				return (p1.EngineSpeed + (area / d.Value()));
-			}
-
-			// non-constant torque, M(n) = k * n + d
-			// area = M(n1) * (n2 - n1) + (M(n1) + M(n2))/2 * (n2 - n1) => solve for n2
-			var retVal = VectoMath.QuadraticEquationSolver(k.Value() / 2.0, d.Value(),
-				(k * p1.EngineSpeed * p1.EngineSpeed + 2 * p1.EngineSpeed * d).Value());
-			if (retVal.Count == 0) {
-				Log.InfoFormat("No real solution found for requested area: P: {0}, p1: {1}, p2: {2}", area, p1, p2);
-			}
-			return retVal.First(x => x >= p1.EngineSpeed.Value() && x <= p2.EngineSpeed.Value()).SI<PerSecond>();
-		}
-
-		/// <summary>
-		///     [rad/s] => index. Get item index for angularVelocity.
-		/// </summary>
-		/// <param name="angularVelocity">[rad/s]</param>
-		/// <returns>index</returns>
-		protected int FindIndex(PerSecond angularVelocity)
-		{
-			int idx;
-			if (angularVelocity < _fullLoadEntries[0].EngineSpeed) {
-				Log.ErrorFormat("requested rpm below minimum rpm in FLD curve - extrapolating. n: {0}, rpm_min: {1}",
-					angularVelocity.ConvertTo().Rounds.Per.Minute, _fullLoadEntries[0].EngineSpeed.ConvertTo().Rounds.Per.Minute);
-				idx = 1;
-			} else {
-				idx = _fullLoadEntries.FindIndex(x => x.EngineSpeed > angularVelocity);
-			}
-			if (idx <= 0) {
-				idx = angularVelocity > _fullLoadEntries[0].EngineSpeed ? _fullLoadEntries.Count - 1 : 1;
-			}
-			return idx;
-		}
-
-		private List<PerSecond> FindEngineSpeedForPower(Watt power)
-		{
-			var retVal = new List<PerSecond>();
-			for (var idx = 1; idx < _fullLoadEntries.Count; idx++) {
-				var solutions = FindEngineSpeedForPower(_fullLoadEntries[idx - 1], _fullLoadEntries[idx], power);
-				retVal.AddRange(solutions);
-			}
-			retVal.Sort();
-			return retVal;
-		}
-
-		private List<PerSecond> FindEngineSpeedForPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2, Watt power)
-		{
-			var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed);
-			var d = p2.TorqueFullLoad - k * p2.EngineSpeed;
-
-			var retVal = new List<PerSecond>();
-			if (k.IsEqual(0, 0.0001)) {
-				// constant torque, solve linear equation
-				// power = M * n
-				retVal.Add((power.Value() / d.Value()).SI<PerSecond>());
-			} else {
-				// non-constant torque, solve quadratic equation for engine speed (n)
-				// power = M(n) * n = (k * n + d) * n =  k * n^2 + d * n
-				retVal = VectoMath.QuadraticEquationSolver(k.Value(), d.Value(), -power.Value()).SI<PerSecond>().ToList();
-				if (retVal.Count == 0) {
-					Log.InfoFormat("No real solution found for requested power demand: P: {0}, p1: {1}, p2: {2}", power, p1, p2);
-				}
-			}
-			retVal = retVal.Where(x => x >= p1.EngineSpeed && x <= p2.EngineSpeed).ToList();
-			return retVal;
-		}
-
-		private double ComputeArea(PerSecond lowEngineSpeed, PerSecond highEngineSpeed)
-		{
-			var startSegment = FindIndex(lowEngineSpeed);
-			var endSegment = FindIndex(highEngineSpeed);
-
-			var area = 0.0;
-			if (lowEngineSpeed < _fullLoadEntries[startSegment].EngineSpeed) {
-				// add part of the first segment
-				area += ((_fullLoadEntries[startSegment].EngineSpeed - lowEngineSpeed) *
-						(FullLoadStationaryTorque(lowEngineSpeed) + _fullLoadEntries[startSegment].TorqueFullLoad) / 2.0).Value();
-			}
-			for (var i = startSegment + 1; i <= endSegment; i++) {
-				var speedHigh = _fullLoadEntries[i].EngineSpeed;
-				var torqueHigh = _fullLoadEntries[i].TorqueFullLoad;
-				if (highEngineSpeed < _fullLoadEntries[i].EngineSpeed) {
-					// add part of the last segment
-					speedHigh = highEngineSpeed;
-					torqueHigh = FullLoadStationaryTorque(highEngineSpeed);
-				}
-				area += ((speedHigh - _fullLoadEntries[i - 1].EngineSpeed) *
-						(torqueHigh + _fullLoadEntries[i - 1].TorqueFullLoad) / 2.0).Value();
-			}
-			return area;
-		}
-
-		private Tuple<PerSecond, Watt> FindMaxPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2)
-		{
-			if (p1.EngineSpeed == p2.EngineSpeed) {
-				return new Tuple<PerSecond, Watt>(p1.EngineSpeed, Formulas.TorqueToPower(p1.TorqueFullLoad, p1.EngineSpeed));
-			}
-			if (p2.EngineSpeed < p1.EngineSpeed) {
-				var tmp = p1;
-				p1 = p2;
-				p2 = tmp;
-			}
-			// y = kx + d
-			var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed);
-			var d = p2.TorqueFullLoad - k * p2.EngineSpeed;
-			if (k == 0.SI()) {
-				return new Tuple<PerSecond, Watt>(p2.EngineSpeed, Formulas.TorqueToPower(p2.TorqueFullLoad, p2.EngineSpeed));
-			}
-			var engineSpeedMaxPower = (-1 * d / (2 * k)).Cast<PerSecond>();
-			if (engineSpeedMaxPower < p1.EngineSpeed || engineSpeedMaxPower > p2.EngineSpeed) {
-				if (k > 0) {
-					return new Tuple<PerSecond, Watt>(p2.EngineSpeed, Formulas.TorqueToPower(p2.TorqueFullLoad, p2.EngineSpeed));
-				}
-				return new Tuple<PerSecond, Watt>(p1.EngineSpeed, Formulas.TorqueToPower(p1.TorqueFullLoad, p1.EngineSpeed));
-			}
-			//return null;
-			var engineTorqueMaxPower = FullLoadStationaryTorque(engineSpeedMaxPower);
-			return new Tuple<PerSecond, Watt>(engineSpeedMaxPower,
-				Formulas.TorqueToPower(engineTorqueMaxPower, engineSpeedMaxPower));
-		}
-
-		private 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";
-		}
-
-		private class FullLoadCurveEntry
-		{
-			/// <summary>
-			///     [rad/s] engine speed
-			/// </summary>
-			public PerSecond EngineSpeed { get; set; }
-
-			/// <summary>
-			///     [Nm] full load torque
-			/// </summary>
-			public NewtonMeter TorqueFullLoad { get; set; }
-
-			/// <summary>
-			///     [Nm] motoring torque
-			/// </summary>
-			public NewtonMeter TorqueDrag { get; set; }
-
-			///// <summary>
-			/////     [s] PT1 time constant
-			///// </summary>
-			//public Second PT1 { get; set; }
-
-			#region Equality members
-
-			protected bool Equals(FullLoadCurveEntry other)
-			{
-				return Equals(EngineSpeed, other.EngineSpeed) && Equals(TorqueFullLoad, other.TorqueFullLoad) &&
-						Equals(TorqueDrag, other.TorqueDrag);
-			}
-
-			public override bool Equals(object obj)
-			{
-				if (ReferenceEquals(null, obj)) {
-					return false;
-				}
-				if (ReferenceEquals(this, obj)) {
-					return true;
-				}
-				if (obj.GetType() != this.GetType()) {
-					return false;
-				}
-				return Equals((FullLoadCurveEntry)obj);
-			}
-
-			public override int GetHashCode()
-			{
-				unchecked {
-					var hashCode = (EngineSpeed != null ? EngineSpeed.GetHashCode() : 0);
-					hashCode = (hashCode * 397) ^ (TorqueFullLoad != null ? TorqueFullLoad.GetHashCode() : 0);
-					hashCode = (hashCode * 397) ^ (TorqueDrag != null ? TorqueDrag.GetHashCode() : 0);
-					return hashCode;
-				}
-			}
-
-			#endregion
-		}
-
-		#region Equality members
-
-		protected bool Equals(FullLoadCurve other)
-		{
-			return Equals(_fullLoadEntries, other._fullLoadEntries) && Equals(_pt1Data, other._pt1Data);
-		}
-
-		public override bool Equals(object obj)
-		{
-			if (ReferenceEquals(null, obj)) {
-				return false;
-			}
-			if (ReferenceEquals(this, obj)) {
-				return true;
-			}
-			if (obj.GetType() != this.GetType()) {
-				return false;
-			}
-			return Equals((FullLoadCurve)obj);
-		}
-
-		public override int GetHashCode()
-		{
-			unchecked {
-				return ((_fullLoadEntries != null ? _fullLoadEntries.GetHashCode() : 0) * 397) ^
-						(_pt1Data != null ? _pt1Data.GetHashCode() : 0);
-			}
-		}
-
-		#endregion
-	}
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using Common.Logging;
+using Newtonsoft.Json;
+using TUGraz.VectoCore.Exceptions;
+using TUGraz.VectoCore.Models.Declaration;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.Utils;
+
+namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
+{
+	/// <summary>
+	/// Represents the Full load curve.
+	/// </summary>
+	public class EngineFullLoadCurve : SimulationComponentData
+	{
+		private List<FullLoadCurveEntry> _fullLoadEntries;
+		private LookupData<PerSecond, Second> _pt1Data;
+
+		private Watt _maxPower;
+
+		private PerSecond _ratedSpeed;
+		private PerSecond _preferredSpeed;
+		private PerSecond _engineSpeedLo; // 55% of Pmax
+		private PerSecond _engineSpeedHi; // 70% of Pmax
+		private PerSecond _n95hSpeed; // 95% of Pmax
+
+		public static EngineFullLoadCurve ReadFromFile(string fileName, bool declarationMode = false)
+		{
+			var data = VectoCSVFile.Read(fileName);
+
+			//todo Contract.Requires<VectoException>(data.Columns.Count != 4, "FullLoadCurve Data File must consist of 4 columns.");
+			if (data.Columns.Count < 3) {
+				throw new VectoException("FullLoadCurve Data File must consist of at least 3 columns.");
+			}
+
+			//todo Contract.Requires<VectoException>(data.Rows.Count < 2, "FullLoadCurve must consist of at least two lines with numeric values (below file header)");
+			if (data.Rows.Count < 2) {
+				throw new VectoException(
+					"FullLoadCurve must consist of at least two lines with numeric values (below file header)");
+			}
+
+			List<FullLoadCurveEntry> entriesFld;
+			if (HeaderIsValid(data.Columns)) {
+				entriesFld = CreateFromColumnNames(data);
+			} else {
+				var log = LogManager.GetLogger<EngineFullLoadCurve>();
+				log.WarnFormat(
+					"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).Reverse()));
+
+				entriesFld = CreateFromColumnIndizes(data);
+			}
+
+			LookupData<PerSecond, Second> tmp;
+			if (declarationMode) {
+				tmp = new PT1();
+			} else {
+				tmp = PT1Curve.ReadFromFile(fileName);
+			}
+
+			return new EngineFullLoadCurve { _fullLoadEntries = entriesFld, _pt1Data = tmp };
+		}
+
+		private static bool HeaderIsValid(DataColumnCollection columns)
+		{
+			Contract.Requires(columns != null);
+			return columns.Contains(Fields.EngineSpeed)
+					&& columns.Contains(Fields.TorqueDrag)
+					&& columns.Contains(Fields.TorqueFullLoad);
+			//&& columns.Contains(Fields.PT1);
+		}
+
+		private static List<FullLoadCurveEntry> CreateFromColumnNames(DataTable data)
+		{
+			Contract.Requires(data != null);
+			return (from DataRow row in data.Rows
+				select new FullLoadCurveEntry {
+					EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(),
+					TorqueFullLoad = row.ParseDouble(Fields.TorqueFullLoad).SI<NewtonMeter>(),
+					TorqueDrag = row.ParseDouble(Fields.TorqueDrag).SI<NewtonMeter>(),
+					//PT1 = row.ParseDouble(Fields.PT1).SI<Second>()
+				}).ToList();
+		}
+
+		private static List<FullLoadCurveEntry> CreateFromColumnIndizes(DataTable data)
+		{
+			Contract.Requires(data != null);
+			return (from DataRow row in data.Rows
+				select new FullLoadCurveEntry {
+					EngineSpeed = row.ParseDouble(0).RPMtoRad(),
+					TorqueFullLoad = row.ParseDouble(1).SI<NewtonMeter>(),
+					TorqueDrag = row.ParseDouble(2).SI<NewtonMeter>(),
+					//PT1 = row.ParseDouble(3).SI<Second>()
+				}).ToList();
+		}
+
+		public CombustionEngineData EngineData { get; internal set; }
+
+		/// <summary>
+		///     [rad/s] => [Nm]
+		/// </summary>
+		/// <param name="angularVelocity">[rad/s]</param>
+		/// <returns>[Nm]</returns>
+		public NewtonMeter FullLoadStationaryTorque(PerSecond angularVelocity)
+		{
+			var idx = FindIndex(angularVelocity);
+			return VectoMath.Interpolate(_fullLoadEntries[idx - 1].EngineSpeed, _fullLoadEntries[idx].EngineSpeed,
+				_fullLoadEntries[idx - 1].TorqueFullLoad, _fullLoadEntries[idx].TorqueFullLoad,
+				angularVelocity);
+		}
+
+		/// <summary>
+		///     [rad/s] => [W]
+		/// </summary>
+		/// <param name="angularVelocity">[rad/s]</param>
+		/// <returns>[W]</returns>
+		public Watt FullLoadStationaryPower(PerSecond angularVelocity)
+		{
+			return Formulas.TorqueToPower(FullLoadStationaryTorque(angularVelocity), angularVelocity);
+		}
+
+		/// <summary>
+		///     [rad/s] => [Nm]
+		/// </summary>
+		/// <param name="angularVelocity">[rad/s]</param>
+		/// <returns>[Nm]</returns>
+		public NewtonMeter DragLoadStationaryTorque(PerSecond angularVelocity)
+		{
+			var idx = FindIndex(angularVelocity);
+			return VectoMath.Interpolate(_fullLoadEntries[idx - 1].EngineSpeed, _fullLoadEntries[idx].EngineSpeed,
+				_fullLoadEntries[idx - 1].TorqueDrag, _fullLoadEntries[idx].TorqueDrag,
+				angularVelocity);
+		}
+
+		/// <summary>
+		///     [rad/s] => [W].
+		/// </summary>
+		/// <param name="angularVelocity">[rad/s]</param>
+		/// <returns>[W]</returns>
+		public Watt DragLoadStationaryPower(PerSecond angularVelocity)
+		{
+			Contract.Requires(angularVelocity.HasEqualUnit(new SI().Radian.Per.Second));
+			Contract.Ensures(Contract.Result<SI>().HasEqualUnit(new SI().Watt));
+
+			return Formulas.TorqueToPower(DragLoadStationaryTorque(angularVelocity), angularVelocity);
+		}
+
+		/// <summary>
+		///     [rad/s] => [s]
+		/// </summary>
+		/// <param name="angularVelocity">[rad/s]</param>
+		/// <returns>[s]</returns>
+		public Second PT1(PerSecond angularVelocity)
+		{
+			return _pt1Data.Lookup(angularVelocity);
+		}
+
+
+		/// <summary>
+		///		Get the engine's rated speed from the given full-load curve (i.e. engine speed with max. power)
+		/// </summary>
+		/// <returns>[1/s]</returns>
+		public PerSecond RatedSpeed
+		{
+			get
+			{
+				if (_ratedSpeed == null) {
+					ComputeRatedSpeed();
+				}
+				return _ratedSpeed;
+			}
+		}
+
+		public Watt MaxPower
+		{
+			get
+			{
+				if (_maxPower == null) {
+					ComputeRatedSpeed();
+				}
+				return _maxPower;
+			}
+		}
+
+		/// <summary>
+		///		Get the engine's preferred speed from the given full-load curve (i.e. Speed at 51% torque/speed-integral between idling and N95h.)
+		/// </summary>
+		public PerSecond PreferredSpeed
+		{
+			get
+			{
+				if (_preferredSpeed == null) {
+					ComputePreferredSpeed();
+				}
+				return _preferredSpeed;
+			}
+		}
+
+		public PerSecond N95hSpeed
+		{
+			get { return _n95hSpeed ?? (_n95hSpeed = FindEngineSpeedForPower(0.95 * MaxPower).Last()); }
+		}
+
+
+		public PerSecond LoSpeed
+		{
+			get { return _engineSpeedLo ?? (_engineSpeedLo = FindEngineSpeedForPower(0.55 * MaxPower).First()); }
+		}
+
+		public PerSecond HiSpeed
+		{
+			get { return _engineSpeedHi ?? (_engineSpeedHi = FindEngineSpeedForPower(0.7 * MaxPower).Last()); }
+		}
+
+
+		public NewtonMeter MaxLoadTorque
+		{
+			get { return _fullLoadEntries.Max(x => x.TorqueFullLoad); }
+		}
+
+		public NewtonMeter MaxDragTorque
+		{
+			get { return _fullLoadEntries.Min(x => x.TorqueDrag); }
+		}
+
+		/// <summary>
+		///		Compute the engine's rated speed from the given full-load curve (i.e. engine speed with max. power)
+		/// </summary>
+		/// <returns>[1/s]</returns>
+		private void ComputeRatedSpeed()
+		{
+			var max = new Tuple<PerSecond, Watt>(0.SI<PerSecond>(), 0.SI<Watt>());
+			for (var idx = 1; idx < _fullLoadEntries.Count; idx++) {
+				var currentMax = FindMaxPower(_fullLoadEntries[idx - 1], _fullLoadEntries[idx]);
+				if (currentMax.Item2 > max.Item2) {
+					max = currentMax;
+				}
+			}
+
+			_ratedSpeed = max.Item1;
+			_maxPower = max.Item2;
+		}
+
+
+		private void ComputePreferredSpeed()
+		{
+			var maxArea = ComputeArea(EngineData.IdleSpeed, N95hSpeed);
+
+			var area = 0.0;
+			var idx = 0;
+			while (++idx < _fullLoadEntries.Count) {
+				var additionalArea = ComputeArea(_fullLoadEntries[idx - 1].EngineSpeed, _fullLoadEntries[idx].EngineSpeed);
+				if (area + additionalArea > 0.51 * maxArea) {
+					var deltaArea = 0.51 * maxArea - area;
+					_preferredSpeed = ComputeEngineSpeedForSegmentArea(_fullLoadEntries[idx - 1], _fullLoadEntries[idx], deltaArea);
+					return;
+				}
+				area += additionalArea;
+			}
+			Log.WarnFormat("Could not compute preferred speed, check FullLoadCurve! N95h: {0}, maxArea: {1}", N95hSpeed, maxArea);
+		}
+
+		private PerSecond ComputeEngineSpeedForSegmentArea(FullLoadCurveEntry p1, FullLoadCurveEntry p2, double area)
+		{
+			var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed);
+			var d = p2.TorqueFullLoad - k * p2.EngineSpeed;
+
+			if (k.IsEqual(0.0)) {
+				// rectangle
+				// area = M * n
+				return (p1.EngineSpeed + (area / d.Value()));
+			}
+
+			// non-constant torque, M(n) = k * n + d
+			// area = M(n1) * (n2 - n1) + (M(n1) + M(n2))/2 * (n2 - n1) => solve for n2
+			var retVal = VectoMath.QuadraticEquationSolver(k.Value() / 2.0, d.Value(),
+				(k * p1.EngineSpeed * p1.EngineSpeed + 2 * p1.EngineSpeed * d).Value());
+			if (retVal.Count == 0) {
+				Log.InfoFormat("No real solution found for requested area: P: {0}, p1: {1}, p2: {2}", area, p1, p2);
+			}
+			return retVal.First(x => x >= p1.EngineSpeed.Value() && x <= p2.EngineSpeed.Value()).SI<PerSecond>();
+		}
+
+		/// <summary>
+		///     [rad/s] => index. Get item index for angularVelocity.
+		/// </summary>
+		/// <param name="angularVelocity">[rad/s]</param>
+		/// <returns>index</returns>
+		protected int FindIndex(PerSecond angularVelocity)
+		{
+			int idx;
+			if (angularVelocity < _fullLoadEntries[0].EngineSpeed) {
+				Log.ErrorFormat("requested rpm below minimum rpm in FLD curve - extrapolating. n: {0}, rpm_min: {1}",
+					angularVelocity.ConvertTo().Rounds.Per.Minute, _fullLoadEntries[0].EngineSpeed.ConvertTo().Rounds.Per.Minute);
+				idx = 1;
+			} else {
+				idx = _fullLoadEntries.FindIndex(x => x.EngineSpeed > angularVelocity);
+			}
+			if (idx <= 0) {
+				idx = angularVelocity > _fullLoadEntries[0].EngineSpeed ? _fullLoadEntries.Count - 1 : 1;
+			}
+			return idx;
+		}
+
+		private List<PerSecond> FindEngineSpeedForPower(Watt power)
+		{
+			var retVal = new List<PerSecond>();
+			for (var idx = 1; idx < _fullLoadEntries.Count; idx++) {
+				var solutions = FindEngineSpeedForPower(_fullLoadEntries[idx - 1], _fullLoadEntries[idx], power);
+				retVal.AddRange(solutions);
+			}
+			retVal.Sort();
+			return retVal;
+		}
+
+		private List<PerSecond> FindEngineSpeedForPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2, Watt power)
+		{
+			var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed);
+			var d = p2.TorqueFullLoad - k * p2.EngineSpeed;
+
+			var retVal = new List<PerSecond>();
+			if (k.IsEqual(0, 0.0001)) {
+				// constant torque, solve linear equation
+				// power = M * n
+				retVal.Add((power.Value() / d.Value()).SI<PerSecond>());
+			} else {
+				// non-constant torque, solve quadratic equation for engine speed (n)
+				// power = M(n) * n = (k * n + d) * n =  k * n^2 + d * n
+				retVal = VectoMath.QuadraticEquationSolver(k.Value(), d.Value(), -power.Value()).SI<PerSecond>().ToList();
+				if (retVal.Count == 0) {
+					Log.InfoFormat("No real solution found for requested power demand: P: {0}, p1: {1}, p2: {2}", power, p1, p2);
+				}
+			}
+			retVal = retVal.Where(x => x >= p1.EngineSpeed && x <= p2.EngineSpeed).ToList();
+			return retVal;
+		}
+
+		private double ComputeArea(PerSecond lowEngineSpeed, PerSecond highEngineSpeed)
+		{
+			var startSegment = FindIndex(lowEngineSpeed);
+			var endSegment = FindIndex(highEngineSpeed);
+
+			var area = 0.0;
+			if (lowEngineSpeed < _fullLoadEntries[startSegment].EngineSpeed) {
+				// add part of the first segment
+				area += ((_fullLoadEntries[startSegment].EngineSpeed - lowEngineSpeed) *
+						(FullLoadStationaryTorque(lowEngineSpeed) + _fullLoadEntries[startSegment].TorqueFullLoad) / 2.0).Value();
+			}
+			for (var i = startSegment + 1; i <= endSegment; i++) {
+				var speedHigh = _fullLoadEntries[i].EngineSpeed;
+				var torqueHigh = _fullLoadEntries[i].TorqueFullLoad;
+				if (highEngineSpeed < _fullLoadEntries[i].EngineSpeed) {
+					// add part of the last segment
+					speedHigh = highEngineSpeed;
+					torqueHigh = FullLoadStationaryTorque(highEngineSpeed);
+				}
+				area += ((speedHigh - _fullLoadEntries[i - 1].EngineSpeed) *
+						(torqueHigh + _fullLoadEntries[i - 1].TorqueFullLoad) / 2.0).Value();
+			}
+			return area;
+		}
+
+		private Tuple<PerSecond, Watt> FindMaxPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2)
+		{
+			if (p1.EngineSpeed == p2.EngineSpeed) {
+				return new Tuple<PerSecond, Watt>(p1.EngineSpeed, Formulas.TorqueToPower(p1.TorqueFullLoad, p1.EngineSpeed));
+			}
+			if (p2.EngineSpeed < p1.EngineSpeed) {
+				var tmp = p1;
+				p1 = p2;
+				p2 = tmp;
+			}
+			// y = kx + d
+			var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed);
+			var d = p2.TorqueFullLoad - k * p2.EngineSpeed;
+			if (k == 0.SI()) {
+				return new Tuple<PerSecond, Watt>(p2.EngineSpeed, Formulas.TorqueToPower(p2.TorqueFullLoad, p2.EngineSpeed));
+			}
+			var engineSpeedMaxPower = (-1 * d / (2 * k)).Cast<PerSecond>();
+			if (engineSpeedMaxPower < p1.EngineSpeed || engineSpeedMaxPower > p2.EngineSpeed) {
+				if (k > 0) {
+					return new Tuple<PerSecond, Watt>(p2.EngineSpeed, Formulas.TorqueToPower(p2.TorqueFullLoad, p2.EngineSpeed));
+				}
+				return new Tuple<PerSecond, Watt>(p1.EngineSpeed, Formulas.TorqueToPower(p1.TorqueFullLoad, p1.EngineSpeed));
+			}
+			//return null;
+			var engineTorqueMaxPower = FullLoadStationaryTorque(engineSpeedMaxPower);
+			return new Tuple<PerSecond, Watt>(engineSpeedMaxPower,
+				Formulas.TorqueToPower(engineTorqueMaxPower, engineSpeedMaxPower));
+		}
+
+		private 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";
+		}
+
+		private class FullLoadCurveEntry
+		{
+			/// <summary>
+			///     [rad/s] engine speed
+			/// </summary>
+			public PerSecond EngineSpeed { get; set; }
+
+			/// <summary>
+			///     [Nm] full load torque
+			/// </summary>
+			public NewtonMeter TorqueFullLoad { get; set; }
+
+			/// <summary>
+			///     [Nm] motoring torque
+			/// </summary>
+			public NewtonMeter TorqueDrag { get; set; }
+
+			///// <summary>
+			/////     [s] PT1 time constant
+			///// </summary>
+			//public Second PT1 { get; set; }
+
+			#region Equality members
+
+			protected bool Equals(FullLoadCurveEntry other)
+			{
+				return Equals(EngineSpeed, other.EngineSpeed) && Equals(TorqueFullLoad, other.TorqueFullLoad) &&
+						Equals(TorqueDrag, other.TorqueDrag);
+			}
+
+			public override bool Equals(object obj)
+			{
+				if (ReferenceEquals(null, obj)) {
+					return false;
+				}
+				if (ReferenceEquals(this, obj)) {
+					return true;
+				}
+				if (obj.GetType() != this.GetType()) {
+					return false;
+				}
+				return Equals((FullLoadCurveEntry)obj);
+			}
+
+			public override int GetHashCode()
+			{
+				unchecked {
+					var hashCode = (EngineSpeed != null ? EngineSpeed.GetHashCode() : 0);
+					hashCode = (hashCode * 397) ^ (TorqueFullLoad != null ? TorqueFullLoad.GetHashCode() : 0);
+					hashCode = (hashCode * 397) ^ (TorqueDrag != null ? TorqueDrag.GetHashCode() : 0);
+					return hashCode;
+				}
+			}
+
+			#endregion
+		}
+
+		#region Equality members
+
+		protected bool Equals(EngineFullLoadCurve other)
+		{
+			return Equals(_fullLoadEntries, other._fullLoadEntries) && Equals(_pt1Data, other._pt1Data);
+		}
+
+		public override bool Equals(object obj)
+		{
+			if (ReferenceEquals(null, obj)) {
+				return false;
+			}
+			if (ReferenceEquals(this, obj)) {
+				return true;
+			}
+			if (obj.GetType() != this.GetType()) {
+				return false;
+			}
+			return Equals((EngineFullLoadCurve)obj);
+		}
+
+		public override int GetHashCode()
+		{
+			unchecked {
+				return ((_fullLoadEntries != null ? _fullLoadEntries.GetHashCode() : 0) * 397) ^
+						(_pt1Data != null ? _pt1Data.GetHashCode() : 0);
+			}
+		}
+
+		#endregion
+	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/SimulationComponent/Data/GearFullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/GearFullLoadCurve.cs
new file mode 100644
index 0000000000..5d5b61c961
--- /dev/null
+++ b/VectoCore/Models/SimulationComponent/Data/GearFullLoadCurve.cs
@@ -0,0 +1,10 @@
+namespace TUGraz.VectoCore.Models.SimulationComponent.Data
+{
+	public class GearFullLoadCurve
+	{
+		public static GearFullLoadCurve ReadFromFile(string file)
+		{
+			throw new System.NotImplementedException();
+		}
+	}
+}
\ No newline at end of file
diff --git a/VectoCore/Models/SimulationComponent/Data/Gearbox/GearData.cs b/VectoCore/Models/SimulationComponent/Data/Gearbox/GearData.cs
index 8ed6c34922..e48fe2d1e0 100644
--- a/VectoCore/Models/SimulationComponent/Data/Gearbox/GearData.cs
+++ b/VectoCore/Models/SimulationComponent/Data/Gearbox/GearData.cs
@@ -2,23 +2,16 @@
 {
 	public class GearData
 	{
-		public ShiftPolygon ShiftPolygon { get; protected set; }
+		public ShiftPolygon ShiftPolygon { get; internal set; }
 
-		public TransmissionLossMap LossMap { get; protected set; }
+		public TransmissionLossMap LossMap { get; internal set; }
 
-		public double Ratio { get; protected set; }
+		public GearFullLoadCurve FullLoadCurve { get; internal set; }
 
-		public bool TorqueConverterActive { get; protected set; } // TODO: think about refactoring...
+		public double Ratio { get; internal set; }
 
-		public double AverageEfficiency { get; set; }
+		public bool TorqueConverterActive { get; internal set; } // TODO: think about refactoring...
 
-		public GearData(TransmissionLossMap lossMap, ShiftPolygon shiftPolygon, double ratio,
-			bool torqueconverterActive)
-		{
-			LossMap = lossMap;
-			ShiftPolygon = shiftPolygon;
-			Ratio = ratio;
-			TorqueConverterActive = torqueconverterActive;
-		}
+		// public double AverageEfficiency { get; internal set; }
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/SimulationComponent/Impl/Clutch.cs b/VectoCore/Models/SimulationComponent/Impl/Clutch.cs
index 1cd9c264c0..3b29a40f62 100644
--- a/VectoCore/Models/SimulationComponent/Impl/Clutch.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/Clutch.cs
@@ -27,7 +27,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			: base(cockpit)
 		{
 			_idleSpeed = engineData.IdleSpeed;
-			_ratedSpeed = engineData.GetFullLoadCurve(0).RatedSpeed;
+			_ratedSpeed = engineData.FullLoadCurve.RatedSpeed;
 		}
 
 		public ClutchState State()
diff --git a/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
index 1aca930d9b..0494191925 100644
--- a/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
@@ -88,12 +88,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				//todo: _currentState.EnginePowerLoss = enginePowerLoss;
 			}
 
-			var currentGear = Cockpit.Gear();
-
-			_currentState.FullDragTorque = _data.GetFullLoadCurve(currentGear).DragLoadStationaryTorque(engineSpeed);
+			_currentState.FullDragTorque = _data.FullLoadCurve.DragLoadStationaryTorque(engineSpeed);
 			_currentState.FullDragPower = Formulas.TorqueToPower(_currentState.FullDragTorque, engineSpeed);
 
-			ComputeFullLoadPower(currentGear, engineSpeed, dt);
+			ComputeFullLoadPower(engineSpeed, dt);
 
 			ValidatePowerDemand(requestedEnginePower);
 
@@ -115,22 +113,21 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		protected override void DoWriteModalResults(IModalDataWriter writer)
 		{
-			writer[ModalResultField.PaEng] = (double)_currentState.EnginePowerLoss;
-			writer[ModalResultField.Pe_drag] = (double)_currentState.FullDragPower;
-			writer[ModalResultField.Pe_full] = (double)_currentState.DynamicFullLoadPower;
-			writer[ModalResultField.Pe_eng] = (double)_currentState.EnginePower;
+			writer[ModalResultField.PaEng] = _currentState.EnginePowerLoss.Value();
+			writer[ModalResultField.Pe_drag] = _currentState.FullDragPower.Value();
+			writer[ModalResultField.Pe_full] = _currentState.DynamicFullLoadPower.Value();
+			writer[ModalResultField.Pe_eng] = _currentState.EnginePower.Value();
 
-			writer[ModalResultField.Tq_drag] = (double)_currentState.FullDragTorque;
-			writer[ModalResultField.Tq_full] = (double)_currentState.DynamicFullLoadTorque;
-			writer[ModalResultField.Tq_eng] = (double)_currentState.EngineTorque;
-			writer[ModalResultField.n] = (double)_currentState.EngineSpeed.ConvertTo().Rounds.Per.Minute;
+			writer[ModalResultField.Tq_drag] = _currentState.FullDragTorque.Value();
+			writer[ModalResultField.Tq_full] = _currentState.DynamicFullLoadTorque.Value();
+			writer[ModalResultField.Tq_eng] = _currentState.EngineTorque.Value();
+			writer[ModalResultField.n] = _currentState.EngineSpeed.ConvertTo().Rounds.Per.Minute.Value();
 
 			try {
 				writer[ModalResultField.FC] =
-					(double)
-						_data.ConsumptionMap.GetFuelConsumption(_currentState.EngineTorque, _currentState.EngineSpeed)
-							.ConvertTo()
-							.Gramm.Per.Hour;
+					_data.ConsumptionMap.GetFuelConsumption(_currentState.EngineTorque, _currentState.EngineSpeed)
+						.ConvertTo()
+						.Gramm.Per.Hour.Value();
 			} catch (VectoException ex) {
 				Log.WarnFormat("t: {0} - {1} n: {2} Tq: {3}", _currentState.AbsTime, ex.Message,
 					_currentState.EngineSpeed, _currentState.EngineTorque);
@@ -223,10 +220,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		/// <summary>
 		///     computes full load power from gear [-], angularVelocity [rad/s] and dt [s].
 		/// </summary>
-		/// <param name="gear"></param>
 		/// <param name="angularVelocity">[rad/s]</param>
 		/// <param name="dt">[s]</param>
-		protected void ComputeFullLoadPower(uint gear, PerSecond angularVelocity, Second dt)
+		protected void ComputeFullLoadPower(PerSecond angularVelocity, Second dt)
 		{
 			if (dt.IsEqual(0)) {
 				throw new VectoException("ComputeFullLoadPower cannot compute for simulation interval length 0.");
@@ -234,11 +230,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			//_currentState.StationaryFullLoadPower = _data.GetFullLoadCurve(gear).FullLoadStationaryPower(rpm);
 			_currentState.StationaryFullLoadTorque =
-				_data.GetFullLoadCurve(gear).FullLoadStationaryTorque(angularVelocity);
+				_data.FullLoadCurve.FullLoadStationaryTorque(angularVelocity);
 			_currentState.StationaryFullLoadPower = Formulas.TorqueToPower(_currentState.StationaryFullLoadTorque,
 				angularVelocity);
 
-			double pt1 = _data.GetFullLoadCurve(gear).PT1(angularVelocity).Value();
+			double pt1 = _data.FullLoadCurve.PT1(angularVelocity).Value();
 
 //			var dynFullPowerCalculated = (1 / (pt1 + 1)) *
 //										(_currentState.StationaryFullLoadPower + pt1 * _previousState.EnginePower);
diff --git a/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs b/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs
index 212f545b5b..80e13b00e9 100644
--- a/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs
@@ -58,7 +58,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			// TODO!!
 			var dx = 0.SI<Meter>();
-			return _outPort.Request((Second)absTime, dx, Data.Entries[index].VehicleTargetSpeed,
+			return _outPort.Request(absTime, dt, Data.Entries[index].VehicleTargetSpeed,
 				Data.Entries[index].RoadGradient);
 		}
 
@@ -86,10 +86,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		protected override void DoWriteModalResults(IModalDataWriter writer)
 		{
-			throw new NotImplementedException();
+			// TODO: write data...
 		}
 
-		protected override void DoCommitSimulationStep() {}
+		protected override void DoCommitSimulationStep()
+		{
+			// TODO: commit step
+		}
 
 		#endregion
 	}
diff --git a/VectoCore/VectoCore.csproj b/VectoCore/VectoCore.csproj
index a9ffb8a21c..2e27b4c27e 100644
--- a/VectoCore/VectoCore.csproj
+++ b/VectoCore/VectoCore.csproj
@@ -151,8 +151,10 @@
     <Compile Include="Models\Declaration\Mission.cs" />
     <Compile Include="Models\Declaration\MissionType.cs" />
     <Compile Include="Models\SimulationComponent\Data\Engine\PT1Curve.cs" />
+    <Compile Include="Models\SimulationComponent\Data\GearFullLoadCurve.cs" />
     <Compile Include="Models\Simulation\Impl\DistanceRun.cs" />
     <Compile Include="Models\Simulation\Impl\PowertrainBuilder.cs" />
+    <Compile Include="Models\Simulation\Impl\TimeRun.cs" />
     <Compile Include="Utils\DataTableExtensionMethods.cs" />
     <Compile Include="Utils\EnumHelper.cs" />
     <Compile Include="Utils\RessourceHelper.cs" />
@@ -164,7 +166,7 @@
     <Compile Include="Models\SimulationComponent\Data\CrossWindCorrectionMode.cs" />
     <Compile Include="Models\SimulationComponent\Data\DrivingCycleData.cs" />
     <Compile Include="Models\SimulationComponent\Data\Engine\FuelConsumptionMap.cs" />
-    <Compile Include="Models\SimulationComponent\Data\Engine\FullLoadCurve.cs" />
+    <Compile Include="Models\SimulationComponent\Data\Engine\EngineFullLoadCurve.cs" />
     <Compile Include="Models\SimulationComponent\Data\IAuxiliaryCycleData.cs" />
     <Compile Include="Models\SimulationComponent\Data\GearboxData.cs" />
     <Compile Include="Models\SimulationComponent\Data\Gearbox\GearData.cs" />
diff --git a/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs b/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs
index 25b0266dbd..68275acd63 100644
--- a/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs
+++ b/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs
@@ -151,7 +151,7 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation
 
 			while (cycleOut.Request(absTime, dt) is ResponseSuccess) {
 				Assert.AreEqual(absTime, outPort.AbsTime);
-				Assert.AreEqual(dt, outPort.Ds);
+				Assert.AreEqual(dt, outPort.Dt);
 
 				var time = absTime + dt / 2;
 				var simulationInterval = dt;
diff --git a/VectoCoreTest/Models/SimulationComponent/CombustionEngineTest.cs b/VectoCoreTest/Models/SimulationComponent/CombustionEngineTest.cs
index 59edcaf7f4..b7b12bbdb9 100644
--- a/VectoCoreTest/Models/SimulationComponent/CombustionEngineTest.cs
+++ b/VectoCoreTest/Models/SimulationComponent/CombustionEngineTest.cs
@@ -174,7 +174,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 			var i = 0;
 			// dt = TimeSpan.FromSeconds(double.Parse(TestContext.DataRow["dt"].ToString(), CultureInfo.InvariantCulture));
 			// dt = TimeSpan.FromSeconds(expectedResults.Rows[i].ParseDouble(0)) - t;
-			var engineLoadPower = engineData.GetFullLoadCurve(0).FullLoadStationaryPower(angularSpeed);
+			var engineLoadPower = engineData.FullLoadCurve.FullLoadStationaryPower(angularSpeed);
 			idlePower = Double.Parse(TestContext.DataRow["finalIdleLoad"].ToString()).SI<Watt>();
 			for (; t < 25; t += dt, i++) {
 				dt = (expectedResults.Rows[i + 1].ParseDouble(0) - expectedResults.Rows[i].ParseDouble(0)).SI<Second>();
@@ -232,10 +232,6 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 			var idle = engineData.IdleSpeed;
 			Assert.AreEqual(58.6430628670095, idle.Value(), 0.000001);
 			Assert.IsTrue(idle.HasEqualUnit(0.SI<PerSecond>()));
-
-			var flc0 = engineData.GetFullLoadCurve(0);
-
-			AssertException<KeyNotFoundException>(() => { var flc10000 = engineData.GetFullLoadCurve(1000); });
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCoreTest/Models/SimulationComponentData/FullLoadCurveTest.cs b/VectoCoreTest/Models/SimulationComponentData/FullLoadCurveTest.cs
index 79d610acec..a8adffc819 100644
--- a/VectoCoreTest/Models/SimulationComponentData/FullLoadCurveTest.cs
+++ b/VectoCoreTest/Models/SimulationComponentData/FullLoadCurveTest.cs
@@ -15,7 +15,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		[TestMethod]
 		public void TestFullLoadStaticTorque()
 		{
-			var fldCurve = FullLoadCurve.ReadFromFile(CoachEngineFLD);
+			var fldCurve = EngineFullLoadCurve.ReadFromFile(CoachEngineFLD);
 
 			Assert.AreEqual(1180, fldCurve.FullLoadStationaryTorque(560.RPMtoRad()).Value(), Tolerance);
 			Assert.AreEqual(1352, fldCurve.FullLoadStationaryTorque(2000.RPMtoRad()).Value(), Tolerance);
@@ -25,14 +25,14 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		[TestMethod]
 		public void TestFullLoadEngineSpeedRated()
 		{
-			var fldCurve = FullLoadCurve.ReadFromFile(CoachEngineFLD);
+			var fldCurve = EngineFullLoadCurve.ReadFromFile(CoachEngineFLD);
 			Assert.AreEqual(181.8444, (double)fldCurve.RatedSpeed, Tolerance);
 		}
 
 		[TestMethod]
 		public void TestFullLoadStaticPower()
 		{
-			var fldCurve = FullLoadCurve.ReadFromFile(CoachEngineFLD);
+			var fldCurve = EngineFullLoadCurve.ReadFromFile(CoachEngineFLD);
 
 			Assert.AreEqual(69198.814183, fldCurve.FullLoadStationaryPower(560.RPMtoRad()).Value(), Tolerance);
 			Assert.AreEqual(283162.218372, fldCurve.FullLoadStationaryPower(2000.RPMtoRad()).Value(), Tolerance);
@@ -42,7 +42,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		[TestMethod]
 		public void TestDragLoadStaticTorque()
 		{
-			var fldCurve = FullLoadCurve.ReadFromFile(CoachEngineFLD);
+			var fldCurve = EngineFullLoadCurve.ReadFromFile(CoachEngineFLD);
 
 			Assert.AreEqual(-149, fldCurve.DragLoadStationaryTorque(560.RPMtoRad()).Value(), Tolerance);
 			Assert.AreEqual(-301, fldCurve.DragLoadStationaryTorque(2000.RPMtoRad()).Value(), Tolerance);
@@ -54,7 +54,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		[TestMethod]
 		public void TestDragLoadStaticPower()
 		{
-			var fldCurve = FullLoadCurve.ReadFromFile(CoachEngineFLD);
+			var fldCurve = EngineFullLoadCurve.ReadFromFile(CoachEngineFLD);
 
 			Assert.AreEqual(-8737.81636, fldCurve.DragLoadStationaryPower(560.RPMtoRad()).Value(), Tolerance);
 			Assert.AreEqual(-63041.29254, fldCurve.DragLoadStationaryPower(2000.RPMtoRad()).Value(), Tolerance);
@@ -64,7 +64,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		[TestMethod]
 		public void TestPT1()
 		{
-			var fldCurve = FullLoadCurve.ReadFromFile(CoachEngineFLD);
+			var fldCurve = EngineFullLoadCurve.ReadFromFile(CoachEngineFLD);
 
 			Assert.AreEqual(0.6, fldCurve.PT1(560.RPMtoRad()).Value(), Tolerance);
 			Assert.AreEqual(0.25, fldCurve.PT1(2000.RPMtoRad()).Value(), Tolerance);
@@ -78,7 +78,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		public void Test_FileRead_WrongFileFormat_InsufficientColumns()
 		{
 			AssertHelper.Exception<VectoException>(
-				() => FullLoadCurve.ReadFromFile(@"TestData\Components\FullLoadCurve insufficient columns.vfld"),
+				() => EngineFullLoadCurve.ReadFromFile(@"TestData\Components\FullLoadCurve insufficient columns.vfld"),
 				"FullLoadCurve Data File must consist of at least 3 columns.");
 		}
 
@@ -88,7 +88,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		[TestMethod]
 		public void Test_FileRead_HeaderColumnsNotNamedCorrectly()
 		{
-			FullLoadCurve.ReadFromFile(@"TestData\Components\FullLoadCurve wrong header.vfld");
+			EngineFullLoadCurve.ReadFromFile(@"TestData\Components\FullLoadCurve wrong header.vfld");
 			//todo: check log file: ensure header warning was written!
 		}
 
@@ -98,7 +98,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		[TestMethod]
 		public void Test_FileRead_NoHeader()
 		{
-			var curve = FullLoadCurve.ReadFromFile(@"TestData\Components\FullLoadCurve no header.vfld");
+			var curve = EngineFullLoadCurve.ReadFromFile(@"TestData\Components\FullLoadCurve no header.vfld");
 			var result = curve.FullLoadStationaryTorque(1.SI<PerSecond>());
 			Assert.AreNotEqual(result.Value(), 0.0);
 		}
@@ -110,7 +110,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		public void Test_FileRead_InsufficientEntries()
 		{
 			AssertHelper.Exception<VectoException>(
-				() => FullLoadCurve.ReadFromFile(@"TestData\Components\FullLoadCurve insufficient entries.vfld"),
+				() => EngineFullLoadCurve.ReadFromFile(@"TestData\Components\FullLoadCurve insufficient entries.vfld"),
 				"FullLoadCurve must consist of at least two lines with numeric values (below file header)");
 		}
 	}
diff --git a/VectoCoreTest/TestData/Components/12t Delivery Truck.veng b/VectoCoreTest/TestData/Components/12t Delivery Truck.veng
index e4c8d2bde4..96d53aa5f1 100644
--- a/VectoCoreTest/TestData/Components/12t Delivery Truck.veng	
+++ b/VectoCoreTest/TestData/Components/12t Delivery Truck.veng	
@@ -1,25 +1,20 @@
 {
   "Header": {
-    "CreatedBy": " ()",
-    "Date": "3/4/2015 12:31:04 PM",
-    "AppVersion": "2.0.4-beta3",
-    "FileVersion": 2
+    "CreatedBy": "Raphael Luz IVT TU-Graz (14fea510-e457-4bf6-860f-a9514dc327f1)",
+    "Date": "25.06.2015 08:59:55",
+    "AppVersion": "2.2 beta",
+    "FileVersion": 3
   },
   "Body": {
-    "SavedInDeclMode": false,
+    "SavedInDeclMode": true,
     "ModelName": "Generic 12t Delivery Truck",
     "Displacement": 7700.0,
     "IdlingSpeed": 600.0,
     "Inertia": 3.789,
-    "FullLoadCurves": [
-      {
-        "Path": "12t Delivery Truck.vfld",
-        "Gears": "0 - 99"
-      }
-    ],
+    "FullLoadCurve": "12t Delivery Truck.vfld",
     "FuelMap": "12t Delivery Truck.vmap",
-    "WHTC-Urban": 215.0,
-    "WHTC-Rural": 202.0,
-    "WHTC-Motorway": 204.0
+    "WHTC-Urban": 0.99,
+    "WHTC-Rural": 0.99,
+    "WHTC-Motorway": 1.01
   }
 }
\ No newline at end of file
diff --git a/VectoCoreTest/TestData/Components/12t Delivery Truck.vgbx b/VectoCoreTest/TestData/Components/12t Delivery Truck.vgbx
index 71a6413e1f..922993ec9f 100644
--- a/VectoCoreTest/TestData/Components/12t Delivery Truck.vgbx	
+++ b/VectoCoreTest/TestData/Components/12t Delivery Truck.vgbx	
@@ -1,9 +1,9 @@
 {
   "Header": {
-    "CreatedBy": "Raphael Luz IVT TU-Graz (85407225-fc3f-48a8-acda-c84a05df6837)",
-    "Date": "29.07.2014 16:58:58",
-    "AppVersion": "2.0.4-beta",
-    "FileVersion": 4
+    "CreatedBy": "Raphael Luz IVT TU-Graz (14fea510-e457-4bf6-860f-a9514dc327f1)",
+    "Date": "24.06.2015 09:33:31",
+    "AppVersion": "2.2 beta",
+    "FileVersion": 5
   },
   "Body": {
     "SavedInDeclMode": true,
@@ -19,37 +19,43 @@
         "Ratio": 6.75,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "-"
+        "ShiftPolygon": "-",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 3.6,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "-"
+        "ShiftPolygon": "-",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 2.13,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "-"
+        "ShiftPolygon": "-",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 1.39,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "-"
+        "ShiftPolygon": "-",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 1.0,
         "LossMap": "Direct Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "-"
+        "ShiftPolygon": "-",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 0.78,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "-"
+        "ShiftPolygon": "-",
+        "FullLoadCurve": "<NOFILE>"
       }
     ],
     "TqReserve": 20.0,
diff --git a/VectoCoreTest/TestData/Components/24t Coach.veng b/VectoCoreTest/TestData/Components/24t Coach.veng
index b113b3cbfc..d93e66348b 100644
--- a/VectoCoreTest/TestData/Components/24t Coach.veng	
+++ b/VectoCoreTest/TestData/Components/24t Coach.veng	
@@ -1,9 +1,9 @@
 {
   "Header": {
-    "CreatedBy": " ()",
-    "Date": "3/4/2015 12:26:24 PM",
-    "AppVersion": "2.0.4-beta3",
-    "FileVersion": 2
+    "CreatedBy": "Raphael Luz IVT TU-Graz (14fea510-e457-4bf6-860f-a9514dc327f1)",
+    "Date": "25.06.2015 11:23:22",
+    "AppVersion": "2.2 beta",
+    "FileVersion": 3
   },
   "Body": {
     "SavedInDeclMode": false,
@@ -11,12 +11,7 @@
     "Displacement": 12730.0,
     "IdlingSpeed": 560.0,
     "Inertia": 3.8,
-    "FullLoadCurves": [
-      {
-        "Path": "24t Coach.vfld",
-        "Gears": "0 - 99"
-      }
-    ],
+    "FullLoadCurve": "24t Coach.vfld",
     "FuelMap": "24t Coach.vmap",
     "WHTC-Urban": 0.0,
     "WHTC-Rural": 0.0,
diff --git a/VectoCoreTest/TestData/Components/24t Coach.vgbx b/VectoCoreTest/TestData/Components/24t Coach.vgbx
index 7d9bfab465..88dc64fa30 100644
--- a/VectoCoreTest/TestData/Components/24t Coach.vgbx	
+++ b/VectoCoreTest/TestData/Components/24t Coach.vgbx	
@@ -1,9 +1,9 @@
 {
   "Header": {
-    "CreatedBy": "Raphael Luz IVT TU-Graz (85407225-fc3f-48a8-acda-c84a05df6837)",
-    "Date": "3/4/2015 12:26:24 PM",
-    "AppVersion": "2.0.4-beta",
-    "FileVersion": 4
+    "CreatedBy": "Raphael Luz IVT TU-Graz (14fea510-e457-4bf6-860f-a9514dc327f1)",
+    "Date": "25.06.2015 11:23:31",
+    "AppVersion": "2.2 beta",
+    "FileVersion": 5
   },
   "Body": {
     "SavedInDeclMode": false,
@@ -19,49 +19,57 @@
         "Ratio": 6.38,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "ShiftPolygons.vgbs"
+        "ShiftPolygon": "ShiftPolygons.vgbs",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 4.63,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "ShiftPolygons.vgbs"
+        "ShiftPolygon": "ShiftPolygons.vgbs",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 3.44,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "ShiftPolygons.vgbs"
+        "ShiftPolygon": "ShiftPolygons.vgbs",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 2.59,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "ShiftPolygons.vgbs"
+        "ShiftPolygon": "ShiftPolygons.vgbs",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 1.86,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "ShiftPolygons.vgbs"
+        "ShiftPolygon": "ShiftPolygons.vgbs",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 1.35,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "ShiftPolygons.vgbs"
+        "ShiftPolygon": "ShiftPolygons.vgbs",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 1.0,
         "LossMap": "Direct Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "ShiftPolygons.vgbs"
+        "ShiftPolygon": "ShiftPolygons.vgbs",
+        "FullLoadCurve": "<NOFILE>"
       },
       {
         "Ratio": 0.76,
         "LossMap": "Indirect Gear.vtlm",
         "TCactive": false,
-        "ShiftPolygon": "ShiftPolygons.vgbs"
+        "ShiftPolygon": "ShiftPolygons.vgbs",
+        "FullLoadCurve": "<NOFILE>"
       }
     ],
     "TqReserve": 20.0,
-- 
GitLab