diff --git a/VectoCommon/VectoCommon/Models/PowertrainPosition.cs b/VectoCommon/VectoCommon/Models/PowertrainPosition.cs
index cf25a4c8e7714f609364984a89ec29a3a2921368..a56c9cade93e42ce4b591a80f36d507b9c486b89 100644
--- a/VectoCommon/VectoCommon/Models/PowertrainPosition.cs
+++ b/VectoCommon/VectoCommon/Models/PowertrainPosition.cs
@@ -18,6 +18,7 @@ namespace TUGraz.VectoCommon.InputData {
 		BatteryElectricE4,
 		BatteryElectricE3,
 		BatteryElectricE2,
+		Generator
 	}
 
 	public static class PowertrainPositionHelper
diff --git a/VectoCore/VectoCore/Models/Simulation/Data/ModalResultField.cs b/VectoCore/VectoCore/Models/Simulation/Data/ModalResultField.cs
index 6241b2ba4c6654602803c9718672e255a2467604..059fc62251cd9dddc84b48640a453c9a4532d5d4 100644
--- a/VectoCore/VectoCore/Models/Simulation/Data/ModalResultField.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Data/ModalResultField.cs
@@ -415,7 +415,11 @@ namespace TUGraz.VectoCore.Models.Simulation.Data
 		
 		[ModalResultField(typeof(SI), caption: "P_E2_mech [kW]", outputFactor: 1e-3)]
 		P_electricMotor_mech_B2,
-        // -->
+
+		[ModalResultField(typeof(SI), caption: "P_Generator_mech [kW]", outputFactor: 1e-3)]
+		P_electricMotor_mech_Gen,
+
+		// -->
 
 		[ModalResultField(typeof(SI), caption: "P_REESS_T [kW]", outputFactor: 1e-3)] P_reess_terminal,
 		[ModalResultField(typeof(SI), caption: "P_REESS_int [kW]", outputFactor: 1e-3)] P_reess_int,
diff --git a/VectoCore/VectoCore/Models/Simulation/DataBus/IDataBus.cs b/VectoCore/VectoCore/Models/Simulation/DataBus/IDataBus.cs
index 715e43c85e5e655ad7657a03a8ccb82a863e8eec..f013632e136a3101729f081182b8df8cd30876c8 100644
--- a/VectoCore/VectoCore/Models/Simulation/DataBus/IDataBus.cs
+++ b/VectoCore/VectoCore/Models/Simulation/DataBus/IDataBus.cs
@@ -98,5 +98,7 @@ namespace TUGraz.VectoCore.Models.Simulation.DataBus
 		bool HasElectricMotor { get; }
 
 		PowertrainPosition[] ElectricMotorPositions { get; }
+
+		VectoSimulationJobType VehicleArchitecutre { get; }
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs b/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs
index 6da75642290ea0dd9a3d6a25539b4c61a28431d2..9c65c7585e9c48cee154e80b36d6d46c8d9b00dc 100644
--- a/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs
+++ b/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs
@@ -13,5 +13,7 @@ namespace TUGraz.VectoCore.Models.Simulation.DataBus
 		Watt DragPower(Volt volt, PerSecond electricMotorSpeed);
 		Watt MaxPowerDrive(Volt volt, PerSecond inAngularVelocity);
 		NewtonMeter GetTorqueForElectricPower(Volt volt, Watt electricPower, PerSecond avgEmSpeed, Second dt);
+
+		bool DeRatingActive { get; }
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs
index 3a363abd3abfcedd74e5808fc3dc96c2aa375dfc..d2b1379ec1550d6139d663c702fa8d296f6cc1eb 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs
@@ -142,7 +142,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 					criterion: response => {
 						var r = (ResponseDryRun)response;
 						return (r.Gearbox?.PowerRequest ?? r.ElectricMotor?.TotalTorqueDemand * r.ElectricMotor?.AvgDrivetrainSpeed).Value();
-					}
+					},
+					searcher: this
 				);
 			} catch (VectoSearchAbortedException) {
 				return gradient;
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
index a464d94aa519c295a1c710619c8eb1cb5c90d0b9..d2464bf61cfe163e07df4be19075c9b6b2e7b9fe 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
@@ -677,6 +677,115 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				.AddAuxiliaries(container, data);
 		}
 
+		public void BuildSimpleSerialHybridPowertrain(VectoRunData data, VehicleContainer container)
+		{
+			var es = new ElectricSystem(container);
+			if (data.BatteryData != null) {
+				var battery = new BatterySystem(container, data.BatteryData);
+				battery.Initialize(data.BatteryData.InitialSoC);
+				es.Connect(battery);
+			}
+
+			if (data.SuperCapData != null) {
+				var superCap = new SuperCap(container, data.SuperCapData);
+				superCap.Initialize(data.SuperCapData.InitialSoC);
+				es.Connect(superCap);
+			}
+
+			//var battery = new Battery(container, data.BatteryData);
+			//battery.Initialize(data.BatteryData.InitialSoC);
+			//es.Connect(battery);
+
+			var aux = new ElectricAuxiliary(container);
+			aux.AddConstant("P_aux_el", data.ElectricAuxDemand ?? 0.SI<Watt>());
+			es.Connect(aux);
+			es.Connect(new GensetChargerAdapter(null));
+
+			var ctl = new SimpleHybridController(container, es);
+
+			var pos = data.ElectricMachinesData.Select(x => x.Item1).First(x => x != PowertrainPosition.Generator);
+
+			var vehicle = new Vehicle(container, data.VehicleData, data.AirdragData);
+			var powertrain = vehicle
+				.AddComponent(new Wheels(container, data.VehicleData.DynamicTyreRadius,
+					data.VehicleData.WheelsInertia))
+				.AddComponent(ctl)
+				.AddComponent(new Brakes(container));
+
+			switch (pos) {
+				case PowertrainPosition.HybridPositionNotSet:
+					throw new VectoException("invalid powertrain position");
+				case PowertrainPosition.BatteryElectricE2:
+					var gearbox = data.GearboxData.Type.AutomaticTransmission()
+						? (IHybridControlledGearbox)new ATGearbox(container, ctl.ShiftStrategy)
+						: new Gearbox(container, ctl.ShiftStrategy);
+					powertrain = powertrain.AddComponent(new AxleGear(container, data.AxleGearData))
+						.AddComponent(data.AngledriveData != null
+							? new Angledrive(container, data.AngledriveData)
+							: null)
+						.AddComponent((IGearbox)gearbox, data.Retarder, container)
+						.AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE2, data.ElectricMachinesData,
+							container,
+							es, ctl));
+					ctl.Gearbox = gearbox;
+
+					break;
+				case PowertrainPosition.BatteryElectricE3:
+					powertrain = powertrain.AddComponent(new AxleGear(container, data.AxleGearData))
+						.AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE3, data.ElectricMachinesData,
+							container,
+							es, ctl));
+					new DummyGearboxInfo(container);
+					//new MockEngineInfo(container);
+					new ATClutchInfo(container);
+					break;
+				case PowertrainPosition.BatteryElectricE4:
+					powertrain = powertrain.AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE4, data.ElectricMachinesData,
+							container,
+							es, ctl));
+					new DummyGearboxInfo(container);
+					//new MockEngineInfo(container);
+					new ATClutchInfo(container);
+					break;
+				case PowertrainPosition.HybridP0:
+				case PowertrainPosition.HybridP1:
+				case PowertrainPosition.HybridP2_5:
+				case PowertrainPosition.HybridP2:
+				case PowertrainPosition.HybridP3:
+				case PowertrainPosition.HybridP4:
+
+					throw new VectoException("testcase does not support parallel powertrain configurations");
+				default:
+					throw new ArgumentOutOfRangeException(nameof(pos), pos, null);
+			}
+
+		}
+
+		public void BuildSimpleGenSet(VectoRunData data, VehicleContainer container)
+		{
+			var es = new ElectricSystem(container);
+			if (data.BatteryData != null) {
+				var battery = new BatterySystem(container, data.BatteryData);
+				battery.Initialize(data.BatteryData.InitialSoC);
+				es.Connect(battery);
+			}
+
+			if (data.SuperCapData != null) {
+				var superCap = new SuperCap(container, data.SuperCapData);
+				superCap.Initialize(data.SuperCapData.InitialSoC);
+				es.Connect(superCap);
+			}
+
+			//var ctl = new SimpleHybridController(container, es);
+			var ctl = new GensetMotorController(container, es);
+
+			var genSet = GetElectricMachine(PowertrainPosition.Generator, data.ElectricMachinesData, container, es, ctl)
+				.AddComponent(new StopStartCombustionEngine(container, data.EngineData));
+
+			new ATClutchInfo(container);
+			new DummyGearboxInfo(container, new GearshiftPosition(0));
+		}
+
 		public void BuildSimpleHybridPowertrain(VectoRunData data, VehicleContainer container)
 		{
 			//if (data.Cycle.CycleType != CycleType.DistanceBased) {
@@ -714,7 +823,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				throw new VectoException("Gearbox can not be used for parallel hybrid");
 			}
 
-			var ctl = new SimpleHybridController(container, es, clutch);
+			var ctl = new SimpleHybridController(container, es);
 
 			ctl.Gearbox = gbx;
 			ctl.Engine = engine;
@@ -1141,6 +1250,27 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 		}
 	}
 
+	public class GensetMotorController : IElectricMotorControl
+	{
+		public GensetMotorController(IVehicleContainer container, ElectricSystem es)
+		{
+
+		}
+
+		#region Implementation of IElectricMotorControl
+
+		public NewtonMeter MechanicalAssistPower(Second absTime, Second dt, NewtonMeter outTorque, PerSecond prevOutAngularVelocity,
+			PerSecond currOutAngularVelocity, NewtonMeter maxDriveTorque, NewtonMeter maxRecuperationTorque,
+			PowertrainPosition position, bool dryRun)
+		{
+			return EMTorque;
+		}
+
+		public NewtonMeter EMTorque { get; set; }
+
+		#endregion
+	}
+
 	public class DummyElectricMotorControl : IElectricMotorControl
 	{
 		#region Implementation of IElectricMotorControl
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
index 4b3973fa2a840e66bff85ed755ba63625c56e224..817b0520a4240aeadd09742cfddd7ecc8bae02d7 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
@@ -246,6 +246,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 
 		public PowertrainPosition[] ElectricMotorPositions => ElectricMotors.Keys.ToArray();
 
+		public VectoSimulationJobType VehicleArchitecutre => RunData.JobType;
+
 		public virtual bool HasCombustionEngine { get; private set; }
 
 		public virtual bool HasGearbox { get; private set; }
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/EfficiencyMap.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/EfficiencyMap.cs
index 823cc7d8563d7e63eb422fc1e24d4004ce94d7d0..4df9c70a3c7a034acd0af0f875d48f3ab0616bad 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/EfficiencyMap.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/EfficiencyMap.cs
@@ -161,7 +161,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor
 					criterion: x => {
 						var myX = (EfficiencyResult)x;
 						return (myX.ElectricalPower - batPower).Value();
-					});
+					},
+					searcher: this);
 				var tmp = LookupElectricPower(avgSpeed, retVal, true);
 				if ((tmp.ElectricalPower - batPower).IsGreater(Constants.SimulationSettings.InterpolateSearchTolerance)) {
 					// searched operating point is not accurate enough...
@@ -176,7 +177,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor
 						criterion: x => {
 							var myX = (EfficiencyResult)x;
 							return (myX.ElectricalPower - batPower).Value() * 1e3;
-						});
+						},
+						searcher: this);
 				}
 				return retVal;
 			} catch (VectoSearchFailedException vsfe) {
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs
index c8f2e69bcc6db03b79920edd5b66335e9044d548..e61002f6f45ea283931bcc61d852082baa3252a4 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs
@@ -68,7 +68,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 				interval: 10.SI<NewtonMeter>(),
 				getYValue: x => (Watt)x - electricPower,
 				evaluateFunction: x => LookupElectricPower(voltage, avgSpeed, x, true).ElectricalPower,
-				criterion: x => ((Watt)x - electricPower).Value()
+				criterion: x => ((Watt)x - electricPower).Value(),
+				searcher: this
 			);
 
 			return searchResult;
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/ElectricSystem.cs b/VectoCore/VectoCore/Models/SimulationComponent/ElectricSystem.cs
index 3cecf2e8b025422c005393c32dd18d3861b6ee51..2e3c4eec48c75de0ddecb430416d0dd6eed10732 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/ElectricSystem.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/ElectricSystem.cs
@@ -15,7 +15,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent
 
 		protected readonly List<IElectricAuxPort> Consumers = new List<IElectricAuxPort>();
 
-		protected IElectricChargerPort Charger;
+		protected internal IElectricChargerPort Charger;
 
 		protected IElectricEnergyStorage Battery;
 
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
index 79f76c00a893cd75fa0965ea3240f9af8663f334..ac304a412001432e5035395607bea58fa378b933 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
@@ -718,7 +718,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 							Constants.SimulationSettings.EngineIdlingSearchInterval,
 							getYValue: result => ((ResponseDryRun)result).DeltaDragLoad,
 							evaluateFunction: n => RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), n, true),
-							criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value());
+							criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value(),
+							searcher: this);
 						Log.Debug("Found operating point for idling. absTime: {0}, dt: {1}, torque: {2}, angularSpeed: {3}", 
 							absTime, dt, 0.SI<NewtonMeter>(), angularSpeed);
 						if (angularSpeed < _engine.ModelData.IdleSpeed) {
@@ -732,7 +733,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 							Constants.SimulationSettings.EngineIdlingSearchInterval,
 							getYValue: result => ((ResponseDryRun)result).DeltaFullLoad,
 							evaluateFunction: n => RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), n, true),
-							criterion: result => ((ResponseDryRun)result).DeltaFullLoad.Value());
+							criterion: result => ((ResponseDryRun)result).DeltaFullLoad.Value(),
+							searcher: this);
 						Log.Debug("Found operating point for idling. absTime: {0}, dt: {1}, torque: {2}, angularSpeed: {3}", 
 							absTime, dt, 0.SI<NewtonMeter>(), angularSpeed2);
 						angularSpeed2 = angularSpeed2.LimitTo(_engine.ModelData.IdleSpeed, engineMaxSpeed);
@@ -787,7 +789,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 							Constants.SimulationSettings.EngineIdlingSearchInterval,
 							getYValue: result => ((ResponseDryRun)result).DeltaDragLoad,
 							evaluateFunction: n => RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), n, true),
-							criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value());
+							criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value(),
+							searcher: this);
 						Log.Debug("Found operating point for idling. absTime: {0}, dt: {1}, torque: {2}, angularSpeed: {3}", 
 							absTime, dt, 0.SI<NewtonMeter>(), angularSpeed);
 						retVal = RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), angularSpeed, false);
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs
index a30715f3873a4573a9e9dd91b4d094dcfa0e5647..dd37bc17dcad64c08544385ca33ae49909f8e021 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs
@@ -390,7 +390,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 						Constants.SimulationSettings.EngineIdlingSearchInterval,
 						getYValue: result => ((ResponseDryRun)result).DeltaDragLoad,
 						evaluateFunction: n => NextComponent.Request(absTime, dt, 0.SI<NewtonMeter>(), n, true),
-						criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value());
+						criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value(),
+						searcher: this);
 				} catch (VectoException) {
 					Log.Warn("CycleGearbox could not find motoring speed for disengaged state.");
 				}
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Driver.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Driver.cs
index ccc0f78eca2c4636fdce3fbd1d219ee60e91a038..163782fcc2787768e6603437e3d6f5cfa19cf989 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Driver.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Driver.cs
@@ -590,7 +590,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					criterion: tOp => {
 						var t = (Tuple<Tuple<TorqueConverterOperatingPoint, NewtonMeter>, NewtonMeter, NewtonMeter>)tOp;
 						return GetTCDelta(t.Item1, t.Item2, t.Item3).Value();
-					});
+					},
+					searcher: this);
 			} catch (Exception e) {
 				Log.Error(e, "Failed to find engine speed for valid torque converter operating point! absTime: {0}", absTime);
 
@@ -671,7 +672,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					var r = (ResponseDryRun)resp;
 
 					return (tcOp.Item1.OutTorque - r.TorqueConverter.TorqueConverterTorqueDemand).Value();
-				}
+				},
+				searcher: this
 			);
 			return acceleration;
 		}
@@ -1082,7 +1084,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 						return DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && response.DeltaDragLoad.Value().IsSmallerOrEqual(-double.MaxValue / 20);
 					},
-					forceLineSearch: DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && !DataBus.GearboxInfo.TCLocked);
+					forceLineSearch: DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && !DataBus.GearboxInfo.TCLocked,
+					searcher: this);
 
 				return operatingPoint;
 			} catch (VectoSearchFailedException vse) {
@@ -1117,7 +1120,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 									: response.Gearbox.PowerRequest;
 								return Math.Min(delta.Value(), 0);
 							},
-							forceLineSearch: true);
+							forceLineSearch: true,
+							searcher: this);
 						return operatingPoint;
 					} catch (Exception e2) {
 						Log.Error("Failed to find operating point for braking power (attempt 2)! absTime: {0}  {1}", absTime, e2);
@@ -1207,7 +1211,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 								return true;
 							}
 							return r != null && !actionRoll && !allowDistanceDecrease && !ds.IsEqual(r.Driver.OperatingPoint.SimulationDistance);
-						});
+						},
+					searcher: this);
 					return ComputeTimeInterval(retVal.Acceleration, retVal.SimulationDistance);
 			} catch (VectoException ve) {
 				switch (ve) {
@@ -1279,7 +1284,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 										return r != null && !allowDistanceDecrease &&
 												!ds.IsEqual(r.Driver.OperatingPoint.SimulationDistance);
 									},
-									forceLineSearch: true);
+									forceLineSearch: true,
+									searcher: this);
 								return ComputeTimeInterval(retVal.Acceleration, retVal.SimulationDistance);
 							} catch (VectoException ve2) {
 								Log.Error(ve2);
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DummyGearboxInfo.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DummyGearboxInfo.cs
index 32b108d69df67cce0396ff904cdd21bc1771f0fb..74ee79b2c1000f1b4084ef1899fc9d936ffccc2a 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DummyGearboxInfo.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DummyGearboxInfo.cs
@@ -11,9 +11,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 {
 	public class DummyGearboxInfo : VectoSimulationComponent, IGearboxInfo
 	{
-		public DummyGearboxInfo(VehicleContainer container) : base(container)
+		public DummyGearboxInfo(VehicleContainer container, GearshiftPosition gear = null) : base(container)
 		{
-
+			Gear = gear ?? new GearshiftPosition(1);
 		}
 
 		#region Overrides of VectoSimulationComponent
@@ -28,7 +28,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public GearboxType GearboxType => GearboxType.AMT;
 
-		public GearshiftPosition Gear => new GearshiftPosition(1);
+		public GearshiftPosition Gear { get; }
 
 		public bool TCLocked => true;
 
@@ -49,7 +49,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public GearData GetGearData(uint gear)
 		{
-			throw new NotImplementedException();
+			return new GearData() {
+				MaxSpeed = null,
+			};
 		}
 
 		public GearshiftPosition NextGear => throw new NotImplementedException();
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs
index 3df3a7789afbdaeba85ae679b9f9527f8a49ca06..61b078923c0ca938f86c779da79407951419328a 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs
@@ -22,14 +22,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 	public class ElectricMotor : StatefulProviderComponent<ElectricMotorState, ITnOutPort, ITnInPort, ITnOutPort>, IPowerTrainComponent, IElectricMotor, ITnOutPort, ITnInPort
 	{
 
-		protected IElectricSystem ElectricPower;
+		protected internal IElectricSystem ElectricPower;
 		internal IElectricMotorControl Control { get; }
 		protected ElectricMotorData ModelData;
 		private PerSecond _maxSpeed;
 
 		protected internal Joule ThermalBuffer = 0.SI<Joule>();
-		protected internal bool DeRatingActive;
 		
+		public bool DeRatingActive { get; protected internal set; }
+
 		public Joule OverloadBuffer { get; }
 		public NewtonMeter ContinuousTorque { get; }
 
@@ -446,7 +447,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		}
 
 
-		protected NewtonMeter ConvertEmTorqueToDrivetrain(PerSecond emSpeed, NewtonMeter emTorque)
+		protected internal NewtonMeter ConvertEmTorqueToDrivetrain(PerSecond emSpeed, NewtonMeter emTorque)
 		{
 			var dtTorque = ModelData.TransmissionLossMap.GetOutTorque(emSpeed, emTorque);
 
@@ -460,7 +461,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					criterion: r => {
 						var i = r as NewtonMeter;
 						return (i - emTorque).Value() * 1e3;
-					});
+					},
+					searcher: this);
 			}
 
 			return dtTorque;
@@ -566,6 +568,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			ElectricPower = powersupply;
 		}
 
+		protected internal PerSecond ConvertEmSpeedToDrivetrain(PerSecond emSpeed)
+		{
+			return emSpeed / ModelData.RatioADC;
+		}
 	}
 
 	public class ElectricMotorState // : SimpleComponentState
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/GensetChargerAdapter.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/GensetChargerAdapter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a3d464490b92d65f22a17a9b1ba257001e3ae5dd
--- /dev/null
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/GensetChargerAdapter.cs
@@ -0,0 +1,74 @@
+using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
+
+namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
+{
+	public class GensetChargerAdapter : IElectricChargerPort
+	{
+		protected IElectricSystem es;
+		protected Watt PowerGenerated;
+
+		public GensetChargerAdapter(ElectricMotor motor)
+		{
+			es = new ChargeElectricSystem(this);
+			motor?.Connect(es);
+			PowerGenerated = 0.SI<Watt>();
+		}
+
+		#region Implementation of IElectricChargerPort
+
+		public Watt Initialize()
+		{
+			PowerGenerated = 0.SI<Watt>();
+			return PowerGenerated;
+		}
+
+		public Watt PowerDemand(Second absTime, Second dt, Watt powerDemandEletricMotor, Watt auxPower, bool dryRun)
+		{
+			return PowerGenerated;
+		}
+
+		public Watt ChargingPower
+		{
+			set { PowerGenerated = value; }
+		}
+
+		#endregion
+
+		public class ChargeElectricSystem : IElectricSystem
+		{
+			protected GensetChargerAdapter Adapter;
+
+
+			public ChargeElectricSystem(GensetChargerAdapter adapter)
+			{
+				Adapter = adapter;
+			}
+
+			#region Implementation of IElectricSystemInfo
+
+			public Watt ElectricAuxPower => 0.SI<Watt>();
+			public Watt ChargePower => 0.SI<Watt>();
+			public Watt BatteryPower => 0.SI<Watt>();
+			public Watt ConsumerPower => 0.SI<Watt>();
+			public IElectricSystemResponse Request(Second absTime, Second dt, Watt powerDemand, bool dryRun = false)
+			{
+				if (!dryRun) {
+					Adapter.PowerGenerated = powerDemand;
+				}
+
+				return new ElectricSystemResponseSuccess(this) {
+					RESSResponse = new RESSResponseSuccess(this) {
+						MaxChargePower = double.MaxValue.SI<Watt>(),
+						MaxDischargePower = -double.MaxValue.SI<Watt>(),
+						AbsTime = absTime,
+					},
+					ConsumerPower = powerDemand
+				};
+			}
+
+			#endregion
+		}
+	}
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/MeasuredSpeedDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/MeasuredSpeedDrivingCycle.cs
index 631fd2c9821f2833aa9c45a0d6bacebaeec11dc6..22c140fce2d05af5ea80f7c4cf5c97a6351cddc3 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/MeasuredSpeedDrivingCycle.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/MeasuredSpeedDrivingCycle.cs
@@ -193,7 +193,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 							getYValue: result => ((ResponseDryRun)result).DeltaEngineSpeed,
 							// ReSharper disable once AccessToModifiedClosure
 							evaluateFunction: x => NextComponent.Request(absTime, dt, x, gradient, true),
-							criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value());
+							criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value(),
+							searcher: this);
 						Log.Info("Found operating point for driver acceleration. absTime: {0}, dt: {1}, acceleration: {2}, gradient: {3}",
 							absTime, dt, acceleration, gradient);
 						break;
@@ -240,7 +241,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				},
 				criterion: y => DataBus.ClutchInfo.ClutchClosed(absTime)
 					? ((ResponseDryRun)y).DeltaDragLoad.Value()
-					: ((ResponseDryRun)y).Gearbox.PowerRequest.Value());
+					: ((ResponseDryRun)y).Gearbox.PowerRequest.Value(),
+				searcher: this);
 			Log.Info(
 				"Found operating point for braking. absTime: {0}, dt: {1}, acceleration: {2}, gradient: {3}, BrakePower: {4}",
 				absTime, dt, acceleration, gradient, DataBus.Brakes.BrakePower);
@@ -254,7 +256,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					Constants.SimulationSettings.OperatingPointInitialSearchIntervalAccelerating,
 					getYValue: result => ((ResponseDryRun)result).DeltaFullLoad,
 					evaluateFunction: x => NextComponent.Request(absTime, dt, x, gradient, true),
-					criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value());
+					criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value(),
+					searcher: this);
 			}
 
 			var response = NextComponent.Request(absTime, dt, acceleration, gradient, false);
@@ -270,7 +273,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					getYValue: result => ((ResponseDryRun)result).DeltaFullLoad,
 					evaluateFunction: x => NextComponent.Request(absTime, dt, x, gradient, true),
 					criterion:
-						y => ((ResponseDryRun)y).DeltaFullLoad.Value());
+						y => ((ResponseDryRun)y).DeltaFullLoad.Value(),
+					searcher: this);
 				Log.Info(
 					"Found operating point for driver acceleration. absTime: {0}, dt: {1}, acceleration: {2}, gradient: {3}",
 					absTime, dt, acceleration, gradient);
@@ -286,7 +290,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					},
 					criterion: y => DataBus.ClutchInfo.ClutchClosed(absTime)
 						? ((ResponseDryRun)y).DeltaDragLoad.Value()
-						: ((ResponseDryRun)y).Gearbox.PowerRequest.Value());
+						: ((ResponseDryRun)y).Gearbox.PowerRequest.Value(),
+					searcher: this);
 				Log.Info(
 					"Found operating point for braking. absTime: {0}, dt: {1}, acceleration: {2}, gradient: {3}, BrakePower: {4}",
 					absTime, dt, acceleration, gradient, DataBus.Brakes.BrakePower);
@@ -300,7 +305,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 						Constants.SimulationSettings.OperatingPointInitialSearchIntervalAccelerating,
 						getYValue: result => ((ResponseDryRun)result).DeltaFullLoad,
 						evaluateFunction: x => NextComponent.Request(absTime, dt, x, gradient, true),
-						criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value());
+						criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value(),
+						searcher: this);
 				}
 			}
 			var response = NextComponent.Request(absTime, dt, acceleration, gradient, false);
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs
index 1c8ee412bba22725e1a01068789efb6c0db3d9c3..693fe029533d2430580a1815dac2fdffd9019170 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs
@@ -127,7 +127,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 						var torque = SearchAlgorithm.Search(CycleIterator.LeftSample.Torque, r.Delta, torqueInterval,
 							getYValue: result => ((ResponseDryRun)result).DeltaDragLoad,
 							evaluateFunction: t => NextComponent.Request(absTime, dt, t, angularVelocity, true),
-							criterion: y => ((ResponseDryRun)y).DeltaDragLoad.Value());
+							criterion: y => ((ResponseDryRun)y).DeltaDragLoad.Value(),
+							searcher: this);
 						response = NextComponent.Request(absTime, dt, torque, angularVelocity, false);
 						CurrentState.InTorque = torque;
 						break;
@@ -135,7 +136,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 						var torque2 = SearchAlgorithm.Search(CycleIterator.LeftSample.Torque, r.Delta, 50.SI<NewtonMeter>(),
 							getYValue: result => ((ResponseDryRun)result).DeltaFullLoad,
 							evaluateFunction: t => NextComponent.Request(absTime, dt, t, angularVelocity, true),
-							criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value());
+							criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value(),
+							searcher: this);
 						response = NextComponent.Request(absTime, dt, torque2, angularVelocity, false);
 						CurrentState.InAngularVelocity = angularVelocity;
 						CurrentState.InTorque = torque2;
@@ -145,7 +147,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 							1.RPMtoRad(),
 							getYValue: result => ((ResponseDryRun)result).DeltaEngineSpeed,
 							evaluateFunction: x => NextComponent.Request(absTime, dt, CurrentState.InTorque, x, true),
-							criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value());
+							criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value(),
+							searcher: this);
 						break;
 					case ResponseFailTimeInterval r:
 						dt = r.DeltaT;
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SerialHybridController.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SerialHybridController.cs
new file mode 100644
index 0000000000000000000000000000000000000000..98c7bf2139b64b7e4ee0c8bd8dfbb645dc4a7918
--- /dev/null
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SerialHybridController.cs
@@ -0,0 +1,285 @@
+using System;
+using System.Collections.Generic;
+using TUGraz.VectoCommon.Exceptions;
+using TUGraz.VectoCommon.InputData;
+using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.Models.Connector.Ports;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
+using TUGraz.VectoCore.Models.Simulation;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.OutputData;
+using TUGraz.VectoCore.Utils;
+
+namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
+{
+	public class SerialHybridController : StatefulProviderComponent<SerialHybridController.HybridControllerState,
+			ITnOutPort, ITnInPort, ITnOutPort>, IHybridController, ITnOutPort, ITnInPort
+	{
+		protected readonly Dictionary<PowertrainPosition, ElectricMotorController> _electricMotorCtl;
+
+		private Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> _electricMotorTorque =
+			new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>();
+
+		protected readonly IHybridControlStrategy _hybridStrategy;
+
+		private HybridStrategyResponse CurrentStrategySettings = null;
+
+		protected DebugData DebugData = new DebugData();
+
+		protected ITnOutPort GenSetPort;
+
+		public SerialHybridController(IVehicleContainer container, IHybridControlStrategy strategy, IElectricSystem es) : base(container)
+		{
+			GenSet = new TnInPortWrapper(this);
+			_electricMotorCtl = new Dictionary<PowertrainPosition, ElectricMotorController>();
+			//_shiftStrategy = container.RunData.GearboxData.Type.AutomaticTransmission()
+			//	? new HybridController.HybridCtlATShiftStrategy(this, container)
+			//	: new HybridController.HybridCtlShiftStrategy(this, container);
+			_hybridStrategy = strategy;
+			strategy.Controller = this;
+
+			ElectricSystem = es;
+		}
+
+		
+
+		public IHybridControlStrategy Strategy => _hybridStrategy;
+
+		public IElectricSystem ElectricSystem { get; }
+
+
+		public IHybridControlledGearbox Gearbox { protected get; set; }
+		public ICombustionEngine Engine { protected get; set; }
+
+		//public 
+
+		#region Overrides of VectoSimulationComponent
+
+		protected override void DoWriteModalResults(Second time, Second simulationInterval, IModalDataContainer container)
+		{
+			Strategy.WriteModalResults(time, simulationInterval, container);
+		}
+
+		#endregion
+
+		#region Implementation of ITnOutPort
+
+		public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, bool dryRun)
+		{
+			var strategyResponse = Strategy.Request(absTime, dt, outTorque, outAngularVelocity, dryRun);
+
+			if (strategyResponse is HybridStrategyLimitedResponse ovl) {
+				if (dryRun) {
+					return new ResponseDryRun(this) {
+						DeltaDragLoad = ovl.Delta,
+						DeltaFullLoad = ovl.Delta,
+						// TODO! delta full/drag torque
+						DeltaEngineSpeed = ovl.DeltaEngineSpeed,
+						Gearbox = {
+							InputTorque = ovl.GearboxResponse?.InputTorque,
+							InputSpeed = ovl.GearboxResponse?.InputSpeed,
+							OutputTorque = ovl.GearboxResponse?.OutputTorque,
+							OutputSpeed = ovl.GearboxResponse?.OutputSpeed,
+							PowerRequest = ovl.GearboxResponse?.PowerRequest,
+							Gear = ovl.GearboxResponse?.Gear
+						}
+
+					};
+				}
+
+				return new ResponseOverload(this) {
+					Delta = ovl.Delta
+				};
+			}
+
+			var strategySettings = strategyResponse as HybridStrategyResponse;
+			ApplyStrategySettings(strategySettings);
+			CurrentStrategySettings = strategySettings;
+			if (!dryRun) {
+				CurrentState.SetState(outTorque, outAngularVelocity, outTorque, outAngularVelocity);
+				CurrentState.StrategyResponse = strategySettings;
+			}
+
+			// Todo: re-think for S2 configuration....
+			//if (!dryRun && /*!DataBus.EngineInfo.EngineOn &&*/ strategySettings.ShiftRequired) {
+			//	DataBus.GearboxCtl.TriggerGearshift(absTime, dt);
+			//	_shiftStrategy.SetNextGear(strategySettings.NextGear);
+			//	SelectedGear = strategySettings.NextGear;
+			//	if (!DataBus.GearboxInfo.GearboxType.AutomaticTransmission()) {
+			//		return new ResponseGearShift(this);
+			//	}
+			//}
+
+			var gensetResponse = GenSetPort.Request(absTime, dt, 0.SI<NewtonMeter>(), _electricMotorTorque[PowertrainPosition.Generator].Item1, dryRun);
+
+			if (!(gensetResponse is ResponseSuccess || gensetResponse is ResponseDryRun)) {
+				throw new VectoException("Invalid operating point for Genset provided by strategy! {0}", gensetResponse);
+			}
+
+			var retVal = NextComponent.Request(absTime, dt, outTorque, outAngularVelocity, dryRun);
+			DebugData.Add(new {
+				DrivingAction = DataBus.DriverInfo.DrivingAction,
+				StrategySettings = strategySettings,
+				Response = retVal,
+				DryRun = dryRun
+			});
+			retVal.HybridController.StrategySettings = strategySettings;
+			var modifiedResponse = Strategy.AmendResponse(retVal, absTime, dt, outTorque, outAngularVelocity, dryRun);
+
+			return modifiedResponse;
+		}
+
+		private void ApplyStrategySettings(HybridStrategyResponse strategySettings)
+		{
+			if (Gearbox != null) {
+				Gearbox.SwitchToNeutral = strategySettings.GearboxInNeutral;
+			}
+
+			Engine.CombustionEngineOn = strategySettings.CombustionEngineOn;
+			_electricMotorTorque = strategySettings.MechanicalAssistPower;
+			//if (DataBus.VehicleInfo.VehicleStopped && strategySettings.NextGear.Gear != 0) {
+				//_shiftStrategy.SetNextGear(strategySettings.NextGear);
+			//}
+		}
+
+		protected override void DoCommitSimulationStep(Second time, Second simulationInterval)
+		{
+			base.DoCommitSimulationStep(time, simulationInterval);
+			Strategy.CommitSimulationStep(time, simulationInterval);
+			DebugData = new DebugData();
+		}
+
+		public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity)
+		{
+			PreviousState.SetState(outTorque, outAngularVelocity, outTorque, outAngularVelocity);
+			var strategyResponse = Strategy.Initialize(outTorque, outAngularVelocity);
+			PreviousState.StrategyResponse = strategyResponse as HybridStrategyResponse;
+			_electricMotorTorque = PreviousState.StrategyResponse.MechanicalAssistPower;
+			var retVal = NextComponent.Initialize(outTorque, outAngularVelocity);
+			if (DataBus.GearboxInfo != null) {
+				SelectedGear = DataBus.GearboxInfo.Gear;
+			}
+
+
+			GenSetPort.Initialize(0.SI<NewtonMeter>(), DataBus.EngineInfo.EngineIdleSpeed);
+
+			return retVal;
+		}
+
+		#endregion
+
+		#region Implementation of IHybridControllerInfo
+
+		public GearshiftPosition SelectedGear { get; protected set; }
+		public PerSecond ICESpeed { get; }
+		public bool GearboxEngaged { get; }
+		public Second SimulationInterval => CurrentStrategySettings.SimulationInterval;
+		public PerSecond ElectricMotorSpeed(PowertrainPosition pos)
+		{
+			return CurrentStrategySettings.MechanicalAssistPower[pos].Item1;
+		}
+
+		#endregion
+
+		#region Implementation of IHybridControllerCtl
+
+		public void RepeatDrivingAction(Second absTime)
+		{
+			Strategy.RepeatDrivingAction(absTime);
+		}
+
+		#endregion
+
+		#region Implementation of IHybridController
+
+		public IShiftStrategy ShiftStrategy { get; }
+		SimpleComponentState IHybridController.PreviousState => PreviousState;
+		public ITnInProvider GenSet { get; }
+
+		public IElectricMotorControl ElectricMotorControl(PowertrainPosition pos)
+		{
+			return _electricMotorCtl[pos];
+		}
+
+		public void AddElectricMotor(PowertrainPosition pos, ElectricMotorData motorData)
+		{
+			if (_electricMotorCtl.ContainsKey(pos)) {
+				throw new VectoException("Electric motor already registered as position {0}", pos);
+			}
+
+			_electricMotorCtl[pos] = new ElectricMotorController(this, motorData);
+		}
+
+
+
+		#endregion
+
+		private NewtonMeter MechanicalAssistPower(PowertrainPosition pos, Second absTime, Second dt,
+			NewtonMeter outTorque, PerSecond prevOutAngularVelocity, PerSecond currOutAngularVelocity, bool dryRun)
+		{
+			return _electricMotorTorque[pos]?.Item2;
+
+			//return CurrentState.StrategyResponse.MechanicalAssistPower[pos];
+		}
+
+		///=======================================================================================
+
+		public class HybridControllerState : SimpleComponentState
+		{
+			public HybridStrategyResponse StrategyResponse { get; set; }
+		}
+
+		///=======================================================================================
+		private class TnInPortWrapper : ITnInProvider, ITnInPort
+		{
+			protected SerialHybridController Controller;
+
+			public TnInPortWrapper(SerialHybridController ctl)
+			{
+				Controller = ctl;
+			}
+
+			#region Implementation of ITnInProvider
+
+			public ITnInPort InPort()
+			{
+				return this;
+			}
+
+			#endregion
+
+			#region Implementation of ITnInPort
+
+			public void Connect(ITnOutPort other)
+			{
+				Controller.GenSetPort = other;
+			}
+
+			#endregion
+		}
+
+		///=======================================================================================
+
+		public class ElectricMotorController : IElectricMotorControl
+		{
+			protected SerialHybridController _controller;
+			protected ElectricMotorData ElectricMotorData;
+
+			public ElectricMotorController(SerialHybridController hybridController, ElectricMotorData motorData)
+			{
+				_controller = hybridController;
+				ElectricMotorData = motorData;
+			}
+
+			public NewtonMeter MechanicalAssistPower(Second absTime, Second dt, NewtonMeter outTorque,
+				PerSecond prevOutAngularVelocity, PerSecond currOutAngularVelocity,
+				NewtonMeter maxDriveTorque, NewtonMeter maxRecuperationTorque, PowertrainPosition position, bool dryRun)
+			{
+				return _controller.MechanicalAssistPower(position, absTime, dt, outTorque, prevOutAngularVelocity,
+					currOutAngularVelocity, dryRun);
+			}
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs
index 6f7fa740d71ecb03431373df3259472d09636d50..6e393d7bb1760c5192c1e5f22ca805af855a000e 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs
@@ -23,7 +23,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl {
 
 		private Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> _electricMotorTorque = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>();
 
-		public SimpleHybridController(VehicleContainer container, ElectricSystem es, SwitchableClutch clutch) : base(container)
+		public SimpleHybridController(VehicleContainer container, ElectricSystem es) : base(container)
 		{
 			ElectricSystem = es;
 			//this.clutch = clutch;
@@ -117,8 +117,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl {
 
 		public void ApplyStrategySettings(HybridStrategyResponse strategySettings)
 		{
-			Gearbox.SwitchToNeutral = strategySettings.GearboxInNeutral;
-			Engine.CombustionEngineOn = strategySettings.CombustionEngineOn;
+			if (Gearbox != null) {
+				Gearbox.SwitchToNeutral = strategySettings.GearboxInNeutral;
+			}
+
+			if (Engine != null) {
+				Engine.CombustionEngineOn = strategySettings.CombustionEngineOn;
+			}
 			_electricMotorTorque = strategySettings.MechanicalAssistPower;
 		}
 
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs
index 1d94509c1fe9b6a5f361782cca641afacd26156d..d59ac9aefc691246e420c6f661fb860be0b82e30 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs
@@ -87,7 +87,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		protected virtual void SetMaxVehicleSpeed()
 		{
-			if (DataBus.PowertrainInfo.HasCombustionEngine) {
+			if (DataBus.PowertrainInfo.VehicleArchitecutre != VectoSimulationJobType.SerialHybridVehicle && DataBus.PowertrainInfo.HasCombustionEngine) {
 				if (DataBus.GearboxInfo == null || DataBus.AxlegearInfo == null) {
 					throw new VectoException("Powertrain with combustion engine requires gearbox and axlegear!");
 					//return;
@@ -101,7 +101,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			
 			if (DataBus.PowertrainInfo.HasElectricMotor) {
-				var positions = DataBus.PowertrainInfo.ElectricMotorPositions;
+				var positions = DataBus.PowertrainInfo.ElectricMotorPositions.Where(x => x != PowertrainPosition.Generator).ToArray();
+				;
 				if (positions.Length > 1) {
 					throw new VectoException("Multiple electrical machines are currently not supported");
 				}
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/VelocitySpeedGearshiftPreprocessor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/VelocitySpeedGearshiftPreprocessor.cs
index 806ce19c832edc5f0ddb06c8689c8a2afb10e8f4..8542399f7b412a002e7916095d0dbfd3c50b1ee7 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/VelocitySpeedGearshiftPreprocessor.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/VelocitySpeedGearshiftPreprocessor.cs
@@ -176,7 +176,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					abortCriterion: (response, cnt) => {
 						var r = (ResponseDryRun)response;
 						return r != null && (vehicle.VehicleSpeed + r.Driver.Acceleration * simulationInterval) < 0.KMPHtoMeterPerSecond();
-					}
+					},
+					searcher: this
 				);
 				var step = vehicle.Request(absTime, simulationInterval, acceleration, gradient);
 				if (!(step is ResponseSuccess)) {
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c37df4055de9428ba6c97bab1cb035323f8773e4
--- /dev/null
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs
@@ -0,0 +1,160 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
+using TUGraz.VectoCore.Models.Declaration;
+using TUGraz.VectoCore.Models.Simulation;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor;
+using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine;
+
+namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
+{
+	public class GensetPreprocessor : ISimulationPreprocessor
+	{
+		protected TestGenset Genset;
+		private CombustionEngineData IceData;
+		private ElectricMotorData EmData;
+		protected GenSetCharacteristics OptimalPoints;
+
+		public GensetPreprocessor(GenSetCharacteristics optimalPoints, TestGenset testGenSet, CombustionEngineData engineData,
+			ElectricMotorData electricMotorData)
+		{
+			Genset = testGenSet;
+			IceData = engineData;
+			EmData = electricMotorData;
+			OptimalPoints = optimalPoints;
+		}
+
+		#region Implementation of ISimulationPreprocessor
+
+		public void RunPreprocessing()
+		{
+			var voltage = EmData.EfficiencyData.VoltageLevels.First().Voltage;
+
+			IterateElectricPower(voltage);
+
+			MaxElectricPower(voltage, false);
+
+			MaxElectricPower(voltage, true);
+		}
+
+		private void MaxElectricPower(Volt voltage, bool emDerated)
+		{
+			var continuousTq = emDerated ? Genset.ElectricMotor.ContinuousTorque : double.MaxValue.SI<NewtonMeter>();
+			var emFldDrivetrain = new ElectricMotorFullLoadCurve(EmData.EfficiencyData.VoltageLevels[0].FullLoadCurve
+				.FullLoadEntries.Select(x =>
+					new ElectricMotorFullLoadCurve.FullLoadEntry() {
+						FullGenerationTorque =
+							Genset.ElectricMotor.ConvertEmTorqueToDrivetrain(x.MotorSpeed, VectoMath.Min(continuousTq ,x.FullGenerationTorque)),
+						FullDriveTorque =
+							Genset.ElectricMotor.ConvertEmTorqueToDrivetrain(x.MotorSpeed, VectoMath.Max(-continuousTq, x.FullDriveTorque)),
+						MotorSpeed = Genset.ElectricMotor.ConvertEmSpeedToDrivetrain(x.MotorSpeed)
+					}).ToList());
+			var iceFld = new ElectricMotorFullLoadCurve(IceData.FullLoadCurves[0].FullLoadEntries.Select(x =>
+				new ElectricMotorFullLoadCurve.FullLoadEntry() {
+					FullDriveTorque = -x.TorqueFullLoad,
+					FullGenerationTorque = 0.SI<NewtonMeter>(),
+					MotorSpeed = x.EngineSpeed
+				}).ToList());
+
+			var combinedFldEntries = AbstractSimulationDataAdapter.IntersectEMFullLoadCurves(iceFld, emFldDrivetrain).FullLoadEntries.Select(x =>
+				new EngineFullLoadCurve.FullLoadCurveEntry() {
+					EngineSpeed = x.MotorSpeed,
+					TorqueFullLoad = -x.FullDriveTorque,
+					TorqueDrag = 0.SI<NewtonMeter>()
+				}).Where(x => x.EngineSpeed > IceData.IdleSpeed && x.EngineSpeed < IceData.FullLoadCurves[0].N95hSpeed).ToList();
+
+			var combinedFld = new EngineFullLoadCurve(combinedFldEntries, null);
+			var absTime = 0.SI<Second>();
+			var dt = 1.SI<Second>();
+
+			var ratedSpeed = combinedFld.RatedSpeed;
+			Genset.ElectricMotorCtl.EMTorque = combinedFld.FullLoadStationaryTorque(ratedSpeed);
+			Genset.ElectricMotor.Initialize(combinedFld.FullLoadStationaryTorque(ratedSpeed), ratedSpeed);
+			var response = Genset.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), ratedSpeed);
+
+			if (response is ResponseSuccess) {
+				var fc = IceData.Fuels.Sum(x =>
+					x.ConsumptionMap.GetFuelConsumptionValue(response.Engine.TotalTorqueDemand,
+						response.Engine.EngineSpeed));
+				var tmp = new GenSetOperatingPoint() {
+					ICEOn = true,
+					ElectricPower = response.ElectricSystem.ConsumerPower,
+					ICESpeed = ratedSpeed,
+					ICETorque = Genset.ElectricMotorCtl.EMTorque,
+					FuelConsumption = fc,
+					EMSpeed = response.ElectricMotor.AngularVelocity,
+					EMTorque = response.ElectricMotor.TorqueRequestEmMap
+				};
+				if (emDerated) {
+					OptimalPoints.MaxPowerDeRated = tmp;
+				} else {
+					OptimalPoints.MaxPower = tmp;
+				}
+			}
+		}
+
+		private void IterateElectricPower(Volt voltage)
+		{
+			var maxPower = IceData.FullLoadCurves[0].MaxPower;
+
+			var speedRange = IceData.FullLoadCurves[0].RatedSpeed - IceData.IdleSpeed;
+			var maxSpeedNorm = (IceData.FullLoadCurves[0].N95hSpeed - IceData.IdleSpeed) / speedRange;
+
+			var absTime = 0.SI<Second>();
+			var dt = 1.SI<Second>();
+
+			var tolerance = 0.5 / 100;
+
+			var stepsPwr = 0.05;
+			for (var i = stepsPwr; i <= 1; i += stepsPwr) {
+				var pwr = i * maxPower;
+				var stepsSpeed = 0.05;
+				var genPts = new List<GenSetOperatingPoint>();
+				var responses = new List<Tuple<PerSecond, IResponse>>();
+				for (var n = 0.0; n <= maxSpeedNorm; n += stepsSpeed) {
+					var speed = n * speedRange + IceData.IdleSpeed;
+
+					try {
+						Genset.ElectricMotor.Initialize(0.SI<NewtonMeter>(), speed);
+						var tq = Genset.ElectricMotor.GetTorqueForElectricPower(voltage, pwr, speed * EmData.RatioADC, dt);
+
+						if (tq == null || tq.IsSmallerOrEqual(0)) {
+							continue;
+						}
+
+						Genset.ElectricMotorCtl.EMTorque = tq;
+
+						var response = Genset.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), speed);
+						responses.Add(Tuple.Create(speed, response));
+						if (response is ResponseSuccess) {
+							var fc = IceData.Fuels.Sum(x =>
+								x.ConsumptionMap.GetFuelConsumptionValue(response.Engine.TotalTorqueDemand,
+									response.Engine.EngineSpeed));
+							genPts.Add(new GenSetOperatingPoint() {
+								ICEOn = true,
+								ElectricPower = pwr,
+								ICESpeed = speed,
+								ICETorque = tq,
+								FuelConsumption = fc,
+								EMSpeed = response.ElectricMotor.AngularVelocity,
+								EMTorque = response.ElectricMotor.TorqueRequestEmMap
+							});
+						}
+					} catch (Exception) { }
+				}
+
+				if (genPts.Any()) {
+					var min = genPts.MinBy(x => x.FuelConsumption.Value()).FuelConsumption;
+					OptimalPoints.OptimalPoints[pwr] = genPts.Where(x => x.FuelConsumption / min < (1 + tolerance)).ToList();
+				}
+			}
+		}
+
+		#endregion
+	}
+}
\ 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 ca55fe5b8753a06585c50b01e4b305021e045ab0..eb8278df26ef59e67dfcf51b21d43ffa5a6b4c9a 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs
@@ -958,7 +958,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 					var r = (IResponse)resp;
 					var deltaMaxTq = r.Engine.TotalTorqueDemand - r.Engine.DynamicFullLoadTorque;
 					return (deltaMaxTq * avgEngineSpeed).Value();
-				});
+				},
+				searcher: this);
 			var rqMaxTorque = RequestDryRun(absTime, dt, maxTorque, outAngularVelocity, currentGear, maxEmDriveSetting);
 			// limiting to ICE FLD with max propulsion - delta gearbox torque
 			var rqMaxGbxInTq = GetGearboxInTorqueLimitedVehiclePorpTorque(rqMaxTorque, emPos);
@@ -1238,7 +1239,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 							deltaDragLoad = response.Gearbox.InputTorque;
 						}
 						return deltaDragLoad.Value();
-					}
+					},
+					searcher: this
 				);
 				if (emRecuperationTq.IsBetween(
 					firstResponse.ElectricMotor.MaxDriveTorque ?? 0.SI<NewtonMeter>(), firstResponse.ElectricMotor.MaxRecuperationTorque ?? 0.SI<NewtonMeter>())) {
@@ -1923,7 +1925,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 								var response = r as IResponse;
 								return response.Engine.TorqueOutDemand.Value();
 							},
-							abortCriterion: (r, c) => r == null
+							abortCriterion: (r, c) => r == null,
+							searcher: this
 						);
 						if (emTorqueICEOff.IsBetween(
 							firstResponse.ElectricMotor.MaxDriveTorque, VectoMath.Min(0.SI<NewtonMeter>(), firstResponse.ElectricMotor.MaxRecuperationTorque))) {
@@ -1962,7 +1965,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 								var response = r as IResponse;
 								return (response.Engine.TotalTorqueDemand - response.Engine.DynamicFullLoadTorque).Value();
 							},
-							abortCriterion: (r, c) => r == null
+							abortCriterion: (r, c) => r == null,
+							searcher: this
 						);
 						if (emTorqueICEMax.IsBetween(maxEmTorque, 0.SI<NewtonMeter>())) {
 							// only consider where EM is recuperating
@@ -2018,7 +2022,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 									var response = r as IResponse;
 									return response.Engine.TorqueOutDemand.Value();
 								},
-								abortCriterion: (r, c) => r == null
+								abortCriterion: (r, c) => r == null,
+								searcher: this
 							);
 							if (emTorqueICEOff.IsBetween(maxEmTorqueRecuperate, 0.SI<NewtonMeter>())) {
 								// only consider where EM is recuperating
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs
new file mode 100644
index 0000000000000000000000000000000000000000..69dcf8652669fb011632d9330831306505942272
--- /dev/null
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs
@@ -0,0 +1,669 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using TUGraz.VectoCommon.Exceptions;
+using TUGraz.VectoCommon.InputData;
+using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.Models.BusAuxiliaries.DownstreamModules.Impl.Electrics;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
+using TUGraz.VectoCore.Models.Simulation;
+using TUGraz.VectoCore.Models.Simulation.Data;
+using TUGraz.VectoCore.Models.Simulation.DataBus;
+using TUGraz.VectoCore.Models.Simulation.Impl;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.Models.SimulationComponent.Impl;
+using TUGraz.VectoCore.OutputData;
+using TUGraz.VectoCore.Utils;
+
+namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
+{
+	public class SerialHybridStrategy : AbstractSerialHybridStrategy
+	{
+		public enum StateMachineState
+		{
+			Undefined,
+			Acc_S0, // GEN = 0
+			Acc_S1, // P_GEN = P_opt, SoC <= SoC_min && P_demand < P_opt || SoC >= SoC_min && SoC <= SoC_target && P_demand <= P_opt
+			Acc_S2, // P_GEN = P_max, SoC <= S
+			Acc_S3, // P_GEN = P_max, P_drive = P_GEN
+
+			Break_S0,
+			Break_S1,
+			Break_S2,
+		}
+
+		protected DryRunSolutionState DryRunSolution { get; set; }
+
+
+		public SerialHybridStrategy(VectoRunData runData, IVehicleContainer container) : base(runData, container) { }
+
+
+		public override IHybridStrategyResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity)
+		{
+			EmPosition = DataBus.PowertrainInfo.ElectricMotorPositions.FirstOrDefault(x =>
+				x != PowertrainPosition.Generator);
+
+			var retVal = new HybridStrategyResponse()
+				{ MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>() };
+
+			foreach (var em in ModelData.ElectricMachinesData) {
+				retVal.MechanicalAssistPower[em.Item1] = null;
+			}
+
+			GenSetCharacteristics.ContinuousTorque =
+				(DataBus.ElectricMotorInfo(PowertrainPosition.Generator) as ElectricMotor).ContinuousTorque;
+
+			PreviousState.AngularVelocity = outAngularVelocity;
+			PreviousState.GearboxEngaged = true;
+			PreviousState.GearshiftTriggerTstmp = -double.MaxValue.SI<Second>();
+			PreviousState.SMState = DataBus.BatteryInfo.StateOfCharge > StrategyParameters.TargetSoC
+				? StateMachineState.Acc_S0
+				: DataBus.BatteryInfo.StateOfCharge > StrategyParameters.MinSoC
+					? StateMachineState.Acc_S1
+					: StateMachineState.Acc_S2;
+			CurrentState.SMState = PreviousState.SMState;
+			CurrentState.GearshiftTriggerTstmp = -double.MaxValue.SI<Second>();
+			return retVal;
+		}
+
+		public override IHybridStrategyResponse Request(Second absTime, Second dt, NewtonMeter outTorque,
+			PerSecond outAngularVelocity,
+			bool dryRun)
+		{
+
+			if (DryRunSolution != null && DryRunSolution.DrivingAction != DataBus.DriverInfo.DrivingAction) {
+				DryRunSolution = null;
+			}
+
+			//if (!dryRun && DryRunSolution != null && !DryRunSolution.Solution.IgnoreReason.AllOK()) {
+			//	DryRunSolution = null;
+			//}
+
+			if (dryRun && DryRunSolution != null && DryRunSolution.DrivingAction == DataBus.DriverInfo.DrivingAction) {
+				var tmp = new HybridStrategyResponse() {
+					SimulationInterval = dt,
+					CombustionEngineOn = DryRunSolution.ICEOn,
+					MechanicalAssistPower = DryRunSolution.Settings
+				};
+				return tmp;
+			}
+
+
+			var maxPowerGenset = GetMaxElectricPowerGenerated(absTime, dt);
+
+			var drivetrainDemand = GetDrivetrainPowerDemand(absTime, dt, outTorque, outAngularVelocity, maxPowerGenset);
+			var emResponse = drivetrainDemand.Response.ElectricMotor;
+
+			//if (((-emResponse.TorqueRequest).IsSmaller(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(), 1e-3) ||
+			//	(-emResponse.TorqueRequest).IsGreater(emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>(), 1e-3))) {
+			//	var delta = emResponse.TorqueRequest -
+			//				(-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(),
+			//					emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>());
+			//	return new HybridStrategyLimitedResponse() {
+			//		Delta = delta * emResponse.AvgDrivetrainSpeed
+			//	};
+			//}
+
+			switch (DataBus.DriverInfo.DrivingAction) {
+				case DrivingAction.Halt:
+				case DrivingAction.Roll:
+				case DrivingAction.Coast:
+				case DrivingAction.Accelerate:
+					CurrentState.SMState = GetStateAccelerate(drivetrainDemand, maxPowerGenset, dt);
+					break;
+				case DrivingAction.Brake:
+					CurrentState.SMState = GetStateBrake(drivetrainDemand);
+					break;
+				default:
+					throw new ArgumentOutOfRangeException();
+			}
+
+			GenSetOperatingPoint genSetOperatingPoint;
+			var emTorque = (-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(),
+				emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>());
+			switch (CurrentState.SMState) {
+				case StateMachineState.Acc_S0:
+					genSetOperatingPoint = GensetOff;
+					// update drivetrain demand if genset uses a different operating point - we are above target SoC, battery might get full
+					var tmp = GensetOff;
+					tmp.ElectricPower = 0.SI<Watt>();
+					drivetrainDemand = GetDrivetrainPowerDemand(absTime, dt, outTorque, outAngularVelocity, tmp);
+					emResponse = drivetrainDemand.Response.ElectricMotor;
+					emTorque = (-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(),
+						emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>());
+					break;
+				case StateMachineState.Acc_S1:
+					var optimalPoint = DataBus.ElectricMotorInfo(PowertrainPosition.Generator).DeRatingActive ?
+						GenSetCharacteristics.OptimalPointDeRated
+						: GenSetCharacteristics.OptimalPoint;
+					genSetOperatingPoint = ApproachGensetOperatingPoint(absTime, dt, optimalPoint);
+					// update drivetrain demand if genset uses a different operating point? - probably not needed as SoC needs to increase anyway
+					//drivetrainDemand = GetDrivetrainPowerDemand(absTime, dt, outTorque, outAngularVelocity, genSetOperatingPoint);
+					//emResponse = drivetrainDemand.Response.ElectricMotor;
+					//emTorque = (-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(),
+					//	emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>());
+					break;
+				case StateMachineState.Acc_S2:
+					genSetOperatingPoint = MaxGensetPower(absTime, dt, drivetrainDemand, maxPowerGenset);
+					break;
+				case StateMachineState.Acc_S3:
+					genSetOperatingPoint = MaxGensetPower(absTime, dt, drivetrainDemand, maxPowerGenset);
+					emTorque = TestPowertrain.ElectricMotor.GetTorqueForElectricPower(
+						DataBus.BatteryInfo.InternalVoltage, drivetrainDemand.Response.ElectricSystem.MaxPowerDrive,
+						drivetrainDemand.Response.ElectricMotor.AngularVelocity, dt).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(),
+						emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>());
+					break;
+				case StateMachineState.Break_S0:
+				case StateMachineState.Break_S1:
+				case StateMachineState.Break_S2:
+					genSetOperatingPoint = DataBus.EngineInfo.EngineOn ? ApproachGensetOperatingPoint(absTime, dt, GensetIdle) : GensetOff;
+					
+					// update drivetrain demand if genset uses a different operating point - we are above target SoC, battery might get full
+					var tmpBr = GensetOff;
+					tmpBr.ElectricPower = 0.SI<Watt>();
+					drivetrainDemand = GetDrivetrainPowerDemand(absTime, dt, outTorque, outAngularVelocity, tmpBr);
+					emResponse = drivetrainDemand.Response.ElectricMotor;
+					if (emTorque > 0 && emResponse.MaxRecuperationTorque == null) {
+						// we could recuperate, but max recuperation is null - so battery is full. turn off EM
+						emTorque = null;
+					} else {
+						emTorque = (-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(),
+							emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>());
+					}
+					break;
+				default:
+					throw new ArgumentOutOfRangeException();
+			}
+
+			var setting = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>() {
+					{
+						EmPosition,
+						Tuple.Create(drivetrainDemand.AvgEmDrivetrainSpeed, emTorque)
+					}, {
+						PowertrainPosition.Generator,
+						Tuple.Create(genSetOperatingPoint.ICESpeed, genSetOperatingPoint.ICETorque)
+					},
+				}
+				;
+
+			DryRunSolution = new DryRunSolutionState(DataBus.DriverInfo.DrivingAction, setting, genSetOperatingPoint.ICEOn);
+
+			return new HybridStrategyResponse() {
+				SimulationInterval = dt,
+				CombustionEngineOn = genSetOperatingPoint.ICEOn,
+				MechanicalAssistPower = setting
+			};
+
+		}
+
+		protected StateMachineState GetStateAccelerate(DrivetrainDemand drivetrainDemand,
+			GenSetOperatingPoint maxPowerGenset, Second dt)
+		{
+			var reqBatteryPower = maxPowerGenset.ElectricPower + drivetrainDemand.ElectricPowerDemand;
+			if (DataBus.BatteryInfo.StateOfCharge.IsEqual(StrategyParameters.MinSoC, 0.01) && reqBatteryPower < 0 && drivetrainDemand.ElectricPowerDemand < drivetrainDemand.Response.ElectricSystem.MaxPowerDrive) {
+				return StateMachineState.Acc_S3;
+			}
+
+			var optimalGensetPoint = DataBus.ElectricMotorInfo(PowertrainPosition.Generator).DeRatingActive
+				? GenSetCharacteristics.OptimalPointDeRated
+				: GenSetCharacteristics.OptimalPoint;
+			switch (PreviousState.SMState) {
+				case StateMachineState.Acc_S0:
+					if (DataBus.BatteryInfo.StateOfCharge < StrategyParameters.MinSoC) {
+						return -drivetrainDemand.ElectricPowerDemand <
+								optimalGensetPoint.ElectricPower
+							? StateMachineState.Acc_S1
+							: StateMachineState.Acc_S2;
+					}
+
+					break;
+				case StateMachineState.Acc_S1:
+					if (/*DataBus.BatteryInfo.StateOfCharge >= StrategyParameters.MinSoC &&*/
+						DataBus.BatteryInfo.StateOfCharge < StrategyParameters.TargetSoC
+						&& -drivetrainDemand.ElectricPowerDemand >
+						optimalGensetPoint.ElectricPower) {
+						return StateMachineState.Acc_S2;
+					}
+
+					if (DataBus.BatteryInfo.StateOfCharge >= StrategyParameters.TargetSoC) {
+						return StateMachineState.Acc_S0;
+					}
+
+					break;
+				case StateMachineState.Acc_S2:
+					if (DataBus.BatteryInfo.StateOfCharge >= StrategyParameters.TargetSoC) {
+						return StateMachineState.Acc_S0;
+					}
+
+					if (DataBus.BatteryInfo.StateOfCharge >= StrategyParameters.MinSoC &&
+						DataBus.BatteryInfo.StateOfCharge < StrategyParameters.TargetSoC
+						&& -drivetrainDemand.ElectricPowerDemand <=
+						optimalGensetPoint.ElectricPower) {
+						return StateMachineState.Acc_S1;
+					}
+					break;
+				case StateMachineState.Break_S0:
+					return StateMachineState.Acc_S0;
+				case StateMachineState.Break_S1:
+					return StateMachineState.Acc_S1;
+				case StateMachineState.Break_S2:
+					return StateMachineState.Acc_S2;
+				default:
+					throw new ArgumentOutOfRangeException();
+			}
+
+			return PreviousState.SMState;
+		}
+
+		protected StateMachineState GetStateBrake(DrivetrainDemand drivetrainDemand)
+		{
+			switch (PreviousState.SMState) {
+				case StateMachineState.Acc_S0:
+					return StateMachineState.Break_S0;
+				case StateMachineState.Acc_S1:
+					return StateMachineState.Break_S1;
+				case StateMachineState.Acc_S2:
+					return StateMachineState.Break_S2;
+				case StateMachineState.Acc_S3:
+					return StateMachineState.Break_S2;
+				case StateMachineState.Break_S0:
+					break;
+				case StateMachineState.Break_S1:
+					break;
+				case StateMachineState.Break_S2:
+					break;
+				default:
+					throw new ArgumentOutOfRangeException();
+			}
+
+			return PreviousState.SMState;
+		}
+	}
+
+	public abstract class AbstractSerialHybridStrategy  : LoggingObject, IHybridControlStrategy
+	{
+		protected VectoRunData ModelData;
+		protected IDataBus DataBus;
+
+		protected HybridStrategyParameters StrategyParameters;
+
+		protected Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> ElectricMotorsOff;
+
+		protected StrategyState CurrentState = new StrategyState();
+		protected StrategyState PreviousState = new StrategyState();
+
+		protected TestPowertrain<Gearbox> TestPowertrain;
+		protected TestGenset TestGenSet;
+		protected GenSetCharacteristics GenSetCharacteristics = new GenSetCharacteristics();
+		
+		protected PowertrainPosition EmPosition;
+
+
+		public AbstractSerialHybridStrategy (VectoRunData runData, IVehicleContainer container)
+		{
+			DataBus = container;
+			ModelData = runData;
+			if (ModelData.ElectricMachinesData.Select(x => x.Item1).Where(x => x != PowertrainPosition.Generator).Distinct().Count() > 1) {
+				throw new VectoException("More than one electric motors are currently not supported");
+			}
+			StrategyParameters = ModelData.HybridStrategyParameters;
+			if (StrategyParameters == null) {
+				throw new VectoException("Model parameters for hybrid strategy required!");
+			}
+
+			ElectricMotorsOff = ModelData.ElectricMachinesData
+				.Select(x => new KeyValuePair<PowertrainPosition, NewtonMeter>(x.Item1, null))
+				.ToDictionary(x => x.Key, x => new Tuple<PerSecond, NewtonMeter>(null, x.Value));
+
+			
+
+			// create testcontainer
+			var modData = new ModalDataContainer(runData, null, null);
+			var builder = new PowertrainBuilder(modData);
+			var testContainer = new SimplePowertrainContainer(runData);
+			builder.BuildSimpleSerialHybridPowertrain(runData, testContainer);
+
+            TestPowertrain = new TestPowertrain<Gearbox>(testContainer, DataBus);
+
+            var gensetContainer = new SimplePowertrainContainer(runData);
+			builder.BuildSimpleGenSet(runData, gensetContainer);
+			TestGenSet = new TestGenset(gensetContainer, DataBus);
+
+			
+			container.AddPreprocessor(new GensetPreprocessor(GenSetCharacteristics ,TestGenSet, runData.EngineData,
+				runData.ElectricMachinesData.FirstOrDefault(x => x.Item1 == PowertrainPosition.Generator)?.Item2));
+		}
+
+		#region Implementation of IHybridControlStrategy
+
+		protected GenSetOperatingPoint MaxGensetPower(Second absTime, Second dt,
+			DrivetrainDemand drivetrainDemand,
+			GenSetOperatingPoint maxPowerGenset)
+		{
+			var electricPowerDemand = drivetrainDemand.ElectricPowerDemand;
+
+			var gensetLimit = DataBus.ElectricMotorInfo(PowertrainPosition.Generator).DeRatingActive
+				? GenSetCharacteristics.MaxPowerDeRated
+				: GenSetCharacteristics.MaxPower;
+			if (maxPowerGenset.ElectricPower.IsSmaller(gensetLimit.ElectricPower)) {
+				gensetLimit = maxPowerGenset;
+			}
+
+			//if (electricPowerDemand.IsGreater(gensetLimit.ElectricPower)) {
+				return ApproachGensetOperatingPoint(absTime, dt, gensetLimit);
+			//}
+
+			//var pair = GenSetCharacteristics.OptimalPoints.Keys.GetSection(x =>
+			//	x.IsSmaller(drivetrainDemand.ElectricPowerDemand));
+
+			//return ApproachGensetOperatingPoint(absTime, dt, GenSetCharacteristics.OptimalPoints[pair.Item2].MinBy(x => x.FuelConsumption));
+			//GenSetCharacteristics.
+		}
+
+		public GenSetOperatingPoint GensetOff => new
+			GenSetOperatingPoint
+			{
+				ICEOn = false,
+				ICESpeed = ModelData.EngineData.IdleSpeed,
+				ICETorque = null,
+				EMTorque =  null
+			};
+
+		public GenSetOperatingPoint GensetIdle => new GenSetOperatingPoint() {
+			ICEOn =  true,
+			ICESpeed = ModelData.EngineData.IdleSpeed,
+			ICETorque =  0.SI<NewtonMeter>(),
+			EMTorque = null,
+		};
+
+		protected DrivetrainDemand GetDrivetrainPowerDemand(Second absTime, Second dt, NewtonMeter outTorque,
+			PerSecond outAngularVelocity, GenSetOperatingPoint maxPowerGenset)
+		{
+			TestPowertrain.ElectricMotor.ThermalBuffer =
+				(DataBus.ElectricMotorInfo(EmPosition) as ElectricMotor).ThermalBuffer;
+			TestPowertrain.ElectricMotor.DeRatingActive =
+				(DataBus.ElectricMotorInfo(EmPosition) as ElectricMotor).DeRatingActive;
+
+			TestPowertrain.Battery?.Initialize(DataBus.BatteryInfo.StateOfCharge);
+			if (TestPowertrain.Battery != null) {
+				TestPowertrain.Battery.PreviousState.PulseDuration =
+					(DataBus.BatteryInfo as Battery).PreviousState.PulseDuration;
+				TestPowertrain.Battery.PreviousState.PowerDemand =
+					(DataBus.BatteryInfo as Battery).PreviousState.PowerDemand;
+			}
+			if (TestPowertrain.BatterySystem != null) {
+				var batSystem = DataBus.BatteryInfo as BatterySystem;
+				foreach (var bsKey in batSystem.Batteries.Keys) {
+					for (var i = 0; i < batSystem.Batteries[bsKey].Batteries.Count; i++) {
+						TestPowertrain.BatterySystem.Batteries[bsKey].Batteries[i]
+							.Initialize(batSystem.Batteries[bsKey].Batteries[i].StateOfCharge);
+					}
+				}
+				TestPowertrain.BatterySystem.PreviousState.PulseDuration =
+					(DataBus.BatteryInfo as BatterySystem).PreviousState.PulseDuration;
+				TestPowertrain.BatterySystem.PreviousState.PowerDemand = (DataBus.BatteryInfo as BatterySystem).PreviousState.PowerDemand;
+			}
+
+			TestPowertrain.Charger.ChargingPower = maxPowerGenset.ElectricPower;
+			TestPowertrain.HybridController.Initialize(Controller.PreviousState.OutTorque,
+				Controller.PreviousState.OutAngularVelocity);
+			var testResponse =
+				TestPowertrain.HybridController.NextComponent.Request(absTime, dt, outTorque, outAngularVelocity, false);
+
+			TestPowertrain.HybridController.ApplyStrategySettings(new HybridStrategyResponse() {
+				CombustionEngineOn = false,
+				MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>() {
+					{
+						EmPosition,
+						Tuple.Create(testResponse.ElectricMotor.AvgDrivetrainSpeed, -testResponse.ElectricMotor.TorqueRequest)
+					}
+				}
+			});
+			var testResponse2 =
+				TestPowertrain.HybridController.NextComponent.Request(absTime, dt, outTorque, outAngularVelocity,
+					false);
+			return new DrivetrainDemand(){
+				AvgEmDrivetrainSpeed = testResponse2.ElectricMotor.AvgDrivetrainSpeed, 
+				EmTorqueDemand = testResponse2.ElectricMotor.TorqueRequest, 
+				ElectricPowerDemand = testResponse2.ElectricSystem.ConsumerPower,
+				Response = testResponse2
+			};
+		}
+
+		public class DrivetrainDemand
+		{
+			public PerSecond AvgEmDrivetrainSpeed { get; set; }
+			public NewtonMeter EmTorqueDemand { get; set; }
+
+			public Watt ElectricPowerDemand { get; set; }
+			public IResponse Response { get; set; }
+		}
+
+		protected GenSetOperatingPoint GetMaxElectricPowerGenerated(Second absTime, Second dt)
+		{
+			var genDerated = DataBus.ElectricMotorInfo(PowertrainPosition.Generator).DeRatingActive;
+			return ApproachGensetOperatingPoint(absTime, dt,
+				genDerated ? GenSetCharacteristics.MaxPowerDeRated : GenSetCharacteristics.MaxPower);
+		}
+
+		protected GenSetOperatingPoint ApproachGensetOperatingPoint(Second absTime, Second dt, GenSetOperatingPoint op)
+		{
+			TestGenSet.CombustionEngine.Initialize(
+				(DataBus.EngineInfo as CombustionEngine).PreviousState.EngineTorque,
+				(DataBus.EngineInfo as CombustionEngine).PreviousState.EngineSpeed);
+			TestGenSet.CombustionEngine.PreviousState.EngineOn = //true;
+				(DataBus.EngineInfo as CombustionEngine).PreviousState.EngineOn;
+			TestGenSet.CombustionEngine.PreviousState.EnginePower =
+				(DataBus.EngineInfo as CombustionEngine).PreviousState.EnginePower;
+			TestGenSet.CombustionEngine.PreviousState.dt = (DataBus.EngineInfo as CombustionEngine).PreviousState.dt;
+			TestGenSet.CombustionEngine.PreviousState.EngineSpeed =
+				(DataBus.EngineInfo as CombustionEngine).PreviousState.EngineSpeed;
+			TestGenSet.CombustionEngine.PreviousState.EngineTorque =
+				(DataBus.EngineInfo as CombustionEngine).PreviousState.EngineTorque;
+			TestGenSet.CombustionEngine.PreviousState.EngineTorqueOut =
+				(DataBus.EngineInfo as CombustionEngine).PreviousState.EngineTorqueOut;
+			TestGenSet.CombustionEngine.PreviousState.DynamicFullLoadTorque =
+				(DataBus.EngineInfo as CombustionEngine).PreviousState.DynamicFullLoadTorque;
+
+			switch (TestGenSet.CombustionEngine.EngineAux) {
+				case EngineAuxiliary engineAux:
+					engineAux.PreviousState.AngularSpeed =
+						((DataBus.EngineInfo as CombustionEngine).EngineAux as EngineAuxiliary).PreviousState
+						.AngularSpeed;
+					break;
+				case BusAuxiliariesAdapter busAux:
+					busAux.PreviousState.AngularSpeed =
+						((DataBus.EngineInfo as CombustionEngine).EngineAux as BusAuxiliariesAdapter).PreviousState
+						.AngularSpeed;
+					if (busAux.ElectricStorage is SimpleBattery bat) {
+						bat.SOC = ((DataBus.EngineInfo as CombustionEngine).EngineAux as BusAuxiliariesAdapter)
+							.ElectricStorage
+							.SOC;
+					}
+
+					break;
+			}
+			TestGenSet.ElectricMotor.ThermalBuffer =
+				(DataBus.ElectricMotorInfo(PowertrainPosition.Generator) as ElectricMotor).ThermalBuffer;
+			TestGenSet.ElectricMotor.DeRatingActive =
+				(DataBus.ElectricMotorInfo(PowertrainPosition.Generator) as ElectricMotor).DeRatingActive;
+
+			var iceSpeed = op.ICESpeed;
+			var emTqDt = op.ICETorque;
+			
+			TestGenSet.ElectricMotorCtl.EMTorque = emTqDt;
+			var r1 = TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), iceSpeed);
+			if (r1 is ResponseOverload ovl) {
+				emTqDt = SearchAlgorithm.Search(emTqDt, ovl.Delta, emTqDt * 0.1,
+					getYValue: r => {
+						var dryRun = r as ResponseDryRun;
+						return dryRun.DeltaFullLoad;
+					},
+					evaluateFunction:
+					x => {
+						TestGenSet.ElectricMotorCtl.EMTorque = x;
+						return TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), iceSpeed, true);
+					},
+					criterion: r => {
+						var dryRun = r as ResponseDryRun;
+						return dryRun.DeltaFullLoad.Value();
+					},
+					searcher: this);
+				TestGenSet.ElectricMotorCtl.EMTorque = emTqDt;
+				r1 = TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), iceSpeed);
+			}
+
+			if (r1 is ResponseUnderload udl) {
+				iceSpeed = SearchAlgorithm.Search(iceSpeed, udl.Delta, iceSpeed * 0.01,
+					getYValue: r => {
+						var dryRun = r as ResponseDryRun;
+						return dryRun.DeltaDragLoad;
+					},
+					evaluateFunction: x => {
+						return TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), x, true);
+					},
+					criterion: r => {
+						var dryRun = r as ResponseDryRun;
+						return dryRun.DeltaDragLoad.Value();
+					},
+					searcher: this);
+				r1 = TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), iceSpeed);
+			}
+
+			return new GenSetOperatingPoint() {
+				ICEOn = true,
+				ElectricPower = r1.ElectricSystem.ConsumerPower,
+				ICETorque = emTqDt,
+				ICESpeed = iceSpeed,
+				EMSpeed = r1.ElectricMotor.AngularVelocity,
+				EMTorque = r1.ElectricMotor.TorqueRequestEmMap
+			};
+		}
+
+		public abstract IHybridStrategyResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity);
+
+		public abstract IHybridStrategyResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
+			bool dryRun);
+
+		public IResponse AmendResponse(IResponse response, Second absTime, Second dt, NewtonMeter outTorque,
+			PerSecond outAngularVelocity, bool dryRun)
+		{
+			return response;
+		}
+
+		public void CommitSimulationStep(Second time, Second simulationInterval)
+		{
+			var iceStart = PreviousState.ICEStartTStmp;
+			PreviousState = CurrentState;
+			if (!DataBus.EngineCtl.CombustionEngineOn) {
+				PreviousState.ICEStartTStmp = iceStart;
+			} else {
+				// ice is on, set start-timestamp if it was off
+				if (!PreviousState.ICEOn) {
+					PreviousState.ICEStartTStmp = time;
+				}
+			}
+			CurrentState = new StrategyState();
+			CurrentState.ICEStartTStmp = PreviousState.ICEStartTStmp;
+			CurrentState.GearshiftTriggerTstmp = PreviousState.GearshiftTriggerTstmp;
+			CurrentState.ICEOn = DataBus.EngineCtl.CombustionEngineOn;
+			AllowEmergencyShift = false;
+			//DebugData = new DebugData();
+			
+			//throw new NotImplementedException();
+		}
+
+		public IHybridController Controller { get; set; }
+		public PerSecond MinICESpeed { get; }
+		public bool AllowEmergencyShift { get; set; }
+		public void WriteModalResults(Second time, Second simulationInterval, IModalDataContainer container)
+		{
+			//throw new NotImplementedException();
+		}
+
+		public void OperatingpointChangedDuringRequest(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
+			bool dryRun, IResponse retVal)
+		{
+			throw new NotImplementedException();
+		}
+
+		public void RepeatDrivingAction(Second absTime)
+		{
+			
+		}
+
+		#endregion
+
+		public class StrategyState
+		{
+			public PerSecond AngularVelocity { get; set; }
+			public HybridStrategyResponse Response { get; set; }
+			public List<HybridResultEntry> Evaluations;
+			public HybridResultEntry Solution { get; set; }
+
+			public bool GearboxEngaged { get; set; }
+
+			public Second ICEStartTStmp { get; set; }
+
+			public Second GearshiftTriggerTstmp { get; set; }
+			public NewtonMeter MaxGbxTq { get; set; }
+			public bool ICEOn { get; set; }
+
+			public SerialHybridStrategy.StateMachineState SMState { get; set; }
+		}
+
+		public class DryRunSolutionState
+		{
+			public DryRunSolutionState(DrivingAction drivingAction, Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> settings, bool iceOn)
+			{
+				DrivingAction = drivingAction;
+				Settings = settings;
+				ICEOn = iceOn;
+			}
+
+
+			public DrivingAction DrivingAction { get; }
+
+			public bool ICEOn { get; }
+
+			public Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> Settings { get; }
+		}
+	}
+
+	public class GenSetCharacteristics
+	{
+		public Dictionary<Watt, List<GenSetOperatingPoint>> OptimalPoints = new Dictionary<Watt, List<GenSetOperatingPoint>>();
+
+		public GenSetOperatingPoint MaxPower;
+
+		public GenSetOperatingPoint MaxPowerDeRated;
+		private GenSetOperatingPoint _optimalPoint;
+		private GenSetOperatingPoint _optimalPointDerated;
+
+		public GenSetOperatingPoint OptimalPoint => _optimalPoint ?? (_optimalPoint =
+			OptimalPoints.Values.SelectMany(x => x).MinBy(x => x.FuelConsumption / x.ElectricPower));
+
+		public GenSetOperatingPoint OptimalPointDeRated => _optimalPointDerated ?? (_optimalPointDerated =
+			OptimalPoints.Values.SelectMany(x => x).Where(x => x.EMTorque.IsSmaller(ContinuousTorque)).MinBy(x => x.FuelConsumption / x.ElectricPower));
+
+		public NewtonMeter ContinuousTorque { get; set; }
+	}
+
+	public class GenSetOperatingPoint
+	{
+		public bool ICEOn;
+
+		public Watt ElectricPower;
+
+		public PerSecond ICESpeed;
+
+		public NewtonMeter ICETorque;
+
+		public KilogramPerSecond FuelConsumption;
+
+		public PerSecond EMSpeed;
+
+		public NewtonMeter EMTorque;
+	}
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/TestPowertrain.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/TestPowertrain.cs
index 3d3ac2e8a7fe99d18396d2e4fceef46ed16d2304..45011d3dcacf8c0214b26894d33adccbd209a3c8 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/TestPowertrain.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/TestPowertrain.cs
@@ -11,7 +11,25 @@ using TUGraz.VectoCore.Models.SimulationComponent.Data;
 using TUGraz.VectoCore.Models.SimulationComponent.Impl;
 using TUGraz.VectoCore.OutputData;
 
-namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies {
+namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies 
+{
+
+	public class TestGenset
+	{
+
+		public SimplePowertrainContainer Container;
+		public StopStartCombustionEngine CombustionEngine;
+		public ElectricMotor ElectricMotor;
+		public GensetMotorController ElectricMotorCtl;
+
+		public TestGenset(SimplePowertrainContainer container, IDataBus realContainer)
+		{
+			Container = container;
+			CombustionEngine = Container.EngineInfo as StopStartCombustionEngine;
+			ElectricMotor = container.ElectricMotors.FirstOrDefault(x => x.Key == PowertrainPosition.Generator).Value as ElectricMotor;
+			ElectricMotorCtl = ElectricMotor.Control as GensetMotorController;
+		}
+	}
 	public class TestPowertrain<T> where T: class, IHybridControlledGearbox, IGearbox
 	{
 		public SimplePowertrainContainer Container;
@@ -26,6 +44,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies {
 
 		public StopStartCombustionEngine CombustionEngine;
 		public ElectricMotor ElectricMotor;
+		public GensetChargerAdapter Charger;
 		public Dictionary<PowertrainPosition, ElectricMotor> ElectricMotorsUpstreamTransmission = new Dictionary<PowertrainPosition, ElectricMotor>();
 		public TorqueConverter TorqueConverter;
 		public DCDCConverter DCDCConverter;
@@ -43,16 +62,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies {
 			Clutch = Container.ClutchInfo as Clutch;
 			CombustionEngine = Container.EngineInfo as StopStartCombustionEngine;
 			ElectricMotor = container.ElectricMotors.FirstOrDefault().Value as ElectricMotor;
+			Charger = (ElectricMotor?.ElectricPower as ElectricSystem)?.Charger as GensetChargerAdapter;
 			foreach (var pos in container.ElectricMotorPositions) {
 				if (pos == PowertrainPosition.HybridP1 || pos == PowertrainPosition.HybridP2 ||
 					pos == PowertrainPosition.HybridP2_5 || pos == PowertrainPosition.HybridP3) {
 					ElectricMotorsUpstreamTransmission[pos] = container.ElectricMotors[pos] as ElectricMotor;
 				}
 			}
-			if (Gearbox == null) {
-			}
-
-			if (Gearbox.GearboxType.AutomaticTransmission()) {
+			
+			if (Gearbox != null && Gearbox.GearboxType.AutomaticTransmission()) {
 				TorqueConverter = Container.TorqueConverterInfo as TorqueConverter;
 				if (TorqueConverter == null) {
 					throw new VectoException("Torque converter missing for automatic transmission: {0}", Container.TorqueConverterInfo?.GetType().FullName);
diff --git a/VectoCore/VectoCore/Utils/SearchAlgorithm.cs b/VectoCore/VectoCore/Utils/SearchAlgorithm.cs
index 8f86e626f6df667d569b3f269c7457fc958b6002..0830a8a2b3bf5766e7ece06172a71b885773a886 100644
--- a/VectoCore/VectoCore/Utils/SearchAlgorithm.cs
+++ b/VectoCore/VectoCore/Utils/SearchAlgorithm.cs
@@ -55,10 +55,10 @@ namespace TUGraz.VectoCore.Utils
 		/// </code>
 		/// </summary>
 		public static T Search<T>(T x, SI y, T interval, Func<object, SI> getYValue, Func<T, object> evaluateFunction,
-			Func<object, double> criterion, bool forceLineSearch = false) where T : SIBase<T>
+			Func<object, double> criterion, bool forceLineSearch = false, object searcher = null) where T : SIBase<T>
 		{
 			var iterationCount = 0;
-			return Search(x, y, interval, getYValue, evaluateFunction, criterion, null, ref iterationCount, forceLineSearch);
+			return Search(x, y, interval, getYValue, evaluateFunction, criterion, null, ref iterationCount, forceLineSearch, searcher);
 		}
 
 		/// <summary>
@@ -72,10 +72,10 @@ namespace TUGraz.VectoCore.Utils
 		/// </code>
 		/// </summary>
 		public static T Search<T>(T x, SI y, T interval, Func<object, SI> getYValue, Func<T, object> evaluateFunction,
-			Func<object, double> criterion, Func<object, int, bool> abortCriterion, bool forceLineSearch = false) where T : SIBase<T>
+			Func<object, double> criterion, Func<object, int, bool> abortCriterion, bool forceLineSearch = false, object searcher = null) where T : SIBase<T>
 		{
 			var iterationCount = 0;
-			return Search(x, y, interval, getYValue, evaluateFunction, criterion, abortCriterion, ref iterationCount, forceLineSearch);
+			return Search(x, y, interval, getYValue, evaluateFunction, criterion, abortCriterion, ref iterationCount, forceLineSearch, searcher);
 		}
 
 		/// <summary>
@@ -89,7 +89,8 @@ namespace TUGraz.VectoCore.Utils
 		/// </code>
 		/// </summary>
 		public static T Search<T>(T x, SI y, T interval, Func<object, SI> getYValue, Func<T, object> evaluateFunction,
-			Func<object, double> criterion, Func<object, int, bool> abortCriterion, ref int iterationCount, bool forceLineSearch) where T : SIBase<T>
+			Func<object, double> criterion, Func<object, int, bool> abortCriterion, ref int iterationCount,
+			bool forceLineSearch, object searcher) where T : SIBase<T>
 		{
 			T result;
 			try {
diff --git a/VectoCore/VectoCore/VectoCore.csproj b/VectoCore/VectoCore/VectoCore.csproj
index f0226fda9c9db1f80179092109fc0187e89f94fe..daca6edbc086f6d3ecab4b7e4bc28647e6a0eab0 100644
--- a/VectoCore/VectoCore/VectoCore.csproj
+++ b/VectoCore/VectoCore/VectoCore.csproj
@@ -310,6 +310,7 @@
     <Compile Include="Models\SimulationComponent\Impl\APTNShiftStrategy.cs" />
     <Compile Include="Models\SimulationComponent\Impl\BatterySystem.cs" />
     <Compile Include="Models\SimulationComponent\Impl\DummyAxleGearInfo.cs" />
+    <Compile Include="Models\SimulationComponent\Impl\GensetChargerAdapter.cs" />
     <Compile Include="Models\SimulationComponent\Impl\PEVGearbox.cs" />
     <Compile Include="Models\SimulationComponent\Impl\PTODriveAuxiliary.cs" />
     <Compile Include="Models\SimulationComponent\Impl\RoadSweeperAuxiliary.cs" />
@@ -439,7 +440,10 @@
     <Compile Include="Models\SimulationComponent\IElectricMotorControl.cs" />
     <Compile Include="Models\SimulationComponent\IHybridControlledGearbox.cs" />
     <Compile Include="Models\SimulationComponent\Impl\PEVAMTShiftStrategy.cs" />
+    <Compile Include="Models\SimulationComponent\Impl\SerialHybridController.cs" />
     <Compile Include="Models\SimulationComponent\Impl\ShiftLineSet.cs" />
+    <Compile Include="Models\SimulationComponent\Strategies\GensetPreprocessor.cs" />
+    <Compile Include="Models\SimulationComponent\Strategies\SerialHybridStrategy.cs" />
     <Compile Include="Models\Simulation\DataBus\IDCDCConverter.cs" />
     <Compile Include="Models\Simulation\DataBus\IHybridControllerInfo.cs" />
     <Compile Include="Models\SimulationComponent\IHybridControlStrategy.cs" />
@@ -1033,8 +1037,8 @@
       <SubType>Designer</SubType>
     </EmbeddedResource>
     <EmbeddedResource Include="Resources\XSD\VectoDeclarationDefinitions.2.3.xsd">
-		<SubType>Designer</SubType>
-	</EmbeddedResource>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
     <EmbeddedResource Include="Resources\XSD\VectoDeclarationDefinitions.2.4.xsd">
       <SubType>Designer</SubType>
     </EmbeddedResource>
diff --git a/VectoCore/VectoCoreTest/Integration/Hybrid/SerialHybridTest.cs b/VectoCore/VectoCoreTest/Integration/Hybrid/SerialHybridTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b8870bb4a6111860e50ec07a05da0b9443622633
--- /dev/null
+++ b/VectoCore/VectoCoreTest/Integration/Hybrid/SerialHybridTest.cs
@@ -0,0 +1,637 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using NUnit.Framework;
+using TUGraz.VectoCommon.Exceptions;
+using TUGraz.VectoCommon.InputData;
+using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.Configuration;
+using TUGraz.VectoCore.InputData.Impl;
+using TUGraz.VectoCore.InputData.Reader.ComponentData;
+using TUGraz.VectoCore.Models.Declaration;
+using TUGraz.VectoCore.Models.Simulation.Data;
+using TUGraz.VectoCore.Models.Simulation.Impl;
+using TUGraz.VectoCore.Models.SimulationComponent;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox;
+using TUGraz.VectoCore.Models.SimulationComponent.Impl;
+using TUGraz.VectoCore.Models.SimulationComponent.Strategies;
+using TUGraz.VectoCore.OutputData;
+using TUGraz.VectoCore.OutputData.FileIO;
+using TUGraz.VectoCore.Tests.Utils;
+using TUGraz.VectoCore.Utils;
+using ElectricSystem = TUGraz.VectoCore.Models.SimulationComponent.ElectricSystem;
+using Wheels = TUGraz.VectoCore.Models.SimulationComponent.Impl.Wheels;
+
+
+namespace TUGraz.VectoCore.Tests.Integration.Hybrid
+{
+	[TestFixture]
+	public class SerialHybridTest
+	{
+		public const string MotorFile = @"TestData\Hybrids\ElectricMotor\GenericEMotor.vem";
+		public const string BatFile = @"TestData\Hybrids\Battery\GenericBattery.vbat";
+
+		public const string AccelerationFile = @"TestData\Components\Truck.vacc";
+		public const string MotorFile240kW = @"TestData\Hybrids\ElectricMotor\GenericEMotor240kW.vem";
+
+		public const string GeneratorFile = @"TestData\Hybrids\ElectricMotor\GenericGenerator.vem";
+
+		public const string GearboxIndirectLoss = @"TestData\Components\Indirect Gear.vtlm";
+		public const string GearboxDirectLoss = @"TestData\Components\Direct Gear.vtlm";
+
+
+
+		public const bool PlotGraphs = true;
+
+		[OneTimeSetUp]
+		public void RunBeforeAnyTests()
+		{
+			Directory.SetCurrentDirectory(TestContext.CurrentContext.TestDirectory);
+		}
+
+		// - - - - - - - - - - - - - - - - - - - - - - - - - 
+
+
+		[
+			TestCase(30, 0.7, 0, 0, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.7, level"),
+			TestCase(50, 0.7, 0, 0, TestName = "S3 Hybrid ConstantSpeed 50km/h SoC: 0.7, level"),
+			TestCase(80, 0.7, 0, 0, TestName = "S3 Hybrid ConstantSpeed 80km/h SoC: 0.7, level"),
+
+			TestCase(30, 0.25, 0, 0, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.25, level"),
+			TestCase(50, 0.25, 0, 0, TestName = "S3 Hybrid ConstantSpeed 50km/h SoC: 0.25, level"),
+			TestCase(80, 0.25, 0, 0, TestName = "S3 Hybrid ConstantSpeed 80km/h SoC: 0.25, level"),
+
+			TestCase(30, 0.5, 5, 0, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.5, UH 5%"),
+			TestCase(50, 0.5, 5, 0, TestName = "S3 Hybrid ConstantSpeed 50km/h SoC: 0.5, UH 5%"),
+			TestCase(80, 0.5, 5, 0, TestName = "S3 Hybrid ConstantSpeed 80km/h SoC: 0.5, UH 5%"),
+
+			TestCase(30, 0.5, -5, 0, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.5, DH 5%"),
+			TestCase(50, 0.5, -5, 0, TestName = "S3 Hybrid ConstantSpeed 50km/h SoC: 0.5, DH 5%"),
+			TestCase(80, 0.5, -5, 0, TestName = "S3 Hybrid ConstantSpeed 80km/h SoC: 0.5, DH 5%"),
+
+			TestCase(30, 0.25, 0, 1000, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.25, level P_auxEl: 1kW"),
+			TestCase(30, 0.25, 0, 5000, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.25, level P_auxEl: 5kW"),
+		]
+		public void S3HybridConstantSpeed(double vmax, double initialSoC, double slope, double pAuxEl)
+		{
+			var cycleData = string.Format(
+				@"   0, {0}, {1},    0
+				  7000, {0}, {1},    0", vmax, slope);
+			var cycle = SimpleDrivingCycles.CreateCycleData(cycleData);
+
+			const bool largeMotor = true;
+
+			var modFilename = $"SimpleParallelHybrid-S3_constant_{vmax}-{initialSoC}_{slope}_{pAuxEl}.vmod";
+			const PowertrainPosition pos = PowertrainPosition.BatteryElectricE3;
+			var job = CreateEngineeringRun(
+				cycle, modFilename, initialSoC, pos, 4.6, largeMotor: true, largeGen: true, pAuxEl: pAuxEl);
+			var run = job.Runs.First().Run;
+
+			var hybridController = (SerialHybridController)((VehicleContainer)run.GetContainer()).HybridController;
+			Assert.NotNull(hybridController);
+
+			var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data;
+
+			var data = run.GetContainer().RunData;
+			//File.WriteAllText(
+			//	$"{modFilename}.json",
+			//	JsonConvert.SerializeObject(data, Formatting.Indented));
+
+			run.Run();
+			Assert.IsTrue(run.FinishedWithoutErrors);
+
+			Assert.IsTrue(modData.Rows.Count > 0);
+			var graphWriter = GetGraphWriter(new[] { ModalResultField.P_electricMotor_mech_B3, ModalResultField.P_electricMotor_mech_Gen });
+			graphWriter.Write(modFilename);
+		}
+
+		[
+			TestCase(30, 0.7, 0, TestName = "S3 Hybrid DriveOff 30km/h SoC: 0.7, level"),
+			TestCase(80, 0.7, 0, TestName = "S3 Hybrid DriveOff 80km/h SoC: 0.7, level"),
+			TestCase(30, 0.22, 0, TestName = "S3 Hybrid DriveOff 30km/h SoC: 0.22, level")
+		]
+		public void S3HybridDriveOff(double vmax, double initialSoC, 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;
+
+			var modFilename = $"SimpleParallelHybrid-S3_acc_{vmax}-{initialSoC}_{slope}.vmod";
+			const PowertrainPosition pos = PowertrainPosition.BatteryElectricE3;
+			var job = CreateEngineeringRun(
+				cycle, modFilename, initialSoC, pos, 1.0, largeMotor: true);
+			var run = job.Runs.First().Run;
+
+			var hybridController = (SerialHybridController)((VehicleContainer)run.GetContainer()).HybridController;
+			Assert.NotNull(hybridController);
+
+			var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data;
+
+			run.Run();
+			Assert.IsTrue(run.FinishedWithoutErrors);
+
+			Assert.IsTrue(modData.Rows.Count > 0);
+
+			var graphWriter = GetGraphWriter(new[] { ModalResultField.P_electricMotor_mech_B3, ModalResultField.P_electricMotor_mech_Gen });
+			graphWriter.Write(modFilename);
+		}
+
+		[TestCase(50, 0.79, 0, TestName = "S3 Hybrid Brake Standstill 50km/h SoC: 0.79, level"),
+		TestCase(50, 0.25, 0, TestName = "S3 Hybrid Brake Standstill 50km/h SoC: 0.25, level"),
+		TestCase(50, 0.65, 0, TestName = "S3 Hybrid Brake Standstill 50km/h SoC: 0.65, level")
+		]
+		public void S3HybridBrakeStandstill(double vmax, double initialSoC, double slope)
+		{
+			//var dst =
+			var cycleData = string.Format(
+				@"   0, {0}, {1},    0
+				   200,   0, {1},    3", vmax, slope);
+			var cycle = SimpleDrivingCycles.CreateCycleData(cycleData);
+
+			const bool largeMotor = true;
+
+			var modFilename = $"SimpleParallelHybrid-S3_stop_{vmax}-{initialSoC}_{slope}.vmod";
+			const PowertrainPosition pos = PowertrainPosition.BatteryElectricE3;
+			var job = CreateEngineeringRun(
+				cycle, modFilename, initialSoC, pos, 1.0, largeMotor: true);
+			var run = job.Runs.First().Run;
+
+			var hybridController = (SerialHybridController)((VehicleContainer)run.GetContainer()).HybridController;
+			Assert.NotNull(hybridController);
+			//var strategy = (DelegateParallelHybridStrategy)hybridController.Strategy;
+			//Assert.NotNull(strategy);
+
+			var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data;
+
+			run.Run();
+			Assert.IsTrue(run.FinishedWithoutErrors);
+
+			Assert.IsTrue(modData.Rows.Count > 0);
+
+			var graphWriter = GetGraphWriter(new[] { ModalResultField.P_electricMotor_mech_B3, ModalResultField.P_electricMotor_mech_Gen });
+			graphWriter.Write(modFilename);
+		}
+
+
+		[
+			TestCase("LongHaul", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle LongHaul, SoC: 0.5 Payload: 2t P_auxEl: 0kW"),
+			TestCase("RegionalDelivery", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle RegionalDelivery, SoC: 0.5 Payload: 2t P_auxEl: 0kW"),
+			TestCase("UrbanDelivery", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle UrbanDelivery, SoC: 0.5 Payload: 2t P_auxEl: 0kW"),
+			TestCase("Construction", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle Construction, SoC: 0.5 Payload: 2t P_auxEl: 0kW"),
+			TestCase("Urban", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle Urban, SoC: 0.5 Payload: 2t P_auxEl: 0kW"),
+			TestCase("Suburban", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle SubUrban, SoC: 0.5 Payload: 2t P_auxEl: 0kW"),
+			TestCase("Interurban", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle InterUrban, SoC: 0.5 Payload: 2t P_auxEl: 0kW"),
+			TestCase("Coach", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle Coach, SoC: 0.5 Payload: 2t P_auxEl: 0kW"),
+		]
+		public void S3HybridDriveCycle(string declarationMission, double payload, double initialSoC, double pAuxEl)
+		{
+			var cycleData = RessourceHelper.ReadStream(
+				DeclarationData.DeclarationDataResourcePrefix + ".MissionCycles." +
+				declarationMission +
+				Constants.FileExtensions.CycleFile);
+			var cycle = DrivingCycleDataReader.ReadFromStream(cycleData, CycleType.DistanceBased, "", false);
+
+			const bool largeMotor = true;
+
+			var modFilename = $"SimpleParallelHybrid-S3_cycle_{declarationMission}-{initialSoC}_{payload}_{pAuxEl}.vmod";
+			const PowertrainPosition pos = PowertrainPosition.BatteryElectricE3;
+			var job = CreateEngineeringRun(
+				cycle, modFilename, initialSoC, pos, 1.0, largeMotor: true, pAuxEl: pAuxEl, payload: payload.SI<Kilogram>());
+			var run = job.Runs.First().Run;
+
+			var hybridController = (SerialHybridController)((VehicleContainer)run.GetContainer()).HybridController;
+			Assert.NotNull(hybridController);
+
+			var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data;
+
+			var data = run.GetContainer().RunData;
+			//File.WriteAllText(
+			//	$"{modFilename}.json",
+			//	JsonConvert.SerializeObject(data, Formatting.Indented));
+
+			run.Run();
+			Assert.IsTrue(run.FinishedWithoutErrors);
+
+			Assert.IsTrue(modData.Rows.Count > 0);
+
+			var graphWriter = GetGraphWriter(new[] { ModalResultField.P_electricMotor_mech_B3, ModalResultField.P_electricMotor_mech_Gen });
+			graphWriter.Write(modFilename);
+		}
+
+
+		// =================================================
+
+		public static JobContainer CreateEngineeringRun(DrivingCycleData cycleData, string modFileName,
+			double initialSoc, PowertrainPosition pos, double ratio, bool largeMotor = false, bool largeGen = false, double pAuxEl = 0,
+			Kilogram payload = null, Watt maxDriveTrainPower = null, GearboxType gearboxType = GearboxType.NoGearbox)
+		{
+			var fileWriter = new FileOutputWriter(Path.GetFileNameWithoutExtension(modFileName));
+			var sumData = new SummaryDataContainer(fileWriter);
+			var jobContainer = new JobContainer(sumData);
+			var container = CreateSerialHybridPowerTrain(
+				cycleData, modFileName, initialSoc, largeMotor, largeGen, sumData, pAuxEl, pos, ratio, payload,
+				maxDriveTrainPower, gearboxType);
+			var run = new DistanceRun(container);
+			jobContainer.AddRun(run);
+			return jobContainer;
+		}
+
+		public static VehicleContainer CreateSerialHybridPowerTrain(DrivingCycleData cycleData, string modFileName,
+			double initialBatCharge, bool largeMotor, bool largeGen, SummaryDataContainer sumData, double pAuxEl,
+			PowertrainPosition pos, double ratio, Kilogram payload = null, Watt maxDriveTrainPower = null, GearboxType gearboxType = GearboxType.NoGearbox)
+		{
+			var gearboxData = CreateGearboxData(gearboxType);
+			var axleGearData = CreateAxleGearData(gearboxType);
+
+			var vehicleData = CreateVehicleData(payload ?? 3300.SI<Kilogram>());
+			var airdragData = CreateAirdragData();
+			var driverData = CreateDriverData(AccelerationFile, true);
+
+			var emFile = largeMotor ? MotorFile240kW : MotorFile;
+			var electricMotorData = MockSimulationDataFactory.CreateElectricMotorData(emFile, 2, pos, ratio, 1);
+
+			var genFile = GeneratorFile;
+			electricMotorData.AddRange(
+				MockSimulationDataFactory.CreateElectricMotorData(genFile, 1, PowertrainPosition.Generator, 2.6, 1));
+
+			var batFile = BatFile;
+			var batteryData = MockSimulationDataFactory.CreateBatteryData(batFile, initialBatCharge);
+			//batteryData.TargetSoC = 0.5;
+
+			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,
+				JobType = VectoSimulationJobType.SerialHybridVehicle,
+				DriverData = driverData,
+				AxleGearData = axleGearData,
+				GearboxData = gearboxData,
+				VehicleData = vehicleData,
+				AirdragData = airdragData,
+				JobName = Path.GetFileNameWithoutExtension(modFileName),
+				Cycle = cycleData,
+				Retarder = new RetarderData() { Type = RetarderType.None },
+				Aux = new List<VectoRunData.AuxData>(),
+				ElectricMachinesData = electricMotorData,
+				EngineData = engineData,
+				BatteryData = batteryData,
+				GearshiftParameters = CreateGearshiftData(gearboxData, axleGearData.AxleGear.Ratio, engineData.IdleSpeed),
+				HybridStrategyParameters = CreateHybridStrategyData(maxDriveTrainPower),
+				ElectricAuxDemand = pAuxEl.SI<Watt>()
+			};
+			var fileWriter = new FileOutputWriter(modFileName);
+			var modDataFilter = new IModalDataFilter[] { }; //new IModalDataFilter[] { new ActualModalDataFilter(), };
+			var modData = new ModalDataContainer(runData, fileWriter, null, modDataFilter) {
+				WriteModalResults = true,
+			};
+			var container = new VehicleContainer(
+				ExecutionMode.Engineering, modData, x => { sumData?.Write(x, 1, 1, runData); });
+			container.RunData = runData;
+
+			var strategy = new SerialHybridStrategy(runData, container);
+			var es = new ElectricSystem(container);
+			var battery = new BatterySystem(container, batteryData);
+			battery.Initialize(initialBatCharge);
+
+			//var clutch = gearboxType.AutomaticTransmission() ? null : new SwitchableClutch(container, runData.EngineData);
+			var ctl = new SerialHybridController(container, strategy, es);
+
+			es.Connect(battery);
+
+			var engine = new StopStartCombustionEngine(container, runData.EngineData);
+			
+			//var hybridStrategy = new DelegateParallelHybridStrategy();
+
+			var idleController = engine.IdleController;
+			ctl.Engine = engine;
+
+			var cycle = new DistanceBasedDrivingCycle(container, cycleData);
+
+			var aux = new ElectricAuxiliary(container);
+			aux.AddConstant("P_aux_el", pAuxEl.SI<Watt>());
+			es.Connect(aux);
+
+			var powertrain = 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(ctl)
+				.AddComponent(new Brakes(container));
+
+			switch (pos) {
+				case PowertrainPosition.HybridPositionNotSet:
+					throw new VectoException("invalid powertrain position");
+				case PowertrainPosition.BatteryElectricE2:
+					var gearbox = gearboxType.AutomaticTransmission()
+						? (IHybridControlledGearbox)new ATGearbox(container, ctl.ShiftStrategy)
+						: new Gearbox(container, ctl.ShiftStrategy);
+					powertrain = powertrain.AddComponent(new AxleGear(container, runData.AxleGearData))
+						.AddComponent(runData.AngledriveData != null
+							? new Angledrive(container, runData.AngledriveData)
+							: null)
+						.AddComponent((IGearbox)gearbox, runData.Retarder, container)
+						.AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE2, runData.ElectricMachinesData,
+							container,
+							es, ctl));
+					ctl.Gearbox = gearbox;
+
+					break;
+					
+				case PowertrainPosition.BatteryElectricE3:
+					powertrain = powertrain.AddComponent(new AxleGear(container, runData.AxleGearData))
+						.AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE3, runData.ElectricMachinesData,
+							container,
+							es, ctl));
+					new DummyGearboxInfo(container);
+					//new MockEngineInfo(container);
+					new ATClutchInfo(container);
+					runData.GearboxData = null;
+					break;
+				case PowertrainPosition.BatteryElectricE4:
+					powertrain = powertrain.AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE4, runData.ElectricMachinesData,
+							container,
+							es, ctl));
+					new DummyGearboxInfo(container);
+					//new MockEngineInfo(container);
+					new ATClutchInfo(container);
+					runData.GearboxData = null;
+					break;
+				case PowertrainPosition.HybridP0:
+				case PowertrainPosition.HybridP1:
+				case PowertrainPosition.HybridP2_5:
+				case PowertrainPosition.HybridP2:
+				case PowertrainPosition.HybridP3:
+				case PowertrainPosition.HybridP4:
+				
+					throw new VectoException("testcase does not support parallel powertrain configurations");
+				default:
+					throw new ArgumentOutOfRangeException(nameof(pos), pos, null);
+			}
+
+			ctl.GenSet.AddComponent(GetElectricMachine(PowertrainPosition.Generator, runData.ElectricMachinesData, container,
+					es, ctl))
+				.AddComponent(engine, idleController)
+				.AddAuxiliaries(container, runData);
+
+			return container;
+		}
+
+		private static HybridStrategyParameters CreateHybridStrategyData(Watt maxDriveTrainPower)
+		{
+			return new HybridStrategyParameters() {
+				EquivalenceFactorDischarge = 2.5,
+				EquivalenceFactorCharge = 2.5,
+				MinSoC = 0.22,
+				MaxSoC = 0.8,
+				TargetSoC = 0.7,
+				AuxReserveTime = 5.SI<Second>(),
+				AuxReserveChargeTime = 2.SI<Second>(),
+				MinICEOnTime = 3.SI<Second>(),
+				ICEStartPenaltyFactor = 0,
+				//MaxDrivetrainPower = maxDriveTrainPower ?? 1e12.SI<Watt>(),
+				CostFactorSOCExponent = 5,
+				// todo: keep this factor?
+				//SerialHybridLoadpointFactor = 0.8,
+			};
+		}
+
+		public static ShiftStrategyParameters CreateGearshiftData(GearboxData gbx, double axleRatio, PerSecond engineIdlingSpeed)
+		{
+			var retVal = new ShiftStrategyParameters {
+				TimeBetweenGearshifts = 2.SI<Second>(),
+				TorqueReserve = 0.2,
+				StartTorqueReserve = 0.2,
+				DownshiftAfterUpshiftDelay = DeclarationData.Gearbox.DownshiftAfterUpshiftDelay,
+				UpshiftAfterDownshiftDelay = DeclarationData.Gearbox.UpshiftAfterDownshiftDelay,
+				UpshiftMinAcceleration = DeclarationData.Gearbox.UpshiftMinAcceleration,
+				StartSpeed = 2.SI<MeterPerSecond>(),
+				StartAcceleration = 0.6.SI<MeterPerSquareSecond>(),
+
+				StartVelocity = DeclarationData.GearboxTCU.StartSpeed,
+				//StartAcceleration = DeclarationData.GearboxTCU.StartAcceleration,
+				GearResidenceTime = DeclarationData.GearboxTCU.GearResidenceTime,
+				DnT99L_highMin1 = DeclarationData.GearboxTCU.DnT99L_highMin1,
+				DnT99L_highMin2 = DeclarationData.GearboxTCU.DnT99L_highMin2,
+				AllowedGearRangeUp = gbx.Type.AutomaticTransmission() ? 1 : DeclarationData.GearboxTCU.AllowedGearRangeUp,
+				AllowedGearRangeDown = gbx.Type.AutomaticTransmission() ? 1 : DeclarationData.GearboxTCU.AllowedGearRangeDown,
+				LookBackInterval = DeclarationData.GearboxTCU.LookBackInterval,
+				DriverAccelerationLookBackInterval = DeclarationData.GearboxTCU.DriverAccelerationLookBackInterval,
+				DriverAccelerationThresholdLow = DeclarationData.GearboxTCU.DriverAccelerationThresholdLow,
+				AverageCardanPowerThresholdPropulsion = DeclarationData.GearboxTCU.AverageCardanPowerThresholdPropulsion,
+				CurrentCardanPowerThresholdPropulsion = DeclarationData.GearboxTCU.CurrentCardanPowerThresholdPropulsion,
+				TargetSpeedDeviationFactor = DeclarationData.GearboxTCU.TargetSpeedDeviationFactor,
+				EngineSpeedHighDriveOffFactor = DeclarationData.GearboxTCU.EngineSpeedHighDriveOffFactor,
+				RatingFactorCurrentGear = gbx.Type.AutomaticTransmission()
+					? DeclarationData.GearboxTCU.RatingFactorCurrentGearAT
+					: DeclarationData.GearboxTCU.RatingFactorCurrentGear,
+
+				//--------------------
+				RatioEarlyUpshiftFC = DeclarationData.GearboxTCU.RatioEarlyUpshiftFC / axleRatio,
+				RatioEarlyDownshiftFC = DeclarationData.GearboxTCU.RatioEarlyDownshiftFC / axleRatio,
+				AllowedGearRangeFC = gbx.Type.AutomaticTransmission()
+					? (gbx.Gears.Count > DeclarationData.GearboxTCU.ATSkipGearsThreshold
+						? DeclarationData.GearboxTCU.AllowedGearRangeFCATSkipGear
+						: DeclarationData.GearboxTCU.AllowedGearRangeFCAT)
+					: DeclarationData.GearboxTCU.AllowedGearRangeFCAMT,
+				VelocityDropFactor = DeclarationData.GearboxTCU.VelocityDropFactor,
+				AccelerationFactor = DeclarationData.GearboxTCU.AccelerationFactor,
+				MinEngineSpeedPostUpshift = 0.RPMtoRad(),
+				ATLookAheadTime = DeclarationData.GearboxTCU.ATLookAheadTime,
+
+				LoadStageThresoldsUp = DeclarationData.GearboxTCU.LoadStageThresholdsUp,
+				LoadStageThresoldsDown = DeclarationData.GearboxTCU.LoadStageThresoldsDown,
+				ShiftSpeedsTCToLocked = DeclarationData.GearboxTCU.ShiftSpeedsTCToLocked
+														.Select(x => x.Select(y => y + engineIdlingSpeed.AsRPM).ToArray()).ToArray(),
+			};
+
+			return retVal;
+		}
+
+		private static IElectricMotor GetElectricMachine(PowertrainPosition pos,
+			IList<Tuple<PowertrainPosition, ElectricMotorData>> electricMachinesData, VehicleContainer container,
+			ElectricSystem es, IHybridController ctl)
+		{
+			var motorData = electricMachinesData.FirstOrDefault(x => x.Item1 == pos);
+			if (motorData == null) {
+				return null;
+			}
+
+			container.ModData.AddElectricMotor(pos);
+			ctl.AddElectricMotor(pos, motorData.Item2);
+			var motor = new ElectricMotor(container, motorData.Item2, ctl.ElectricMotorControl(pos), pos);
+			if (pos == PowertrainPosition.Generator) {
+				es.Connect(new GensetChargerAdapter(motor));
+			} else {
+				motor.Connect(es);
+			}
+
+			return motor;
+		}
+
+		private static GearboxData CreateGearboxData(GearboxType gearboxType = GearboxType.NoGearbox)
+		{
+			switch (gearboxType) {
+
+				case GearboxType.NoGearbox:
+				case GearboxType.AMT:
+					return CreateAMTGearbox();
+				//case GearboxType.ATSerial:
+				//	return CreateATSerial();
+				//case GearboxType.ATPowerSplit:
+				//	return CreateATPowerSplit();
+				default:
+					throw new ArgumentOutOfRangeException(nameof(gearboxType), gearboxType, null);
+			}
+		}
+
+		private static GearboxData CreateAMTGearbox()
+		{
+			var ratios = new[] { 14.93, 11.64, 9.02, 7.04, 5.64, 4.4, 3.39, 2.65, 2.05, 1.6, 1.28, 1.0 };
+
+			return new GearboxData {
+				Gears = ratios.Select(
+					(ratio, i) => Tuple.Create(
+						(uint)i, new GearData {
+							//MaxTorque = 2300.SI<NewtonMeter>(),
+							LossMap =
+								TransmissionLossMapReader.ReadFromFile(
+									ratio.IsEqual(1) ? GearboxIndirectLoss : GearboxDirectLoss, ratio,
+									$"Gear {i}"),
+							Ratio = ratio,
+							//ShiftPolygon = DeclarationData.Gearbox.ComputeEfficiencyShiftPolygon(i,)
+						})).ToDictionary(k => k.Item1 + 1, v => v.Item2),
+				Inertia = 0.SI<KilogramSquareMeter>(),
+				TractionInterruption = 1.SI<Second>(),
+			};
+		}
+
+
+		private static AxleGearData CreateAxleGearData(GearboxType gearboxType)
+		{
+			var ratio = 2.59;
+			switch (gearboxType) {
+				case GearboxType.ATSerial:
+					ratio = 6.2;
+					break;
+				case GearboxType.ATPowerSplit:
+					ratio = 5.8;
+					break;
+			}
+			return new AxleGearData {
+				AxleGear = new GearData {
+					Ratio = ratio,
+					LossMap = TransmissionLossMapReader.Create(0.95, ratio, "Axlegear"),
+				}
+			};
+		}
+
+		private static VehicleData CreateVehicleData(Kilogram loading)
+		{
+			var axles = new List<Axle> {
+				new Axle {
+					AxleWeightShare = 0.38,
+					Inertia = 20.SI<KilogramSquareMeter>(),
+					RollResistanceCoefficient = 0.007,
+					TwinTyres = false,
+					TyreTestLoad = 30436.0.SI<Newton>()
+				},
+				new Axle {
+					AxleWeightShare = 0.62,
+					Inertia = 18.SI<KilogramSquareMeter>(),
+					RollResistanceCoefficient = 0.007,
+					TwinTyres = true,
+					TyreTestLoad = 30436.SI<Newton>()
+				},
+			};
+			return new VehicleData {
+				AirDensity = DeclarationData.AirDensity,
+				AxleConfiguration = AxleConfiguration.AxleConfig_4x2,
+				CurbMass = 11500.SI<Kilogram>(),
+				Loading = loading,
+				DynamicTyreRadius = 0.465.SI<Meter>(),
+				AxleData = axles,
+				SavedInDeclarationMode = false,
+				ADAS = new VehicleData.ADASData() {
+					EngineStopStart = true
+				}
+			};
+		}
+
+		private static AirdragData CreateAirdragData()
+		{
+			return new AirdragData() {
+				CrossWindCorrectionCurve =
+					new CrosswindCorrectionCdxALookup(
+						3.2634.SI<SquareMeter>(),
+						CrossWindCorrectionCurveReader.GetNoCorrectionCurve(3.2634.SI<SquareMeter>()),
+						CrossWindCorrectionMode.NoCorrection),
+			};
+		}
+
+		private static DriverData CreateDriverData(string accelerationFile, bool overspeed = false)
+		{
+			return new DriverData {
+				AccelerationCurve = AccelerationCurveReader.ReadFromFile(accelerationFile),
+				LookAheadCoasting = new DriverData.LACData {
+					Enabled = true,
+					MinSpeed = 50.KMPHtoMeterPerSecond(),
+
+					//Deceleration = -0.5.SI<MeterPerSquareSecond>()
+					LookAheadDistanceFactor = DeclarationData.Driver.LookAhead.LookAheadDistanceFactor,
+					LookAheadDecisionFactor = new LACDecisionFactor()
+				},
+				OverSpeed = new DriverData.OverSpeedData() {
+					Enabled = true,
+					MinSpeed = 50.KMPHtoMeterPerSecond(),
+					OverSpeed = 5.KMPHtoMeterPerSecond()
+				},
+				EngineStopStart = new DriverData.EngineStopStartData() {
+					EngineOffStandStillActivationDelay = DeclarationData.Driver.EngineStopStart.ActivationDelay,
+					MaxEngineOffTimespan = DeclarationData.Driver.EngineStopStart.MaxEngineOffTimespan,
+					UtilityFactorStandstill = DeclarationData.Driver.EngineStopStart.UtilityFactor
+				}
+			};
+		}
+
+
+		// ======================
+
+		private GraphWriter GetGraphWriter(ModalResultField[] emYFields)
+		{
+			var Yfields = new[] {
+				ModalResultField.v_act, ModalResultField.altitude, ModalResultField.acc, ModalResultField.Gear,
+				ModalResultField.P_ice_out, ModalResultField.REESSStateOfCharge, ModalResultField.FCMap
+			}.Concat(emYFields).ToArray();
+
+			var graphWriter = new GraphWriter();
+			graphWriter.Xfields = new[] { ModalResultField.dist };
+			graphWriter.Yfields = Yfields;
+			graphWriter.Series1Label = "Hybrid";
+			graphWriter.PlotIgnitionState = true;
+
+			if (PlotGraphs) {
+				graphWriter.Enable();
+			} else {
+				graphWriter.Disable();
+			}
+
+			return graphWriter;
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericDragGenerator.vemd b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericDragGenerator.vemd
new file mode 100644
index 0000000000000000000000000000000000000000..b4ff91987652279e4b96e2a857b77644cc644126
--- /dev/null
+++ b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericDragGenerator.vemd
@@ -0,0 +1,23 @@
+n [rpm] , T_drag [Nm]
+0, -4.35
+80, -4.51
+800, -6
+1600, -7.66
+2400, -9.31
+3200, -10.97
+4000, -12.62
+4800, -14.28
+5600, -15.93
+6400, -17.59
+7200, -19.24
+8000, -20.9
+8800, -22.55
+9600, -24.21
+10400, -25.87
+11200, -27.52
+12000, -29.18
+12800, -30.83
+13600, -32.49
+14400, -34.14
+15200, -35.8
+16000, -37.45
diff --git a/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vem b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vem
new file mode 100644
index 0000000000000000000000000000000000000000..6862c4c5594c18d7c15cfe7d0d8a3bb1c0b59de3
--- /dev/null
+++ b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vem
@@ -0,0 +1,20 @@
+{
+	"Header": {
+		"CreatedBy": " ()",
+		"Date": "2016-10-13T08:54:28.7387223Z",
+		"AppVersion": "3",
+		"FileVersion": 1
+	},
+	"Body": {
+		"SavedInDeclMode": false,
+		"Model": "Generic Electric Motor",
+		"FullLoadCurve": "GenericGenerator.vemp",
+		"DragCurve": "GenericDragGenerator.vemd",
+		"EfficiencyMap": "GenericMapGenerator.vemo",
+		"Inertia": 0.2,
+		"ContinuousPower": 50000,
+    "ContinuousPowerSpeed": 2000,
+    "OverloadTime": 30,
+    "ThermalOverloadRecoveryFactor": 0.9
+	}
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vemp b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vemp
new file mode 100644
index 0000000000000000000000000000000000000000..5b32c7a31cfa3f49020251d69167b1db37ddf78a
--- /dev/null
+++ b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vemp
@@ -0,0 +1,24 @@
+n [rpm] , T_drive [Nm] , T_recuperation [Nm]
+0, 900.00, -900.00
+80, 900.00, -900.00
+800, 900.00, -900.00
+1600, 900.00, -900.00
+2400, 900.00, -900.00
+3200, 900.00, -900.00
+4000, 900.00, -900.00
+4800, 750.00, -750.00
+5600, 642.86, -642.86
+6400, 562.50, -562.50
+7200, 500.00, -500.00
+8000, 450.00, -450.00
+8800, 409.09, -409.09
+9600, 375.00, -375.00
+10400, 346.15, -346.15
+11200, 321.43, -321.43
+12000, 300.00, -300.00
+12800, 281.25, -281.25
+13600, 264.71, -264.71
+14400, 250.00, -250.00
+15200, 236.84, -236.84
+16000, 225.00, -225.00
+
diff --git a/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericMapGenerator.vemo b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericMapGenerator.vemo
new file mode 100644
index 0000000000000000000000000000000000000000..0f3ab230b762aa5feb996f9f0cb246efd87efcbf
--- /dev/null
+++ b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericMapGenerator.vemo
@@ -0,0 +1,925 @@
+n [rpm], T [Nm], P_bat [W]
+0, -900, 0.000
+0, -855, 0.000
+0, -810, 0.000
+0, -765, 0.000
+0, -720, 0.000
+0, -675, 0.000
+0, -630, 0.000
+0, -585, 0.000
+0, -540, -0.069
+0, -495, -0.171
+0, -450, -0.253
+0, -405, -0.316
+0, -360, -0.358
+0, -315, -0.381
+0, -270, -0.383
+0, -225, -0.366
+0, -180, -0.328
+0, -135, -0.271
+0, -90, -0.194
+0, -45, -0.097
+0, -9, -0.005
+0, 9, 0.082
+0, 45, 0.331
+0, 90, 0.662
+0, 135, 1.015
+0, 180, 1.389
+0, 225, 1.785
+0, 270, 2.202
+0, 315, 2.641
+0, 360, 3.102
+0, 405, 3.584
+0, 450, 4.088
+0, 495, 4.614
+0, 540, 5.161
+0, 585, 5.730
+0, 630, 6.320
+0, 675, 6.932
+0, 720, 7.566
+0, 765, 8.221
+0, 810, 8.898
+0, 855, 9.597
+0, 900, 10.317
+80, -900, 0.000
+80, -855, 0.000
+80, -810, 0.000
+80, -765, 0.000
+80, -720, 0.000
+80, -675, 0.000
+80, -630, -0.135
+80, -585, -0.335
+80, -540, -0.502
+80, -495, -0.637
+80, -450, -0.739
+80, -405, -0.808
+80, -360, -0.845
+80, -315, -0.849
+80, -270, -0.820
+80, -225, -0.759
+80, -180, -0.665
+80, -135, -0.539
+80, -90, -0.380
+80, -45, -0.188
+80, -9, -0.011
+80, 9, 0.145
+80, 45, 0.582
+80, 90, 1.159
+80, 135, 1.772
+80, 180, 2.420
+80, 225, 3.104
+80, 270, 3.822
+80, 315, 4.577
+80, 360, 5.367
+80, 405, 6.192
+80, 450, 7.052
+80, 495, 7.949
+80, 540, 8.880
+80, 585, 9.847
+80, 630, 10.849
+80, 675, 11.887
+80, 720, 12.960
+80, 765, 14.068
+80, 810, 15.212
+80, 855, 16.391
+80, 900, 17.606
+800, -900, -62.530
+800, -855, -59.716
+800, -810, -56.868
+800, -765, -53.984
+800, -720, -51.066
+800, -675, -48.112
+800, -630, -45.123
+800, -585, -42.099
+800, -540, -39.040
+800, -495, -35.946
+800, -450, -32.817
+800, -405, -29.652
+800, -360, -26.453
+800, -315, -23.218
+800, -270, -19.949
+800, -225, -16.644
+800, -180, -13.304
+800, -135, -9.929
+800, -90, -6.519
+800, -45, -3.074
+800, -9, -0.292
+800, 9, 1.254
+800, 45, 4.519
+800, 90, 8.635
+800, 135, 12.788
+800, 180, 16.980
+800, 225, 21.210
+800, 270, 25.478
+800, 315, 29.784
+800, 360, 34.129
+800, 405, 38.511
+800, 450, 42.931
+800, 495, 47.390
+800, 540, 51.887
+800, 585, 56.421
+800, 630, 60.994
+800, 675, 65.605
+800, 720, 70.254
+800, 765, 74.941
+800, 810, 79.666
+800, 855, 84.429
+800, 900, 89.231
+1600, -900, -133.005
+1600, -855, -126.707
+1600, -810, -120.367
+1600, -765, -113.984
+1600, -720, -107.560
+1600, -675, -101.094
+1600, -630, -94.586
+1600, -585, -88.035
+1600, -540, -81.443
+1600, -495, -74.809
+1600, -450, -68.133
+1600, -405, -61.415
+1600, -360, -54.654
+1600, -315, -47.852
+1600, -270, -41.008
+1600, -225, -34.122
+1600, -180, -27.194
+1600, -135, -20.224
+1600, -90, -13.212
+1600, -45, -6.158
+1600, -9, -0.484
+1600, 9, 2.616
+1600, 45, 9.026
+1600, 90, 17.080
+1600, 135, 25.179
+1600, 180, 33.324
+1600, 225, 41.515
+1600, 270, 49.751
+1600, 315, 58.033
+1600, 360, 66.360
+1600, 405, 74.733
+1600, 450, 83.151
+1600, 495, 91.615
+1600, 540, 100.124
+1600, 585, 108.679
+1600, 630, 117.280
+1600, 675, 125.926
+1600, 720, 134.617
+1600, 765, 143.354
+1600, 810, 152.137
+1600, 855, 160.965
+1600, 900, 169.839
+2400, -900, -202.436
+2400, -855, -192.737
+2400, -810, -182.985
+2400, -765, -173.180
+2400, -720, -163.322
+2400, -675, -153.410
+2400, -630, -143.446
+2400, -585, -133.428
+2400, -540, -123.357
+2400, -495, -113.233
+2400, -450, -103.055
+2400, -405, -92.824
+2400, -360, -82.540
+2400, -315, -72.203
+2400, -270, -61.813
+2400, -225, -51.370
+2400, -180, -40.873
+2400, -135, -30.323
+2400, -90, -19.720
+2400, -45, -9.064
+2400, -9, -0.500
+2400, 9, 4.170
+2400, 45, 13.727
+2400, 90, 25.727
+2400, 135, 37.783
+2400, 180, 49.898
+2400, 225, 62.070
+2400, 270, 74.300
+2400, 315, 86.588
+2400, 360, 98.933
+2400, 405, 111.337
+2400, 450, 123.798
+2400, 495, 136.316
+2400, 540, 148.893
+2400, 585, 161.527
+2400, 630, 174.219
+2400, 675, 186.968
+2400, 720, 199.775
+2400, 765, 212.640
+2400, 810, 225.563
+2400, 855, 238.544
+2400, 900, 251.582
+3200, -900, -270.769
+3200, -855, -257.755
+3200, -810, -244.672
+3200, -765, -231.520
+3200, -720, -218.299
+3200, -675, -205.010
+3200, -630, -191.652
+3200, -585, -178.225
+3200, -540, -164.729
+3200, -495, -151.165
+3200, -450, -137.531
+3200, -405, -123.829
+3200, -360, -110.059
+3200, -315, -96.219
+3200, -270, -82.311
+3200, -225, -68.334
+3200, -180, -54.288
+3200, -135, -40.174
+3200, -90, -25.990
+3200, -45, -11.738
+3200, -9, -0.287
+3200, 9, 5.972
+3200, 45, 18.679
+3200, 90, 34.631
+3200, 135, 50.657
+3200, 180, 66.757
+3200, 225, 82.933
+3200, 270, 99.182
+3200, 315, 115.507
+3200, 360, 131.906
+3200, 405, 148.380
+3200, 450, 164.928
+3200, 495, 181.551
+3200, 540, 198.249
+3200, 585, 215.021
+3200, 630, 231.868
+3200, 675, 248.789
+3200, 720, 265.785
+3200, 765, 282.856
+3200, 810, 300.001
+3200, 855, 317.221
+3200, 900, 334.515
+4000, -900, -337.953
+4000, -855, -321.708
+4000, -810, -305.374
+4000, -765, -288.951
+4000, -720, -272.440
+4000, -675, -255.840
+4000, -630, -239.151
+4000, -585, -222.374
+4000, -540, -205.508
+4000, -495, -188.553
+4000, -450, -171.510
+4000, -405, -154.378
+4000, -360, -137.157
+4000, -315, -119.848
+4000, -270, -102.450
+4000, -225, -84.963
+4000, -180, -67.388
+4000, -135, -49.724
+4000, -90, -31.971
+4000, -45, -14.130
+4000, -9, 0.000
+4000, 9, 8.079
+4000, 45, 23.938
+4000, 90, 43.849
+4000, 135, 63.856
+4000, 180, 83.959
+4000, 225, 104.159
+4000, 270, 124.454
+4000, 315, 144.846
+4000, 360, 165.334
+4000, 405, 185.918
+4000, 450, 206.599
+4000, 495, 227.376
+4000, 540, 248.249
+4000, 585, 269.218
+4000, 630, 290.283
+4000, 675, 311.445
+4000, 720, 332.703
+4000, 765, 354.057
+4000, 810, 375.507
+4000, 855, 397.053
+4000, 900, 418.696
+4800, -900, -403.935
+4800, -855, -384.544
+4800, -810, -365.039
+4800, -765, -345.422
+4800, -720, -325.691
+4800, -675, -305.848
+4800, -630, -285.892
+4800, -585, -265.823
+4800, -540, -245.641
+4800, -495, -225.346
+4800, -450, -204.938
+4800, -405, -184.417
+4800, -360, -163.784
+4800, -315, -143.037
+4800, -270, -122.178
+4800, -225, -101.205
+4800, -180, -80.120
+4800, -135, -58.922
+4800, -90, -37.611
+4800, -45, -16.186
+4800, -9, 0.000
+4800, 9, 10.547
+4800, 45, 29.560
+4800, 90, 53.438
+4800, 135, 77.438
+4800, 180, 101.560
+4800, 225, 125.805
+4800, 270, 150.172
+4800, 315, 174.662
+4800, 360, 199.274
+4800, 405, 224.009
+4800, 450, 248.867
+4800, 495, 273.847
+4800, 540, 298.949
+4800, 585, 324.174
+4800, 630, 349.522
+4800, 675, 374.992
+4800, 720, 400.584
+4800, 765, 426.300
+4800, 810, 452.137
+4800, 855, 478.097
+4800, 900, 504.180
+5600, -900, -468.664
+5600, -855, -446.211
+5600, -810, -423.616
+5600, -765, -400.880
+5600, -720, -378.002
+5600, -675, -354.983
+5600, -630, -331.822
+5600, -585, -308.520
+5600, -540, -285.076
+5600, -495, -261.491
+5600, -450, -237.764
+5600, -405, -213.896
+5600, -360, -189.886
+5600, -315, -165.735
+5600, -270, -141.442
+5600, -225, -117.008
+5600, -180, -92.432
+5600, -135, -67.715
+5600, -90, -42.856
+5600, -45, -17.856
+5600, -9, 0.000
+5600, 9, 13.433
+5600, 45, 35.603
+5600, 90, 63.454
+5600, 135, 91.458
+5600, 180, 119.616
+5600, 225, 147.928
+5600, 270, 176.393
+5600, 315, 205.011
+5600, 360, 233.783
+5600, 405, 262.709
+5600, 450, 291.788
+5600, 495, 321.021
+5600, 540, 350.407
+5600, 585, 379.947
+5600, 630, 409.640
+5600, 675, 439.487
+5600, 720, 469.487
+5600, 765, 499.641
+5600, 810, 529.949
+5600, 855, 560.410
+5600, 900, 591.025
+6400, -900, -532.087
+6400, -855, -506.657
+6400, -810, -481.052
+6400, -765, -455.273
+6400, -720, -429.320
+6400, -675, -403.192
+6400, -630, -376.890
+6400, -585, -350.413
+6400, -540, -323.762
+6400, -495, -296.936
+6400, -450, -269.936
+6400, -405, -242.762
+6400, -360, -215.413
+6400, -315, -187.889
+6400, -270, -160.191
+6400, -225, -132.319
+6400, -180, -104.272
+6400, -135, -76.051
+6400, -90, -47.656
+6400, -45, -19.086
+6400, -9, 0.000
+6400, 9, 16.794
+6400, 45, 42.122
+6400, 90, 73.954
+6400, 135, 105.975
+6400, 180, 138.185
+6400, 225, 170.584
+6400, 270, 203.172
+6400, 315, 235.950
+6400, 360, 268.917
+6400, 405, 302.074
+6400, 450, 335.419
+6400, 495, 368.954
+6400, 540, 402.678
+6400, 585, 436.592
+6400, 630, 470.695
+6400, 675, 504.987
+6400, 720, 539.468
+6400, 765, 574.139
+6400, 810, 608.999
+6400, 855, 644.048
+6400, 900, 679.286
+7200, -900, -594.152
+7200, -855, -565.829
+7200, -810, -537.295
+7200, -765, -508.549
+7200, -720, -479.592
+7200, -675, -450.423
+7200, -630, -421.042
+7200, -585, -391.449
+7200, -540, -361.645
+7200, -495, -331.629
+7200, -450, -301.401
+7200, -405, -270.962
+7200, -360, -240.311
+7200, -315, -209.448
+7200, -270, -178.373
+7200, -225, -147.087
+7200, -180, -115.589
+7200, -135, -83.879
+7200, -90, -51.957
+7200, -45, -19.824
+7200, -9, 0.000
+7200, 9, 20.685
+7200, 45, 49.175
+7200, 90, 84.994
+7200, 135, 121.043
+7200, 180, 157.322
+7200, 225, 193.830
+7200, 270, 230.568
+7200, 315, 267.535
+7200, 360, 304.733
+7200, 405, 342.160
+7200, 450, 379.817
+7200, 495, 417.704
+7200, 540, 455.820
+7200, 585, 494.166
+7200, 630, 532.742
+7200, 675, 571.547
+7200, 720, 610.583
+7200, 765, 649.848
+7200, 810, 689.342
+7200, 855, 729.067
+7200, 900, 769.021
+8000, -900, -654.806
+8000, -855, -623.677
+8000, -810, -592.293
+8000, -765, -560.657
+8000, -720, -528.767
+8000, -675, -496.624
+8000, -630, -464.227
+8000, -585, -431.578
+8000, -540, -398.674
+8000, -495, -365.518
+8000, -450, -332.108
+8000, -405, -298.445
+8000, -360, -264.528
+8000, -315, -230.358
+8000, -270, -195.935
+8000, -225, -161.259
+8000, -180, -126.329
+8000, -135, -91.146
+8000, -90, -55.709
+8000, -45, -20.019
+8000, -9, 0.000
+8000, 9, 25.165
+8000, 45, 56.818
+8000, 90, 96.631
+8000, 135, 136.720
+8000, 180, 177.084
+8000, 225, 217.722
+8000, 270, 258.636
+8000, 315, 299.824
+8000, 360, 341.287
+8000, 405, 383.025
+8000, 450, 425.038
+8000, 495, 467.326
+8000, 540, 509.888
+8000, 585, 552.726
+8000, 630, 595.838
+8000, 675, 639.226
+8000, 720, 682.888
+8000, 765, 726.825
+8000, 810, 771.037
+8000, 855, 815.524
+8000, 900, 860.286
+8800, -900, -713.999
+8800, -855, -680.147
+8800, -810, -645.995
+8800, -765, -611.543
+8800, -720, -576.793
+8800, -675, -541.743
+8800, -630, -506.394
+8800, -585, -470.745
+8800, -540, -434.798
+8800, -495, -398.550
+8800, -450, -362.004
+8800, -405, -325.158
+8800, -360, -288.013
+8800, -315, -250.569
+8800, -270, -212.826
+8800, -225, -174.783
+8800, -180, -136.441
+8800, -135, -97.799
+8800, -90, -58.858
+8800, -45, -19.618
+8800, -9, 0.000
+8800, 9, 30.288
+8800, 45, 65.107
+8800, 90, 108.922
+8800, 135, 153.063
+8800, 180, 197.528
+8800, 225, 242.318
+8800, 270, 287.432
+8800, 315, 332.872
+8800, 360, 378.636
+8800, 405, 424.725
+8800, 450, 471.138
+8800, 495, 517.877
+8800, 540, 564.940
+8800, 585, 612.328
+8800, 630, 660.041
+8800, 675, 708.078
+8800, 720, 756.441
+8800, 765, 805.128
+8800, 810, 854.139
+8800, 855, 903.476
+8800, 900, 953.137
+9600, -900, -771.678
+9600, -855, -735.187
+9600, -810, -698.347
+9600, -765, -661.157
+9600, -720, -623.617
+9600, -675, -585.728
+9600, -630, -547.489
+9600, -585, -508.900
+9600, -540, -469.962
+9600, -495, -430.675
+9600, -450, -391.037
+9600, -405, -351.051
+9600, -360, -310.714
+9600, -315, -270.028
+9600, -270, -228.992
+9600, -225, -187.607
+9600, -180, -145.872
+9600, -135, -103.788
+9600, -90, -61.353
+9600, -45, -18.570
+9600, -9, 0.000
+9600, 9, 36.112
+9600, 45, 74.098
+9600, 90, 121.923
+9600, 135, 170.127
+9600, 180, 218.710
+9600, 225, 267.672
+9600, 270, 317.014
+9600, 315, 366.735
+9600, 360, 416.836
+9600, 405, 467.316
+9600, 450, 518.175
+9600, 495, 569.414
+9600, 540, 621.032
+9600, 585, 673.029
+9600, 630, 725.406
+9600, 675, 778.162
+9600, 720, 831.297
+9600, 765, 884.812
+9600, 810, 938.706
+9600, 855, 992.979
+9600, 900, 1047.632
+10400, -900, -827.790
+10400, -855, -788.746
+10400, -810, -749.297
+10400, -765, -709.444
+10400, -720, -669.187
+10400, -675, -628.526
+10400, -630, -587.460
+10400, -585, -545.991
+10400, -540, -504.117
+10400, -495, -461.838
+10400, -450, -419.156
+10400, -405, -376.069
+10400, -360, -332.578
+10400, -315, -288.682
+10400, -270, -244.383
+10400, -225, -199.679
+10400, -180, -154.571
+10400, -135, -109.059
+10400, -90, -63.142
+10400, -45, -16.821
+10400, -9, 0.000
+10400, 9, 42.693
+10400, 45, 83.850
+10400, 90, 135.690
+10400, 135, 187.969
+10400, 180, 240.687
+10400, 225, 293.843
+10400, 270, 347.438
+10400, 315, 401.472
+10400, 360, 455.944
+10400, 405, 510.855
+10400, 450, 566.205
+10400, 495, 621.993
+10400, 540, 678.220
+10400, 585, 734.885
+10400, 630, 791.989
+10400, 675, 849.532
+10400, 720, 907.513
+10400, 765, 965.934
+10400, 810, 1024.792
+10400, 855, 1084.090
+10400, 900, 1143.826
+11200, -900, -882.284
+11200, -855, -840.771
+11200, -810, -798.794
+11200, -765, -756.355
+11200, -720, -713.452
+11200, -675, -670.086
+11200, -630, -626.257
+11200, -585, -581.964
+11200, -540, -537.208
+11200, -495, -491.989
+11200, -450, -446.307
+11200, -405, -400.162
+11200, -360, -353.553
+11200, -315, -306.481
+11200, -270, -258.945
+11200, -225, -210.947
+11200, -180, -162.485
+11200, -135, -113.560
+11200, -90, -64.172
+11200, -45, -14.320
+11200, -9, 0.000
+11200, 9, 50.088
+11200, 45, 94.417
+11200, 90, 150.280
+11200, 135, 206.647
+11200, 180, 263.515
+11200, 225, 320.887
+11200, 270, 378.761
+11200, 315, 437.137
+11200, 360, 496.017
+11200, 405, 555.399
+11200, 450, 615.283
+11200, 495, 675.671
+11200, 540, 736.561
+11200, 585, 797.953
+11200, 630, 859.848
+11200, 675, 922.246
+11200, 720, 985.147
+11200, 765, 1048.550
+11200, 810, 1112.456
+11200, 855, 1176.865
+11200, 900, 1241.776
+12000, -900, -935.107
+12000, -855, -891.210
+12000, -810, -846.786
+12000, -765, -801.836
+12000, -720, -756.359
+12000, -675, -710.355
+12000, -630, -663.825
+12000, -585, -616.769
+12000, -540, -569.185
+12000, -495, -521.076
+12000, -450, -472.439
+12000, -405, -423.276
+12000, -360, -373.587
+12000, -315, -323.371
+12000, -270, -272.628
+12000, -225, -221.359
+12000, -180, -169.563
+12000, -135, -117.240
+12000, -90, -64.391
+12000, -45, -11.016
+12000, -9, 0.000
+12000, 9, 58.354
+12000, 45, 105.857
+12000, 90, 165.750
+12000, 135, 226.215
+12000, 180, 287.252
+12000, 225, 348.859
+12000, 270, 411.038
+12000, 315, 473.788
+12000, 360, 537.110
+12000, 405, 601.003
+12000, 450, 665.468
+12000, 495, 730.504
+12000, 540, 796.111
+12000, 585, 862.290
+12000, 630, 929.040
+12000, 675, 996.361
+12000, 720, 1064.254
+12000, 765, 1132.718
+12000, 810, 1201.753
+12000, 855, 1271.360
+12000, 900, 1341.539
+12800, -900, -986.207
+12800, -855, -940.011
+12800, -810, -893.220
+12800, -765, -845.835
+12800, -720, -797.856
+12800, -675, -749.282
+12800, -630, -700.114
+12800, -585, -650.352
+12800, -540, -599.996
+12800, -495, -549.045
+12800, -450, -497.500
+12800, -405, -445.361
+12800, -360, -392.628
+12800, -315, -339.300
+12800, -270, -285.378
+12800, -225, -230.862
+12800, -180, -175.751
+12800, -135, -120.047
+12800, -90, -63.748
+12800, -45, -6.855
+12800, -9, 0.000
+12800, 9, 67.546
+12800, 45, 118.226
+12800, 90, 182.157
+12800, 135, 246.732
+12800, 180, 311.952
+12800, 225, 377.817
+12800, 270, 444.327
+12800, 315, 511.482
+12800, 360, 579.281
+12800, 405, 647.726
+12800, 450, 716.815
+12800, 495, 786.549
+12800, 540, 856.928
+12800, 585, 927.951
+12800, 630, 999.619
+12800, 675, 1071.933
+12800, 720, 1144.891
+12800, 765, 1218.493
+12800, 810, 1292.741
+12800, 855, 1367.633
+12800, 900, 1443.171
+13600, -900, -1035.533
+13600, -855, -987.122
+13600, -810, -938.044
+13600, -765, -888.300
+13600, -720, -837.890
+13600, -675, -786.814
+13600, -630, -735.071
+13600, -585, -682.662
+13600, -540, -629.587
+13600, -495, -575.845
+13600, -450, -521.438
+13600, -405, -466.364
+13600, -360, -410.623
+13600, -315, -354.217
+13600, -270, -297.144
+13600, -225, -239.405
+13600, -180, -180.999
+13600, -135, -121.927
+13600, -90, -62.189
+13600, -45, -1.785
+13600, -9, 0.000
+13600, 9, 77.721
+13600, 45, 131.581
+13600, 90, 199.556
+13600, 135, 268.253
+13600, 180, 337.674
+13600, 225, 407.818
+13600, 270, 478.684
+13600, 315, 550.274
+13600, 360, 622.587
+13600, 405, 695.622
+13600, 450, 769.381
+13600, 495, 843.862
+13600, 540, 919.067
+13600, 585, 994.994
+13600, 630, 1071.644
+13600, 675, 1149.018
+13600, 720, 1227.114
+13600, 765, 1305.933
+13600, 810, 1385.475
+13600, 855, 1465.740
+13600, 900, 1546.729
+14400, -900, -1083.032
+14400, -855, -1032.490
+14400, -810, -981.206
+14400, -765, -929.180
+14400, -720, -876.411
+14400, -675, -822.899
+14400, -630, -768.644
+14400, -585, -713.647
+14400, -540, -657.907
+14400, -495, -601.425
+14400, -450, -544.200
+14400, -405, -486.232
+14400, -360, -427.522
+14400, -315, -368.069
+14400, -270, -307.873
+14400, -225, -246.935
+14400, -180, -185.254
+14400, -135, -122.830
+14400, -90, -59.664
+14400, -45, 0.000
+14400, -9, 0.000
+14400, 9, 88.937
+14400, 45, 145.978
+14400, 90, 218.004
+14400, 135, 290.836
+14400, 180, 364.473
+14400, 225, 438.917
+14400, 270, 514.166
+14400, 315, 590.222
+14400, 360, 667.083
+14400, 405, 744.749
+14400, 450, 823.222
+14400, 495, 902.501
+14400, 540, 982.585
+14400, 585, 1063.475
+14400, 630, 1145.171
+14400, 675, 1227.673
+14400, 720, 1310.980
+14400, 765, 1395.094
+14400, 810, 1480.013
+14400, 855, 1565.738
+14400, 900, 1652.269
+15200, -900, -1128.651
+15200, -855, -1076.065
+15200, -810, -1022.655
+15200, -765, -968.421
+15200, -720, -913.365
+15200, -675, -857.485
+15200, -630, -800.781
+15200, -585, -743.255
+15200, -540, -684.904
+15200, -495, -625.731
+15200, -450, -565.734
+15200, -405, -504.914
+15200, -360, -443.271
+15200, -315, -380.804
+15200, -270, -317.514
+15200, -225, -253.400
+15200, -180, -188.463
+15200, -135, -122.703
+15200, -90, -56.119
+15200, -45, 0.000
+15200, -9, 0.000
+15200, 9, 101.249
+15200, 45, 161.473
+15200, 90, 237.558
+15200, 135, 314.536
+15200, 180, 392.407
+15200, 225, 471.172
+15200, 270, 550.830
+15200, 315, 631.381
+15200, 360, 712.826
+15200, 405, 795.164
+15200, 450, 878.396
+15200, 495, 962.521
+15200, 540, 1047.539
+15200, 585, 1133.451
+15200, 630, 1220.256
+15200, 675, 1307.954
+15200, 720, 1396.546
+15200, 765, 1486.032
+15200, 810, 1576.410
+15200, 855, 1667.682
+15200, 900, 1759.848
+16000, -900, -1172.340
+16000, -855, -1117.793
+16000, -810, -1062.337
+16000, -765, -1005.973
+16000, -720, -948.700
+16000, -675, -890.519
+16000, -630, -831.430
+16000, -585, -771.432
+16000, -540, -710.526
+16000, -495, -648.712
+16000, -450, -585.989
+16000, -405, -522.358
+16000, -360, -457.818
+16000, -315, -392.370
+16000, -270, -326.013
+16000, -225, -258.749
+16000, -180, -190.575
+16000, -135, -121.494
+16000, -90, -51.504
+16000, -45, 0.000
+16000, -9, 0.000
+16000, 9, 114.714
+16000, 45, 178.124
+16000, 90, 258.274
+16000, 135, 339.410
+16000, 180, 421.531
+16000, 225, 504.638
+16000, 270, 588.731
+16000, 315, 673.809
+16000, 360, 759.873
+16000, 405, 846.922
+16000, 450, 934.958
+16000, 495, 1023.979
+16000, 540, 1113.985
+16000, 585, 1204.977
+16000, 630, 1296.955
+16000, 675, 1389.919
+16000, 720, 1483.868
+16000, 765, 1578.803
+16000, 810, 1674.724
+16000, 855, 1771.630
+16000, 900, 1869.523
diff --git a/VectoCore/VectoCoreTest/Utils/MockVehicleContainer.cs b/VectoCore/VectoCoreTest/Utils/MockVehicleContainer.cs
index f9a5e6fb20186c2096ada2751fd24fdfafbdfccb..e0a140d76476dd2915b747008636da2ffd07ff46 100644
--- a/VectoCore/VectoCoreTest/Utils/MockVehicleContainer.cs
+++ b/VectoCore/VectoCoreTest/Utils/MockVehicleContainer.cs
@@ -330,6 +330,7 @@ namespace TUGraz.VectoCore.Tests.Utils
 
 		public bool HasElectricMotor { get; set; }
 		public PowertrainPosition[] ElectricMotorPositions { get; set; }
+		public VectoSimulationJobType VehicleArchitecutre { get; }
 
 		#endregion
 	}
diff --git a/VectoCore/VectoCoreTest/VectoCoreTest.csproj b/VectoCore/VectoCoreTest/VectoCoreTest.csproj
index 0d6a30ca91032ac382c94b56a1bf8662afe33629..cb1aca2f62b8e1a5e52ed4f3d1c3c143ecc15a32 100644
--- a/VectoCore/VectoCoreTest/VectoCoreTest.csproj
+++ b/VectoCore/VectoCoreTest/VectoCoreTest.csproj
@@ -121,6 +121,7 @@
     <Compile Include="Integration\Declaration\VocationalVehicleTest.cs" />
     <Compile Include="Integration\Declaration\TestMaxMassInMUCycle.cs" />
     <Compile Include="Integration\DualFuel\DualFuelTests.cs" />
+    <Compile Include="Integration\Hybrid\SerialHybridTest.cs" />
     <Compile Include="Integration\RoadSweepers\RoadSweeperTests.cs" />
     <Compile Include="Integration\Hybrid\ParallelHybridTest.cs" />
     <Compile Include="Integration\Multistage\MultistageVehicleTest.cs" />
@@ -664,6 +665,9 @@
     <None Include="TestData\Hybrids\ElectricMotor\GenericDrag.vemd">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
+    <None Include="TestData\Hybrids\ElectricMotor\GenericDragGenerator.vemd">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
     <None Include="TestData\Hybrids\ElectricMotor\GenericDragHV.vemd">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
@@ -688,6 +692,12 @@
     <None Include="TestData\Hybrids\ElectricMotor\GenericEMotorV3.vem">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
+    <None Include="TestData\Hybrids\ElectricMotor\GenericGenerator.vem">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Hybrids\ElectricMotor\GenericGenerator.vemp">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
     <None Include="TestData\Hybrids\ElectricMotor\GenericMap.vemo">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
@@ -751,6 +761,9 @@
     <None Include="TestData\Hybrids\BusAuxEngineeringMode\MT_6_Bus.vgbx">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
+    <None Include="TestData\Hybrids\ElectricMotor\GenericMapGenerator.vemo">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
     <None Include="TestData\Hybrids\ElectricMotor\GenericMapHV.vemo">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>