From 4d099c5925be2eeeff9bf0a40de1ff6fb52915a4 Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Mon, 18 Jan 2016 16:57:43 +0100
Subject: [PATCH] gearbox fullload curve has only two columns

---
 .../Data/Engine/EngineFullLoadCurve.cs        | 93 ++++++++++---------
 .../SimulationComponent/Data/FullLoadCurve.cs | 36 ++++---
 2 files changed, 70 insertions(+), 59 deletions(-)

diff --git a/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs
index 5d21f7b858..5f3b04d0c7 100644
--- a/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs
+++ b/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs
@@ -16,8 +16,9 @@
 
 using System;
 using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
 using System.Data;
+using System.Diagnostics.Contracts;
+using System.Dynamic;
 using System.Linq;
 using TUGraz.VectoCore.Utils;
 
@@ -33,15 +34,53 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
 		private PerSecond _engineSpeedHi; // 70% of Pmax
 		private PerSecond _n95hSpeed; // 95% of Pmax
 
-		[Required]
+		public static EngineFullLoadCurve ReadFromFile(string fileName, bool declarationMode = false)
+		{
+			var curve = FullLoadCurve.ReadFromFile(fileName, declarationMode, true);
+			return new EngineFullLoadCurve { FullLoadEntries = curve.FullLoadEntries, PT1Data = curve.PT1Data };
+		}
+
+		public static EngineFullLoadCurve Create(DataTable data, bool declarationMode = false)
+		{
+			var curve = FullLoadCurve.Create(data, declarationMode, true);
+			return new EngineFullLoadCurve() { FullLoadEntries = curve.FullLoadEntries, PT1Data = curve.PT1Data };
+		}
+
+		public Watt FullLoadStationaryPower(PerSecond angularVelocity)
+		{
+			return Formulas.TorqueToPower(FullLoadStationaryTorque(angularVelocity), angularVelocity);
+		}
+
+		public Watt DragLoadStationaryPower(PerSecond angularVelocity)
+		{
+			Contract.Requires(angularVelocity.HasEqualUnit(new SI().Radian.Per.Second));
+			Contract.Ensures(Contract.Result<SI>().HasEqualUnit(new SI().Watt));
+
+			return Formulas.TorqueToPower(DragLoadStationaryTorque(angularVelocity), angularVelocity);
+		}
+
+
 		public CombustionEngineData EngineData { get; internal set; }
 
+
+		public Second PT1(PerSecond angularVelocity)
+		{
+			return PT1Data.Lookup(angularVelocity);
+		}
+
+
 		/// <summary>
 		///	Get the engine's preferred speed from the given full-load curve (i.e. Speed at 51% torque/speed-integral between idling and N95h.)
 		/// </summary>
 		public PerSecond PreferredSpeed
 		{
-			get { return _preferredSpeed ?? (_preferredSpeed = ComputePreferredSpeed()); }
+			get
+			{
+				if (_preferredSpeed == null) {
+					ComputePreferredSpeed();
+				}
+				return _preferredSpeed;
+			}
 		}
 
 		public PerSecond N95hSpeed
@@ -49,6 +88,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
 			get { return _n95hSpeed ?? (_n95hSpeed = FindEngineSpeedForPower(0.95 * MaxPower).Last()); }
 		}
 
+
 		public PerSecond LoSpeed
 		{
 			get { return _engineSpeedLo ?? (_engineSpeedLo = FindEngineSpeedForPower(0.55 * MaxPower).First()); }
@@ -59,6 +99,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
 			get { return _engineSpeedHi ?? (_engineSpeedHi = FindEngineSpeedForPower(0.7 * MaxPower).Last()); }
 		}
 
+
 		public NewtonMeter MaxLoadTorque
 		{
 			get { return FullLoadEntries.Max(x => x.TorqueFullLoad); }
@@ -69,44 +110,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
 			get { return FullLoadEntries.Min(x => x.TorqueDrag); }
 		}
 
-		/// <summary>
-		/// Reads the EngineFullLoadCurve from a csv file.
-		/// </summary>
-		/// <param name="fileName">Name of the file.</param>
-		/// <param name="declarationMode">if set to <c>true</c> then the file is read in declaration mode.</param>
-		public new static EngineFullLoadCurve ReadFromFile(string fileName, bool declarationMode = false)
-		{
-			var curve = FullLoadCurve.ReadFromFile(fileName, declarationMode);
-			return new EngineFullLoadCurve { FullLoadEntries = curve.FullLoadEntries, PT1Data = curve.PT1Data };
-		}
-
-		/// <summary>
-		/// Creates the FullLoadCurve from a datatable.
-		/// </summary>
-		/// <param name="data">The data.</param>
-		/// <param name="declarationMode">if set to <c>true</c> then the file is read in declaration mode.</param>
-		public new static EngineFullLoadCurve Create(DataTable data, bool declarationMode = false)
-		{
-			var curve = FullLoadCurve.Create(data, declarationMode);
-			return new EngineFullLoadCurve() { FullLoadEntries = curve.FullLoadEntries, PT1Data = curve.PT1Data };
-		}
-
-		public Watt FullLoadStationaryPower(PerSecond angularVelocity)
-		{
-			return Formulas.TorqueToPower(FullLoadStationaryTorque(angularVelocity), angularVelocity);
-		}
-
-		public Watt DragLoadStationaryPower(PerSecond angularVelocity)
-		{
-			return DragLoadStationaryTorque(angularVelocity) * angularVelocity;
-		}
-
-		public Second PT1(PerSecond angularVelocity)
-		{
-			return PT1Data.Lookup(angularVelocity);
-		}
 
-		private PerSecond ComputePreferredSpeed()
+		private void ComputePreferredSpeed()
 		{
 			var maxArea = ComputeArea(EngineData.IdleSpeed, N95hSpeed);
 
@@ -116,12 +121,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
 				var additionalArea = ComputeArea(FullLoadEntries[idx - 1].EngineSpeed, FullLoadEntries[idx].EngineSpeed);
 				if (area + additionalArea > 0.51 * maxArea) {
 					var deltaArea = 0.51 * maxArea - area;
-					return ComputeEngineSpeedForSegmentArea(FullLoadEntries[idx - 1], FullLoadEntries[idx], deltaArea);
+					_preferredSpeed = ComputeEngineSpeedForSegmentArea(FullLoadEntries[idx - 1], FullLoadEntries[idx], deltaArea);
+					return;
 				}
 				area += additionalArea;
 			}
 			Log.Warn("Could not compute preferred speed, check FullLoadCurve! N95h: {0}, maxArea: {1}", N95hSpeed, maxArea);
-			return null;
 		}
 
 		private PerSecond ComputeEngineSpeedForSegmentArea(FullLoadCurveEntry p1, FullLoadCurveEntry p2, Watt area)
@@ -145,7 +150,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
 			return retVal.First(x => x >= p1.EngineSpeed && x <= p2.EngineSpeed).SI<PerSecond>();
 		}
 
-		private IEnumerable<PerSecond> FindEngineSpeedForPower(Watt power)
+		private List<PerSecond> FindEngineSpeedForPower(Watt power)
 		{
 			var retVal = new List<PerSecond>();
 			for (var idx = 1; idx < FullLoadEntries.Count; idx++) {
@@ -156,7 +161,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
 			return retVal;
 		}
 
-		private IEnumerable<PerSecond> FindEngineSpeedForPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2, Watt power)
+		private List<PerSecond> FindEngineSpeedForPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2, Watt power)
 		{
 			var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed);
 			var d = p2.TorqueFullLoad - k * p2.EngineSpeed;
diff --git a/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs
index 40832e2e42..9fe9f82d58 100644
--- a/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs
+++ b/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs
@@ -53,21 +53,27 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 			get { return _maxPower ?? ComputeRatedSpeed().Item2; }
 		}
 
-		public static FullLoadCurve ReadFromFile(string fileName, bool declarationMode = false)
+		public static FullLoadCurve ReadFromFile(string fileName, bool declarationMode = false, bool engineFld = false)
 		{
 			try {
 				var data = VectoCSVFile.Read(fileName);
-				return Create(data, declarationMode);
+				return Create(data, declarationMode, engineFld);
 			} catch (Exception ex) {
 				throw new VectoException("ERROR while reading FullLoadCurve File: " + ex.Message);
 			}
 		}
 
 
-		public static FullLoadCurve Create(DataTable data, bool declarationMode = false)
+		public static FullLoadCurve Create(DataTable data, bool declarationMode = false, bool engineFld = false)
 		{
-			if (data.Columns.Count < 3) {
-				throw new VectoException("FullLoadCurve Data File must consist of at least 3 columns.");
+			if (engineFld) {
+				if (data.Columns.Count < 3) {
+					throw new VectoException("Engine FullLoadCurve Data File must consist of at least 3 columns.");
+				}
+			} else {
+				if (data.Columns.Count < 2) {
+					throw new VectoException("Gearbox FullLoadCurve Data File must consist of at least 2 columns.");
+				}
 			}
 
 			if (data.Rows.Count < 2) {
@@ -76,8 +82,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 			}
 
 			List<FullLoadCurveEntry> entriesFld;
-			if (HeaderIsValid(data.Columns)) {
-				entriesFld = CreateFromColumnNames(data);
+			if (HeaderIsValid(data.Columns, engineFld)) {
+				entriesFld = CreateFromColumnNames(data, engineFld);
 			} else {
 				Logger<FullLoadCurve>().Warn(
 					"FullLoadCurve: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: '{3}'. Falling back to column index.",
@@ -85,7 +91,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 					Fields.TorqueDrag,
 					string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName)));
 
-				entriesFld = CreateFromColumnIndizes(data);
+				entriesFld = CreateFromColumnIndizes(data, engineFld);
 			}
 
 			LookupData<PerSecond, Second> tmp;
@@ -98,30 +104,30 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 			return new FullLoadCurve { FullLoadEntries = entriesFld, PT1Data = tmp };
 		}
 
-		private static bool HeaderIsValid(DataColumnCollection columns)
+		private static bool HeaderIsValid(DataColumnCollection columns, bool engineFld)
 		{
 			return columns.Contains(Fields.EngineSpeed)
-					&& columns.Contains(Fields.TorqueDrag)
-					&& columns.Contains(Fields.TorqueFullLoad);
+					&& columns.Contains(Fields.TorqueFullLoad)
+					&& (!engineFld || columns.Contains(Fields.TorqueDrag));
 		}
 
-		private static List<FullLoadCurveEntry> CreateFromColumnNames(DataTable data)
+		private static List<FullLoadCurveEntry> CreateFromColumnNames(DataTable data, bool engineFld)
 		{
 			return (from DataRow row in data.Rows
 				select new FullLoadCurveEntry {
 					EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(),
 					TorqueFullLoad = row.ParseDouble(Fields.TorqueFullLoad).SI<NewtonMeter>(),
-					TorqueDrag = row.ParseDouble(Fields.TorqueDrag).SI<NewtonMeter>()
+					TorqueDrag = (engineFld ? row.ParseDouble(Fields.TorqueDrag).SI<NewtonMeter>() : null)
 				}).ToList();
 		}
 
-		private static List<FullLoadCurveEntry> CreateFromColumnIndizes(DataTable data)
+		private static List<FullLoadCurveEntry> CreateFromColumnIndizes(DataTable data, bool engineFld)
 		{
 			return (from DataRow row in data.Rows
 				select new FullLoadCurveEntry {
 					EngineSpeed = row.ParseDouble(0).RPMtoRad(),
 					TorqueFullLoad = row.ParseDouble(1).SI<NewtonMeter>(),
-					TorqueDrag = row.ParseDouble(2).SI<NewtonMeter>()
+					TorqueDrag = (engineFld ? row.ParseDouble(2).SI<NewtonMeter>() : null)
 				}).ToList();
 		}
 
-- 
GitLab