From 6cec041a3eb9372f10eb30c3379614e7d5dc950b Mon Sep 17 00:00:00 2001
From: Michael Krisper <michael.krisper@tugraz.at>
Date: Wed, 31 Aug 2016 11:49:27 +0200
Subject: [PATCH] PTO Cycle now works, but stop-times have to be split up

---
 .../Reader/DrivingCycleDataReader.cs          |  2 +-
 .../Simulation/Impl/PowertrainBuilder.cs      | 24 ++++---
 .../Impl/DistanceBasedDrivingCycle.cs         | 32 +++++++--
 .../Impl/IdleControllerSwitcher.cs            | 70 +++++++++++++++++++
 .../Impl/PTOCycleController.cs                | 13 ++--
 .../VectoSimulationComponent.cs               |  6 +-
 .../VectoCore/Utils/ProviderExtensions.cs     | 59 ----------------
 VectoCore/VectoCore/VectoCore.csproj          |  1 +
 8 files changed, 126 insertions(+), 81 deletions(-)
 create mode 100644 VectoCore/VectoCore/Models/SimulationComponent/Impl/IdleControllerSwitcher.cs

diff --git a/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs b/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs
index fa04c1a336..cfcdf3764b 100644
--- a/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs
+++ b/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs
@@ -400,7 +400,7 @@ namespace TUGraz.VectoCore.InputData.Reader
 						crossWindRequired ? row.ParseDouble(Fields.AirSpeedRelativeToVehicle).KMPHtoMeterPerSecond() : null,
 					WindYawAngle = crossWindRequired ? row.ParseDoubleOrGetDefault(Fields.WindYawAngle) : 0,
 					AuxiliarySupplyPower = row.GetAuxiliaries(),
-					PTOActive = table.Columns.Contains(Fields.PTOActive) && row.Field<char>(Fields.PTOActive) == '1'
+					PTOActive = table.Columns.Contains(Fields.PTOActive) && row.Field<string>(Fields.PTOActive) == "1"
 				});
 			}
 
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
index a5d6fa2d4f..96dfeee458 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
@@ -70,8 +70,11 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 					return BuildMeasuredSpeed(data);
 				case CycleType.MeasuredSpeedGear:
 					return BuildMeasuredSpeedGear(data);
+				case CycleType.DistanceBased:
+					return BuildFullPowertrain(data);
+				default:
+					throw new VectoException("Powertrain Builder cannot build Powertrain for CycleType: {0}", data.Cycle.CycleType);
 			}
-			return BuildFullPowertrain(data);
 		}
 
 		private VehicleContainer BuildEngineOnly(VectoRunData data)
@@ -110,7 +113,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				.AddComponent(gearbox, data.Retarder, data.PTO, container)
 				.AddComponent(new CycleClutch(container));
 			var engine = new CombustionEngine(container, data.EngineData, pt1Disabled: true);
-			var idleController = GetIdleController(data.PTO, engine, container);
+			var idleController = GetIdleController(data.PTO, engine);
 
 			powertrain.AddComponent(engine, idleController, container)
 				.AddAuxiliaries(container, data);
@@ -141,7 +144,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			}
 
 			var engine = new CombustionEngine(container, data.EngineData);
-			var idleController = GetIdleController(data.PTO, engine, container);
+			var idleController = GetIdleController(data.PTO, engine);
 
 			powertrain.AddComponent(engine, idleController, container)
 				.AddAuxiliaries(container, data);
@@ -170,7 +173,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				.AddComponent(new CycleClutch(container));
 
 			var engine = new CombustionEngine(container, data.EngineData);
-			powertrain.AddComponent(engine, GetIdleController(data.PTO, engine, container), container)
+			powertrain.AddComponent(engine, GetIdleController(data.PTO, engine), container)
 				.AddAuxiliaries(container, data);
 
 			return container;
@@ -199,7 +202,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			}
 
 			var engine = new CombustionEngine(container, data.EngineData);
-			var idleController = GetIdleController(data.PTO, engine, container);
+			var idleController = GetIdleController(data.PTO, engine);
 			cycle.IdleController = idleController as IdleControllerSwitcher;
 
 			powertrain.AddComponent(engine, idleController, container)
@@ -210,11 +213,14 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			return container;
 		}
 
-		private static IIdleController GetIdleController(PTOData pto, CombustionEngine engine, IVehicleContainer container)
+		private static IIdleController GetIdleController(PTOData pto, ICombustionEngine engine)
 		{
-			return pto == null
-				? engine.IdleController
-				: new IdleControllerSwitcher(engine.IdleController, new PTOCycleController(container, pto.PTOCycle));
+			if (pto == null)
+				return engine.IdleController;
+			else {
+				var ptoController = new PTOCycleController(pto.PTOCycle);
+				return new IdleControllerSwitcher(engine.IdleController, ptoController);
+			}
 		}
 
 		internal static IAuxInProvider CreateAdvancedAuxiliaries(VectoRunData data, IVehicleContainer container)
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
index 7407267ad8..c2ceae2d3b 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
@@ -57,6 +57,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		private readonly DrivingCycleData _data;
 		internal readonly DrivingCycleEnumerator CycleIntervalIterator;
 		private bool _intervalProlonged;
+		internal IdleControllerSwitcher IdleController;
 
 		public DistanceBasedDrivingCycle(IVehicleContainer container, DrivingCycleData cycle) : base(container)
 		{
@@ -106,17 +107,38 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 						throw new VectoSimulationException("Stopping Time only allowed when target speed is zero!");
 					}
 					var dt = CycleIntervalIterator.LeftSample.StoppingTime - PreviousState.WaitTime;
-					if (CycleIntervalIterator.LeftSample.StoppingTime.IsGreater(3 * Constants.SimulationSettings.TargetTimeInterval)) {
-						// split into 3 parts
+
+					if (CycleIntervalIterator.LeftSample.PTOActive) {
 						if (PreviousState.WaitTime.IsEqual(0)) {
+							// waiting just started. Activate PTO
+							IdleController.Reset();
+							IdleController.ActivatePTO();
+						} else {
+							// we already started pto cycle and are now in the follow up call.
+							// So we have to manually commit the previous simulation step to go further.
+							IdleController.CommitSimulationStep();
+						}
+						var nextCycleTime = IdleController.GetNextCycleTime();
+						if (nextCycleTime == null) {
+							// PTO Cycle has finished. Switch to normal idle controller.
+							IdleController.ActivateIdle();
 							dt = Constants.SimulationSettings.TargetTimeInterval;
 						} else {
-							if (dt > Constants.SimulationSettings.TargetTimeInterval) {
-								dt -= Constants.SimulationSettings.TargetTimeInterval;
+							// set dt to the next time interval in the pto cycle (to synchronize driving cycle with pto cycle)
+							dt = nextCycleTime - PreviousState.WaitTime;
+						}
+					} else {
+						if (CycleIntervalIterator.LeftSample.StoppingTime.IsGreater(3 * Constants.SimulationSettings.TargetTimeInterval)) {
+							// split into 3 parts or use idle controller time intervals
+							if (PreviousState.WaitTime.IsEqual(0)) {
+								dt = Constants.SimulationSettings.TargetTimeInterval;
+							} else {
+								if (dt > Constants.SimulationSettings.TargetTimeInterval) {
+									dt -= Constants.SimulationSettings.TargetTimeInterval;
+								}
 							}
 						}
 					}
-
 					CurrentState.Response = DriveTimeInterval(absTime, dt);
 					return CurrentState.Response;
 				}
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/IdleControllerSwitcher.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/IdleControllerSwitcher.cs
new file mode 100644
index 0000000000..ef0db2c630
--- /dev/null
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/IdleControllerSwitcher.cs
@@ -0,0 +1,70 @@
+using System;
+using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.Models.Connector.Ports;
+
+namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
+{
+	public class IdleControllerSwitcher : IIdleController
+	{
+		private readonly IIdleController _idleController;
+		private readonly PTOCycleController _ptoController;
+		private IIdleController _currentController;
+
+		public IdleControllerSwitcher(IIdleController idleController, PTOCycleController ptoController)
+		{
+			_idleController = idleController;
+			_ptoController = ptoController;
+
+			// default state is idleController
+			_currentController = _idleController;
+		}
+
+		public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
+			bool dryRun = false)
+		{
+			return _currentController.Request(absTime, dt, outTorque, outAngularVelocity, dryRun);
+		}
+
+		public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity)
+		{
+			throw new InvalidOperationException(string.Format("{0} cannot initialize.", GetType().FullName));
+		}
+
+		public ITnOutPort RequestPort
+		{
+			set
+			{
+				_idleController.RequestPort = value;
+				_ptoController.RequestPort = value;
+			}
+		}
+
+		public void Reset()
+		{
+			_idleController.Reset();
+			_ptoController.Reset();
+			_currentController = _idleController;
+		}
+
+		public void ActivatePTO()
+		{
+			_currentController = _ptoController;
+		}
+
+		public void ActivateIdle()
+		{
+			_currentController = _idleController;
+		}
+
+		public Second GetNextCycleTime()
+		{
+			return _ptoController.GetNextCycleTime();
+		}
+
+		public void CommitSimulationStep()
+		{
+			_ptoController.CommitSimulationStep(null);
+		}
+	}
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PTOCycleController.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PTOCycleController.cs
index 2ab8e025a1..17d894ad92 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PTOCycleController.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PTOCycleController.cs
@@ -3,7 +3,6 @@ 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;
 
 namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
@@ -17,8 +16,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		protected Second IdleStart;
 
-		public PTOCycleController(IVehicleContainer container, DrivingCycleData cycle)
-			: base(container, cycle) {}
+		public PTOCycleController(DrivingCycleData cycle) : base(null, cycle) {}
 
 		public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
 			bool dryRun = false)
@@ -42,10 +40,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public void Reset()
 		{
-			LeftSample = Data.Entries.GetEnumerator();
+			LeftSample.Reset();
 			LeftSample.MoveNext();
 
-			RightSample = Data.Entries.GetEnumerator();
+			RightSample.Reset();
 			RightSample.MoveNext();
 			RightSample.MoveNext();
 
@@ -54,7 +52,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public Second GetNextCycleTime()
 		{
-			return IdleStart + RightSample.Current.Time;
+			if (RightSample.Current == null)
+				return null;
+
+			return RightSample.Current.Time;
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/VectoSimulationComponent.cs b/VectoCore/VectoCore/Models/SimulationComponent/VectoSimulationComponent.cs
index 20cef18b86..2ccd934015 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/VectoSimulationComponent.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/VectoSimulationComponent.cs
@@ -52,7 +52,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent
 		protected VectoSimulationComponent(IVehicleContainer dataBus)
 		{
 			DataBus = dataBus;
-			dataBus.AddComponent(this);
+
+			// if a component doesn't want to be registered in DataBus, it supplies null to the constructor
+			// (mk 2016-08-31: currently the only example is PTOCycleController, to not interfere with the real DrivingCycle)
+			if (dataBus != null)
+				dataBus.AddComponent(this);
 		}
 
 		public virtual void CommitSimulationStep(IModalDataContainer container)
diff --git a/VectoCore/VectoCore/Utils/ProviderExtensions.cs b/VectoCore/VectoCore/Utils/ProviderExtensions.cs
index 053a66714a..0eb11c65e2 100644
--- a/VectoCore/VectoCore/Utils/ProviderExtensions.cs
+++ b/VectoCore/VectoCore/Utils/ProviderExtensions.cs
@@ -32,7 +32,6 @@
 using System;
 using System.Collections.Generic;
 using TUGraz.VectoCommon.Models;
-using TUGraz.VectoCommon.Utils;
 using TUGraz.VectoCore.InputData.Reader;
 using TUGraz.VectoCore.Models.Connector.Ports;
 using TUGraz.VectoCore.Models.Declaration;
@@ -134,62 +133,4 @@ namespace TUGraz.VectoCore.Utils
 			}
 		}
 	}
-
-	public class IdleControllerSwitcher : IIdleController
-	{
-		private readonly IIdleController _idleController;
-		private readonly PTOCycleController _ptoController;
-		private IIdleController _currentController;
-
-		public IdleControllerSwitcher(IIdleController idleController, PTOCycleController ptoController)
-		{
-			_idleController = idleController;
-			_ptoController = ptoController;
-
-			// default state is idleController
-			_currentController = _idleController;
-		}
-
-		public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
-			bool dryRun = false)
-		{
-			return _currentController.Request(absTime, dt, outTorque, outAngularVelocity, dryRun);
-		}
-
-		public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity)
-		{
-			throw new InvalidOperationException(string.Format("{0} cannot initialize.", GetType().FullName));
-		}
-
-		public ITnOutPort RequestPort
-		{
-			set
-			{
-				_idleController.RequestPort = value;
-				_ptoController.RequestPort = value;
-			}
-		}
-
-		public void Reset()
-		{
-			_idleController.Reset();
-			_ptoController.Reset();
-			_currentController = _idleController;
-		}
-
-		public void ActivatePTO()
-		{
-			_currentController = _ptoController;
-		}
-
-		public void ActivateIdle()
-		{
-			_currentController = _idleController;
-		}
-
-		public Second GetNextCycleTime()
-		{
-			return _ptoController.GetNextCycleTime();
-		}
-	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/VectoCore.csproj b/VectoCore/VectoCore/VectoCore.csproj
index 5b1eccc80b..c8fd7f14e1 100644
--- a/VectoCore/VectoCore/VectoCore.csproj
+++ b/VectoCore/VectoCore/VectoCore.csproj
@@ -153,6 +153,7 @@
     <Compile Include="Models\SimulationComponent\Impl\PTOCycleController.cs" />
     <Compile Include="Models\SimulationComponent\Impl\PWheelCycle.cs" />
     <Compile Include="Models\SimulationComponent\Impl\TorqueConverter.cs" />
+    <Compile Include="Models\SimulationComponent\Impl\IdleControllerSwitcher.cs" />
     <Compile Include="Utils\ProviderExtensions.cs" />
     <Compile Include="Models\Declaration\AirDrag.cs" />
     <Compile Include="Models\Declaration\Fan.cs" />
-- 
GitLab