From 680d184c1ee30d31a2c9c0044573987b3edf6b1e Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Mon, 22 Jun 2020 21:17:16 +0200
Subject: [PATCH] more work on hybrid strategy

---
 .../Models/Declaration/DeclarationData.cs     |   3 +
 .../Simulation/Impl/PowertrainBuilder.cs      |  24 +-
 .../SimulationComponent/IHybridController.cs  |   2 +-
 .../Impl/AMTShiftStrategy.cs                  |   8 +-
 .../Impl/AMTShiftStrategyOptimized.cs         |  40 +--
 .../SimulationComponent/Impl/Battery.cs       |   2 +-
 .../SimulationComponent/Impl/Gearbox.cs       |   4 +-
 .../Impl/HybridController.cs                  |  20 +-
 .../Impl/SimpleHybridController.cs            |  12 +-
 .../Impl/StopStartCombustionEngine.cs         |   9 +
 .../Strategies/HybridStrategy.cs              | 287 +++++++++++++-----
 .../Integration/Hybrid/ParallelHybridTest.cs  | 186 +++++++++++-
 12 files changed, 466 insertions(+), 131 deletions(-)

diff --git a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs
index 15ea2fb218..c86439a6fb 100644
--- a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs
+++ b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs
@@ -452,6 +452,9 @@ namespace TUGraz.VectoCore.Models.Declaration
 
 		public static class GearboxTCU
 		{
+
+			public static readonly MeterPerSecond MIN_SPEED_AFTER_TRACTION_INTERRUPTION = 5.KMPHtoMeterPerSecond();
+
 			public const double TorqueReserve = 0;
 			public const double TorqueReserveStart = 0.2;
 
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
index 23a8b92bc3..954c55c70b 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
@@ -39,6 +39,8 @@ using TUGraz.VectoCommon.Models;
 using TUGraz.VectoCommon.Utils;
 using TUGraz.VectoCore.Configuration;
 using TUGraz.VectoCore.InputData.Reader.ComponentData;
+using TUGraz.VectoCore.Models.Connector.Ports;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
 using TUGraz.VectoCore.Models.Declaration;
 using TUGraz.VectoCore.Models.Simulation.Data;
 using TUGraz.VectoCore.Models.Simulation.DataBus;
@@ -493,7 +495,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			if (gbx == null) {
 				throw new VectoException("Gearbox can not be used for parallel hybrid");
 			}
-			var engine = new CombustionEngine(container, data.EngineData);
+			var engine = new StopStartCombustionEngine(container, data.EngineData);
 
 			var ctl = new SimpleHybridController(container, es, clutch);
 
@@ -501,9 +503,11 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			ctl.Engine = engine;
 
 			var vehicle = new Vehicle(container, data.VehicleData, data.AirdragData);
+			
 			//var dummyDriver = new Driver(container, data.DriverData, new DefaultDriverStrategy(container));
 			var powertrain = vehicle
-				.AddComponent(new Wheels(container, data.VehicleData.DynamicTyreRadius, data.VehicleData.WheelsInertia))
+				.AddComponent(
+					new Wheels(container, data.VehicleData.DynamicTyreRadius, data.VehicleData.WheelsInertia))
 				.AddComponent(ctl)
 				.AddComponent(GetElectricMachine(PowertrainPosition.HybridP4, data.ElectricMachinesData, container, es, ctl))
 				.AddComponent(new AxleGear(container, data.AxleGearData))
@@ -734,6 +738,22 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 		}
 	}
 
+	//public class DummyFvOutPort : IFvOutPort {
+	//	#region Implementation of IFvOutPort
+
+	//	public IResponse Request(Second absTime, Second dt, Newton force, MeterPerSecond velocity, bool dryRun)
+	//	{
+	//		return new ResponseSuccess(this);
+	//	}
+
+	//	public IResponse Initialize(Newton vehicleForce, MeterPerSecond vehicleSpeed)
+	//	{
+	//		return new ResponseSuccess(this);
+	//	}
+
+	//	#endregion
+	//}
+
 	internal class DummyDriverInfo : VectoSimulationComponent, IDriverInfo
 	{
 		public DummyDriverInfo(VehicleContainer container) : base(container)
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/IHybridController.cs b/VectoCore/VectoCore/Models/SimulationComponent/IHybridController.cs
index 4fb7c26f19..2be5d30ce2 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/IHybridController.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/IHybridController.cs
@@ -12,6 +12,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent {
 
 		IElectricMotorControl ElectricMotorControl(PowertrainPosition pos);
 		void AddElectricMotor(PowertrainPosition pos, ElectricMotorData motorDataItem2);
-		ResponseDryRun RequestDryRun(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, HybridStrategyResponse strategySettings);
+		//ResponseDryRun RequestDryRun(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, HybridStrategyResponse strategySettings);
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AMTShiftStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AMTShiftStrategy.cs
index 515ab13e53..50e7027162 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AMTShiftStrategy.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AMTShiftStrategy.cs
@@ -117,10 +117,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		public override uint InitGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity)
 		{
 			if (DataBus.VehicleInfo.VehicleSpeed.IsEqual(0)) {
-				return InitStartGear(outTorque, outAngularVelocity);
+				return InitStartGear(absTime, outTorque, outAngularVelocity);
 			}
 			for (var gear = (uint)ModelData.Gears.Count; gear > 1; gear--) {
-				var response = _gearbox.Initialize(gear, outTorque, outAngularVelocity);
+				var response = _gearbox.Initialize(absTime, gear, outTorque, outAngularVelocity);
 
 				var inAngularSpeed = outAngularVelocity * ModelData.Gears[gear].Ratio;
 				var fullLoadPower = response.Engine.PowerRequest - response.DeltaFullLoad;
@@ -150,7 +150,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			return 1;
 		}
 
-		private uint InitStartGear(NewtonMeter outTorque, PerSecond outAngularVelocity)
+		private uint InitStartGear(Second absTime, NewtonMeter outTorque, PerSecond outAngularVelocity)
 		{
 			for (var gear = MaxStartGear; gear > 1; gear--) {
 				var inAngularSpeed = outAngularVelocity * ModelData.Gears[gear].Ratio;
@@ -160,7 +160,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					continue;
 				}
 
-				var response = _gearbox.Initialize(gear, outTorque, outAngularVelocity);
+				var response = _gearbox.Initialize(absTime, gear, outTorque, outAngularVelocity);
 
 				var fullLoadPower = response.Engine.DynamicFullLoadPower; //EnginePowerRequest - response.DeltaFullLoad;
 				var reserve = 1 - response.Engine.PowerRequest / fullLoadPower;
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AMTShiftStrategyOptimized.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AMTShiftStrategyOptimized.cs
index 11f494e2d6..265cf8f686 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AMTShiftStrategyOptimized.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AMTShiftStrategyOptimized.cs
@@ -31,7 +31,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		private Kilogram vehicleMass;
 		protected internal ResponseDryRun minFCResponse;
 
-		public static readonly MeterPerSecond MIN_SPEED_AFTER_TRACTION_INTERRUPTION = 5.KMPHtoMeterPerSecond();
+		
 
 		public AMTShiftStrategyOptimized(VectoRunData runData, IVehicleContainer dataBus) : base(runData, dataBus)
 		{
@@ -91,7 +91,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			}
 
 			var estimatedVelocityPostShift = VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
-			if (!estimatedVelocityPostShift.IsGreater(MIN_SPEED_AFTER_TRACTION_INTERRUPTION)) {
+			if (!estimatedVelocityPostShift.IsGreater(DeclarationData.GearboxTCU.MIN_SPEED_AFTER_TRACTION_INTERRUPTION)) {
 				return currentGear;
 			}
 
@@ -234,7 +234,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			var fcCurrent = double.NaN;
 
 			var estimatedVelocityPostShift = VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
-			if (!estimatedVelocityPostShift.IsGreater(MIN_SPEED_AFTER_TRACTION_INTERRUPTION)) {
+			if (!estimatedVelocityPostShift.IsGreater(DeclarationData.GearboxTCU.MIN_SPEED_AFTER_TRACTION_INTERRUPTION)) {
 				return currentGear;
 			}
 
@@ -286,23 +286,23 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		#endregion
 
-		protected ResponseDryRun RequestDryRunWithGear(
-			Second absTime, Second dt, MeterPerSecond vehicleSpeed, MeterPerSquareSecond acceleration, uint tryNextGear)
-		{
-			LogEnabled = false;
-			TestContainerGbx.Disengaged = false;
-			TestContainerGbx.Gear = tryNextGear;
-
-			//TestContainer.GearboxOutPort.Initialize(outTorque, outAngularVelocity);
-			TestContainer.VehiclePort.Initialize(vehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient);
-			var response = (ResponseDryRun)TestContainer.VehiclePort.Request(
-				0.SI<Second>(), dt, acceleration, DataBus.DrivingCycleInfo.RoadGradient, true);
-
-			//var response = (ResponseDryRun)TestContainer.GearboxOutPort.Request(
-			//	0.SI<Second>(), dt, outTorque, outAngularVelocity, true);
-			LogEnabled = true;
-			return response;
-		}
+		//protected ResponseDryRun RequestDryRunWithGear(
+		//	Second absTime, Second dt, MeterPerSecond vehicleSpeed, MeterPerSquareSecond acceleration, uint tryNextGear)
+		//{
+		//	LogEnabled = false;
+		//	TestContainerGbx.Disengaged = false;
+		//	TestContainerGbx.Gear = tryNextGear;
+
+		//	//TestContainer.GearboxOutPort.Initialize(outTorque, outAngularVelocity);
+		//	TestContainer.VehiclePort.Initialize(vehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient);
+		//	var response = (ResponseDryRun)TestContainer.VehiclePort.Request(
+		//		0.SI<Second>(), dt, acceleration, DataBus.DrivingCycleInfo.RoadGradient, true);
+
+		//	//var response = (ResponseDryRun)TestContainer.GearboxOutPort.Request(
+		//	//	0.SI<Second>(), dt, outTorque, outAngularVelocity, true);
+		//	LogEnabled = true;
+		//	return response;
+		//}
 
 		protected override ResponseDryRun RequestDryRunWithGear(
 			Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, uint tryNextGear)
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Battery.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Battery.cs
index 2afbaa5e43..3e78dd9d2d 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Battery.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Battery.cs
@@ -34,7 +34,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public void Initialize(double initialSoC)
 		{
-			if (initialSoC < ModelData.MinSOC || initialSoC > ModelData.MaxSOC)
+			if (initialSoC.IsSmaller(ModelData.MinSOC) || initialSoC.IsGreater(ModelData.MaxSOC))
 			{
 				throw new VectoException("SoC must be between {0} and {1}", ModelData.MinSOC, ModelData.MaxSOC);
 			}
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs
index 9b1b8f4b28..017dcdc51e 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs
@@ -127,7 +127,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			get { return true; }
 		}
 
-		internal ResponseDryRun Initialize(uint gear, NewtonMeter outTorque, PerSecond outAngularVelocity)
+		internal ResponseDryRun Initialize(Second absTime, uint gear, NewtonMeter outTorque, PerSecond outAngularVelocity)
 		{
 			var oldGear = Gear;
 			Gear = gear;
@@ -148,7 +148,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			var response =
 				(ResponseDryRun)
-				NextComponent.Request(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, inTorque,
+				NextComponent.Request(absTime, Constants.SimulationSettings.TargetTimeInterval, inTorque,
 					inAngularVelocity, true); //NextComponent.Initialize(inTorque, inAngularVelocity);
 			//response.Switch().
 			//	Case<ResponseSuccess>().
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/HybridController.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/HybridController.cs
index f06fd82d6e..4b1789c3f7 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/HybridController.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/HybridController.cs
@@ -55,13 +55,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			_electricMotorCtl[pos] = new ElectricMotorController(this, motorData);
 		}
 
-		public ResponseDryRun RequestDryRun(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, HybridStrategyResponse strategySettings)
-		{
-			ApplyStrategySettings(strategySettings);
-			var retVal = NextComponent.Request(absTime, dt, outTorque, outAngularVelocity, true);
+		//public ResponseDryRun RequestDryRun(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, HybridStrategyResponse strategySettings)
+		//{
+		//	ApplyStrategySettings(strategySettings);
+		//	var retVal = NextComponent.Request(absTime, dt, outTorque, outAngularVelocity, true);
 
-			return retVal as ResponseDryRun;
-		}
+		//	return retVal as ResponseDryRun;
+		//}
 
 		private void ApplyStrategySettings(HybridStrategyResponse strategySettings)
 		{
@@ -242,11 +242,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				PerSecond outAngularVelocity)
 			{
 				if (DataBus.VehicleInfo.VehicleSpeed.IsEqual(0)) {
-					return InitStartGear(outTorque, outAngularVelocity);
+					return InitStartGear(absTime, outTorque, outAngularVelocity);
 				}
 
 				for (var gear = (uint)ModelData.Gears.Count; gear > 1; gear--) {
-					var response = _gearbox.Initialize(gear, outTorque, outAngularVelocity);
+					var response = _gearbox.Initialize(absTime, gear, outTorque, outAngularVelocity);
 
 					var inAngularSpeed = outAngularVelocity * ModelData.Gears[gear].Ratio;
 					var fullLoadPower = response.Engine.PowerRequest - response.DeltaFullLoad;
@@ -279,7 +279,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				return 1;
 			}
 
-			protected uint InitStartGear(NewtonMeter outTorque, PerSecond outAngularVelocity)
+			protected uint InitStartGear(Second absTime, NewtonMeter outTorque, PerSecond outAngularVelocity)
 			{
 				for (var gear = MaxStartGear; gear > 1; gear--) {
 					var inAngularSpeed = outAngularVelocity * ModelData.Gears[gear].Ratio;
@@ -289,7 +289,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 						continue;
 					}
 
-					var response = _gearbox.Initialize(gear, outTorque, outAngularVelocity);
+					var response = _gearbox.Initialize(absTime, gear, outTorque, outAngularVelocity);
 
 					var fullLoadPower =
 						response.Engine.DynamicFullLoadPower; //EnginePowerRequest - response.DeltaFullLoad;
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs
index fc55b43ae9..0d54cb86e1 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs
@@ -85,12 +85,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl {
 			_electricMotorCtl[pos] = new ElectricMotorController(this, motorData);
 		}
 
-		public ResponseDryRun RequestDryRun(
-			Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
-			HybridStrategyResponse strategySettings)
-		{
-			throw new System.NotImplementedException();
-		}
+		//public ResponseDryRun RequestDryRun(
+		//	Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
+		//	HybridStrategyResponse strategySettings)
+		//{
+		//	throw new System.NotImplementedException();
+		//}
 
 		#endregion
 
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/StopStartCombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/StopStartCombustionEngine.cs
index 514ce4b6c8..fba8022dcb 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/StopStartCombustionEngine.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/StopStartCombustionEngine.cs
@@ -172,4 +172,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl {
 			container[ModalResultField.P_WHR_mech_corr] = (1 - EngineStopStartUtilityFactor) * pWHRmechCorr;
 		}
 	}
+
+	public class SimplePowerrtrainCombustionEngine : StopStartCombustionEngine
+	{
+		public SimplePowerrtrainCombustionEngine(
+			IVehicleContainer container, CombustionEngineData modelData, bool pt1Disabled = false) : base(
+			container, modelData, pt1Disabled) { }
+
+		public EngineState EnginePreviousState { get { return PreviousState; } }
+	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs
index 571750f250..da91b3aa31 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
+using System.Runtime.InteropServices;
 using TUGraz.VectoCommon.Exceptions;
 using TUGraz.VectoCommon.InputData;
 using TUGraz.VectoCommon.Models;
@@ -17,8 +18,45 @@ using TUGraz.VectoCore.OutputData;
 
 namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 {
+	public class TestPowertrain
+	{
+		public SimplePowertrainContainer Container;
+		public Gearbox Gearbox;
+		public SimpleHybridController HybridController;
+		public Battery Battery;
+		public Clutch Clutch;
+
+		public StopStartCombustionEngine CombustionEngine;
+
+		public TestPowertrain(SimplePowertrainContainer container)
+		{
+			Container = container;
+			Gearbox = Container.GearboxCtl as Gearbox;
+			HybridController = Container.HybridController as SimpleHybridController;
+			Battery = Container.BatteryInfo as Battery;
+			Clutch = Container.ClutchInfo as Clutch;
+			CombustionEngine = Container.EngineInfo as StopStartCombustionEngine;
+			if (Gearbox == null) {
+				throw new VectoException("Unknown gearboxtype in TestContainer: {0}", Container.GearboxCtl.GetType().FullName);
+			}
+
+			if (HybridController == null) {
+				throw new VectoException("Unknown HybridController in TestContainer: {0}", Container.HybridController.GetType().FullName);
+			}
+		}
+	}
+
 	public class HybridStrategy : LoggingObject, IHybridControlStrategy
 	{
+		public class StrategyState
+		{
+			public HybridStrategyResponse Response { get; set; }
+			public List<HybridResultEntry> Evaluations;
+			public HybridResultEntry Solution { get; set; }
+
+			public bool GearboxEngaged;
+		}
+
 		private VectoRunData ModelData;
 		private IDataBus DataBus;
 
@@ -27,15 +65,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 		private bool ElectricMotorCanPropellDuringTractionInterruption;
 
 		//private Second lastShiftTime;
-		private Gearbox TestContainerGbx;
-		private SimplePowertrainContainer TestContainer;
+		
+
+		private TestPowertrain TestPoweretrain;
+
 		protected readonly VelocityRollingLookup VelocityDropData;
-		private SimpleHybridController TestContainerHybCtl;
-		public Battery TestContainerBattery;
-		private Clutch TestContainerClutch;
 
 
-		protected HybridStrategyResponse Response { get; set; }
+		protected StrategyState CurrentState = new StrategyState();
+		protected StrategyState PreviousState = new StrategyState();
 
 		public HybridStrategy(VectoRunData runData, IVehicleContainer vehicleContainer)
 		{
@@ -54,20 +92,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 
 			var modData = new ModalDataContainer(runData, null, new[] { FuelData.Diesel }, null, false);
 			var builder = new PowertrainBuilder(modData);
-			TestContainer = new SimplePowertrainContainer(runData);
-			builder.BuildSimpleHybridPowertrain(runData, TestContainer);
-			TestContainerGbx = TestContainer.GearboxCtl as Gearbox;
-			TestContainerHybCtl = TestContainer.HybridController as SimpleHybridController;
-			TestContainerBattery = TestContainer.BatteryInfo as Battery;
-			TestContainerClutch = TestContainer.ClutchInfo as Clutch;
-			if (TestContainerGbx == null) {
-				throw new VectoException("Unknown gearboxtype in TestContainer: {0}", TestContainer.GearboxCtl.GetType().FullName);
-			}
-
-			if (TestContainerHybCtl == null) {
-				throw new VectoException("Unknown HybridController in TestContainer: {0}", TestContainer.HybridController.GetType().FullName);
-			}
+			var testContainer = new SimplePowertrainContainer(runData);
+			builder.BuildSimpleHybridPowertrain(runData, testContainer);
 
+			TestPoweretrain = new TestPowertrain(testContainer);
+			
 			// register pre-processors
 			var maxG = runData.Cycle.Entries.Max(x => Math.Abs(x.RoadGradientPercent.Value())) + 1;
 			var grad = Convert.ToInt32(maxG / 2) * 2;
@@ -77,7 +106,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 
 			VelocityDropData = new VelocityRollingLookup();
 			vehicleContainer.AddPreprocessor(
-				new VelocitySpeedGearshiftPreprocessor(VelocityDropData, runData.GearboxData.TractionInterruption, TestContainer, -grad, grad, 2));
+				new VelocitySpeedGearshiftPreprocessor(VelocityDropData, runData.GearboxData.TractionInterruption, testContainer, -grad, grad, 2));
 
 			var shiftStrategyParameters = runData.GearshiftParameters;
 			if (shiftStrategyParameters == null) {
@@ -100,16 +129,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 			}
 
 
-			HybridResultEntry tmp = null;
-			Tuple<bool, uint> gs = null;
+			var eval = new List<HybridResultEntry>();
+			
 			if (DataBus.DriverInfo.DrivingAction == DrivingAction.Accelerate || DataBus.DriverInfo.DrivingAction == DrivingAction.Brake) {
 				if (ElectricMotorCanPropellDuringTractionInterruption || DataBus.GearboxInfo.GearEngaged(absTime)) {
-					tmp = FindSolution(absTime, dt, outTorque, outAngularVelocity);
-					if (tmp != null) {
-						gs = HandleGearshift(absTime, tmp.Response);
-					}
+					eval = FindSolution(absTime, dt, outTorque, outAngularVelocity);
 				} else {
-					tmp = new HybridResultEntry {
+					eval.Add(new HybridResultEntry {
 						U = double.NaN,
 						Response = null,
 						Setting = new HybridStrategyResponse() {
@@ -118,11 +144,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 							MechanicalAssistPower = ElectricMotorsOff
 						},
 						FuelCosts = double.NaN
-					};
+					});
 				}
 			}
 			if (DataBus.DriverInfo.DrivingAction == DrivingAction.Roll || DataBus.DriverInfo.DrivingAction == DrivingAction.Coast) {
-				tmp = new HybridResultEntry {
+				eval.Add(new HybridResultEntry {
 					U = double.NaN,
 					Response = null,
 					Setting = new HybridStrategyResponse() {
@@ -131,29 +157,38 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 						MechanicalAssistPower = ElectricMotorsOff
 					},
 					FuelCosts = double.NaN
-				};
+				});
 			}
-			if (DataBus.DriverInfo.DrivingAction == DrivingAction.Brake && tmp == null) {
-				tmp = MaxRecuperationSetting(absTime, dt, outTorque, outAngularVelocity);
-				gs = HandleGearshift(absTime, tmp.Response);
+			if (DataBus.DriverInfo.DrivingAction == DrivingAction.Brake && eval.Count  == 0) {
+				eval.Add(MaxRecuperationSetting(absTime, dt, outTorque, outAngularVelocity));
 			}
 
+			var best = eval.Where(x => !double.IsNaN(x.Score)).OrderBy(x => x.Score).FirstOrDefault() ?? eval.FirstOrDefault();
+			if (best == null) {
+				// TODO!
+			}
+			Tuple<bool, uint> gs = null;
+			if (best?.Response != null) {
+				gs = HandleGearshift(absTime, best);
+			}
 
 			var retVal = new HybridStrategyResponse() {
-				CombustionEngineOn = tmp.Setting.CombustionEngineOn,
-				GearboxInNeutral = tmp.Setting.GearboxInNeutral,
-				MechanicalAssistPower = tmp.Setting.MechanicalAssistPower,
+				CombustionEngineOn = best.Setting.CombustionEngineOn,
+				GearboxInNeutral = best.Setting.GearboxInNeutral,
+				MechanicalAssistPower = best.Setting.MechanicalAssistPower,
 				ShiftRequired = gs?.Item1 ?? false,
 				NextGear = gs?.Item2 ?? 0,
 			};
-			Response = dryRun ? null : retVal;
+			CurrentState.Response = dryRun ? null : retVal;
 			if (!dryRun) {
-				Solution = tmp;
+				CurrentState.Solution = best;
+				CurrentState.Evaluations = eval;
+				CurrentState.GearboxEngaged = DataBus.GearboxInfo.GearEngaged(absTime);
 			}
 			return retVal;
 		}
 
-		public HybridResultEntry Solution { get; set; }
+		
 
 		private HybridResultEntry MaxRecuperationSetting(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity)
 		{
@@ -162,22 +197,22 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 				GearboxInNeutral = false, // DataBus.GearboxInfo.GearEngaged(absTime),
 				MechanicalAssistPower = ElectricMotorsOff
 			};
-			var firstResponse = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, first);
+			var firstResponse = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, DataBus.GearboxInfo.Gear, first);
 
 		
 			var emPos = ModelData.ElectricMachinesData.First().Item1;
 			var emTorque = firstResponse.ElectricMotor.MaxRecuperationTorque;
-			return TryConfiguration(absTime, dt, outTorque, outAngularVelocity, emPos, emTorque, double.NaN);
+			return TryConfiguration(absTime, dt, outTorque, outAngularVelocity, DataBus.GearboxInfo.Gear, emPos, emTorque, double.NaN);
 		}
 
-		private HybridResultEntry FindSolution(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity)
+		private List<HybridResultEntry> FindSolution(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity)
 		{
 			var first = new HybridStrategyResponse() {
 				CombustionEngineOn = true, //DataBus.EngineCtl.CombustionEngineOn,
 				GearboxInNeutral = false, // DataBus.GearboxInfo.GearEngaged(absTime),
 				MechanicalAssistPower = ElectricMotorsOff
 			};
-			var firstResponse = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, first);
+			var firstResponse = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, DataBus.GearboxInfo.Gear, first);
 
 			//var gearboxEngaged = DataBus.GearboxInfo.GearEngaged(absTime);
 			var emPos = ModelData.ElectricMachinesData.First().Item1;
@@ -188,14 +223,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 				U = double.NaN,
 				Response = firstResponse,
 				Setting = first,
-
+				Gear = DataBus.GearboxInfo.Gear,
 				//Score = CalcualteCosts(firstResponse, dt)
 			};
 			CalcualteCosts(firstResponse, dt, entry);
 			responses.Add(entry);
 
 			if (firstResponse.Gearbox.Gear == 0 && !ElectricMotorCanPropellDuringTractionInterruption) {
-				return responses.First();
+				return responses;
 			}
 
 			var minimumShiftTimePassed = (DataBus.GearboxInfo.LastShift + ModelData.GearboxData.ShiftTime).IsSmallerOrEqual(absTime);
@@ -210,27 +245,35 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 
 			var gear = DataBus.GearboxInfo.Gear;
 			var numGears = ModelData.GearboxData.Gears.Count;
-			for (var nextGear = Math.Max(1, gear - gearRangeDownshift);
+			for (uint nextGear = (uint)Math.Max(1, gear - gearRangeDownshift);
 				nextGear <= Math.Min(numGears, gear + gearRangeUpshift);
-				nextGear++) 
-				{
-					if (!ElectricMotorCanPropellDuringTractionInterruption) {
-						// em is at gearbox input side - angular speed is different so get new 
-					}
-				IterateEMTorque(absTime, dt, outTorque, outAngularVelocity, firstResponse, emTqReq, emPos, responses);
-			}
+				nextGear++) {
+				var baseResponse = firstResponse;
 
-			if (responses.All(x => double.IsNaN(x.Score))) {
-				return null;
+				//if (!ElectricMotorCanPropellDuringTractionInterruption) {
+				// em is at gearbox input side - angular speed is different so get new 
+				baseResponse = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, first);
+
+				//}
+				if (baseResponse == null) {
+					continue;
+				}
+
+				var gearEntry = new HybridResultEntry() {
+					U = double.NaN,
+					Response = baseResponse,
+					Setting = first,
+					Gear = nextGear
+				};
+				CalcualteCosts(baseResponse, dt, gearEntry);
+				responses.Add(gearEntry);
+				IterateEMTorque(absTime, dt, outTorque, outAngularVelocity, nextGear, baseResponse, emTqReq, emPos, responses);
 			}
 
-			var best = responses.Where(x => !double.IsNaN(x.Score)).OrderBy(x => x.Score).First();
-			return best;
+			return responses;
 		}
 
-		private void IterateEMTorque(
-			Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, ResponseDryRun firstResponse,
-			NewtonMeter emTqReq, PowertrainPosition emPos, List<HybridResultEntry> responses)
+		private void IterateEMTorque(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, uint nextGear, ResponseDryRun firstResponse, NewtonMeter emTqReq, PowertrainPosition emPos, List<HybridResultEntry> responses)
 		{
 			const double stepSize = 0.1;
 
@@ -244,7 +287,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 						continue;
 					}
 
-					var tmp = TryConfiguration(absTime, dt, outTorque, outAngularVelocity, emPos, emTorque, u);
+					var tmp = TryConfiguration(absTime, dt, outTorque, outAngularVelocity, nextGear, emPos, emTorque, u);
 					responses.Add(tmp);
 				}
 
@@ -252,11 +295,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 				var emTorqueM = emTqReq * maxU;
 				if (emTorqueM.IsBetween(
 					0.SI<NewtonMeter>(), firstResponse.ElectricMotor.MaxDriveTorque)) {
-					var tmp = TryConfiguration(absTime, dt, outTorque, outAngularVelocity, emPos, emTorqueM, maxU);
+					var tmp = TryConfiguration(absTime, dt, outTorque, outAngularVelocity, nextGear, emPos, emTorqueM, maxU);
 					responses.Add(tmp);
 				}
 			}
-
+			
 			// iterate over 'EM recuperates' up to max available recuperation potential
 			if (firstResponse.ElectricMotor.MaxRecuperationTorque != null) {
 				for (var u = stepSize; u <= 1.0; u += stepSize) {
@@ -266,15 +309,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 						continue;
 					}
 
-					var tmp = TryConfiguration(absTime, dt, outTorque, outAngularVelocity, emPos, emTorque, u);
+					var tmp = TryConfiguration(absTime, dt, outTorque, outAngularVelocity, nextGear, emPos, emTorque, u);
 					responses.Add(tmp);
 				}
 			}
 		}
 
-		private HybridResultEntry TryConfiguration(
-			Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, PowertrainPosition emPos,
-			NewtonMeter emTorque, double u)
+		private HybridResultEntry TryConfiguration(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, uint nextGear, PowertrainPosition emPos, NewtonMeter emTorque, double u)
 		{
 			var cfg = new HybridStrategyResponse() {
 				CombustionEngineOn = true,
@@ -283,35 +324,87 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 					{ emPos, emTorque }
 				}
 			};
-			var resp = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, cfg);
+			var resp = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, cfg);
 			
 			var tmp = new HybridResultEntry {
 				U = u,
 				Setting = cfg,
 				Response = resp,
-				//Score = cost
+				Gear = nextGear,
 			};
 			CalcualteCosts(resp, dt, tmp);
 			return tmp;
 		}
 
-		private ResponseDryRun RequestDryRun(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, HybridStrategyResponse cfg)
+		private ResponseDryRun RequestDryRun(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, uint nextGear, HybridStrategyResponse cfg)
 		{
-			TestContainerHybCtl.ApplyStrategySettings(cfg);
-			TestContainerGbx.Gear = DataBus.GearboxInfo.Gear;
-			TestContainerHybCtl.Initialize(Controller.PreviousState.OutTorque, Controller.PreviousState.OutAngularVelocity);
-			TestContainerClutch.Initialize(DataBus.ClutchInfo.ClutchLosses);
-			TestContainerBattery.Initialize(DataBus.BatteryInfo.StateOfCharge);
-			var retVal = TestContainerHybCtl.NextComponent.Request(absTime, dt, outTorque, outAngularVelocity, true);
-			var retVal2 = Controller.RequestDryRun(absTime, dt, outTorque, outAngularVelocity, cfg);
+			TestPoweretrain.Gearbox.Gear = PreviousState.GearboxEngaged ? DataBus.GearboxInfo.Gear : Controller.ShiftStrategy.NextGear.Gear;
+			TestPoweretrain.Container.VehiclePort.Initialize(DataBus.VehicleInfo.VehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
+			TestPoweretrain.HybridController.ApplyStrategySettings(cfg);
+			TestPoweretrain.HybridController.Initialize(Controller.PreviousState.OutTorque, Controller.PreviousState.OutAngularVelocity);
+			TestPoweretrain.Clutch.Initialize(DataBus.ClutchInfo.ClutchLosses);
+			TestPoweretrain.Battery.Initialize(DataBus.BatteryInfo.StateOfCharge);
+
+			TestPoweretrain.CombustionEngine.PreviousState.EnginePower = (DataBus.EngineInfo as CombustionEngine).PreviousState.EnginePower;
+			TestPoweretrain.CombustionEngine.PreviousState.dt = (DataBus.EngineInfo as CombustionEngine).PreviousState.dt;
+			TestPoweretrain.CombustionEngine.PreviousState.EngineSpeed = (DataBus.EngineInfo as CombustionEngine).PreviousState.EngineSpeed;
+			TestPoweretrain.CombustionEngine.PreviousState.EngineTorque = (DataBus.EngineInfo as CombustionEngine).PreviousState.EngineTorque;
+			TestPoweretrain.CombustionEngine.PreviousState.EngineTorqueOut = (DataBus.EngineInfo as CombustionEngine).PreviousState.EngineTorqueOut;
+			TestPoweretrain.CombustionEngine.PreviousState.DynamicFullLoadTorque = (DataBus.EngineInfo as CombustionEngine).PreviousState.DynamicFullLoadTorque;
+			
+			if (nextGear != DataBus.GearboxInfo.Gear) {
+				if (ModelData.GearboxData.Gears[nextGear].Ratio > ModelData.GearshiftParameters.RatioEarlyUpshiftFC) {
+					return null;
+				}
+
+				if (ModelData.GearboxData.Gears[nextGear].Ratio >= ModelData.GearshiftParameters.RatioEarlyDownshiftFC) {
+					return null;
+				}
+
+				var estimatedVelocityPostShift = VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
+				if (!estimatedVelocityPostShift.IsGreater(DeclarationData.GearboxTCU.MIN_SPEED_AFTER_TRACTION_INTERRUPTION)) {
+					return null;
+				}
+
+
+				var vDrop = DataBus.VehicleInfo.VehicleSpeed - estimatedVelocityPostShift;
+				var vehicleSpeedPostShift = DataBus.VehicleInfo.VehicleSpeed - vDrop * ModelData.GearshiftParameters.VelocityDropFactor;
+				TestPoweretrain.Gearbox.Gear = nextGear;
+				TestPoweretrain.Container.VehiclePort.Initialize(
+					vehicleSpeedPostShift, DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
+			}
+
+			// AMT EffShift: estimatedVelocityPostShift < MIN_SPEED => no shift
+
+			// AMT EffShift: engine torqueOut close to dragCurve => no shift
+
+			// AMT EffShift: Ratio EarlyUpshift / Ratio RealyDownshift
+
+			// initialize with new vehicle speed
+			// set gear
+
+			var retVal = TestPoweretrain.HybridController.NextComponent.Request(absTime, dt, outTorque, outAngularVelocity, true);
+
+			if (nextGear != DataBus.GearboxInfo.Gear) {
+				if (retVal.Engine.TorqueOutDemand.IsSmaller(DeclarationData.GearboxTCU.DragMarginFactor * retVal.Engine.DragTorque)) {
+					return null;
+				}
+			}
+
+			//var retVal2 = Controller.RequestDryRun(absTime, dt, outTorque, outAngularVelocity, cfg);
 			return retVal as ResponseDryRun;
 		}
 
 		private void CalcualteCosts(ResponseDryRun resp, Second dt, HybridResultEntry tmp)
 		{
+			if (resp == null) {
+				tmp.FuelCosts = double.NaN;
+				return;
+			}
 			if (!resp.Engine.TotalTorqueDemand.IsBetween(
 				resp.Engine.DragTorque, resp.Engine.DynamicFullLoadTorque)) {
 				tmp.FuelCosts = double.NaN;
+				return;
 			}
 
 			tmp.FuelCosts = ModelData.EngineData.Fuels.Sum(
@@ -321,10 +414,18 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 			tmp.SoCPenalty = 1 - Math.Pow((DataBus.BatteryInfo.StateOfCharge - ModelData.BatteryData.TargetSoC) / (0.5 * (ModelData.BatteryData.MaxSOC - ModelData.BatteryData.MinSOC)), 5);
 
 			tmp.EqualityFactor = 2.5;
+			tmp.GearshiftPenalty = resp.Gearbox.Gear != DataBus.GearboxInfo.Gear
+				? ModelData.GearshiftParameters.RatingFactorCurrentGear
+				: 1;
 		}
 
-		private Tuple<bool, uint> HandleGearshift(Second absTime, ResponseDryRun response)
+		private Tuple<bool, uint> HandleGearshift(Second absTime, HybridResultEntry config)
 		{
+			// search for EM operating point already selected another gear
+			if (config.Gear != DataBus.GearboxInfo.Gear) {
+				return Tuple.Create(true, config.Gear);
+			}
+			var response = config.Response;
 			var retVal = Tuple.Create(false, response.Gearbox.Gear);
 
 			var gear = DataBus.GearboxInfo.Gear;
@@ -384,7 +485,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 				GearboxInNeutral = false,
 				MechanicalAssistPower = ElectricMotorsOff
 			};
-			Response = dryRun ? null : tmp;
+			CurrentState.Response = dryRun ? null : tmp;
 			return tmp;
 		}
 
@@ -402,16 +503,30 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 
 		public virtual void CommitSimulationStep(Second time, Second simulationInterval)
 		{
-			
+			PreviousState = CurrentState;
+			CurrentState = new StrategyState();
 		}
 
 		public void WriteModalResults(Second time, Second simulationInterval, IModalDataContainer container)
 		{
-			container[ModalResultField.HybridStrategyScore] = Solution?.Score ?? 0;
-			container[ModalResultField.HybridStrategySolution] = Solution?.U ?? -100;
+			container[ModalResultField.HybridStrategyScore] = CurrentState.Solution?.Score ?? 0;
+			container[ModalResultField.HybridStrategySolution] = CurrentState.Solution?.U ?? -100;
+
+			if (CurrentState.Evaluations != null) {
+				container.SetDataValue(
+					"HybridStrategyEvaluation",
+					string.Join(
+						" | ", CurrentState.Evaluations.Select(
+							x => {
+								var foo = string.Join(" ",  x.Setting.MechanicalAssistPower.Select(e => $"{e.Key.GetName()}: {e.Value}"));
+								return $"{x.U}: G{x.Gear} ({x.FuelCosts} + {x.EqualityFactor} * {x.BatCosts} * {x.SoCPenalty} = {x.Score}) * {x.GearshiftPenalty} ({foo})";
+							})
+						)
+					);
+			}
 		}
 
-		[DebuggerDisplay("{U}: {Score} {Setting.MechanicalAssistPower}")]
+		[DebuggerDisplay("{U}: {Score} {Gear} {Setting.MechanicalAssistPower}")]
 		public class HybridResultEntry
 		{
 			public double U { get; set; }
@@ -420,7 +535,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 
 			public ResponseDryRun Response { get; set; }
 
-			public double Score { get { return FuelCosts + EqualityFactor * BatCosts * SoCPenalty; } }
+			public double Score { get { return (FuelCosts + EqualityFactor * BatCosts * SoCPenalty) / GearshiftPenalty; } }
 
 			public double FuelCosts { get; set; }
 
@@ -429,6 +544,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 			public double SoCPenalty { get; set; }
 
 			public double EqualityFactor { get; set; }
+
+			public double GearshiftPenalty { get; set; }
+
+			public uint Gear { get; set; }
 		}
 
 	}
diff --git a/VectoCore/VectoCoreTest/Integration/Hybrid/ParallelHybridTest.cs b/VectoCore/VectoCoreTest/Integration/Hybrid/ParallelHybridTest.cs
index 5c9f3ceeaa..f5fe4fe535 100644
--- a/VectoCore/VectoCoreTest/Integration/Hybrid/ParallelHybridTest.cs
+++ b/VectoCore/VectoCoreTest/Integration/Hybrid/ParallelHybridTest.cs
@@ -82,7 +82,9 @@ namespace TUGraz.VectoCore.Tests.Integration.Hybrid
 		//	Assert.IsTrue(modData.Rows.Count > 0);
 		//}
 
-		[TestCase(30, 0.7, 0, TestName = "P2 Hybrid DriveOff 30km/h SoC: 0.7, level"),
+		[
+			TestCase(30, 0.7, 0, TestName = "P2 Hybrid DriveOff 30km/h SoC: 0.7, level"),
+			TestCase(80, 0.7, 0, TestName = "P2 Hybrid DriveOff 80km/h SoC: 0.7, level"),
 		TestCase(30, 0.22, 0, TestName = "P2 Hybrid DriveOff 30km/h SoC: 0.22, level")
 			]
 		public void P2HybridDriveOff(double vmax, double initialSoC, double slope)
@@ -110,6 +112,88 @@ namespace TUGraz.VectoCore.Tests.Integration.Hybrid
 
 			
 
+			run.Run();
+			Assert.IsTrue(run.FinishedWithoutErrors);
+
+			Assert.IsTrue(modData.Rows.Count > 0);
+		}
+
+		[
+		TestCase(30, 0.7, 0, TestName = "P2 Hybrid ConstantSpeed 30km/h SoC: 0.7, level"),
+		TestCase(50, 0.7, 0, TestName = "P2 Hybrid ConstantSpeed 50km/h SoC: 0.7, level"),
+		TestCase(80, 0.7, 0, TestName = "P2 Hybrid ConstantSpeed 80km/h SoC: 0.7, level"),
+
+		TestCase(30, 0.2, 0, TestName = "P2 Hybrid ConstantSpeed 30km/h SoC: 0.2, level"),
+		TestCase(50, 0.2, 0, TestName = "P2 Hybrid ConstantSpeed 50km/h SoC: 0.2, level"),
+		TestCase(80, 0.2, 0, TestName = "P2 Hybrid ConstantSpeed 80km/h SoC: 0.2, level"),
+
+		TestCase(30, 0.5, 5, TestName = "P2 Hybrid ConstantSpeed 30km/h SoC: 0.5, UH 5%"),
+		TestCase(50, 0.5, 5, TestName = "P2 Hybrid ConstantSpeed 50km/h SoC: 0.5, UH 5%"),
+		TestCase(80, 0.5, 5, TestName = "P2 Hybrid ConstantSpeed 80km/h SoC: 0.5, UH 5%"),
+
+		TestCase(30, 0.5, -5, TestName = "P2 Hybrid ConstantSpeed 30km/h SoC: 0.5, DH 5%"),
+		TestCase(50, 0.5, -5, TestName = "P2 Hybrid ConstantSpeed 50km/h SoC: 0.5, DH 5%"),
+		TestCase(80, 0.5, -5, TestName = "P2 Hybrid ConstantSpeed 80km/h SoC: 0.5, DH 5%"),
+		]
+		public void P2HybridConstantSpeed(double vmax, double initialSoC, double slope)
+		{
+			var cycleData = string.Format(
+				@"   0, {0}, {1},    0
+				  5000, {0}, {1},    0", vmax, slope);
+			var cycle = SimpleDrivingCycles.CreateCycleData(cycleData);
+
+			const bool largeMotor = true;
+
+			const PowertrainPosition pos = PowertrainPosition.HybridP2;
+			var run = CreateEngineeringRun(
+				cycle, string.Format("SimpleParallelHybrid_constant_{0}-{1}_{2}.vmod", vmax, initialSoC, slope), initialSoC, pos, largeMotor: true);
+
+			var hybridController = (HybridController)((VehicleContainer)run.GetContainer()).HybridController;
+			Assert.NotNull(hybridController);
+			//var strategy = (DelegateParallelHybridStrategy)hybridController.Strategy;
+			//Assert.NotNull(strategy);
+
+			var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data;
+
+			var nextState = new StrategyState();
+			var currentState = new StrategyState();
+
+
+
+			run.Run();
+			Assert.IsTrue(run.FinishedWithoutErrors);
+
+			Assert.IsTrue(modData.Rows.Count > 0);
+		}
+
+		[
+			TestCase(80, 0, TestName = "Conventional DriveOff 80km/h  level"),
+		]
+		public void ConventionalVehicleDriveOff(double vmax, double slope)
+		{
+			var cycleData = string.Format(
+				@"   0,   0, {1},    3
+				   700, {0}, {1},    0", vmax, slope);
+			var cycle = SimpleDrivingCycles.CreateCycleData(cycleData);
+
+			//const bool largeMotor = true;
+
+			//const PowertrainPosition pos = PowertrainPosition.HybridP2;
+			var run = CreateConventionalEngineeringRun(
+				cycle, string.Format("ConventionalVehicle_acc_{0}_{1}.vmod", vmax, slope));
+
+			//var hybridController = (HybridController)((VehicleContainer)run.GetContainer()).HybridController;
+			//Assert.NotNull(hybridController);
+			//var strategy = (DelegateParallelHybridStrategy)hybridController.Strategy;
+			//Assert.NotNull(strategy);
+
+			var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data;
+
+			var nextState = new StrategyState();
+			var currentState = new StrategyState();
+
+
+
 			run.Run();
 			Assert.IsTrue(run.FinishedWithoutErrors);
 
@@ -170,6 +254,14 @@ namespace TUGraz.VectoCore.Tests.Integration.Hybrid
 			return new DistanceRun(container);
 		}
 
+		public static VectoRun CreateConventionalEngineeringRun(DrivingCycleData cycleData, string modFileName, 
+			SummaryDataContainer sumData = null, double pAuxEl = 0)
+		{
+			var container = CreateConventionalPowerTrain(
+				cycleData, Path.GetFileNameWithoutExtension(modFileName), sumData, pAuxEl);
+			return new DistanceRun(container);
+		}
+
 		public static VehicleContainer CreateParallelHybridPowerTrain(DrivingCycleData cycleData, string modFileName,
 			double initialBatCharge, bool largeMotor, SummaryDataContainer sumData, double pAuxEl, PowertrainPosition pos)
 		{
@@ -278,6 +370,98 @@ namespace TUGraz.VectoCore.Tests.Integration.Hybrid
 			return container;
 		}
 
+
+		public static VehicleContainer CreateConventionalPowerTrain(DrivingCycleData cycleData, string modFileName,
+			SummaryDataContainer sumData, double pAuxEl)
+		{
+			//var strategySettings = GetHybridStrategyParameters(largeMotor);
+
+			//strategySettings.StrategyName = "SimpleParallelHybridStrategy";
+
+			var fileWriter = new FileOutputWriter(modFileName);
+			var modDataFilter = new IModalDataFilter[] { }; //new IModalDataFilter[] { new ActualModalDataFilter(), };
+			var modData = new ModalDataContainer(
+				modFileName, new IFuelProperties[] { FuelData.Diesel }, fileWriter,
+				filters: modDataFilter) {
+				WriteModalResults = true,
+			};
+
+			var gearboxData = CreateGearboxData();
+			var axleGearData = CreateAxleGearData();
+
+			var vehicleData = CreateVehicleData(3300.SI<Kilogram>());
+			var airdragData = CreateAirdragData();
+			var driverData = CreateDriverData(AccelerationFile, true);
+
+			var engineData = MockSimulationDataFactory.CreateEngineDataFromFile(
+				 Truck40tPowerTrain.EngineFile, gearboxData.Gears.Count);
+
+			foreach (var entry in gearboxData.Gears) {
+				entry.Value.ShiftPolygon = DeclarationData.Gearbox.ComputeEfficiencyShiftPolygon(
+					(int)entry.Key, engineData.FullLoadCurves[entry.Key], new TransmissionInputData().Repeat(gearboxData.Gears.Count + 1).Cast<ITransmissionInputData>().ToList(), engineData, axleGearData.AxleGear.Ratio,
+					vehicleData.DynamicTyreRadius);
+			}
+
+			var runData = new VectoRunData() {
+				//PowertrainConfiguration = PowertrainConfiguration.ParallelHybrid,
+				JobRunId = 0,
+				DriverData = driverData,
+				AxleGearData = axleGearData,
+				GearboxData = gearboxData,
+				VehicleData = vehicleData,
+				AirdragData = airdragData,
+				JobName = modFileName,
+				Cycle = cycleData,
+				Retarder = new RetarderData() { Type = RetarderType.None },
+				Aux = new List<VectoRunData.AuxData>(),
+				//ElectricMachinesData = electricMotorData,
+				EngineData = engineData,
+				//BatteryData = batteryData,
+				//HybridStrategy = strategySettings
+				GearshiftParameters = CreateGearshiftData(gearboxData, axleGearData.AxleGear.Ratio, engineData.IdleSpeed)
+			};
+			var container = new VehicleContainer(
+				ExecutionMode.Engineering, modData, x => { sumData?.Write(x, 1, 1, runData); });
+			container.RunData = runData;
+
+
+			var clutch = new SwitchableClutch(container, runData.EngineData);
+
+			var gbxStrategy = new AMTShiftStrategyOptimized(runData,container);
+			
+			var gearbox = new Gearbox(container, gbxStrategy, runData);
+
+			var engine = new StopStartCombustionEngine(container, runData.EngineData);
+			var idleController = engine.IdleController;
+			var cycle = new DistanceBasedDrivingCycle(container, cycleData);
+
+			var aux = new ElectricAuxiliary(container);
+			aux.AddConstant("P_aux_el", pAuxEl.SI<Watt>());
+			cycle
+				.AddComponent(new Driver(container, runData.DriverData, new DefaultDriverStrategy(container)))
+				.AddComponent(new Vehicle(container, runData.VehicleData, runData.AirdragData))
+				.AddComponent(new Wheels(container, runData.VehicleData.DynamicTyreRadius,
+					runData.VehicleData.WheelsInertia))
+				.AddComponent(new Brakes(container))
+				//.AddComponent(ctl)
+				//.AddComponent(GetElectricMachine(PowertrainPosition.HybridP4, runData.ElectricMachinesData, container,
+				//	es, ctl))
+				.AddComponent(new AxleGear(container, runData.AxleGearData))
+				//.AddComponent(GetElectricMachine(PowertrainPosition.HybridP3, runData.ElectricMachinesData, container,
+				//	es, ctl))
+				.AddComponent(runData.AngledriveData != null ? new Angledrive(container, runData.AngledriveData) : null)
+				.AddComponent(gearbox, runData.Retarder, container)
+				//.AddComponent(GetElectricMachine(PowertrainPosition.HybridP2, runData.ElectricMachinesData, container,
+				//	es, ctl))
+				.AddComponent(clutch)
+				//.AddComponent(GetElectricMachine(PowertrainPosition.HybridP1, runData.ElectricMachinesData, container,
+				//	es, ctl))
+				.AddComponent(engine, idleController)
+				.AddAuxiliaries(container, runData);
+
+			return container;
+		}
+
 		public static ShiftStrategyParameters CreateGearshiftData(GearboxData gbx, double axleRatio, PerSecond engineIdlingSpeed)
 		{
 			var retVal = new ShiftStrategyParameters {
-- 
GitLab