From 9785522334d23e343685a170a49069596ce7dad8 Mon Sep 17 00:00:00 2001
From: Michael Krisper <michael.krisper@tugraz.at>
Date: Mon, 29 Aug 2016 17:46:47 +0200
Subject: [PATCH] PTOCycleController

---
 .../InputData/EngineeringInputData.cs         |  2 +
 .../InputData/FileIO/JSON/JSONVehicleData.cs  |  6 ++-
 .../EngineeringDataAdapter.cs                 |  3 +-
 .../Reader/DrivingCycleDataReader.cs          | 46 +++++++++++++++++++
 VectoCore/VectoCore/JsonKeys.Designer.cs      |  9 ++++
 VectoCore/VectoCore/JsonKeys.resx             |  3 ++
 .../Simulation/Impl/PowertrainBuilder.cs      |  7 ++-
 .../Data/DrivingCycleData.cs                  |  3 +-
 .../Data/PTOTransmissionData.cs               |  1 +
 .../Models/SimulationComponent/IGearbox.cs    |  6 ++-
 .../Impl/AbstractGearbox.cs                   |  4 +-
 .../Impl/DistanceBasedDrivingCycle.cs         |  1 +
 .../Impl/PowertrainDrivingCycle.cs            |  5 ++
 .../VectoCore/Utils/ProviderExtensions.cs     |  3 ++
 VectoCore/VectoCoreTest/Utils/MockGearbox.cs  |  3 ++
 15 files changed, 93 insertions(+), 9 deletions(-)

diff --git a/VectoCommon/VectoCommon/InputData/EngineeringInputData.cs b/VectoCommon/VectoCommon/InputData/EngineeringInputData.cs
index d507c2f37f..2ddf4f962b 100644
--- a/VectoCommon/VectoCommon/InputData/EngineeringInputData.cs
+++ b/VectoCommon/VectoCommon/InputData/EngineeringInputData.cs
@@ -106,6 +106,8 @@ namespace TUGraz.VectoCommon.InputData
 		/// The PTO Loss map for idling losses of the "consumer" part.
 		/// </summary>
 		DataTable PTOLossMap { get; }
+
+		DataTable PTOCycle { get; }
 	}
 
 	public interface IAxleEngineeringInputData : IAxleDeclarationInputData
diff --git a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONVehicleData.cs b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONVehicleData.cs
index bb730e0a9c..2bf988cf53 100644
--- a/VectoCore/VectoCore/InputData/FileIO/JSON/JSONVehicleData.cs
+++ b/VectoCore/VectoCore/InputData/FileIO/JSON/JSONVehicleData.cs
@@ -34,7 +34,6 @@ using System.Collections.Generic;
 using System.Data;
 using System.Linq;
 using Newtonsoft.Json.Linq;
-using TUGraz.VectoCommon.Exceptions;
 using TUGraz.VectoCommon.InputData;
 using TUGraz.VectoCommon.Models;
 using TUGraz.VectoCommon.Utils;
@@ -238,6 +237,11 @@ namespace TUGraz.VectoCore.InputData.FileIO.JSON
 			}
 		}
 
+		public DataTable PTOCycle
+		{
+			get { return ReadTableData(Body.GetEx(JsonKeys.Vehicle_PTO).GetEx<string>(JsonKeys.Vehicle_PTO_Cycle), "Cycle"); }
+		}
+
 		#endregion
 
 		public string Vendor
diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs
index 79e2bbf343..23e0459bae 100644
--- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs
+++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs
@@ -307,7 +307,8 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter
 			if (pto.PTOTransmissionType != "None") {
 				return new PTOTransmissionData {
 					TransmissionType = pto.PTOTransmissionType,
-					LossMap = PTOIdleLossMapReader.Create(pto.PTOLossMap)
+					LossMap = PTOIdleLossMapReader.Create(pto.PTOLossMap),
+					PTOCycle = DrivingCycleDataReader.ReadFromDataTable(pto.PTOCycle, CycleType.PTO, "PTO", false)
 				};
 			}
 
diff --git a/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs b/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs
index f4fc790a21..be0236aab4 100644
--- a/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs
+++ b/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs
@@ -55,6 +55,10 @@ namespace TUGraz.VectoCore.InputData.Reader
 		{
 			var cols = cycleData.Columns.Cast<DataColumn>().Select(c => c.ColumnName).ToArray();
 
+			if (PTOCycleDataParser.ValidateHeader(cols, false)) {
+				return CycleType.PTO;
+			}
+
 			if (PWheelCycleDataParser.ValidateHeader(cols, false)) {
 				return CycleType.PWheel;
 			}
@@ -86,6 +90,8 @@ namespace TUGraz.VectoCore.InputData.Reader
 					return new MeasuredSpeedGearDataParser();
 				case CycleType.MeasuredSpeed:
 					return new MeasuredSpeedDataParser();
+				case CycleType.PTO:
+					return new PTOCycleDataParser();
 				default:
 					throw new ArgumentOutOfRangeException("type");
 			}
@@ -294,6 +300,8 @@ namespace TUGraz.VectoCore.InputData.Reader
 
 		private static class Fields
 		{
+			public const string PTOTorque = "PTO Torque";
+			public const string EngineSpeedFull = "Engine Speed";
 			public const string PWheel = "Pwheel";
 			public const string Distance = "s";
 			public const string Time = "t";
@@ -639,6 +647,44 @@ namespace TUGraz.VectoCore.InputData.Reader
 						CheckComboColumns(header, new[] { Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle }, throwExceptions);
 			}
 		}
+
+		/// <summary>
+		/// Parser for PTO Cycles.
+		/// </summary>
+		// <t> [s], <Engine Speed> [rpm], <PTO Torque> [Nm]
+		private class PTOCycleDataParser : AbstractCycleDataParser
+		{
+			public override IEnumerable<DrivingCycleData.DrivingCycleEntry> Parse(DataTable table, bool crossWindRequired)
+			{
+				ValidateHeader(table.Columns.Cast<DataColumn>().Select(col => col.ColumnName).ToArray());
+
+				var entries = table.Rows.Cast<DataRow>().Select(row => new DrivingCycleData.DrivingCycleEntry {
+					Time = row.ParseDouble(Fields.Time).SI<Second>(),
+					AngularVelocity = row.ParseDouble(Fields.EngineSpeedFull).RPMtoRad(),
+					Torque = row.ParseDouble(Fields.PTOTorque).SI<NewtonMeter>()
+				}).ToArray();
+
+				return entries;
+			}
+
+			public static bool ValidateHeader(string[] header, bool throwExceptions = true)
+			{
+				var requiredCols = new[] {
+					Fields.Time,
+					Fields.EngineSpeedFull,
+					Fields.PTOTorque
+				};
+				var allowedCols = new[] {
+					Fields.Time,
+					Fields.EngineSpeedFull,
+					Fields.PTOTorque
+				};
+
+				var allowAux = false;
+
+				return CheckColumns(header, allowedCols, requiredCols, throwExceptions, allowAux);
+			}
+		}
 	}
 
 	#endregion
diff --git a/VectoCore/VectoCore/JsonKeys.Designer.cs b/VectoCore/VectoCore/JsonKeys.Designer.cs
index 7d0b2c195f..f2337736ac 100644
--- a/VectoCore/VectoCore/JsonKeys.Designer.cs
+++ b/VectoCore/VectoCore/JsonKeys.Designer.cs
@@ -735,6 +735,15 @@ namespace TUGraz.VectoCore {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Cycle.
+        /// </summary>
+        internal static string Vehicle_PTO_Cycle {
+            get {
+                return ResourceManager.GetString("Vehicle_PTO_Cycle", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to LossMap.
         /// </summary>
diff --git a/VectoCore/VectoCore/JsonKeys.resx b/VectoCore/VectoCore/JsonKeys.resx
index d7fc848dd8..b19f7fe807 100644
--- a/VectoCore/VectoCore/JsonKeys.resx
+++ b/VectoCore/VectoCore/JsonKeys.resx
@@ -178,6 +178,9 @@
   </data>
 	<data name="Vehicle_PTO_LossMapFile" xml:space="preserve">
     <value>LossMap</value>
+  </data>
+	<data name="Vehicle_PTO_Cycle" xml:space="preserve">
+    <value>Cycle</value>
   </data>
 	<data name="Vehicle_PTO_Type" xml:space="preserve">
     <value>Type</value>
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
index b6022d683b..839cf4107f 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
@@ -79,7 +79,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			if (data.Cycle.CycleType != CycleType.EngineOnly) {
 				throw new VectoException("CycleType must be EngineOnly.");
 			}
-			
+
 			var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data };
 			var cycle = new PowertrainDrivingCycle(container, data.Cycle);
 
@@ -104,7 +104,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 
 			// PWheelCycle --> AxleGear --> CycleClutch --> Engine <-- Aux
 			new PWheelCycle(container, data.Cycle, data.AxleGearData.AxleGear.Ratio,
-				gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio))
+					gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio))
 				.AddComponent(new AxleGear(container, data.AxleGearData))
 				.AddComponent(data.AngularGearData != null ? new AngularGear(container, data.AngularGearData) : null)
 				.AddComponent(gearbox, data.Retarder, data.PTOTransmission, container)
@@ -187,8 +187,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			if (data.GearboxData.Type.ManualTransmission()) {
 				powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData));
 			}
-			powertrain.AddComponent(new CombustionEngine(container, data.EngineData))
-				.AddAuxiliaries(container, data);
+			powertrain.AddComponent(new CombustionEngine(container, data.EngineData)).AddAuxiliaries(container, data);
 
 			_modData.HasTorqueConverter = data.GearboxData.Type.AutomaticTransmission();
 
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs
index 28f7540235..4bc10f4004 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs
@@ -42,7 +42,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 		DistanceBased,
 		PWheel,
 		MeasuredSpeed,
-		MeasuredSpeedGear
+		MeasuredSpeedGear,
+		PTO
 	}
 
 	public class DrivingCycleData : SimulationComponentData
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/PTOTransmissionData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/PTOTransmissionData.cs
index 5eaf34933d..4ef59fd2b9 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Data/PTOTransmissionData.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/PTOTransmissionData.cs
@@ -4,5 +4,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 	{
 		public string TransmissionType;
 		public ILossMap LossMap;
+		public DrivingCycleData PTOCycle;
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/IGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/IGearbox.cs
index 498cf7abe1..565684dfa1 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/IGearbox.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/IGearbox.cs
@@ -30,11 +30,15 @@
 */
 
 using TUGraz.VectoCore.Models.Simulation.DataBus;
+using TUGraz.VectoCore.Models.SimulationComponent.Impl;
 
 namespace TUGraz.VectoCore.Models.SimulationComponent
 {
 	/// <summary>
 	/// Defines interfaces for a gearbox.
 	/// </summary>
-	public interface IGearbox : IPowerTrainComponent, IAuxOutProvider, IGearboxInfo {}
+	public interface IGearbox : IPowerTrainComponent, IAuxOutProvider, IGearboxInfo
+	{
+		PTOEngineCycleController PTOController { get; set; }
+	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs
index d3b438c429..35dbc628d4 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs
@@ -11,7 +11,8 @@ using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox;
 namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 {
 	public abstract class AbstractGearbox<TStateType> :
-		StatefulProviderComponent<TStateType, ITnOutPort, ITnInPort, ITnOutPort>, ITnOutPort, ITnInPort, IGearbox, IClutchInfo
+			StatefulProviderComponent<TStateType, ITnOutPort, ITnInPort, ITnOutPort>, ITnOutPort, ITnInPort, IGearbox,
+			IClutchInfo
 		where TStateType : GearboxState, new()
 	{
 		/// <summary>
@@ -87,6 +88,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		#endregion
 
 		public abstract bool ClutchClosed(Second absTime);
+		public PTOEngineCycleController PTOController { get; set; }
 	}
 
 	public class GearboxState : SimpleComponentState
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
index f216e777b9..7407267ad8 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
@@ -116,6 +116,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 							}
 						}
 					}
+
 					CurrentState.Response = DriveTimeInterval(absTime, dt);
 					return CurrentState.Response;
 				}
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs
index 60dd67a49f..47d2a07dcd 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs
@@ -77,6 +77,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			AbsTime = 0.SI<Second>();
 		}
 
+		protected PowertrainDrivingCycle(IVehicleContainer container) : base(container)
+		{
+			AbsTime = 0.SI<Second>();
+		}
+
 		#region ISimulationOutPort
 
 		public IResponse Request(Second absTime, Meter ds)
diff --git a/VectoCore/VectoCore/Utils/ProviderExtensions.cs b/VectoCore/VectoCore/Utils/ProviderExtensions.cs
index b640bb8d70..9cab25a445 100644
--- a/VectoCore/VectoCore/Utils/ProviderExtensions.cs
+++ b/VectoCore/VectoCore/Utils/ProviderExtensions.cs
@@ -32,6 +32,7 @@
 using System;
 using System.Collections.Generic;
 using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCore.InputData.Reader;
 using TUGraz.VectoCore.Models.Connector.Ports;
 using TUGraz.VectoCore.Models.Declaration;
 using TUGraz.VectoCore.Models.Simulation;
@@ -104,6 +105,7 @@ namespace TUGraz.VectoCore.Utils
 			if (atGbx != null) {
 				atGbx.IdleController = next.IdleController;
 			}
+
 			return next;
 		}
 
@@ -114,6 +116,7 @@ namespace TUGraz.VectoCore.Utils
 				var aux = new GearboxAuxiliary(container);
 				aux.AddConstant("PTO_TRANSM", DeclarationData.PTOTransmission.Lookup(pto.TransmissionType));
 				aux.Add("PTO_IDLE", n => pto.LossMap.GetTorqueLoss(n) * n);
+				gearbox.PTOController = new PTOEngineCycleController(container, pto.PTOCycle);
 			}
 
 			switch (data.Type) {
diff --git a/VectoCore/VectoCoreTest/Utils/MockGearbox.cs b/VectoCore/VectoCoreTest/Utils/MockGearbox.cs
index 5f69f9afdd..a604172af5 100644
--- a/VectoCore/VectoCoreTest/Utils/MockGearbox.cs
+++ b/VectoCore/VectoCoreTest/Utils/MockGearbox.cs
@@ -37,6 +37,7 @@ using TUGraz.VectoCore.Models.Simulation;
 using TUGraz.VectoCore.Models.Simulation.DataBus;
 using TUGraz.VectoCore.Models.SimulationComponent;
 using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.Models.SimulationComponent.Impl;
 using TUGraz.VectoCore.OutputData;
 
 namespace TUGraz.VectoCore.Tests.Utils
@@ -121,5 +122,7 @@ namespace TUGraz.VectoCore.Tests.Utils
 		{
 			throw new NotImplementedException();
 		}
+
+		public PTOEngineCycleController PTOController { get; set; }
 	}
 }
\ No newline at end of file
-- 
GitLab