From fd9ba1b87b39d3289cfe7ea603e24a2b4489a25f Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Thu, 9 Nov 2017 10:52:38 +0100
Subject: [PATCH] more work on eptp mode

---
 VECTO.sln.DotSettings                         |   2 +
 .../EngineeringEPTPModeVectoRunDataFactory.cs |   5 +-
 .../Models/Simulation/Data/VectoRunData.cs    |   4 +-
 .../Simulation/Impl/PowertrainBuilder.cs      |  22 ++-
 .../Simulation/Impl/VehicleContainer.cs       |   3 +-
 .../Impl/CombustionEngine.cs                  |   9 +-
 .../Impl/EPTPCombustionEngine.cs              |  78 +++++++++
 .../SimulationComponent/Impl/EPTPCycle.cs     | 156 ++++++++++++++++++
 .../Impl/EngineAuxiliary.cs                   |   5 +
 .../SimulationComponent/Impl/PWheelCycle.cs   |  67 ++++----
 .../Integration/EPTP/EPTPTest.cs              |   6 +
 .../Models/Simulation/PwheelModeTests.cs      |  35 +++-
 12 files changed, 341 insertions(+), 51 deletions(-)
 create mode 100644 VectoCore/VectoCore/Models/SimulationComponent/Impl/EPTPCombustionEngine.cs
 create mode 100644 VectoCore/VectoCore/Models/SimulationComponent/Impl/EPTPCycle.cs

diff --git a/VECTO.sln.DotSettings b/VECTO.sln.DotSettings
index 1cd409260f..34ea44b952 100644
--- a/VECTO.sln.DotSettings
+++ b/VECTO.sln.DotSettings
@@ -11,6 +11,7 @@
 	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_IFELSE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
 	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_USING_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
 	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
+	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_STYLE/@EntryValue">Tab</s:String>
 	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INITIALIZER_BRACES/@EntryValue">END_OF_LINE</s:String>
 	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/OTHER_BRACES/@EntryValue">END_OF_LINE</s:String>
 	<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_CATCH_ON_NEW_LINE/@EntryValue">False</s:Boolean>
@@ -21,6 +22,7 @@
 	<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_MULTIPLICATIVE_OP/@EntryValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_TYPEOF_PARENTHESES/@EntryValue">False</s:Boolean>
 	<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/USE_INDENT_FROM_VS/@EntryValue">False</s:Boolean>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AMT/@EntryIndexedValue">AMT</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AT/@EntryIndexedValue">AT</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CSV/@EntryIndexedValue">CSV</s:String>
diff --git a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringEPTPModeVectoRunDataFactory.cs b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringEPTPModeVectoRunDataFactory.cs
index bf955d0242..c0821243ea 100644
--- a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringEPTPModeVectoRunDataFactory.cs
+++ b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringEPTPModeVectoRunDataFactory.cs
@@ -67,10 +67,11 @@ namespace TUGraz.VectoCore.InputData.Reader.Impl {
                     DriverData = null,
                     Aux = aux,
                     AdvancedAux = null,
-                    Retarder = dao.CreateRetarderData(InputDataProvider.JobInputData.Vehicle.RetarderInputData),
+                    Retarder = retarderData,
                     PTO = ptoTransmissionData,
                     Cycle = new DrivingCycleProxy(drivingCycle, cycle.Name),
-                    ExecutionMode = ExecutionMode.Engineering
+                    ExecutionMode = ExecutionMode.Engineering,
+                    AuxFanParameters = InputDataProvider.JobInputData.FanPowerCoefficents.ToArray()
                 };
             });
         }
diff --git a/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs b/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs
index a37cd3514b..0232302186 100644
--- a/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs
@@ -103,7 +103,9 @@ namespace TUGraz.VectoCore.Models.Simulation.Data
 
 		public int JobRunId { get; internal set; }
 
-		public class AuxData
+        public double[] AuxFanParameters { get; internal set; }
+
+        public class AuxData
 		{
 			// ReSharper disable once InconsistentNaming
 			public string ID;
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
index 88a5c904a9..019b7e49d1 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
@@ -112,8 +112,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			var gearbox = new CycleGearbox(container, data);
 
 			// PWheelCycle --> AxleGear --> Clutch --> Engine <-- Aux
-			var powertrain = new PWheelCycle(container, data.Cycle, data.AxleGearData.AxleGear.Ratio, data.VehicleData,
-					gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio))
+			var powertrain = new PWheelCycle(container, data.Cycle)
 				.AddComponent(new AxleGear(container, data.AxleGearData))
 				.AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null)
 				.AddComponent(gearbox, data.Retarder, container)
@@ -129,8 +128,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 
         private VehicleContainer BuildEPTP(VectoRunData data)
         {
-            if (data.Cycle.CycleType != CycleType.PWheel) {
-                throw new VectoException("CycleType must be PWheel.");
+            if (data.Cycle.CycleType != CycleType.EPTP) {
+                throw new VectoException("CycleType must be EPTP.");
             }
 
             var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data };
@@ -143,16 +142,25 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
                 .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null)
                 .AddComponent(gearbox, data.Retarder, container)
                 .AddComponent(new Clutch(container, data.EngineData));
-            var engine = new CombustionEngine(container, data.EngineData, pt1Disabled: true);
+            var engine = new EPTPCombustionEngine(container, data.EngineData, pt1Disabled: true);
 
             var aux = CreateAuxiliaries(data, container);
             aux.AddCycle(Constants.Auxiliaries.IDs.Fan, cycleEntry => {
                 var fanSpeed = cycleEntry.FanSpeed.AsRPM;
-                return (c1 * Math.Pow(fanSpeed / c2, 3) * Math.Pow(fanSpeed / c3, 5)*1000).SI<Watt>();
+                var c1 = data.AuxFanParameters.Length > 0 ? data.AuxFanParameters[0] : 0;
+                var c2 = data.AuxFanParameters.Length > 1 ? data.AuxFanParameters[1] : 1;
+                var c3 = data.AuxFanParameters.Length > 2 ? data.AuxFanParameters[2] : 1;
+                return (c1 * Math.Pow(fanSpeed / c2, 3) * Math.Pow(fanSpeed / c3, 5) * 1000).SI<Watt>();
             });
+            container.ModalData.AddAuxiliary(Constants.Auxiliaries.IDs.Fan);
 
             engine.Connect(aux.Port());
-            var idleController = GetIdleController(data.PTO, engine, container);
+
+            var idleController = new CombustionEngine.CombustionEngineNoDubleclutchIdleController(engine, container);
+            //if (data.PTO != null && data.PTO.PTOCycle != null) {
+            //    var ptoController = new PTOCycleController(container, data.PTO.PTOCycle);
+            //    idleController = new IdleControllerSwitcher(engine.IdleController, ptoController);
+            //}
 
             powertrain.AddComponent(engine, idleController);
                 //.AddAuxiliaries(container, data);
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
index a0968b24da..bc70a64d85 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
@@ -298,7 +298,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 					DrivingCycle = c;
 					commitPriority = 6;
 				})
-				.If<PTOCycleController>(c => { commitPriority = 99; });
+				.If<PTOCycleController>(c => { commitPriority = 99; })
+                .If<EPTPCycle>(_ => { commitPriority = 0; });
 
 			_components.Add(Tuple.Create(commitPriority, component));
 			_components = _components.OrderBy(x => x.Item1).Reverse().ToList();
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
index a7cb1b718b..4a74927908 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
@@ -179,7 +179,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			//	CurrentState.OperationMode = EngineOperationMode.Stopped;
 			//}
 
-			var avgEngineSpeed = (PreviousState.EngineSpeed + angularVelocity) / 2.0;
+			var avgEngineSpeed = GetEngineSpeed(angularVelocity);
 
 			var engineSpeedLimit = GetEngineSpeedLimit(absTime);
 			if (!dryRun && avgEngineSpeed.IsGreater(engineSpeedLimit, Constants.SimulationSettings.LineSearchTolerance)) {
@@ -295,6 +295,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			};
 		}
 
+		protected virtual PerSecond GetEngineSpeed(PerSecond angularVelocity)
+		{
+			return (PreviousState.EngineSpeed + angularVelocity) / 2.0;
+		}
+
 		protected virtual PerSecond GetEngineSpeedLimit(Second absTime)
 		{
 			return DataBus.Gear == 0 || !DataBus.ClutchClosed(absTime)
@@ -351,7 +356,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		{
 			ValidatePowerDemand(CurrentState.EngineTorque, CurrentState.DynamicFullLoadTorque, CurrentState.FullDragTorque);
 
-			var avgEngineSpeed = (PreviousState.EngineSpeed + CurrentState.EngineSpeed) / 2.0;
+			var avgEngineSpeed = GetEngineSpeed(CurrentState.EngineSpeed);
 			if (avgEngineSpeed.IsSmaller(EngineIdleSpeed,
 				DataBus.ExecutionMode == ExecutionMode.Engineering ? 20.RPMtoRad() : 1e-3.RPMtoRad())) {
 				Log.Warn("EngineSpeed below idling speed! n_eng_avg: {0}, n_idle: {1}", avgEngineSpeed, EngineIdleSpeed);
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/EPTPCombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/EPTPCombustionEngine.cs
new file mode 100644
index 0000000000..0405652043
--- /dev/null
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/EPTPCombustionEngine.cs
@@ -0,0 +1,78 @@
+using System;
+using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.Models.Simulation;
+using TUGraz.VectoCore.Models.Simulation.Data;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.OutputData;
+
+namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
+{
+    public class EPTPCombustionEngine : CombustionEngine
+    {
+        public EPTPCombustionEngine(IVehicleContainer container, CombustionEngineData modelData, bool pt1Disabled = false) : base(container, modelData, pt1Disabled) { }
+
+        //protected override void DoWriteModalResults(IModalDataContainer container)
+        //{
+        //    ValidatePowerDemand(CurrentState.EngineTorque, CurrentState.DynamicFullLoadTorque,
+        //        CurrentState.FullDragTorque);
+
+        //    //var avgEngineSpeed = (PreviousState.EngineSpeed + CurrentState.EngineSpeed) / 2.0;
+        //    var avgEngineSpeed = DataBus.CycleData.LeftSample.EngineSpeed;
+        //    if (avgEngineSpeed.IsSmaller(EngineIdleSpeed,
+        //        DataBus.ExecutionMode == ExecutionMode.Engineering ? 20.RPMtoRad() : 1e-3.RPMtoRad())) {
+        //        Log.Warn("EngineSpeed below idling speed! n_eng_avg: {0}, n_idle: {1}", avgEngineSpeed,
+        //            EngineIdleSpeed);
+        //    }
+        //    container[ModalResultField.P_eng_fcmap] = CurrentState.EngineTorque * avgEngineSpeed;
+        //    container[ModalResultField.P_eng_out] = container[ModalResultField.P_eng_out] is DBNull
+        //        ? CurrentState.EngineTorqueOut * avgEngineSpeed
+        //        : container[ModalResultField.P_eng_out];
+        //    container[ModalResultField.P_eng_inertia] = CurrentState.InertiaTorqueLoss * avgEngineSpeed;
+
+        //    container[ModalResultField.n_eng_avg] = avgEngineSpeed;
+        //    container[ModalResultField.T_eng_fcmap] = CurrentState.EngineTorque;
+
+        //    container[ModalResultField.P_eng_full] = CurrentState.DynamicFullLoadTorque * avgEngineSpeed;
+        //    container[ModalResultField.P_eng_full_stat] = CurrentState.StationaryFullLoadTorque * avgEngineSpeed;
+        //    container[ModalResultField.P_eng_drag] = CurrentState.FullDragTorque * avgEngineSpeed;
+        //    container[ModalResultField.Tq_full] = CurrentState.DynamicFullLoadTorque;
+        //    container[ModalResultField.Tq_drag] = CurrentState.FullDragTorque;
+
+        //    var result = ModelData.ConsumptionMap.GetFuelConsumption(CurrentState.EngineTorque, avgEngineSpeed,
+        //        DataBus.ExecutionMode != ExecutionMode.Declaration);
+        //    if (DataBus.ExecutionMode != ExecutionMode.Declaration && result.Extrapolated) {
+        //        Log.Warn("FuelConsumptionMap was extrapolated: range for FC-Map is not sufficient: n: {0}, torque: {1}",
+        //            avgEngineSpeed.Value(), CurrentState.EngineTorque.Value());
+        //    }
+        //    var pt1 = ModelData.FullLoadCurves[DataBus.Gear].PT1(avgEngineSpeed);
+        //    if (DataBus.ExecutionMode == ExecutionMode.Declaration && pt1.Extrapolated) {
+        //        Log.Error("requested rpm below minimum rpm in pt1 - extrapolating. n_eng_avg: {0}",
+        //            avgEngineSpeed);
+        //    }
+
+        //    var fc = result.Value;
+        //    var fcAux = fc;
+
+        //    var fcWHTC = fcAux * ModelData.FuelConsumptionCorrectionFactor;
+        //    var fcAAUX = fcWHTC;
+        //    var advancedAux = EngineAux as BusAuxiliariesAdapter;
+        //    if (advancedAux != null) {
+        //        advancedAux.DoWriteModalResults(container);
+        //        fcAAUX = advancedAux.AAuxFuelConsumption;
+        //    }
+        //    var fcFinal = fcAAUX;
+
+        //    container[ModalResultField.FCMap] = fc;
+        //    container[ModalResultField.FCAUXc] = fcAux;
+        //    container[ModalResultField.FCWHTCc] = fcWHTC;
+        //    container[ModalResultField.FCAAUX] = fcAAUX;
+        //    container[ModalResultField.FCFinal] = fcFinal;
+        //}
+
+        protected override PerSecond GetEngineSpeed(PerSecond angularSpeed)
+        {
+            return DataBus.CycleData.LeftSample.EngineSpeed;
+        }
+    }
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/EPTPCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/EPTPCycle.cs
new file mode 100644
index 0000000000..93521a6144
--- /dev/null
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/EPTPCycle.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.Configuration;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
+using TUGraz.VectoCore.Models.Simulation.Data;
+using TUGraz.VectoCore.Models.Simulation.Impl;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.OutputData;
+using TUGraz.VectoCore.Utils;
+
+namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
+{
+    internal class EPTPCycle : PWheelCycle
+    {
+        private uint StartGear;
+
+        public EPTPCycle(VehicleContainer container, IDrivingCycleData cycle, double axleGearRatio,
+            VehicleData vehicleData, Dictionary<uint, double> gearRatios) : base(container, cycle) { }
+
+        public override IResponse Initialize()
+        {
+            SelectStartGear();
+            return base.Initialize();
+        }
+
+        private void SelectStartGear()
+        {
+            var transmissionRatio = RunData.AxleGearData.AxleGear.Ratio *
+                                    (RunData.AngledriveData == null ? 1.0 : RunData.AngledriveData.Angledrive.Ratio) /
+                                    RunData.VehicleData.DynamicTyreRadius;
+            var cardanStartSpeed = (RunData.GearboxData.StartSpeed * transmissionRatio).Cast<PerSecond>();
+            var minEngineSpeed = (RunData.EngineData.FullLoadCurves[0].RatedSpeed - RunData.EngineData.IdleSpeed) *
+                                 Constants.SimulationSettings.ClutchClosingSpeedNorm + RunData.EngineData.IdleSpeed;
+            var wheelStartTorque =
+            (RunData.VehicleData.VehicleCategory == VehicleCategory.Tractor
+                ? 40000.SI<Kilogram>()
+                : RunData.VehicleData.GrossVehicleWeight) * RunData.GearboxData.StartAcceleration *
+            RunData.VehicleData.DynamicTyreRadius;
+            var wheelStartSpeed = RunData.GearboxData.StartSpeed / RunData.VehicleData.DynamicTyreRadius;
+            CycleIterator.LeftSample.WheelAngularVelocity = wheelStartSpeed;
+            var maxStartGear = 1u;
+            foreach (var gearData in RunData.GearboxData.Gears.Reverse()) {
+                if (cardanStartSpeed * gearData.Value.Ratio > minEngineSpeed) {
+                     maxStartGear = gearData.Key;
+                    break;
+                }
+            }
+            for (var gear = maxStartGear; gear > 1; gear--) {
+                var inAngularSpeed = cardanStartSpeed * RunData.GearboxData.Gears[gear].Ratio;
+
+                var ratedSpeed = DataBus.EngineRatedSpeed;
+                if (inAngularSpeed > ratedSpeed || inAngularSpeed.IsEqual(0)) {
+                    continue;
+                }
+
+                var response = Initialize(gear, wheelStartTorque, wheelStartSpeed);
+
+                var fullLoadPower = response.DynamicFullLoadPower; //EnginePowerRequest - response.DeltaFullLoad;
+                var reserve = 1 - response.EnginePowerRequest / fullLoadPower;
+
+                if (response.EngineSpeed > DataBus.EngineIdleSpeed && reserve >= RunData.GearboxData.StartTorqueReserve) {
+                    StartGear = gear;
+                    return;
+                }
+            }
+            StartGear = 1;
+        }
+
+        internal ResponseDryRun Initialize(uint gear, NewtonMeter outTorque, PerSecond outAngularVelocity)
+        {
+            CycleIterator.RightSample.Gear = gear;
+           //var inAngularVelocity = outAngularVelocity * RunData.GearboxData.Gears[gear].Ratio;
+            //var torqueLossResult = RunData.GearboxData.Gears[gear].LossMap.GetTorqueLoss(outAngularVelocity, outTorque);
+            //var inTorque = outTorque / RunData.GearboxData.Gears[gear].Ratio + torqueLossResult.Value;
+
+            var response =
+                (ResponseDryRun)
+                NextComponent.Request(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, outTorque,
+                    outAngularVelocity, true);
+            
+            //var fullLoad = DataBus.EngineStationaryFullPower(inAngularVelocity);
+
+            return new ResponseDryRun {
+                Source = this,
+                EnginePowerRequest = response.EnginePowerRequest,
+                EngineSpeed = response.EngineSpeed,
+                DynamicFullLoadPower = response.DynamicFullLoadPower,
+                ClutchPowerRequest = response.ClutchPowerRequest,
+                GearboxPowerRequest = outTorque * outAngularVelocity,
+                //DeltaFullLoad = response.EnginePowerRequest - fullLoad
+            };
+        }
+
+        protected override void InitializeCycleData()
+        {
+            FirstRun = false;
+            var gearRatios = RunData.GearboxData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio);
+
+            var stopped = false;
+           
+            foreach (var entry in Data.Entries) {
+                stopped = stopped || entry.VehicleTargetSpeed.IsEqual(0.KMPHtoMeterPerSecond(),
+                              0.3.KMPHtoMeterPerSecond());
+                entry.WheelAngularVelocity =
+                    entry.VehicleTargetSpeed.IsEqual(0.KMPHtoMeterPerSecond(), 0.3.KMPHtoMeterPerSecond())
+                        ? 0.RPMtoRad()
+                        : entry.VehicleTargetSpeed / RunData.VehicleData.DynamicTyreRadius;
+                entry.Torque = entry.VehicleTargetSpeed.IsEqual(0, 0.1)
+                    ? 0.SI<NewtonMeter>()
+                    : entry.PWheel / entry.WheelAngularVelocity;
+
+                var cardanSpeed = entry.VehicleTargetSpeed / RunData.VehicleData.DynamicTyreRadius *
+                                  RunData.AxleGearData.AxleGear.Ratio * (RunData.AngledriveData?.Angledrive.Ratio ?? 1);
+                if (cardanSpeed.IsEqual(0, 1)) {
+                    entry.Gear = 0;
+                    continue;
+                }
+                var ratio = (entry.EngineSpeed / cardanSpeed).Value();
+                var gear = gearRatios.Aggregate((x, y) =>
+                    Math.Abs(x.Value / ratio - 1) < Math.Abs(y.Value / ratio - 1) ? x : y).Key;
+
+                
+                //entry.Gear = entry.EngineSpeed < (RunData.EngineData.IdleSpeed + 50.RPMtoRad()) && entry.VehicleTargetSpeed < 5.KMPHtoMeterPerSecond() ? 0 :  gear;
+                if (stopped && gear < StartGear)
+                    entry.Gear = StartGear;
+                else
+                    entry.Gear = gear == 1 && cardanSpeed * gearRatios[1] < RunData.EngineData.IdleSpeed ? 0 : gear;
+                if (gear > StartGear)
+                    stopped = false;
+            }
+        }
+
+        public override bool VehicleStopped
+        {
+            get
+            {
+                if (CycleIterator.LeftSample.Gear == 0)
+                    return true;
+                if (CycleIterator.LeftSample.Gear != StartGear)
+                    return false;
+
+                var transmissionRatio = RunData.AxleGearData.AxleGear.Ratio *
+                                        (RunData.AngledriveData?.Angledrive.Ratio ?? 1.0);
+                return CycleIterator.LeftSample.WheelAngularVelocity * transmissionRatio *
+                       RunData.GearboxData.Gears[CycleIterator.LeftSample.Gear].Ratio < DataBus.EngineIdleSpeed;
+                //return CycleIterator.LeftSample.VehicleTargetSpeed.IsEqual(0.KMPHtoMeterPerSecond(),
+                //    0.3.KMPHtoMeterPerSecond());
+            }
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/EngineAuxiliary.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/EngineAuxiliary.cs
index f3c84e2500..64d54acc79 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/EngineAuxiliary.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/EngineAuxiliary.cs
@@ -76,6 +76,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			Add(auxId, _ => DataBus.CycleData.LeftSample.AdditionalAuxPowerDemand);
 		}
 
+        public void AddCycle(string auxId, Func<DrivingCycleData.DrivingCycleEntry, Watt> powerLossFunc)
+        {
+            Add(auxId, _ => powerLossFunc(DataBus.CycleData.LeftSample));
+        }
+
 		/// <summary>
 		/// Adds an auxiliary which calculates the demand based on a aux-map and the engine speed.
 		/// </summary>
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PWheelCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PWheelCycle.cs
index 098c05e6f8..4711b22174 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PWheelCycle.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PWheelCycle.cs
@@ -29,7 +29,7 @@
 *   Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology
 */
 
-using System.Collections.Generic;
+using System.Linq;
 using TUGraz.VectoCommon.Models;
 using TUGraz.VectoCommon.Utils;
 using TUGraz.VectoCore.Models.Connector.Ports.Impl;
@@ -46,30 +46,39 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 	/// </summary>
 	public class PWheelCycle : PowertrainDrivingCycle, IDriverInfo, IVehicleInfo
 	{
-		private readonly VehicleData _vehicleData;
-
-		/// <summary>
-		/// Initializes a new instance of the <see cref="PWheelCycle"/> class.
-		/// </summary>
-		/// <param name="container">The container.</param>
-		/// <param name="cycle">The cycle.</param>
-		/// <param name="axleRatio">The axle ratio.</param>
-		/// <param name="vehicleData"></param>
-		/// <param name="gearRatios"></param>
-		public PWheelCycle(IVehicleContainer container, IDrivingCycleData cycle, double axleRatio, VehicleData vehicleData,
-			IDictionary<uint, double> gearRatios) : base(container, cycle)
-		{
-			// just to ensure that null-gear has ratio 1
-			gearRatios[0] = 1;
-			_vehicleData = vehicleData;
-			foreach (var entry in Data.Entries) {
-				entry.WheelAngularVelocity = entry.AngularVelocity / (axleRatio * gearRatios[entry.Gear]);
-				entry.Torque = entry.PWheel / entry.WheelAngularVelocity;
-			}
-		}
-
-		public override IResponse Initialize()
+		protected bool FirstRun = true;
+        protected readonly VectoRunData RunData;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PWheelCycle"/> class.
+        /// </summary>
+        /// <param name="container">The container.</param>
+        /// <param name="cycle">The cycle.</param>
+        public PWheelCycle(IVehicleContainer container, IDrivingCycleData cycle) : base(container, cycle)
+        {
+            RunData = container.RunData;
+        }
+
+        protected virtual void InitializeCycleData()
+        {
+            FirstRun = false;
+            var gearRatios = RunData.GearboxData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio);
+            // just to ensure that null-gear has ratio 1
+            gearRatios[0] = 1;
+            var axleRatio = RunData.AxleGearData.AxleGear.Ratio;
+
+            foreach (var entry in Data.Entries) {
+                entry.WheelAngularVelocity = entry.AngularVelocity / (axleRatio * gearRatios[entry.Gear]);
+                entry.Torque = entry.PWheel / entry.WheelAngularVelocity;
+            }
+        }
+
+        public override IResponse Initialize()
 		{
+            if (FirstRun) {
+                InitializeCycleData();
+               
+            }
 			var first = Data.Entries[0];
 			AbsTime = first.Time;
 			var response = NextComponent.Initialize(first.Torque, first.WheelAngularVelocity);
@@ -108,29 +117,29 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		/// <summary>
 		/// True if the angularVelocity at the wheels is 0.
 		/// </summary>
-		public bool VehicleStopped
+		public virtual bool VehicleStopped
 		{
 			get { return CycleIterator.LeftSample.WheelAngularVelocity.IsEqual(0); }
 		}
 
 		public Kilogram VehicleMass
 		{
-			get { return _vehicleData.TotalCurbWeight; }
+			get { return RunData.VehicleData.TotalCurbWeight; }
 		}
 
 		public Kilogram VehicleLoading
 		{
-			get { return _vehicleData.Loading; }
+			get { return RunData.VehicleData.Loading; }
 		}
 
 		public Kilogram TotalMass
 		{
-			get { return _vehicleData.TotalVehicleWeight; }
+			get { return RunData.VehicleData.TotalVehicleWeight; }
 		}
 
 		public CubicMeter CargoVolume
 		{
-			get { return _vehicleData.CargoVolume; }
+			get { return RunData.VehicleData.CargoVolume; }
 		}
 
 		public Newton AirDragResistance(MeterPerSecond previousVelocity, MeterPerSecond nextVelocity)
diff --git a/VectoCore/VectoCoreTest/Integration/EPTP/EPTPTest.cs b/VectoCore/VectoCoreTest/Integration/EPTP/EPTPTest.cs
index 67f0d53702..a18db88d38 100644
--- a/VectoCore/VectoCoreTest/Integration/EPTP/EPTPTest.cs
+++ b/VectoCore/VectoCoreTest/Integration/EPTP/EPTPTest.cs
@@ -27,7 +27,13 @@ namespace TUGraz.VectoCore.Tests.Integration.EPTP
             };
             
             jobContainer.AddRuns(runsFactory);
+
+            //var i = 0;
+            //jobContainer.Runs[i].Run.Run();
+            //Assert.IsTrue(jobContainer.Runs[i].Run.FinishedWithoutErrors);
+
             jobContainer.Execute();
+            jobContainer.WaitFinished();
 
             Assert.AreEqual(true, jobContainer.AllCompleted);
             
diff --git a/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs b/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs
index d76d7f19f4..8b4a078495 100644
--- a/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs
+++ b/VectoCore/VectoCoreTest/Models/Simulation/PwheelModeTests.cs
@@ -60,8 +60,26 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation
 		/// <remarks>VECTO-177</remarks>
 		[TestCase]
 		public void Pwheel_ReadCycle_Test()
-		{
-			var container = new VehicleContainer(ExecutionMode.Engineering);
+        {
+            var runData = new VectoRunData() {
+                GearboxData = new GearboxData {
+                    Gears = new Dictionary<uint, GearData> {
+                        { 1, new GearData { Ratio = 2.0 } },
+                        { 2, new GearData { Ratio = 3.5 } }
+                    }
+                },
+                VehicleData = new VehicleData {
+                    //DynamicTyreRadius = 
+                },
+                AxleGearData = new AxleGearData {
+                    AxleGear = new TransmissionData {
+                        Ratio = 2.3
+                    }
+                }
+            };
+
+            var container = new VehicleContainer(ExecutionMode.Engineering);
+            container.RunData = runData;
 			var inputData = @"<t>,<Pwheel>,<gear>,<n>,<Padd>
 							   1,89,2,1748,1.300
 							   2,120,2,1400,0.4";
@@ -69,15 +87,14 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation
 			var cycleFile = new MemoryStream(Encoding.UTF8.GetBytes(inputData));
 			var drivingCycle = DrivingCycleDataReader.ReadFromStream(cycleFile, CycleType.PWheel, "", false);
 
-			var gearbox = new CycleGearbox(container, new VectoRunData() {
-				GearboxData = new GearboxData {
-					Gears = new Dictionary<uint, GearData> { { 1, new GearData { Ratio = 2.0 } }, { 2, new GearData { Ratio = 3.5 } } }
-				}
-			});
+			var gearbox = new CycleGearbox(container, runData);
+
 
-			var cycle = new PWheelCycle(container, drivingCycle, 2.3, null,
-				gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio));
+			var cycle = new PWheelCycle(container, drivingCycle);
+            cycle.Connect(new MockTnOutPort());
 
+            cycle.Initialize();
+            
 			Assert.AreEqual(container.CycleData.LeftSample.Time, 1.SI<Second>());
 			Assert.AreEqual(container.CycleData.RightSample.Time, 2.SI<Second>());
 
-- 
GitLab