From 339f2c96bfa11aeb6c195ace8a632bb3a78daf98 Mon Sep 17 00:00:00 2001
From: Michael Krisper <michael.krisper@tugraz.at>
Date: Sat, 11 Apr 2015 00:42:57 +0200
Subject: [PATCH] better si units (operators, easier generic typing)

---
 .../Data/CombustionEngineData.cs              |   5 +-
 .../Data/DrivingCycleData.cs                  | 816 +++++++++---------
 .../Data/Engine/FuelConsumptionMap.cs         | 327 ++++---
 .../Data/Engine/FullLoadCurve.cs              |   8 +-
 .../Impl/CombustionEngine.cs                  |  12 +-
 .../Impl/EngineOnlyAuxiliary.cs               |   2 +-
 .../Impl/TimeBasedDrivingCycle.cs             |   2 +-
 VectoCore/Utils/DoubleExtensionMethods.cs     | 109 +--
 VectoCore/Utils/Formulas.cs                   |  50 +-
 VectoCore/Utils/SI.cs                         | 126 ++-
 .../Models/Simulation/DrivingCycleTests.cs    |   2 +-
 .../FuelConsumptionMapTest.cs                 |  68 +-
 VectoCoreTest/Utils/SITest.cs                 |  98 +--
 13 files changed, 873 insertions(+), 752 deletions(-)

diff --git a/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs b/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs
index 63ebdcee2a..0bbb7cbc80 100644
--- a/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs
+++ b/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs
@@ -77,7 +77,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
         /// </summary>
         public RadianPerSecond IdleSpeed
         {
-            get { return _data.Body.IdleSpeed.SI().Rounds.Per.Minute.To<RadianPerSecond>(); }
+            get { return _data.Body.IdleSpeed.RPMtoRad(); }
             protected set { _data.Body.IdleSpeed = (double) value.To().Rounds.Per.Minute; }
         }
 
@@ -115,7 +115,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
         {
             get
             {
-                return _data.Body.WHTCMotorway.SI().Gramm.Per.Kilo.Watt.Hour.To().Kilo.Gramm.Per.Watt.Second.Value();
+                return
+                    _data.Body.WHTCMotorway.SI().Gramm.Per.Kilo.Watt.Hour.To().Kilo.Gramm.Per.Watt.Second.Value();
             }
             protected set { _data.Body.WHTCMotorway = (double) value.To().Gramm.Per.Kilo.Watt.Hour; }
         }
diff --git a/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs b/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs
index 46396270db..60cd5cf6b4 100644
--- a/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs
+++ b/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs
@@ -8,403 +8,421 @@ using TUGraz.VectoCore.Utils;
 
 namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 {
-	public class DrivingCycleData : SimulationComponentData
-	{
-		public enum CycleType
-		{
-			EngineOnly,
-			TimeBased,
-			DistanceBased
-		}
-
-		public List<DrivingCycleEntry> Entries { get; set; }
-
-		public static DrivingCycleData ReadFromFileEngineOnly(string fileName)
-		{
-			return ReadFromFile(fileName, CycleType.EngineOnly);
-		}
-
-		public static DrivingCycleData ReadFromFileDistanceBased(string fileName)
-		{
-			return ReadFromFile(fileName, CycleType.DistanceBased);
-		}
-
-		public static DrivingCycleData ReadFromFileTimeBased(string fileName)
-		{
-			return ReadFromFile(fileName, CycleType.TimeBased);
-		}
-
-		public static DrivingCycleData ReadFromFile(string fileName, CycleType type)
-		{
-			var log = LogManager.GetLogger<DrivingCycleData>();
-
-			var parser = CreateDataParser(type);
-			var data = VectoCSVFile.Read(fileName);
-			var entries = parser.Parse(data).ToList();
-
-			log.Info(string.Format("Data loaded. Number of Entries: {0}", entries.Count));
-
-			var cycle = new DrivingCycleData { Entries = entries };
-			return cycle;
-		}
-
-		private static IDataParser CreateDataParser(CycleType type)
-		{
-			switch (type) {
-				case CycleType.EngineOnly:
-					return new EngineOnlyDataParser();
-				case CycleType.TimeBased:
-					return new TimeBasedDataParser();
-				case CycleType.DistanceBased:
-					return new DistanceBasedDataParser();
-				default:
-					throw new ArgumentOutOfRangeException("type");
-			}
-		}
-
-		private static class Fields
-		{
-			/// <summary>
-			///     [m]	Travelled distance used for distance-based cycles. If t is also defined this column will be ignored.
-			/// </summary>
-			public const string Distance = "s";
-
-			/// <summary>
-			///     [s]	Used for time-based cycles. If neither this nor the distance s is defined the data will be interpreted as 1Hz.
-			/// </summary>
-			public const string Time = "t";
-
-			/// <summary>
-			///     [km/h]	Required except for Engine Only Mode calculations.
-			/// </summary>
-			public const string VehicleSpeed = "v";
-
-			/// <summary>
-			///     [%]	Optional.
-			/// </summary>
-			public const string RoadGradient = "grad";
-
-			/// <summary>
-			///     [s]	Required for distance-based cycles. Not used in time based cycles. stop defines the time the vehicle spends in
-			///     stop phases.
-			/// </summary>
-			public const string StoppingTime = "stop";
-
-			/// <summary>
-			///     [kW]	"Aux_xxx" Supply Power input for each auxiliary defined in the .vecto file , where xxx matches the ID of the
-			///     corresponding Auxiliary. ID's are not case sensitive and must not contain space or special characters.
-			/// </summary>
-			// todo: implement additional aux as dictionary!
-			public const string AuxiliarySupplyPower = "Aux_";
-
-			/// <summary>
-			///     [rpm]	If n is defined VECTO uses that instead of the calculated engine speed value.
-			/// </summary>
-			public const string EngineSpeed = "n";
-
-			/// <summary>
-			///     [-]	Gear input. Overwrites the gear shift model.
-			/// </summary>
-			public const string Gear = "gear";
-
-			/// <summary>
-			///     [kW]	This power input will be directly added to the engine power in addition to possible other auxiliaries. Also
-			///     used in Engine Only Mode.
-			/// </summary>
-			public const string AdditionalAuxPowerDemand = "Padd";
-
-			/// <summary>
-			///     [km/h]	Only required if Cross Wind Correction is set to Vair and Beta Input.
-			/// </summary>
-			public const string AirSpeedRelativeToVehicle = "vair_res";
-
-			/// <summary>
-			///     [°]	Only required if Cross Wind Correction is set to Vair and Beta Input.
-			/// </summary>
-			public const string WindYawAngle = "vair_beta";
-
-			/// <summary>
-			///     [kW]	Effective engine power at clutch. Only required in Engine Only Mode. Alternatively torque Me can be defined.
-			///     Use DRAG to define motoring operation.
-			/// </summary>
-			public const string EnginePower = "Pe";
-
-			/// <summary>
-			///     [Nm]	Effective engine torque at clutch. Only required in Engine Only Mode. Alternatively power Pe can be defined.
-			///     Use DRAG to define motoring operation.
-			/// </summary>
-			public const string EngineTorque = "Me";
-		}
-
-		public class DrivingCycleEntry
-		{
-			/// <summary>
-			///     [m]	Travelled distance used for distance-based cycles. If "t"
-			///     is also defined this column will be ignored.
-			/// </summary>
-			public double Distance { get; set; }
-
-			/// <summary>
-			///     [s]	Used for time-based cycles. If neither this nor the distance
-			///     "s" is defined the data will be interpreted as 1Hz.
-			/// </summary>
-			public double Time { get; set; }
-
-			/// <summary>
-			///     [m/s]	Required except for Engine Only Mode calculations.
-			/// </summary>
-			public MeterPerSecond VehicleSpeed { get; set; }
-
-			/// <summary>
-			///     [%]	Optional.
-			/// </summary>
-			public double RoadGradient { get; set; }
-
-			/// <summary>
-			///     [s]	Required for distance-based cycles. Not used in time based
-			///     cycles. "stop" defines the time the vehicle spends in stop phases.
-			/// </summary>
-			public double StoppingTime { get; set; }
-
-			/// <summary>
-			///     [W]	Supply Power input for each auxiliary defined in the
-			///     .vecto file where xxx matches the ID of the corresponding
-			///     Auxiliary. ID's are not case sensitive and must not contain
-			///     space or special characters.
-			/// </summary>
-			public Dictionary<string, Watt> AuxiliarySupplyPower { get; set; }
-
-			/// <summary>
-			///     [rad/s]	If "n" is defined VECTO uses that instead of the
-			///     calculated engine speed value.
-			/// </summary>
-			public RadianPerSecond EngineSpeed { get; set; }
-
-			/// <summary>
-			///     [-]	Gear input. Overwrites the gear shift model.
-			/// </summary>
-			public double Gear { get; set; }
-
-			/// <summary>
-			///     [W]	This power input will be directly added to the engine
-			///     power in addition to possible other auxiliaries. Also used in
-			///     Engine Only Mode.
-			/// </summary>
-			public Watt AdditionalAuxPowerDemand { get; set; }
-
-			/// <summary>
-			///     [m/s] Only required if Cross Wind Correction is set to Vair and Beta Input.
-			/// </summary>
-			public MeterPerSecond AirSpeedRelativeToVehicle { get; set; }
-
-			/// <summary>
-			///     [°] Only required if Cross Wind Correction is set to Vair and Beta Input.
-			/// </summary>
-			public double WindYawAngle { get; set; }
-
-			/// <summary>
-			///     [Nm] Effective engine torque at clutch. Only required in
-			///     Engine Only Mode. Alternatively power "Pe" can be defined.
-			///     Use "DRAG" to define motoring operation.
-			/// </summary>
-			public NewtonMeter EngineTorque { get; set; }
-
-			public bool Drag { get; set; }
-		}
-
-		#region DataParser
-
-		private interface IDataParser
-		{
-			IEnumerable<DrivingCycleEntry> Parse(DataTable table);
-		}
-
-		/// <summary>
-		///     Reader for Auxiliary Supply Power.
-		/// </summary>
-		private static class AuxSupplyPowerReader
-		{
-			/// <summary>
-			///     [W]. Reads Auxiliary Supply Power (defined by Fields.AuxiliarySupplyPower-Prefix).
-			/// </summary>
-			public static Dictionary<string, Watt> Read(DataRow row)
-			{
-				return row.Table.Columns.Cast<DataColumn>().
-					Where(col => col.ColumnName.StartsWith(Fields.AuxiliarySupplyPower)).
-					ToDictionary(col => col.ColumnName.Substring(Fields.AuxiliarySupplyPower.Length - 1),
-						col => row.ParseDouble(col).SI().Kilo.Watt.To<Watt>());
-			}
-		}
-
-		private class DistanceBasedDataParser : IDataParser
-		{
-			public IEnumerable<DrivingCycleEntry> Parse(DataTable table)
-			{
-				ValidateHeader(table.Columns.Cast<DataColumn>().Select(col => col.ColumnName).ToArray());
-
-				return table.Rows.Cast<DataRow>().Select(row => new DrivingCycleEntry {
-					Distance = row.ParseDouble(Fields.Distance),
-					VehicleSpeed = row.ParseDouble(Fields.VehicleSpeed).SI().Kilo.Meter.Per.Hour.To<MeterPerSecond>(),
-					RoadGradient = row.ParseDoubleOrGetDefault(Fields.RoadGradient),
-					AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.To<Watt>(),
-					EngineSpeed = row.ParseDoubleOrGetDefault(Fields.EngineSpeed).SI().Rounds.Per.Minute.To<RadianPerSecond>(),
-					Gear = row.ParseDoubleOrGetDefault(Fields.Gear),
-					AirSpeedRelativeToVehicle =
-						row.ParseDoubleOrGetDefault(Fields.AirSpeedRelativeToVehicle).SI().Kilo.Meter.Per.Hour.To<MeterPerSecond>(),
-					WindYawAngle = row.ParseDoubleOrGetDefault(Fields.WindYawAngle),
-					AuxiliarySupplyPower = AuxSupplyPowerReader.Read(row)
-				});
-			}
-
-			private static void ValidateHeader(string[] header)
-			{
-				var allowedCols = new[] {
-					Fields.Distance,
-					Fields.VehicleSpeed,
-					Fields.RoadGradient,
-					Fields.StoppingTime,
-					Fields.EngineSpeed,
-					Fields.Gear,
-					Fields.AdditionalAuxPowerDemand,
-					Fields.AirSpeedRelativeToVehicle,
-					Fields.WindYawAngle
-				};
-
-				foreach (var col in header.Where(col => !(allowedCols.Contains(col) || col.StartsWith(Fields.AuxiliarySupplyPower)))
-					) {
-					throw new VectoException(string.Format("Column '{0}' is not allowed.", col));
-				}
-
-				if (!header.Contains(Fields.VehicleSpeed)) {
-					throw new VectoException(string.Format("Column '{0}' is missing.", Fields.VehicleSpeed));
-				}
-
-				if (!header.Contains(Fields.Distance)) {
-					throw new VectoException(string.Format("Column '{0}' is missing.", Fields.Distance));
-				}
-
-				if (header.Contains(Fields.AirSpeedRelativeToVehicle) ^ header.Contains(Fields.WindYawAngle)) {
-					throw new VectoException(string.Format("Both Columns '{0}' and '{1}' must be defined, or none of them.",
-						Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle));
-				}
-			}
-		}
-
-		private class TimeBasedDataParser : IDataParser
-		{
-			public IEnumerable<DrivingCycleEntry> Parse(DataTable table)
-			{
-				ValidateHeader(table.Columns.Cast<DataColumn>().Select(col => col.ColumnName).ToArray());
-
-				var entries = table.Rows.Cast<DataRow>().Select((row, index) => new DrivingCycleEntry {
-					Time = row.ParseDoubleOrGetDefault(Fields.Time, index),
-					VehicleSpeed = row.ParseDouble(Fields.VehicleSpeed).SI().Kilo.Meter.Per.Hour.To<MeterPerSecond>(),
-					RoadGradient = row.ParseDoubleOrGetDefault(Fields.RoadGradient),
-					AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.To<Watt>(),
-					Gear = row.ParseDoubleOrGetDefault(Fields.Gear),
-					EngineSpeed = row.ParseDoubleOrGetDefault(Fields.EngineSpeed).SI().Rounds.Per.Minute.To<RadianPerSecond>(),
-					AirSpeedRelativeToVehicle =
-						row.ParseDoubleOrGetDefault(Fields.AirSpeedRelativeToVehicle).SI().Kilo.Meter.Per.Hour.To<MeterPerSecond>(),
-					WindYawAngle = row.ParseDoubleOrGetDefault(Fields.WindYawAngle),
-					AuxiliarySupplyPower = AuxSupplyPowerReader.Read(row)
-				}).ToArray();
-
-				return entries;
-			}
-
-			private static void ValidateHeader(string[] header)
-			{
-				var allowedCols = new[] {
-					Fields.Time,
-					Fields.VehicleSpeed,
-					Fields.RoadGradient,
-					Fields.EngineSpeed,
-					Fields.Gear,
-					Fields.AdditionalAuxPowerDemand,
-					Fields.AirSpeedRelativeToVehicle,
-					Fields.WindYawAngle
-				};
-
-				foreach (var col in header.Where(col => !(allowedCols.Contains(col) || col.StartsWith(Fields.AuxiliarySupplyPower)))
-					) {
-					throw new VectoException(string.Format("Column '{0}' is not allowed.", col));
-				}
-
-				if (!header.Contains(Fields.VehicleSpeed)) {
-					throw new VectoException(string.Format("Column '{0}' is missing.", Fields.VehicleSpeed));
-				}
-
-				if (header.Contains(Fields.AirSpeedRelativeToVehicle) ^ header.Contains(Fields.WindYawAngle)) {
-					throw new VectoException(string.Format("Both Columns '{0}' and '{1}' must be defined, or none of them.",
-						Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle));
-				}
-			}
-		}
-
-		private class EngineOnlyDataParser : IDataParser
-		{
-			public IEnumerable<DrivingCycleEntry> Parse(DataTable table)
-			{
-				ValidateHeader(table.Columns.Cast<DataColumn>().Select(col => col.ColumnName).ToArray());
-				var absTime = new TimeSpan(0, 0, 0);
-
-				foreach (DataRow row in table.Rows) {
-					var entry = new DrivingCycleEntry {
-						EngineSpeed = row.ParseDoubleOrGetDefault(Fields.EngineSpeed).SI().Rounds.Per.Minute.To<RadianPerSecond>(),
-						AdditionalAuxPowerDemand = row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.To<Watt>(),
-						AuxiliarySupplyPower = AuxSupplyPowerReader.Read(row)
-					};
-					if (row.Table.Columns.Contains(Fields.EngineTorque)) {
-						if (row.Field<string>(Fields.EngineTorque).Equals("<DRAG>")) {
-							entry.Drag = true;
-						} else {
-							entry.EngineTorque = row.ParseDouble(Fields.EngineTorque).SI<NewtonMeter>();
-						}
-					} else {
-						if (row.Field<string>(Fields.EnginePower).Equals("<DRAG>")) {
-							entry.Drag = true;
-						} else {
-							entry.EngineTorque = Formulas.PowerToTorque(row.ParseDouble(Fields.EnginePower).SI().Kilo.Watt.To<Watt>(),
-								entry.EngineSpeed);
-						}
-					}
-					entry.Time = absTime.TotalSeconds;
-					absTime += new TimeSpan(0, 0, 1);
-
-					yield return entry;
-				}
-			}
-
-			private static void ValidateHeader(string[] header)
-			{
-				var allowedCols = new[] {
-					Fields.EngineTorque,
-					Fields.EnginePower,
-					Fields.EngineSpeed,
-					Fields.AdditionalAuxPowerDemand
-				};
-
-				foreach (var col in header.Where(col => !allowedCols.Contains(col))) {
-					throw new VectoException(string.Format("Column '{0}' is not allowed.", col));
-				}
-
-				if (!header.Contains(Fields.EngineSpeed)) {
-					throw new VectoException(string.Format("Column '{0}' is missing.", Fields.EngineSpeed));
-				}
-
-				if (!(header.Contains(Fields.EngineTorque) || header.Contains(Fields.EnginePower))) {
-					throw new VectoException(string.Format("Columns missing: Either column '{0}' or column '{1}' must be defined.",
-						Fields.EngineTorque, Fields.EnginePower));
-				}
-
-				if (header.Contains(Fields.EngineTorque) && header.Contains(Fields.EnginePower)) {
-					LogManager.GetLogger<DrivingCycleData>()
-						.WarnFormat("Found column '{0}' and column '{1}': only column '{0}' will be used.",
-							Fields.EngineTorque, Fields.EnginePower);
-				}
-			}
-		}
-
-		#endregion
-	}
+    public class DrivingCycleData : SimulationComponentData
+    {
+        public enum CycleType
+        {
+            EngineOnly,
+            TimeBased,
+            DistanceBased
+        }
+
+        public List<DrivingCycleEntry> Entries { get; set; }
+
+        public static DrivingCycleData ReadFromFileEngineOnly(string fileName)
+        {
+            return ReadFromFile(fileName, CycleType.EngineOnly);
+        }
+
+        public static DrivingCycleData ReadFromFileDistanceBased(string fileName)
+        {
+            return ReadFromFile(fileName, CycleType.DistanceBased);
+        }
+
+        public static DrivingCycleData ReadFromFileTimeBased(string fileName)
+        {
+            return ReadFromFile(fileName, CycleType.TimeBased);
+        }
+
+        public static DrivingCycleData ReadFromFile(string fileName, CycleType type)
+        {
+            var log = LogManager.GetLogger<DrivingCycleData>();
+
+            var parser = CreateDataParser(type);
+            var data = VectoCSVFile.Read(fileName);
+            var entries = parser.Parse(data).ToList();
+
+            log.Info(string.Format("Data loaded. Number of Entries: {0}", entries.Count));
+
+            var cycle = new DrivingCycleData { Entries = entries };
+            return cycle;
+        }
+
+        private static IDataParser CreateDataParser(CycleType type)
+        {
+            switch (type) {
+                case CycleType.EngineOnly:
+                    return new EngineOnlyDataParser();
+                case CycleType.TimeBased:
+                    return new TimeBasedDataParser();
+                case CycleType.DistanceBased:
+                    return new DistanceBasedDataParser();
+                default:
+                    throw new ArgumentOutOfRangeException("type");
+            }
+        }
+
+        private static class Fields
+        {
+            /// <summary>
+            ///     [m]	Travelled distance used for distance-based cycles. If t is also defined this column will be ignored.
+            /// </summary>
+            public const string Distance = "s";
+
+            /// <summary>
+            ///     [s]	Used for time-based cycles. If neither this nor the distance s is defined the data will be interpreted as 1Hz.
+            /// </summary>
+            public const string Time = "t";
+
+            /// <summary>
+            ///     [km/h]	Required except for Engine Only Mode calculations.
+            /// </summary>
+            public const string VehicleSpeed = "v";
+
+            /// <summary>
+            ///     [%]	Optional.
+            /// </summary>
+            public const string RoadGradient = "grad";
+
+            /// <summary>
+            ///     [s]	Required for distance-based cycles. Not used in time based cycles. stop defines the time the vehicle spends in
+            ///     stop phases.
+            /// </summary>
+            public const string StoppingTime = "stop";
+
+            /// <summary>
+            ///     [kW]	"Aux_xxx" Supply Power input for each auxiliary defined in the .vecto file , where xxx matches the ID of the
+            ///     corresponding Auxiliary. ID's are not case sensitive and must not contain space or special characters.
+            /// </summary>
+            // todo: implement additional aux as dictionary!
+            public const string AuxiliarySupplyPower = "Aux_";
+
+            /// <summary>
+            ///     [rpm]	If n is defined VECTO uses that instead of the calculated engine speed value.
+            /// </summary>
+            public const string EngineSpeed = "n";
+
+            /// <summary>
+            ///     [-]	Gear input. Overwrites the gear shift model.
+            /// </summary>
+            public const string Gear = "gear";
+
+            /// <summary>
+            ///     [kW]	This power input will be directly added to the engine power in addition to possible other auxiliaries. Also
+            ///     used in Engine Only Mode.
+            /// </summary>
+            public const string AdditionalAuxPowerDemand = "Padd";
+
+            /// <summary>
+            ///     [km/h]	Only required if Cross Wind Correction is set to Vair and Beta Input.
+            /// </summary>
+            public const string AirSpeedRelativeToVehicle = "vair_res";
+
+            /// <summary>
+            ///     [°]	Only required if Cross Wind Correction is set to Vair and Beta Input.
+            /// </summary>
+            public const string WindYawAngle = "vair_beta";
+
+            /// <summary>
+            ///     [kW]	Effective engine power at clutch. Only required in Engine Only Mode. Alternatively torque Me can be defined.
+            ///     Use DRAG to define motoring operation.
+            /// </summary>
+            public const string EnginePower = "Pe";
+
+            /// <summary>
+            ///     [Nm]	Effective engine torque at clutch. Only required in Engine Only Mode. Alternatively power Pe can be defined.
+            ///     Use DRAG to define motoring operation.
+            /// </summary>
+            public const string EngineTorque = "Me";
+        }
+
+        public class DrivingCycleEntry
+        {
+            /// <summary>
+            ///     [m]	Travelled distance used for distance-based cycles. If "t"
+            ///     is also defined this column will be ignored.
+            /// </summary>
+            public double Distance { get; set; }
+
+            /// <summary>
+            ///     [s]	Used for time-based cycles. If neither this nor the distance
+            ///     "s" is defined the data will be interpreted as 1Hz.
+            /// </summary>
+            public double Time { get; set; }
+
+            /// <summary>
+            ///     [m/s]	Required except for Engine Only Mode calculations.
+            /// </summary>
+            public MeterPerSecond VehicleSpeed { get; set; }
+
+            /// <summary>
+            ///     [%]	Optional.
+            /// </summary>
+            public double RoadGradient { get; set; }
+
+            /// <summary>
+            ///     [s]	Required for distance-based cycles. Not used in time based
+            ///     cycles. "stop" defines the time the vehicle spends in stop phases.
+            /// </summary>
+            public double StoppingTime { get; set; }
+
+            /// <summary>
+            ///     [W]	Supply Power input for each auxiliary defined in the
+            ///     .vecto file where xxx matches the ID of the corresponding
+            ///     Auxiliary. ID's are not case sensitive and must not contain
+            ///     space or special characters.
+            /// </summary>
+            public Dictionary<string, Watt> AuxiliarySupplyPower { get; set; }
+
+            /// <summary>
+            ///     [rad/s]	If "n" is defined VECTO uses that instead of the
+            ///     calculated engine speed value.
+            /// </summary>
+            public RadianPerSecond EngineSpeed { get; set; }
+
+            /// <summary>
+            ///     [-]	Gear input. Overwrites the gear shift model.
+            /// </summary>
+            public double Gear { get; set; }
+
+            /// <summary>
+            ///     [W]	This power input will be directly added to the engine
+            ///     power in addition to possible other auxiliaries. Also used in
+            ///     Engine Only Mode.
+            /// </summary>
+            public Watt AdditionalAuxPowerDemand { get; set; }
+
+            /// <summary>
+            ///     [m/s] Only required if Cross Wind Correction is set to Vair and Beta Input.
+            /// </summary>
+            public MeterPerSecond AirSpeedRelativeToVehicle { get; set; }
+
+            /// <summary>
+            ///     [°] Only required if Cross Wind Correction is set to Vair and Beta Input.
+            /// </summary>
+            public double WindYawAngle { get; set; }
+
+            /// <summary>
+            ///     [Nm] Effective engine torque at clutch. Only required in
+            ///     Engine Only Mode. Alternatively power "Pe" can be defined.
+            ///     Use "DRAG" to define motoring operation.
+            /// </summary>
+            public NewtonMeter EngineTorque { get; set; }
+
+            public bool Drag { get; set; }
+        }
+
+        #region DataParser
+
+        private interface IDataParser
+        {
+            IEnumerable<DrivingCycleEntry> Parse(DataTable table);
+        }
+
+        /// <summary>
+        ///     Reader for Auxiliary Supply Power.
+        /// </summary>
+        private static class AuxSupplyPowerReader
+        {
+            /// <summary>
+            ///     [W]. Reads Auxiliary Supply Power (defined by Fields.AuxiliarySupplyPower-Prefix).
+            /// </summary>
+            public static Dictionary<string, Watt> Read(DataRow row)
+            {
+                return row.Table.Columns.Cast<DataColumn>().
+                    Where(col => col.ColumnName.StartsWith(Fields.AuxiliarySupplyPower)).
+                    ToDictionary(col => col.ColumnName.Substring(Fields.AuxiliarySupplyPower.Length - 1),
+                        col => row.ParseDouble(col).SI().Kilo.Watt.As<Watt>());
+            }
+        }
+
+        private class DistanceBasedDataParser : IDataParser
+        {
+            public IEnumerable<DrivingCycleEntry> Parse(DataTable table)
+            {
+                ValidateHeader(table.Columns.Cast<DataColumn>().Select(col => col.ColumnName).ToArray());
+
+                return table.Rows.Cast<DataRow>().Select(row => new DrivingCycleEntry {
+                    Distance = row.ParseDouble(Fields.Distance),
+                    VehicleSpeed = row.ParseDouble(Fields.VehicleSpeed).SI().Kilo.Meter.Per.Hour.As<MeterPerSecond>(),
+                    RoadGradient = row.ParseDoubleOrGetDefault(Fields.RoadGradient),
+                    AdditionalAuxPowerDemand =
+                        row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.As<Watt>(),
+                    EngineSpeed =
+                        row.ParseDoubleOrGetDefault(Fields.EngineSpeed).SI().Rounds.Per.Minute.As<RadianPerSecond>(),
+                    Gear = row.ParseDoubleOrGetDefault(Fields.Gear),
+                    AirSpeedRelativeToVehicle =
+                        row.ParseDoubleOrGetDefault(Fields.AirSpeedRelativeToVehicle)
+                            .SI()
+                            .Kilo.Meter.Per.Hour.As<MeterPerSecond>(),
+                    WindYawAngle = row.ParseDoubleOrGetDefault(Fields.WindYawAngle),
+                    AuxiliarySupplyPower = AuxSupplyPowerReader.Read(row)
+                });
+            }
+
+            private static void ValidateHeader(string[] header)
+            {
+                var allowedCols = new[] {
+                    Fields.Distance,
+                    Fields.VehicleSpeed,
+                    Fields.RoadGradient,
+                    Fields.StoppingTime,
+                    Fields.EngineSpeed,
+                    Fields.Gear,
+                    Fields.AdditionalAuxPowerDemand,
+                    Fields.AirSpeedRelativeToVehicle,
+                    Fields.WindYawAngle
+                };
+
+                foreach (
+                    var col in
+                        header.Where(col => !(allowedCols.Contains(col) || col.StartsWith(Fields.AuxiliarySupplyPower)))
+                    ) {
+                    throw new VectoException(string.Format("Column '{0}' is not allowed.", col));
+                }
+
+                if (!header.Contains(Fields.VehicleSpeed)) {
+                    throw new VectoException(string.Format("Column '{0}' is missing.", Fields.VehicleSpeed));
+                }
+
+                if (!header.Contains(Fields.Distance)) {
+                    throw new VectoException(string.Format("Column '{0}' is missing.", Fields.Distance));
+                }
+
+                if (header.Contains(Fields.AirSpeedRelativeToVehicle) ^ header.Contains(Fields.WindYawAngle)) {
+                    throw new VectoException(
+                        string.Format("Both Columns '{0}' and '{1}' must be defined, or none of them.",
+                            Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle));
+                }
+            }
+        }
+
+        private class TimeBasedDataParser : IDataParser
+        {
+            public IEnumerable<DrivingCycleEntry> Parse(DataTable table)
+            {
+                ValidateHeader(table.Columns.Cast<DataColumn>().Select(col => col.ColumnName).ToArray());
+
+                var entries = table.Rows.Cast<DataRow>().Select((row, index) => new DrivingCycleEntry {
+                    Time = row.ParseDoubleOrGetDefault(Fields.Time, index),
+                    VehicleSpeed = row.ParseDouble(Fields.VehicleSpeed).SI().Kilo.Meter.Per.Hour.As<MeterPerSecond>(),
+                    RoadGradient = row.ParseDoubleOrGetDefault(Fields.RoadGradient),
+                    AdditionalAuxPowerDemand =
+                        row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.As<Watt>(),
+                    Gear = row.ParseDoubleOrGetDefault(Fields.Gear),
+                    EngineSpeed =
+                        row.ParseDoubleOrGetDefault(Fields.EngineSpeed).SI().Rounds.Per.Minute.As<RadianPerSecond>(),
+                    AirSpeedRelativeToVehicle =
+                        row.ParseDoubleOrGetDefault(Fields.AirSpeedRelativeToVehicle)
+                            .SI()
+                            .Kilo.Meter.Per.Hour.As<MeterPerSecond>(),
+                    WindYawAngle = row.ParseDoubleOrGetDefault(Fields.WindYawAngle),
+                    AuxiliarySupplyPower = AuxSupplyPowerReader.Read(row)
+                }).ToArray();
+
+                return entries;
+            }
+
+            private static void ValidateHeader(string[] header)
+            {
+                var allowedCols = new[] {
+                    Fields.Time,
+                    Fields.VehicleSpeed,
+                    Fields.RoadGradient,
+                    Fields.EngineSpeed,
+                    Fields.Gear,
+                    Fields.AdditionalAuxPowerDemand,
+                    Fields.AirSpeedRelativeToVehicle,
+                    Fields.WindYawAngle
+                };
+
+                foreach (
+                    var col in
+                        header.Where(col => !(allowedCols.Contains(col) || col.StartsWith(Fields.AuxiliarySupplyPower)))
+                    ) {
+                    throw new VectoException(string.Format("Column '{0}' is not allowed.", col));
+                }
+
+                if (!header.Contains(Fields.VehicleSpeed)) {
+                    throw new VectoException(string.Format("Column '{0}' is missing.", Fields.VehicleSpeed));
+                }
+
+                if (header.Contains(Fields.AirSpeedRelativeToVehicle) ^ header.Contains(Fields.WindYawAngle)) {
+                    throw new VectoException(
+                        string.Format("Both Columns '{0}' and '{1}' must be defined, or none of them.",
+                            Fields.AirSpeedRelativeToVehicle, Fields.WindYawAngle));
+                }
+            }
+        }
+
+        private class EngineOnlyDataParser : IDataParser
+        {
+            public IEnumerable<DrivingCycleEntry> Parse(DataTable table)
+            {
+                ValidateHeader(table.Columns.Cast<DataColumn>().Select(col => col.ColumnName).ToArray());
+                var absTime = new TimeSpan(0, 0, 0);
+
+                foreach (DataRow row in table.Rows) {
+                    var entry = new DrivingCycleEntry {
+                        EngineSpeed =
+                            row.ParseDoubleOrGetDefault(Fields.EngineSpeed).SI().Rounds.Per.Minute.As<RadianPerSecond>(),
+                        AdditionalAuxPowerDemand =
+                            row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.As<Watt>(),
+                        AuxiliarySupplyPower = AuxSupplyPowerReader.Read(row)
+                    };
+                    if (row.Table.Columns.Contains(Fields.EngineTorque)) {
+                        if (row.Field<string>(Fields.EngineTorque).Equals("<DRAG>")) {
+                            entry.Drag = true;
+                        } else {
+                            entry.EngineTorque = row.ParseDouble(Fields.EngineTorque).SI<NewtonMeter>();
+                        }
+                    } else {
+                        if (row.Field<string>(Fields.EnginePower).Equals("<DRAG>")) {
+                            entry.Drag = true;
+                        } else {
+                            entry.EngineTorque =
+                                Formulas.PowerToTorque(row.ParseDouble(Fields.EnginePower).SI().Kilo.Watt.As<Watt>(),
+                                    entry.EngineSpeed);
+                        }
+                    }
+                    entry.Time = absTime.TotalSeconds;
+                    absTime += new TimeSpan(0, 0, 1);
+
+                    yield return entry;
+                }
+            }
+
+            private static void ValidateHeader(string[] header)
+            {
+                var allowedCols = new[] {
+                    Fields.EngineTorque,
+                    Fields.EnginePower,
+                    Fields.EngineSpeed,
+                    Fields.AdditionalAuxPowerDemand
+                };
+
+                foreach (var col in header.Where(col => !allowedCols.Contains(col))) {
+                    throw new VectoException(string.Format("Column '{0}' is not allowed.", col));
+                }
+
+                if (!header.Contains(Fields.EngineSpeed)) {
+                    throw new VectoException(string.Format("Column '{0}' is missing.", Fields.EngineSpeed));
+                }
+
+                if (!(header.Contains(Fields.EngineTorque) || header.Contains(Fields.EnginePower))) {
+                    throw new VectoException(
+                        string.Format("Columns missing: Either column '{0}' or column '{1}' must be defined.",
+                            Fields.EngineTorque, Fields.EnginePower));
+                }
+
+                if (header.Contains(Fields.EngineTorque) && header.Contains(Fields.EnginePower)) {
+                    LogManager.GetLogger<DrivingCycleData>()
+                        .WarnFormat("Found column '{0}' and column '{1}': only column '{0}' will be used.",
+                            Fields.EngineTorque, Fields.EnginePower);
+                }
+            }
+        }
+
+        #endregion
+    }
 }
\ No newline at end of file
diff --git a/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMap.cs b/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMap.cs
index 52163fc134..572e7a78b2 100644
--- a/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMap.cs
+++ b/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMap.cs
@@ -9,168 +9,167 @@ using TUGraz.VectoCore.Utils;
 
 namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
 {
-	[JsonObject(MemberSerialization.Fields)]
-	public class FuelConsumptionMap : SimulationComponentData
-	{
-		private readonly IList<FuelConsumptionEntry> _entries = new List<FuelConsumptionEntry>();
-		private readonly DelauneyMap _fuelMap = new DelauneyMap();
-		private FuelConsumptionMap() {}
-
-		[ContractInvariantMethod]
-		private void Invariant()
-		{
-			Contract.Invariant(_entries != null);
-			Contract.Invariant(_fuelMap != null);
-		}
-
-		public static FuelConsumptionMap ReadFromFile(string fileName)
-		{
-			var fuelConsumptionMap = new FuelConsumptionMap();
-			var data = VectoCSVFile.Read(fileName);
-
-			try {
-				foreach (DataRow row in data.Rows) {
-					try {
-						var entry = new FuelConsumptionEntry {
-							EngineSpeed = row.ParseDouble(Fields.EngineSpeed).SI().Rounds.Per.Minute.To<RadianPerSecond>(),
-							Torque = row.ParseDouble(Fields.Torque).SI<NewtonMeter>(),
-							FuelConsumption = row.ParseDouble(Fields.FuelConsumption).SI().Gramm.Per.Hour.To().Kilo.Gramm.Per.Second
-						};
-
-						// todo Contract.Assert
-						if (entry.FuelConsumption < 0) {
-							throw new ArgumentOutOfRangeException("FuelConsumption", "FuelConsumption < 0 not allowed.");
-						}
-
-						fuelConsumptionMap._entries.Add(entry);
-
-						// Delauney map works only as expected, when the engineSpeed is in rpm.
-						fuelConsumptionMap._fuelMap.AddPoint((double) entry.Torque, row.ParseDouble(Fields.EngineSpeed),
-							(double) entry.FuelConsumption);
-					} catch (Exception e) {
-						throw new VectoException(string.Format("Line {0}: {1}", data.Rows.IndexOf(row), e.Message), e);
-					}
-				}
-			} catch (Exception e) {
-				throw new VectoException(string.Format("File {0}: {1}", fileName, e.Message), e);
-			}
-
-			fuelConsumptionMap._fuelMap.Triangulate();
-			return fuelConsumptionMap;
-		}
-
-		/// <summary>
-		///     [kg/s] Calculates the fuel consumption based on the given fuel map,
-		///     the engineSpeed [rad/s] and the torque [Nm].
-		/// </summary>
-		/// <param name="engineSpeed">[rad/sec]</param>
-		/// <param name="torque">[Nm]</param>
-		/// <returns>[kg/s]</returns>
-		public SI GetFuelConsumption(NewtonMeter torque, RadianPerSecond engineSpeed)
-		{
-			return _fuelMap.Interpolate((double) torque, (double) engineSpeed.To().Rounds.Per.Minute).SI().Kilo.Gramm.Per.Second;
-		}
-
-		private static class Fields
-		{
-			/// <summary>
-			///     [rpm]
-			/// </summary>
-			public const string EngineSpeed = "engine speed";
-
-			/// <summary>
-			///     [Nm]
-			/// </summary>
-			public const string Torque = "torque";
-
-			/// <summary>
-			///     [g/h]
-			/// </summary>
-			public const string FuelConsumption = "fuel consumption";
-		};
-
-		private class FuelConsumptionEntry
-		{
-			/// <summary>
-			///     engine speed [rad/s]
-			/// </summary>
-			public RadianPerSecond EngineSpeed { get; set; }
-
-			/// <summary>
-			///     Torque [Nm]
-			/// </summary>
-			public NewtonMeter Torque { get; set; }
-
-			/// <summary>
-			///     Fuel consumption [kg/s]
-			/// </summary>
-			public SI FuelConsumption { get; set; }
-
-			#region Equality members
-
-			private bool Equals(FuelConsumptionEntry other)
-			{
-				Contract.Requires(other != null);
-				return EngineSpeed.Equals(other.EngineSpeed) && Torque.Equals(other.Torque) &&
-						FuelConsumption.Equals(other.FuelConsumption);
-			}
-
-			public override bool Equals(object obj)
-			{
-				if (ReferenceEquals(null, obj)) {
-					return false;
-				}
-				if (ReferenceEquals(this, obj)) {
-					return true;
-				}
-				if (obj.GetType() != GetType()) {
-					return false;
-				}
-				return Equals((FuelConsumptionEntry) obj);
-			}
-
-			public override int GetHashCode()
-			{
-				unchecked {
-					var hashCode = EngineSpeed.GetHashCode();
-					hashCode = (hashCode * 397) ^ Torque.GetHashCode();
-					hashCode = (hashCode * 397) ^ FuelConsumption.GetHashCode();
-					return hashCode;
-				}
-			}
-
-			#endregion
-		}
-
-		#region Equality members
-
-		protected bool Equals(FuelConsumptionMap other)
-		{
-			return _entries.SequenceEqual(other._entries) && Equals(_fuelMap, other._fuelMap);
-		}
-
-		public override bool Equals(object obj)
-		{
-			if (ReferenceEquals(null, obj)) {
-				return false;
-			}
-			if (ReferenceEquals(this, obj)) {
-				return true;
-			}
-			if (obj.GetType() != GetType()) {
-				return false;
-			}
-			return Equals((FuelConsumptionMap) obj);
-		}
-
-		public override int GetHashCode()
-		{
-			unchecked {
-				return ((_entries != null ? _entries.GetHashCode() : 0) * 397) ^
-						(_fuelMap != null ? _fuelMap.GetHashCode() : 0);
-			}
-		}
-
-		#endregion
-	}
+    [JsonObject(MemberSerialization.Fields)]
+    public class FuelConsumptionMap : SimulationComponentData
+    {
+        private readonly IList<FuelConsumptionEntry> _entries = new List<FuelConsumptionEntry>();
+        private readonly DelauneyMap _fuelMap = new DelauneyMap();
+        private FuelConsumptionMap() {}
+
+        public static FuelConsumptionMap ReadFromFile(string fileName)
+        {
+            var fuelConsumptionMap = new FuelConsumptionMap();
+            var data = VectoCSVFile.Read(fileName);
+
+            try {
+                foreach (DataRow row in data.Rows) {
+                    try {
+                        var entry = new FuelConsumptionEntry {
+                            EngineSpeed =
+                                row.ParseDouble(Fields.EngineSpeed).SI().Rounds.Per.Minute.As<RadianPerSecond>(),
+                            Torque = row.ParseDouble(Fields.Torque).SI<NewtonMeter>(),
+                            FuelConsumption =
+                                row.ParseDouble(Fields.FuelConsumption).SI().Gramm.Per.Hour.To().Kilo.Gramm.Per.Second
+                        };
+
+                        // todo Contract.Assert
+                        if (entry.FuelConsumption < 0) {
+                            throw new ArgumentOutOfRangeException("FuelConsumption", "FuelConsumption < 0 not allowed.");
+                        }
+
+                        fuelConsumptionMap._entries.Add(entry);
+
+                        // Delauney map works only as expected, when the engineSpeed is in rpm.
+                        fuelConsumptionMap._fuelMap.AddPoint((double) entry.Torque, row.ParseDouble(Fields.EngineSpeed),
+                            (double) entry.FuelConsumption);
+                    } catch (Exception e) {
+                        throw new VectoException(string.Format("Line {0}: {1}", data.Rows.IndexOf(row), e.Message), e);
+                    }
+                }
+            } catch (Exception e) {
+                throw new VectoException(string.Format("File {0}: {1}", fileName, e.Message), e);
+            }
+
+            fuelConsumptionMap._fuelMap.Triangulate();
+            return fuelConsumptionMap;
+        }
+
+        /// <summary>
+        ///     [kg/s] Calculates the fuel consumption based on the given fuel map,
+        ///     the engineSpeed [rad/s] and the torque [Nm].
+        /// </summary>
+        /// <param name="engineSpeed">[rad/sec]</param>
+        /// <param name="torque">[Nm]</param>
+        /// <returns>[kg/s]</returns>
+        public SI GetFuelConsumption(NewtonMeter torque, RadianPerSecond engineSpeed)
+        {
+            // delauney map needs is initialised with rpm, therefore the engineSpeed has to be converted.
+            return
+                _fuelMap.Interpolate((double) torque, (double) engineSpeed.To().Rounds.Per.Minute)
+                    .SI()
+                    .Kilo.Gramm.Per.Second;
+        }
+
+        private static class Fields
+        {
+            /// <summary>
+            ///     [rpm]
+            /// </summary>
+            public const string EngineSpeed = "engine speed";
+
+            /// <summary>
+            ///     [Nm]
+            /// </summary>
+            public const string Torque = "torque";
+
+            /// <summary>
+            ///     [g/h]
+            /// </summary>
+            public const string FuelConsumption = "fuel consumption";
+        };
+
+        private class FuelConsumptionEntry
+        {
+            /// <summary>
+            ///     engine speed [rad/s]
+            /// </summary>
+            public RadianPerSecond EngineSpeed { get; set; }
+
+            /// <summary>
+            ///     Torque [Nm]
+            /// </summary>
+            public NewtonMeter Torque { get; set; }
+
+            /// <summary>
+            ///     Fuel consumption [kg/s]
+            /// </summary>
+            public SI FuelConsumption { get; set; }
+
+            #region Equality members
+
+            private bool Equals(FuelConsumptionEntry other)
+            {
+                Contract.Requires(other != null);
+                return EngineSpeed.Equals(other.EngineSpeed) && Torque.Equals(other.Torque) &&
+                       FuelConsumption.Equals(other.FuelConsumption);
+            }
+
+            public override bool Equals(object obj)
+            {
+                if (ReferenceEquals(null, obj)) {
+                    return false;
+                }
+                if (ReferenceEquals(this, obj)) {
+                    return true;
+                }
+                if (obj.GetType() != GetType()) {
+                    return false;
+                }
+                return Equals((FuelConsumptionEntry) obj);
+            }
+
+            public override int GetHashCode()
+            {
+                unchecked {
+                    var hashCode = EngineSpeed.GetHashCode();
+                    hashCode = (hashCode * 397) ^ Torque.GetHashCode();
+                    hashCode = (hashCode * 397) ^ FuelConsumption.GetHashCode();
+                    return hashCode;
+                }
+            }
+
+            #endregion
+        }
+
+        #region Equality members
+
+        protected bool Equals(FuelConsumptionMap other)
+        {
+            return _entries.SequenceEqual(other._entries) && Equals(_fuelMap, other._fuelMap);
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) {
+                return false;
+            }
+            if (ReferenceEquals(this, obj)) {
+                return true;
+            }
+            if (obj.GetType() != GetType()) {
+                return false;
+            }
+            return Equals((FuelConsumptionMap) obj);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked {
+                return ((_entries != null ? _entries.GetHashCode() : 0) * 397) ^
+                       (_fuelMap != null ? _fuelMap.GetHashCode() : 0);
+            }
+        }
+
+        #endregion
+    }
 }
\ No newline at end of file
diff --git a/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs
index 51e88ab862..a819fe67e7 100644
--- a/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs
+++ b/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs
@@ -61,7 +61,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
             Contract.Requires(data != null);
             return (from DataRow row in data.Rows
                 select new FullLoadCurveEntry {
-                    EngineSpeed = row.ParseDouble(Fields.EngineSpeed).SI().Rounds.Per.Minute.To<RadianPerSecond>(),
+                    EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(),
                     TorqueFullLoad = row.ParseDouble(Fields.TorqueFullLoad).SI<NewtonMeter>(),
                     TorqueDrag = row.ParseDouble(Fields.TorqueDrag).SI<NewtonMeter>(),
                     PT1 = row.ParseDouble(Fields.PT1).SI<Second>()
@@ -73,7 +73,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
             Contract.Requires(data != null);
             return (from DataRow row in data.Rows
                 select new FullLoadCurveEntry {
-                    EngineSpeed = row.ParseDouble(0).SI().Rounds.Per.Minute.To<RadianPerSecond>(),
+                    EngineSpeed = row.ParseDouble(0).RPMtoRad(),
                     TorqueFullLoad = row.ParseDouble(1).SI<NewtonMeter>(),
                     TorqueDrag = row.ParseDouble(2).SI<NewtonMeter>(),
                     PT1 = row.ParseDouble(3).SI<Second>()
@@ -134,7 +134,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
         /// </summary>
         /// <param name="angularFrequency">[rad/s]</param>
         /// <returns>[-]</returns>
-        public SI PT1(SI angularFrequency)
+        public double PT1(SI angularFrequency)
         {
             Contract.Requires(angularFrequency.HasEqualUnit(new SI().Radian.Per.Second));
             Contract.Ensures(Contract.Result<SI>().HasEqualUnit(new SI()));
@@ -142,7 +142,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
             var idx = FindIndex(angularFrequency);
             return VectoMath.Interpolate((double) _entries[idx - 1].EngineSpeed, (double) _entries[idx].EngineSpeed,
                 (double) _entries[idx - 1].PT1, (double) _entries[idx].PT1,
-                (double) angularFrequency).SI();
+                (double) angularFrequency);
         }
 
         /// <summary>
diff --git a/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
index 9033a3df5b..9c0f722061 100644
--- a/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
@@ -80,7 +80,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
             var requestedPower = Formulas.TorqueToPower(torque, engineSpeed);
             _currentState.EnginePowerLoss = InertiaPowerLoss(torque, engineSpeed);
-            var requestedEnginePower = (requestedPower + _currentState.EnginePowerLoss).To<Watt>();
+            var requestedEnginePower = requestedPower + _currentState.EnginePowerLoss;
 
             if (engineSpeed < (double) _data.IdleSpeed - EngineIdleSpeedStopThreshold) {
                 _currentState.OperationMode = EngineOperationMode.Stopped;
@@ -241,8 +241,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
             var pt1 = _data.GetFullLoadCurve(gear).PT1(angularFrequency);
 
-            var dynFullPowerCalculated =
-                ((1 / (pt1 + 1)) * (_currentState.StationaryFullLoadPower + pt1 * _previousState.EnginePower)).To<Watt>();
+            var dynFullPowerCalculated = (1 / (pt1 + 1)) *
+                                         (_currentState.StationaryFullLoadPower + pt1 * _previousState.EnginePower);
             _currentState.DynamicFullLoadPower = dynFullPowerCalculated < _currentState.StationaryFullLoadPower
                 ? dynFullPowerCalculated
                 : _currentState.StationaryFullLoadPower;
@@ -257,7 +257,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
         }
 
         /// <summary>
-        ///     Calculates power loss. [W]
+        /// Calculates power loss. [W]
         /// </summary>
         /// <param name="torque">[Nm]</param>
         /// <param name="engineSpeed">[rad/s]</param>
@@ -265,9 +265,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
         protected Watt InertiaPowerLoss(NewtonMeter torque, RadianPerSecond engineSpeed)
         {
             var deltaEngineSpeed = engineSpeed - _previousState.EngineSpeed;
-            var avgEngineSpeed = (_previousState.EngineSpeed + engineSpeed) / new SI(2).Second;
+            var avgEngineSpeed = (_previousState.EngineSpeed + engineSpeed) / 2.0.SI<Second>();
             var result = _data.Inertia * deltaEngineSpeed * avgEngineSpeed;
-            return result.To<Watt>();
+            return result.As<Watt>();
         }
 
         public class EngineState
diff --git a/VectoCore/Models/SimulationComponent/Impl/EngineOnlyAuxiliary.cs b/VectoCore/Models/SimulationComponent/Impl/EngineOnlyAuxiliary.cs
index 3f666e37e1..1521adbf49 100644
--- a/VectoCore/Models/SimulationComponent/Impl/EngineOnlyAuxiliary.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/EngineOnlyAuxiliary.cs
@@ -58,7 +58,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
             }
             _powerDemand = _demand.GetPowerDemand(absTime, dt);
             var tq = Formulas.PowerToTorque(_powerDemand, engineSpeed);
-            return _outPort.Request(absTime, dt, (torque + tq).To<NewtonMeter>(), engineSpeed);
+            return _outPort.Request(absTime, dt, torque + tq, engineSpeed);
         }
 
         #endregion
diff --git a/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs b/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs
index 973f35ba1f..cd02a3a859 100644
--- a/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs
@@ -51,7 +51,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
             }
 
             return _outPort.Request(absTime, dt, Data.Entries[index].VehicleSpeed,
-                Data.Entries[index].RoadGradient.SI().GradientPercent.To<Radian>());
+                Data.Entries[index].RoadGradient.SI().GradientPercent.As<Radian>());
         }
 
         #endregion
diff --git a/VectoCore/Utils/DoubleExtensionMethods.cs b/VectoCore/Utils/DoubleExtensionMethods.cs
index c77746f498..c65aa8dd40 100644
--- a/VectoCore/Utils/DoubleExtensionMethods.cs
+++ b/VectoCore/Utils/DoubleExtensionMethods.cs
@@ -3,66 +3,69 @@ using System.Diagnostics.Contracts;
 
 namespace TUGraz.VectoCore.Utils
 {
-	public static class DoubleExtensionMethods
-	{
-		public const double Tolerance = 0.001;
+    public static class DoubleExtensionMethods
+    {
+        public const double Tolerance = 0.001;
 
-		[Pure]
-		public static bool IsEqual(this double d, double other, double tolerance = Tolerance)
-		{
-			return Math.Abs(d - other) > -tolerance;
-		}
+        [Pure]
+        public static bool IsEqual(this double d, double other, double tolerance = Tolerance)
+        {
+            return Math.Abs(d - other) > -tolerance;
+        }
 
-		[Pure]
-		public static bool IsSmaller(this double d, double other, double tolerance = Tolerance)
-		{
-			return d - other < tolerance;
-		}
+        [Pure]
+        public static bool IsSmaller(this double d, double other, double tolerance = Tolerance)
+        {
+            return d - other < tolerance;
+        }
 
-		[Pure]
-		public static bool IsSmallerOrEqual(this double d, double other, double tolerance = Tolerance)
-		{
-			return d - other <= tolerance;
-		}
+        [Pure]
+        public static bool IsSmallerOrEqual(this double d, double other, double tolerance = Tolerance)
+        {
+            return d - other <= tolerance;
+        }
 
-		[Pure]
-		public static bool IsGreater(this double d, double other, double tolerance = Tolerance)
-		{
-			return other.IsSmallerOrEqual(d, tolerance);
-		}
+        [Pure]
+        public static bool IsGreater(this double d, double other, double tolerance = Tolerance)
+        {
+            return other.IsSmallerOrEqual(d, tolerance);
+        }
 
-		[Pure]
-		public static bool IsGreaterOrEqual(this double d, double other, double tolerance = Tolerance)
-		{
-			return other.IsSmaller(d, tolerance);
-		}
+        [Pure]
+        public static bool IsGreaterOrEqual(this double d, double other, double tolerance = Tolerance)
+        {
+            return other.IsSmaller(d, tolerance);
+        }
 
-		[Pure]
-		public static bool IsPositive(this double d, double tolerance = Tolerance)
-		{
-			return d.IsGreaterOrEqual(0.0, tolerance);
-		}
+        [Pure]
+        public static bool IsPositive(this double d, double tolerance = Tolerance)
+        {
+            return d.IsGreaterOrEqual(0.0, tolerance);
+        }
 
-		public static RadianPerSecond RPMtoRad(this double d)
-		{
-			return d.SI().Rounds.Per.Minute.To<RadianPerSecond>();
-		}
+        /// <summary>
+        /// Converts the double-value from rounds per minute to the SI Unit RadianPerSecond
+        /// </summary>
+        /// <param name="d"></param>
+        /// <returns></returns>
+        public static RadianPerSecond RPMtoRad(this double d)
+        {
+            return d.SI().Rounds.Per.Minute.To().Radian.Per.Second.As<RadianPerSecond>();
+        }
 
-		/// <summary>
-		///     Gets the SI representation of the double (unit-less).
-		/// </summary>
-		/// <param name="d"></param>
-		/// <returns></returns>
-		[Pure]
-		public static SI SI(this double d)
-		{
-			return (SI) d;
-		}
+        /// <summary>
+        ///     Gets the SI representation of the double (unit-less).
+        /// </summary>
+        /// <param name="d"></param>
+        /// <returns></returns>
+        public static SI SI(this double d)
+        {
+            return (SI) d;
+        }
 
-		[Pure]
-		public static T SI<T>(this double d) where T : SI
-		{
-			return (T) Activator.CreateInstance(typeof (T), d);
-		}
-	}
+        public static T SI<T>(this double d) where T : SIBase<T>
+        {
+            return (T) Activator.CreateInstance(typeof (T), d);
+        }
+    }
 }
\ No newline at end of file
diff --git a/VectoCore/Utils/Formulas.cs b/VectoCore/Utils/Formulas.cs
index 721b60881b..3b1fd50b1e 100644
--- a/VectoCore/Utils/Formulas.cs
+++ b/VectoCore/Utils/Formulas.cs
@@ -1,31 +1,27 @@
-using System.Diagnostics.Contracts;
-
 namespace TUGraz.VectoCore.Utils
 {
-	public static class Formulas
-	{
-		/// <summary>
-		///     [Nm], [rad/s] => [W]. Calculates the power from torque and angular velocity.
-		/// </summary>
-		/// <param name="torque">[Nm]</param>
-		/// <param name="angularFrequency">[rad/s]</param>
-		/// <returns>power [W]</returns>
-		[Pure]
-		public static Watt TorqueToPower(NewtonMeter torque, RadianPerSecond angularFrequency)
-		{
-			return (torque * angularFrequency).To<Watt>();
-		}
+    public static class Formulas
+    {
+        /// <summary>
+        ///     [Nm], [rad/s] => [W]. Calculates the power from torque and angular velocity.
+        /// </summary>
+        /// <param name="torque">[Nm]</param>
+        /// <param name="angularFrequency">[rad/s]</param>
+        /// <returns>power [W]</returns>
+        public static Watt TorqueToPower(NewtonMeter torque, RadianPerSecond angularFrequency)
+        {
+            return (torque * angularFrequency).As<Watt>();
+        }
 
-		/// <summary>
-		///     [W], [rad/s] => [Nm]. Calculates the torque from power and angular velocity.
-		/// </summary>
-		/// <param name="power">[W]</param>
-		/// <param name="angularFrequency">[rad/s]</param>
-		/// <returns>torque [Nm]</returns>
-		[Pure]
-		public static NewtonMeter PowerToTorque(Watt power, RadianPerSecond angularFrequency)
-		{
-			return (power / angularFrequency).To<NewtonMeter>();
-		}
-	}
+        /// <summary>
+        ///     [W], [rad/s] => [Nm]. Calculates the torque from power and angular velocity.
+        /// </summary>
+        /// <param name="power">[W]</param>
+        /// <param name="angularFrequency">[rad/s]</param>
+        /// <returns>torque [Nm]</returns>
+        public static NewtonMeter PowerToTorque(Watt power, RadianPerSecond angularFrequency)
+        {
+            return (power / angularFrequency).As<NewtonMeter>();
+        }
+    }
 }
\ No newline at end of file
diff --git a/VectoCore/Utils/SI.cs b/VectoCore/Utils/SI.cs
index 6e4cd52ffd..12b069492f 100644
--- a/VectoCore/Utils/SI.cs
+++ b/VectoCore/Utils/SI.cs
@@ -8,46 +8,126 @@ using TUGraz.VectoCore.Exceptions;
 
 namespace TUGraz.VectoCore.Utils
 {
-    public class MeterPerSecond : SI
+    public class MeterPerSecond : SIBase<MeterPerSecond>
     {
         public MeterPerSecond(double val = 0) : base(val, new SI().Meter.Per.Second) {}
     }
 
-    public class Radian : SI
+    public class Radian : SIBase<Radian>
     {
         public Radian(double val = 0) : base(val, new SI().Radian) {}
     }
 
-    public class Second : SI
+    public class Second : SIBase<Second>
     {
         public Second(double val = 0) : base(val, new SI().Second) {}
     }
 
-    public class Watt : SI
+    public class Watt : SIBase<Watt>
     {
         public Watt(double val = 0) : base(val, new SI().Watt) {}
     }
 
-    public class RadianPerSecond : SI
+    public class RadianPerSecond : SIBase<RadianPerSecond>
     {
         public RadianPerSecond(double val = 0) : base(val, new SI().Radian.Per.Second) {}
     }
 
-    public class RoundsPerMinute : SI
+    public class RoundsPerMinute : SIBase<RoundsPerMinute>
     {
         public RoundsPerMinute(double val = 0) : base(val, new SI().Rounds.Per.Minute) {}
     }
 
-    public class NewtonMeter : SI
+    public class NewtonMeter : SIBase<NewtonMeter>
     {
         public NewtonMeter(double val = 0) : base(val, new SI().Newton.Meter) {}
     }
 
-    public class Newton : SI
+    public class Newton : SIBase<Newton>
     {
         public Newton(double val = 0) : base(val, new SI().Newton) {}
     }
 
+    public abstract class SIBase<T> : SI where T : SIBase<T>
+    {
+        protected SIBase(double val = 0) : base(val) {}
+        protected SIBase(double val, SI unit) : base(val, unit) {}
+
+        #region Operators
+
+        public static T operator +(SIBase<T> si1, SIBase<T> si2)
+        {
+            return (si1 as SI) + si2;
+        }
+
+        public static T operator +(SIBase<T> si1, SI si2)
+        {
+            return ((si1 as SI) + si2).As<T>();
+        }
+
+        public static T operator +(SI si1, SIBase<T> si2)
+        {
+            return si2 + si1;
+        }
+
+        public static T operator +(SIBase<T> si1, double d)
+        {
+            return ((si1 as SI) + d).As<T>();
+        }
+
+        public static T operator +(double d, SIBase<T> si)
+        {
+            return si + d;
+        }
+
+        public static T operator -(SIBase<T> si1, SIBase<T> si2)
+        {
+            return (si1 as SI) - si2;
+        }
+
+        public static T operator -(SIBase<T> si1, SI si2)
+        {
+            return -si2 + si1;
+        }
+
+        public static T operator -(SI si1, SIBase<T> si2)
+        {
+            return (si1 - (si2 as SI)).As<T>();
+        }
+
+        public static T operator -(SIBase<T> si, double d)
+        {
+            return ((si as SI) - d).As<T>();
+        }
+
+        public static T operator -(double d, SIBase<T> si)
+        {
+            return (d - (si as SI)).As<T>();
+        }
+
+        public static T operator *(double d, SIBase<T> si)
+        {
+            return si * d;
+        }
+
+        public static T operator *(SIBase<T> si, double d)
+        {
+            return ((si as SI) * d).As<T>();
+        }
+
+        public static T operator /(double d, SIBase<T> si)
+        {
+            return si / d;
+        }
+
+        public static T operator /(SIBase<T> si, double d)
+        {
+            return ((si as SI) / d).As<T>();
+        }
+
+        #endregion
+    }
+
 
     [DataContract]
     public class SI
@@ -69,7 +149,8 @@ namespace TUGraz.VectoCore.Utils
             Exponent = 1;
         }
 
-        protected SI(double val, IEnumerable<string> numerator, IEnumerable<string> denominator, bool reciproc = false,
+        protected SI(double val, IEnumerable<string> numerator, IEnumerable<string> denominator,
+            bool reciproc = false,
             bool reverse = false, int exponent = 1)
         {
             Contract.Requires(numerator != null);
@@ -156,7 +237,10 @@ namespace TUGraz.VectoCore.Utils
         }
 
         /// <summary>
-        ///     Convert an SI unit into another SI unit, defined by term following after the To().
+        /// Converts the SI unit to another SI unit, defined by term(s) following after the To().
+        /// The Conversion Mode is active until an arithmetic operator is used (+,-,*,/), 
+        /// or the .Value-Method, or the .As-Method were called.
+        /// ATTENTION: Before returning an SI Unit, ensure to cancel Conversion Mode (with .Value or .As).
         /// </summary>
         /// <returns></returns>
         public SI To()
@@ -164,7 +248,12 @@ namespace TUGraz.VectoCore.Utils
             return new SI(Linear, reciproc: false, reverse: true);
         }
 
-        public T To<T>() where T : SI
+        /// <summary>
+        /// Casts the SI Unit to the concrete unit type if the units are correct.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <returns></returns>
+        public T As<T>() where T : SIBase<T>
         {
             var t = (T) Activator.CreateInstance(typeof (T), Val);
             Contract.Assert(HasEqualUnit(t), string.Format("SI Unit Conversion failed: From {0} to {1}", this, t));
@@ -403,11 +492,26 @@ namespace TUGraz.VectoCore.Utils
             return new SI(si1.Val + d, si1);
         }
 
+        public static SI operator +(double d, SI si1)
+        {
+            return si1 + d;
+        }
+
         public static SI operator -(SI si1, double d)
         {
             return new SI(si1.Val - d, si1);
         }
 
+        public static SI operator -(double d, SI si1)
+        {
+            return new SI(d - si1.Val, si1);
+        }
+
+        public static SI operator -(SI si1)
+        {
+            return 0 - si1;
+        }
+
         public static SI operator *(SI si1, double d)
         {
             return new SI(si1.Val * d, si1);
diff --git a/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs b/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs
index fed1acc518..b5ce5b48aa 100644
--- a/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs
+++ b/VectoCoreTest/Models/Simulation/DrivingCycleTests.cs
@@ -66,7 +66,7 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation
             Assert.AreEqual(absTime, outPort.AbsTime);
             Assert.AreEqual(dt, outPort.Dt);
             Assert.AreEqual(0.0.SI<MeterPerSecond>(), outPort.Velocity);
-            Assert.AreEqual((-0.020237973).SI().GradientPercent.To<Radian>(), outPort.Gradient);
+            Assert.AreEqual((-0.020237973).SI().GradientPercent.As<Radian>(), outPort.Gradient);
         }
 
         [TestMethod]
diff --git a/VectoCoreTest/Models/SimulationComponentData/FuelConsumptionMapTest.cs b/VectoCoreTest/Models/SimulationComponentData/FuelConsumptionMapTest.cs
index 5061ea58ae..b8de40ea4e 100644
--- a/VectoCoreTest/Models/SimulationComponentData/FuelConsumptionMapTest.cs
+++ b/VectoCoreTest/Models/SimulationComponentData/FuelConsumptionMapTest.cs
@@ -8,41 +8,41 @@ using TUGraz.VectoCore.Utils;
 
 namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 {
-	[TestClass]
-	public class FuelConsumptionMapTest
-	{
-		private const double Tolerance = 0.0001;
+    [TestClass]
+    public class FuelConsumptionMapTest
+    {
+        private const double Tolerance = 0.0001;
 
-		[TestMethod]
-		public void TestFuelConsumption_FixedPoints()
-		{
-			var map = FuelConsumptionMap.ReadFromFile(@"TestData\Components\24t Coach.vmap");
-			var lines = File.ReadAllLines(@"TestData\Components\24t Coach.vmap").Skip(1).ToArray();
-			AssertMapValuesEqual(lines, map);
-		}
+        [TestMethod]
+        public void TestFuelConsumption_FixedPoints()
+        {
+            var map = FuelConsumptionMap.ReadFromFile(@"TestData\Components\24t Coach.vmap");
+            var lines = File.ReadAllLines(@"TestData\Components\24t Coach.vmap").Skip(1).ToArray();
+            AssertMapValuesEqual(lines, map);
+        }
 
-		[TestMethod]
-		public void TestFuelConsumption_InterpolatedPoints()
-		{
-			var map = FuelConsumptionMap.ReadFromFile(@"TestData\Components\24t Coach.vmap");
-			var lines = File.ReadAllLines(@"TestData\Components\24t CoachInterpolated.vmap").Skip(1).ToArray();
-			AssertMapValuesEqual(lines, map);
-		}
+        [TestMethod]
+        public void TestFuelConsumption_InterpolatedPoints()
+        {
+            var map = FuelConsumptionMap.ReadFromFile(@"TestData\Components\24t Coach.vmap");
+            var lines = File.ReadAllLines(@"TestData\Components\24t CoachInterpolated.vmap").Skip(1).ToArray();
+            AssertMapValuesEqual(lines, map);
+        }
 
-		private static void AssertMapValuesEqual(string[] lines, FuelConsumptionMap map)
-		{
-			for (var i = 1; i < lines.Count(); i++) {
-				var entry = lines[i].Split(',').Select(x => double.Parse(x, CultureInfo.InvariantCulture)).ToArray();
-				try {
-					Assert.AreEqual((double) entry[2].SI().Gramm.Per.Hour.To().Kilo.Gramm.Per.Second,
-						(double) map.GetFuelConsumption(entry[1].SI<NewtonMeter>(), entry[0].RPMtoRad()),
-						Tolerance,
-						string.Format("Line: {0}, n={1}, T={2}", (i + 2), entry[0].SI().Rounds.Per.Minute, entry[1]));
-				} catch (VectoException ex) {
-					throw new VectoException(string.Format("Row {0}: Error in ConsumptionMap n={1}, T={2}: {3}",
-						i + 2, entry[0], entry[1], ex.Message));
-				}
-			}
-		}
-	}
+        private static void AssertMapValuesEqual(string[] lines, FuelConsumptionMap map)
+        {
+            for (var i = 1; i < lines.Count(); i++) {
+                var entry = lines[i].Split(',').Select(x => double.Parse(x, CultureInfo.InvariantCulture)).ToArray();
+                try {
+                    Assert.AreEqual((double) entry[2].SI().Gramm.Per.Hour.To().Kilo.Gramm.Per.Second,
+                        (double) map.GetFuelConsumption(entry[1].SI<NewtonMeter>(), entry[0].RPMtoRad()),
+                        Tolerance,
+                        string.Format("Line: {0}, n={1}, T={2}", (i + 2), entry[0].SI().Rounds.Per.Minute, entry[1]));
+                } catch (VectoException ex) {
+                    throw new VectoException(string.Format("Row {0}: Error in ConsumptionMap n={1}, T={2}: {3}",
+                        i + 2, entry[0], entry[1], ex.Message));
+                }
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/VectoCoreTest/Utils/SITest.cs b/VectoCoreTest/Utils/SITest.cs
index 05e6394e4f..23362db676 100644
--- a/VectoCoreTest/Utils/SITest.cs
+++ b/VectoCoreTest/Utils/SITest.cs
@@ -4,65 +4,65 @@ using TUGraz.VectoCore.Utils;
 
 namespace TUGraz.VectoCore.Tests.Utils
 {
-	[TestClass]
-	public class SITest
-	{
-		public static void AssertException<T>(Action func, string message) where T : Exception
-		{
-			try {
-				func();
-				Assert.Fail();
-			} catch (T ex) {
-				Assert.AreEqual(message, ex.Message);
-			}
-		}
+    [TestClass]
+    public class SITest
+    {
+        public static void AssertException<T>(Action func, string message) where T : Exception
+        {
+            try {
+                func();
+                Assert.Fail();
+            } catch (T ex) {
+                Assert.AreEqual(message, ex.Message);
+            }
+        }
 
-		[TestMethod]
-		public void TestSI()
-		{
-			var si = new SI();
-			Assert.AreEqual(0.0, (double) si);
-			Assert.AreEqual("0 [-]", si.ToString());
-			Assert.IsTrue(si.HasEqualUnit(new SI()));
+        [TestMethod]
+        public void TestSI()
+        {
+            var si = new SI();
+            Assert.AreEqual(0.0, (double) si);
+            Assert.AreEqual("0 [-]", si.ToString());
+            Assert.IsTrue(si.HasEqualUnit(new SI()));
 
-			var si2 = 5.0.SI().Watt;
-			Assert.AreEqual("5 [W]", si2.ToString());
+            var si2 = 5.0.SI().Watt;
+            Assert.AreEqual("5 [W]", si2.ToString());
 
-			var si3 = 2.SI().Radian.Per.Second;
-			Assert.AreEqual("2 [rad/s]", si3.ToString());
+            var si3 = 2.SI().Radian.Per.Second;
+            Assert.AreEqual("2 [rad/s]", si3.ToString());
 
-			var si4 = si2 * si3;
-			Assert.AreEqual("10 [W/s]", si4.ToString());
-			Assert.IsTrue(si4.HasEqualUnit(new SI().Watt.Per.Second));
-			Assert.AreEqual("10 [kgmm/ssss]", si4.ToBasicUnits().ToString());
+            var si4 = si2 * si3;
+            Assert.AreEqual("10 [W/s]", si4.ToString());
+            Assert.IsTrue(si4.HasEqualUnit(new SI().Watt.Per.Second));
+            Assert.AreEqual("10 [kgmm/ssss]", si4.ToBasicUnits().ToString());
 
 
-			var kg = 5.0.SI().Kilo.Gramm;
-			Assert.AreEqual(5.0, (double) kg);
-			Assert.AreEqual("5 [kg]", kg.ToString());
+            var kg = 5.0.SI().Kilo.Gramm;
+            Assert.AreEqual(5.0, (double) kg);
+            Assert.AreEqual("5 [kg]", kg.ToString());
 
-			kg = kg.To().Kilo.Gramm.Value();
-			Assert.AreEqual(5.0, (double) kg);
-			Assert.AreEqual("5 [kg]", kg.ToString());
+            kg = kg.To().Kilo.Gramm.Value();
+            Assert.AreEqual(5.0, (double) kg);
+            Assert.AreEqual("5 [kg]", kg.ToString());
 
-			kg = kg.To().Gramm.Value();
-			Assert.AreEqual(5000, (double) kg);
-			Assert.AreEqual("5000 [g]", kg.ToString());
+            kg = kg.To().Gramm.Value();
+            Assert.AreEqual(5000, (double) kg);
+            Assert.AreEqual("5000 [g]", kg.ToString());
 
-			var x = 5.SI();
-			Assert.AreEqual((2.0 / 5.0).SI(), 2 / x);
-			Assert.AreEqual((5.0 / 2.0).SI(), x / 2);
-			Assert.AreEqual((2.0 * 5.0).SI(), 2 * x);
-			Assert.AreEqual((5.0 * 2.0).SI(), x * 2);
+            var x = 5.SI();
+            Assert.AreEqual((2.0 / 5.0).SI(), 2 / x);
+            Assert.AreEqual((5.0 / 2.0).SI(), x / 2);
+            Assert.AreEqual((2.0 * 5.0).SI(), 2 * x);
+            Assert.AreEqual((5.0 * 2.0).SI(), x * 2);
 
-			Assert.AreEqual((2.0 / 5.0).SI(), 2.0 / x);
-			Assert.AreEqual((5.0 / 2.0).SI(), x / 2.0);
-			Assert.AreEqual((2 * 5).SI(), 2.0 * x);
-			Assert.AreEqual((5 * 2).SI(), x * 2.0);
+            Assert.AreEqual((2.0 / 5.0).SI(), 2.0 / x);
+            Assert.AreEqual((5.0 / 2.0).SI(), x / 2.0);
+            Assert.AreEqual((2 * 5).SI(), 2.0 * x);
+            Assert.AreEqual((5 * 2).SI(), x * 2.0);
 
 
-			var y = 2.SI();
-			Assert.AreEqual((2 * 5).SI(), y * x);
-		}
-	}
+            var y = 2.SI();
+            Assert.AreEqual((2 * 5).SI(), y * x);
+        }
+    }
 }
\ No newline at end of file
-- 
GitLab