From ce8b38add50b47e482a1ee00ec15107dee85411a Mon Sep 17 00:00:00 2001
From: Michael Krisper <michael.krisper@tugraz.at>
Date: Tue, 31 May 2016 13:22:30 +0200
Subject: [PATCH] gear calculation in 1Hz mode

---
 .../Utils/EnumberableExtensionMethods.cs      | 20 +++++++
 .../Models/Simulation/Data/ModalResult.cs     |  3 +-
 .../OutputData/ModalDataContainer.cs          | 54 +++++++++++--------
 .../Utils/DictionaryExtensionMethods.cs       | 12 ++++-
 VectoCore/VectoCore/Utils/SwitchExtension.cs  |  6 +++
 5 files changed, 69 insertions(+), 26 deletions(-)

diff --git a/VectoCommon/VectoCommon/Utils/EnumberableExtensionMethods.cs b/VectoCommon/VectoCommon/Utils/EnumberableExtensionMethods.cs
index e201aff1d9..d60a984f40 100644
--- a/VectoCommon/VectoCommon/Utils/EnumberableExtensionMethods.cs
+++ b/VectoCommon/VectoCommon/Utils/EnumberableExtensionMethods.cs
@@ -189,6 +189,26 @@ namespace TUGraz.VectoCommon.Utils
 			}
 		}
 
+		public static TSource MaxBy<TSource>(this IEnumerable<TSource> source,
+			Func<TSource, IComparable> projectionToComparable)
+		{
+			using (var e = source.GetEnumerator()) {
+				if (!e.MoveNext()) {
+					throw new InvalidOperationException("Sequence is empty.");
+				}
+				var max = e.Current;
+				var maxProjection = projectionToComparable(e.Current);
+
+				while (e.MoveNext()) {
+					var currentProjection = projectionToComparable(e.Current);
+					if (currentProjection.CompareTo(maxProjection) > 0) {
+						max = e.Current;
+						maxProjection = currentProjection;
+					}
+				}
+				return max;
+			}
+		}
 
 		public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> source,
 			Func<TSource, TSource, TResult> resultSelector)
diff --git a/VectoCore/VectoCore/Models/Simulation/Data/ModalResult.cs b/VectoCore/VectoCore/Models/Simulation/Data/ModalResult.cs
index 4c98903fd6..912f7cad86 100644
--- a/VectoCore/VectoCore/Models/Simulation/Data/ModalResult.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Data/ModalResult.cs
@@ -53,7 +53,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Data
 			public const string ShowUnit = "showUnit";
 		}
 
-		protected ModalResults(SerializationInfo info, StreamingContext context) : base(info, context){}
+		protected ModalResults(SerializationInfo info, StreamingContext context) : base(info, context) {}
 
 		public ModalResults()
 		{
@@ -332,7 +332,6 @@ namespace TUGraz.VectoCore.Models.Simulation.Data
 
 		[ModalResultField(typeof(SI), name: "ds [m]")] simulationDistance,
 
-
 		[ModalResultField(typeof(double), caption: "AA_NonSmartAlternatorsEfficiency [%]")] AA_NonSmartAlternatorsEfficiency,
 		[ModalResultField(typeof(SI), caption: "AA_SmartIdleCurrent_Amps [A]")] AA_SmartIdleCurrent_Amps,
 		[ModalResultField(typeof(double), caption: "AA_SmartIdleAlternatorsEfficiency [%]")] AA_SmartIdleAlternatorsEfficiency,
diff --git a/VectoCore/VectoCore/OutputData/ModalDataContainer.cs b/VectoCore/VectoCore/OutputData/ModalDataContainer.cs
index 15e38a591d..c994b0f011 100644
--- a/VectoCore/VectoCore/OutputData/ModalDataContainer.cs
+++ b/VectoCore/VectoCore/OutputData/ModalDataContainer.cs
@@ -271,27 +271,31 @@ namespace TUGraz.VectoCore.OutputData
 				var remainingDt = 0.SI<Second>();
 
 				object[] remainingRow = null;
+				var gearsList = new Dictionary<object, Second>(3);
 
 				foreach (DataRow row in data.Rows) {
 					var currentDt = row.Field<Second>((int)ModalResultField.simulationInterval);
 
-					// if remaining + current >= 1: split current row and add remaining row.
-					// 1) take full remaining row
-					// 2) split current row on difference to next full second
-					// 3) continue with remaining time on current row
+					// if current + remaining time >= 1 second: take remaining row and split up currentRow to fill up 1 second.
 					if (remainingDt > 0 && remainingDt + currentDt >= 1) {
 						var diffDt = 1.SI<Second>() - remainingDt;
 						var r = results.NewRow();
+
+						var gear = row[(int)ModalResultField.Gear];
+						gearsList[gear] = gearsList.GetValueOrZero(gear) + diffDt;
+
 						r.ItemArray = AddRow(remainingRow, MultiplyRow(row.ItemArray, diffDt));
 						absTime += diffDt;
 						r[(int)ModalResultField.time] = absTime;
 						r[(int)ModalResultField.simulationInterval] = 1.SI<Second>();
+						r[(int)ModalResultField.Gear] = gearsList.MaxBy(kv => kv.Value).Key;
+						gearsList.Clear();
 						results.Rows.Add(r);
 						currentDt = VectoMath.Max(remainingDt + currentDt - 1.SI<Second>(), 0.SI<Second>());
 						remainingDt = 0.SI<Second>();
 					}
 
-					// split current Row until dt < 1
+					// if current row still longer than 1 second: split it to 1 second slices until it is < 1 second
 					while (currentDt >= 1) {
 						currentDt = currentDt - 1.SI<Second>();
 						var r = results.NewRow();
@@ -302,49 +306,55 @@ namespace TUGraz.VectoCore.OutputData
 						results.Rows.Add(r);
 					}
 
-					// normalize rest of the remaining row if dt > 0 for summation of next row
+					// if the there still is something left in current row: add the weighted values to remainder-buffer
 					if (currentDt > 0) {
-						if (remainingDt > 0)
-							remainingRow = AddRow(remainingRow, MultiplyRow(row.ItemArray, currentDt));
-						else
-							remainingRow = MultiplyRow(row.ItemArray, currentDt);
+						var gear = row[(int)ModalResultField.Gear];
+						gearsList[gear] = gearsList.GetValueOrZero(gear) + currentDt;
+
+						remainingRow = AddRow(remainingRow, MultiplyRow(row.ItemArray, currentDt));
 						remainingDt += currentDt;
 						absTime += currentDt;
 					} else {
 						remainingRow = null;
 						remainingDt = 0.SI<Second>();
+						gearsList.Clear();
 					}
 				}
 
 				// if last row was not enough to full second: take last row as whole second
-				if (remainingDt >= 0) {
+				if (remainingDt > 0) {
 					var r = results.NewRow();
-					r.ItemArray = MultiplyRow(remainingRow, 1 / remainingDt);
+					r.ItemArray = remainingRow;
 					r[(int)ModalResultField.time] = VectoMath.Ceiling(absTime);
 					r[(int)ModalResultField.simulationInterval] = 1.SI<Second>();
+					r[(int)ModalResultField.Gear] = gearsList.MaxBy(kv => kv.Value).Key;
 					results.Rows.Add(r);
 				}
 
 				return results;
 			}
 
-			private static object[] MultiplyRow(IEnumerable<object> row, SI dt)
+			private static IEnumerable<object> MultiplyRow(IEnumerable<object> row, SI dt)
 			{
 				return row.Select(val => {
-					if (val is SI) {
-						val = (val as SI) * dt.Value();
-					} else
-						val.Switch()
-							.Case<int>(i => val = i * dt.Value())
-							.Case<double>(d => val = d * dt.Value())
-							.Case<float>(f => val = f * dt.Value())
-							.Case<uint>(ui => val = ui * dt.Value());
+					val.Switch()
+						.Case<SI>(si => val = si * dt.Value())
+						.Case<int>(i => val = i * dt.Value())
+						.Case<double>(d => val = d * dt.Value())
+						.Case<float>(f => val = f * dt.Value())
+						.Case<uint>(ui => val = ui * dt.Value());
 					return val;
-				}).ToArray();
+				});
 			}
 
 			private static object[] AddRow(IEnumerable<object> row, IEnumerable<object> addRow)
 			{
+				if (row == null) {
+					return addRow.ToArray();
+				}
+				if (addRow == null) {
+					return row.ToArray();
+				}
 				return row.ZipAll(addRow, (val, addVal) => {
 					val.Switch()
 						.Case<SI>(si => val = si + (SI)addVal)
diff --git a/VectoCore/VectoCore/Utils/DictionaryExtensionMethods.cs b/VectoCore/VectoCore/Utils/DictionaryExtensionMethods.cs
index 5b901e91ed..f32c59dd05 100644
--- a/VectoCore/VectoCore/Utils/DictionaryExtensionMethods.cs
+++ b/VectoCore/VectoCore/Utils/DictionaryExtensionMethods.cs
@@ -31,15 +31,23 @@
 
 using System;
 using System.Collections.Generic;
+using TUGraz.VectoCommon.Utils;
 
 namespace TUGraz.VectoCore.Utils
 {
 	internal static class DictionaryExtensionMethods
 	{
-		public static object GetValueOrNull<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,TKey key)
+		public static object GetValueOrNull<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
 		{
 			TValue value;
 			return dictionary.TryGetValue(key, out value) ? (object)value : DBNull.Value;
 		}
+
+		public static TValue GetValueOrZero<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
+			where TValue : SIBase<TValue>
+		{
+			TValue value;
+			return dictionary.TryGetValue(key, out value) ? value : 0.SI<TValue>();
+		}
 	}
-}
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Utils/SwitchExtension.cs b/VectoCore/VectoCore/Utils/SwitchExtension.cs
index 936dd629dc..be4d29ad28 100644
--- a/VectoCore/VectoCore/Utils/SwitchExtension.cs
+++ b/VectoCore/VectoCore/Utils/SwitchExtension.cs
@@ -31,6 +31,7 @@
 
 using System;
 using System.Diagnostics;
+using TUGraz.VectoCommon.Utils;
 
 namespace TUGraz.VectoCore.Utils
 {
@@ -120,5 +121,10 @@ namespace TUGraz.VectoCore.Utils
 				action(_value);
 			}
 		}
+
+		public Switch<T> Case(Func<object, bool> action, Func<object, SI> func)
+		{
+			throw new NotImplementedException();
+		}
 	}
 }
\ No newline at end of file
-- 
GitLab