From e11799bdf5a2cc2752feb64be0c6b004871eb022 Mon Sep 17 00:00:00 2001
From: Michael Krisper <michael.krisper@tugraz.at>
Date: Tue, 28 Apr 2015 09:44:00 +0200
Subject: [PATCH] changes for sum file

---
 .../Simulation/Data/IModalDataWriter.cs       |   8 +
 .../Models/Simulation/Data/ModalDataWriter.cs | 207 +++++++++++++++++-
 .../Models/Simulation/IVehicleContainer.cs    |  42 ++--
 .../Models/Simulation/Impl/JobContainer.cs    |  10 +-
 .../Simulation/Impl/SimulatorFactory.cs       | 133 +++++------
 .../Models/Simulation/Impl/VectoSimulator.cs  | 161 +-------------
 .../Simulation/Impl/VehicleContainer.cs       |  22 +-
 .../Models/Simulation/SimulationTests.cs      |   6 +-
 8 files changed, 329 insertions(+), 260 deletions(-)

diff --git a/VectoCore/Models/Simulation/Data/IModalDataWriter.cs b/VectoCore/Models/Simulation/Data/IModalDataWriter.cs
index cd7ad3baa3..81eb386117 100644
--- a/VectoCore/Models/Simulation/Data/IModalDataWriter.cs
+++ b/VectoCore/Models/Simulation/Data/IModalDataWriter.cs
@@ -1,3 +1,7 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+
 namespace TUGraz.VectoCore.Models.Simulation.Data
 {
 	public interface IModalDataWriter
@@ -15,5 +19,9 @@ namespace TUGraz.VectoCore.Models.Simulation.Data
 		void CommitSimulationStep();
 
 		void Finish();
+
+		Object Compute(string expression, string filter);
+
+		IEnumerable<object> GetValues(ModalResultField key);
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Data/ModalDataWriter.cs b/VectoCore/Models/Simulation/Data/ModalDataWriter.cs
index cfb75f2132..c658012cfe 100644
--- a/VectoCore/Models/Simulation/Data/ModalDataWriter.cs
+++ b/VectoCore/Models/Simulation/Data/ModalDataWriter.cs
@@ -1,21 +1,32 @@
+using System.Collections.Generic;
 using System.Data;
+using System.IO;
+using System.Linq;
 using TUGraz.VectoCore.Utils;
 
 namespace TUGraz.VectoCore.Models.Simulation.Data
 {
 	public class ModalDataWriter : IModalDataWriter
 	{
-		public ModalDataWriter(string fileName)
+		private string JobName { get; set; }
+		private SummaryFileWriter SumWriter { get; set; }
+		private string CycleFileName { get; set; }
+		private string JobFileName { get; set; }
+		private ModalResults Data { get; set; }
+		private DataRow CurrentRow { get; set; }
+		private string FileName { get; set; }
+
+
+		public ModalDataWriter(string fileName, string jobName, string cycleFileName, SummaryFileWriter sumWriter)
 		{
 			FileName = fileName;
 			Data = new ModalResults();
 			CurrentRow = Data.NewRow();
+			SumWriter = sumWriter;
+			JobName = jobName;
+			CycleFileName = cycleFileName;
 		}
 
-		private ModalResults Data { get; set; }
-		private DataRow CurrentRow { get; set; }
-		public string FileName { get; set; }
-
 		public void CommitSimulationStep()
 		{
 			Data.Rows.Add(CurrentRow);
@@ -25,12 +36,194 @@ namespace TUGraz.VectoCore.Models.Simulation.Data
 		public void Finish()
 		{
 			VectoCSVFile.Write(FileName, Data);
+			SumWriter.Write(this, jobName, cycleFileName);
+		}
+
+		public object Compute(string expression, string filter)
+		{
+			return Data.Compute(expression, filter);
 		}
 
+		public IEnumerable<object> GetValues(ModalResultField key)
+		{
+			return Data.Rows.Cast<DataRow>().Select(x => x[(int)key]);
+		}
+
+
 		public object this[ModalResultField key]
 		{
-			get { return CurrentRow[(int) key]; }
-			set { CurrentRow[(int) key] = value; }
+			get { return CurrentRow[(int)key]; }
+			set { CurrentRow[(int)key] = value; }
+		}
+	}
+
+
+	/*
+	jobName	Unit	Description
+	Job	[-]	Job number. Format is "x-y" with x = file number and y = cycle number
+	Input File	[-]	jobName of the input file
+	Cycle	[-]	jobName of the cycle file
+	time	[s]	Total simulation time
+	distance	[km]	Total travelled distance
+	speed	[km/h]	Average vehicle speed
+	∆altitude	[m]	Altitude difference between start and end of cycle
+	Ppos	[kW]	Average positive engine power
+	Pneg	[kW]	Average negative engine power
+	FC	[g/km]	Average fuel consumption
+	FC-AUXc	[g/km]	Fuel consumption after Auxiliary-Start/Stop Correction. (Based on FC.)
+	FC-WHTCc	[g/km]	Fuel consumption after WHTC Correction. (Based on FC-AUXc.)
+	Pbrake	[kW]	Average brake power (not including engine drag)
+	EposICE	[kWh]	Total positive engine work
+	EnegICE	[kWh]	Total negative engine work (engine brake)
+	Eair	[kWh]	Total work of air resistance
+	Eroll	[kWh]	Total work of rolling resistance
+	Egrad	[kWh]	Total work of gradient resistance
+	Eacc	[kWh]	Total work from accelerations (<0) / decelerations (>0) 
+	Eaux	[kWh]	Total energy demand of auxiliaries
+	Eaux_xxx	[kWh]	Energy demand of auxiliary with ID xxx. See also Aux Dialog and Driving Cycle.
+	Ebrake	[kWh]	Total work dissipated in mechanical braking (sum of service brakes, retader and additional engine exhaust brakes)
+	Etransm	[kWh]	Total work of transmission losses
+	Eretarder	[kWh]	Total retarder losses
+	Mass	[kg]	Vehicle mass (equals Curb Weight Vehicle plus Curb Weight Extra Trailer/Body, see Vehicle Editor)
+	Loading	[kg]	Vehicle loading (see Vehicle Editor)
+	a	[m/s2]	Average acceleration
+	a_pos	[m/s2]	Average acceleration in acceleration phases*
+	a_neg	[m/s2]	Average deceleration in deceleration phases*
+	Acc.Noise	[m/s2]	Acceleration noise
+	pAcc	[%]	Time share of acceleration phases*
+	pDec	[%]	Time share of deceleration phases*
+	pCruise	[%]	Time share of cruise phases*
+	pStop	[%]	Time share of stop phases*
+	*/
+
+	public class SummaryFileWriter
+	{
+		private readonly DataTable _table;
+		private readonly string _jobFileName;
+		private readonly string _sumFileName;
+
+		public SummaryFileWriter(string sumFileName, string jobFileName)
+		{
+			_sumFileName = sumFileName;
+			_jobFileName = jobFileName;
+
+			_table = new DataTable();
+			_table.Columns.Add("Job [-]", typeof(string));
+			_table.Columns.Add("Input File [-]", typeof(string));
+			_table.Columns.Add("Cycle [-]", typeof(string));
+			_table.Columns.Add("Time [s]", typeof(double));
+			_table.Columns.Add("distance [km]", typeof(double));
+			_table.Columns.Add("speed [km/h]", typeof(double));
+			_table.Columns.Add("∆altitude [m]", typeof(double));
+			_table.Columns.Add("Ppos [kw]", typeof(double));
+			_table.Columns.Add("Pneg [kw]", typeof(double));
+			_table.Columns.Add("FC [g/km]", typeof(double));
+			_table.Columns.Add("FC-AUXc [g/km]", typeof(double));
+			_table.Columns.Add("FC-WHTCc [g/km]", typeof(double));
+			_table.Columns.Add("Pbrake [kw]", typeof(double));
+			_table.Columns.Add("EposICE [kwh]", typeof(double));
+			_table.Columns.Add("EnegICE [kwh]", typeof(double));
+			_table.Columns.Add("Eair [kwh]", typeof(double));
+			_table.Columns.Add("Eroll [kwh]", typeof(double));
+			_table.Columns.Add("Egrad [kwh]", typeof(double));
+			_table.Columns.Add("Eacc [kwh]", typeof(double));
+			_table.Columns.Add("Eaux [kwh]", typeof(double));
+			_table.Columns.Add("Eaux_xxx [kwh]", typeof(double));
+			_table.Columns.Add("Ebrake [kwh]", typeof(double));
+			_table.Columns.Add("Etransm [kwh]", typeof(double));
+			_table.Columns.Add("Eretarder [kwh]", typeof(double));
+			_table.Columns.Add("Mass [kg]", typeof(double));
+			_table.Columns.Add("Loading [kg]", typeof(double));
+			_table.Columns.Add("a [m/s2]", typeof(double));
+			_table.Columns.Add("a_pos [m/s2]", typeof(double));
+			_table.Columns.Add("a_neg [m/s2]", typeof(double));
+			_table.Columns.Add("pAcc [%]", typeof(double));
+			_table.Columns.Add("pDec [%]", typeof(double));
+			_table.Columns.Add("pCruise [%]", typeof(double));
+			_table.Columns.Add("pStop [%]", typeof(double));
+		}
+
+
+		public void Write(IModalDataWriter data, string jobName, string cycleFileName)
+		{
+			var row = _table.NewRow();
+			row["Job [-]"] = jobName;
+			row["Input File [-]"] = _jobFileName;
+			row["Cycle [-]"] = cycleFileName;
+			row["time [s]"] = data.Compute("Max(time)", "");
+			row["distance [km]"] = data.Compute("Max(dist)", "");
+			row["speed [km/h]"] = data.Compute("Avg(v_act)", "");
+
+
+			row["Ppos [kw]"] = data.Compute("Avg(Peng)", "Pe_eng > 0");
+			row["Pneg [kw]"] = data.Compute("Avg(Peng)", "Pe_eng < 0");
+			row["FC [g/km]"] = data.Compute("Avg(FC)", "");
+			row["FC-AUXc [g/km]"] = data.Compute("Avg(FC-AUXc)", "");
+			row["FC-WHTCc [g/km]"] = data.Compute("Avg(FC-WHTCc)", "");
+			row["Pbrake [kw]"] = data.Compute("Avg(Pbrake)", "");
+			row["EposICE [kwh]"] = data.Compute("Avg(pos)", "pos > 0");
+			row["EnegICE [kwh]"] = data.Compute("Avg(pos)", "pos < 0");
+			row["Eair [kwh]"] = data.Compute("Sum(Pair)", "");
+			row["Eroll [kwh]"] = data.Compute("Sum(Proll)", "");
+			row["Egrad [kwh]"] = data.Compute("Sum(Pgrad)", "");
+			row["Eaux [kwh]"] = data.Compute("Sum(Paux)", "");
+			row["Ebrake [kwh]"] = data.Compute("Sum(brake)", "");
+			row["Etransm [kwh]"] = data.Compute("Sum(transm)", "");
+			row["Eretarder [kwh]"] = data.Compute("Sum(retarder)", "");
+			row["Eacc [kwh]"] = data.Compute("Sum(Pa+PaGB+PaEng)", "");
+			row["a [m/s2]"] = data.Compute("Avg(a)", "");
+
+
+			//todo altitude - calculate when reading the cycle file, add column for altitude
+			//row["∆altitude [m]"] = Data.Rows[Data.Rows.Count - 1].Field<double>("altitude") -
+			//						Data.Rows[0].Field<double>("altitude");
+
+			//todo auxiliaries
+			//foreach (var auxCol in data.Auxiliaries) {
+			//    row["Eaux_" + auxCol.jobName + " [kwh]"] = data.Compute("Sum(aux_" + auxCol.jobName + ")", "");
+			//}
+
+			//todo get data from vehicle file
+			//row["Mass [kg]"] = Container.VehicleMass();
+			//row["Loading [kg]"] = Container.LoadingMass();
+
+			var acceleration = data.GetValues(ModalResultField.acc).Cast<double>().ToList();
+			var simInterval = data.GetValues(ModalResultField.simulationInterval).Cast<double>().ToList();
+
+			//todo dynamic time steps!!!
+			var runningAverage = (acceleration[0] + acceleration[1] + acceleration[2]) / 3;
+			var accelerationAvg = new List<double>();
+
+			for (var i = 2; i < acceleration.Count() - 1; i++) {
+				runningAverage -= acceleration[i - 2] / 3;
+				runningAverage += acceleration[i + 1] / 3;
+				accelerationAvg.Add(runningAverage);
+			}
+
+			row["a_pos [m/s2]"] = accelerationAvg.Where(x => x > 0.125).Average();
+			row["a_neg [m/s2]"] = accelerationAvg.Where(x => x < -0.125).Average();
+
+
+			row["pAcc [%]"] = 100.0 * accelerationAvg.Count(x => x > 0.125) / accelerationAvg.Count;
+			row["pDec [%]"] = 100.0 * accelerationAvg.Count(x => x < -0.125) / accelerationAvg.Count;
+			row["pCruise [%]"] = 100.0 * accelerationAvg.Count(x => x < 0.125 && x > -0.125) / accelerationAvg.Count;
+
+
+			var velocity = data.GetValues(ModalResultField.v_act).Cast<double>().ToList();
+			var timeSum = 0.0;
+			for (var i = 0; i < velocity.Count; i++) {
+				if (velocity[i] < 0.1) {
+					timeSum += simInterval[i];
+				}
+			}
+			row["pStop [%]"] = 100.0 * timeSum / (double)data.Compute("Max(v_act)", "");
+
+			_table.ImportRow(row);
+		}
+
+		public void Finish()
+		{
+			VectoCSVFile.Write(_sumFileName, _table);
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/IVehicleContainer.cs b/VectoCore/Models/Simulation/IVehicleContainer.cs
index 16a89af63a..e68e3838f6 100644
--- a/VectoCore/Models/Simulation/IVehicleContainer.cs
+++ b/VectoCore/Models/Simulation/IVehicleContainer.cs
@@ -4,28 +4,26 @@ using TUGraz.VectoCore.Models.SimulationComponent;
 
 namespace TUGraz.VectoCore.Models.Simulation
 {
-    /// <summary>
-    /// Defines Methods for adding components, commiting a simulation step and finishing the simulation.
-    /// Also defines interfaces for all cockpit access to data.
-    /// </summary>
-    public interface IVehicleContainer : ICockpit
-    {
-        /// <summary>
-        /// Adds a component to the vehicle container.
-        /// </summary>
-        /// <param name="component"></param>
-        void AddComponent(VectoSimulationComponent component);
+	/// <summary>
+	/// Defines Methods for adding components, commiting a simulation step and finishing the simulation.
+	/// Also defines interfaces for all cockpit access to data.
+	/// </summary>
+	public interface IVehicleContainer : ICockpit
+	{
+		/// <summary>
+		/// Adds a component to the vehicle container.
+		/// </summary>
+		/// <param name="component"></param>
+		void AddComponent(VectoSimulationComponent component);
 
-        /// <summary>
-        /// Commits the current simulation step.
-        /// </summary>
-        /// <param name="dataWriter"></param>
-        void CommitSimulationStep(IModalDataWriter dataWriter);
+		/// <summary>
+		/// Commits the current simulation step.
+		/// </summary>
+		void CommitSimulationStep();
 
-        /// <summary>
-        /// Finishes the simulation.
-        /// </summary>
-        /// <param name="dataWriter"></param>
-        void FinishSimulation(IModalDataWriter dataWriter);
-    }
+		/// <summary>
+		/// Finishes the simulation.
+		/// </summary>
+		void FinishSimulation();
+	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/JobContainer.cs b/VectoCore/Models/Simulation/Impl/JobContainer.cs
index 8a3df18985..f6b420a28c 100644
--- a/VectoCore/Models/Simulation/Impl/JobContainer.cs
+++ b/VectoCore/Models/Simulation/Impl/JobContainer.cs
@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
 using Common.Logging;
@@ -6,7 +7,7 @@ using TUGraz.VectoCore.Models.Simulation.Data;
 
 namespace TUGraz.VectoCore.Models.Simulation.Impl
 {
-	//todo: add job tracking (state of jobs, iteration, ...)
+	//todo: add job tracking (state of jobs, ...)
 	//todo: add job control (pause, stop)
 
 
@@ -16,12 +17,14 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 	public class JobContainer
 	{
 		private readonly List<IVectoSimulator> _simulators = new List<IVectoSimulator>();
+		private readonly SummaryFileWriter _sumWriter;
 
 		public JobContainer() {}
 
 		public JobContainer(VectoJobData data)
 		{
-			_simulators.AddRange(SimulatorFactory.CreateJobs(data));
+			_sumWriter = new SummaryFileWriter(Path.GetFileNameWithoutExtension(data.FileName) + ".vsum", data.FileName);
+			_simulators.AddRange(SimulatorFactory.CreateJobs(data, _sumWriter));
 		}
 
 
@@ -36,7 +39,10 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 		public void RunJobs()
 		{
 			LogManager.GetLogger(GetType()).Info("VectoSimulator started running. Starting Jobs.");
+
 			Task.WaitAll(_simulators.Select(job => Task.Factory.StartNew(job.Run)).ToArray());
+
+			_sumWriter.Finish();
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs b/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs
index d333e246cd..ad748df543 100644
--- a/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs
+++ b/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs
@@ -24,7 +24,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			return simulator;
 		}
 
-		public static IEnumerable<IVectoSimulator> CreateJobs(VectoJobData data)
+		public static IEnumerable<IVectoSimulator> CreateJobs(VectoJobData data, SummaryFileWriter sumWriter)
 		{
 			foreach (var cycle in data.Cycles) {
 				var builder = new SimulatorBuilder(data.IsEngineOnly);
@@ -38,7 +38,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				builder.AddDriver(data.StartStop, data.OverSpeedEcoRoll, data.LookAheadCoasting,
 					data.AccelerationLimitingFile);
 
-				var job = builder.Build(cycle, data.FileName);
+				var job = builder.Build(cycle, data.FileName, sumWriter);
 
 				yield return job;
 			}
@@ -64,14 +64,76 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				_container = new VehicleContainer();
 			}
 
-			public IVectoSimulator Build(string cycleFile, string jobFile)
+			public IVectoSimulator Build(string cycleFile, string jobFile, SummaryFileWriter sumWriter)
 			{
+				var modFileName = string.Format("{0}_{1}.vmod", Path.GetFileNameWithoutExtension(jobFile),
+					Path.GetFileNameWithoutExtension(cycleFile));
+				var dataWriter = new ModalDataWriter(modFileName, sumWriter);
+
+
 				if (_engineOnly) {
-					return BuildEngineOnly(cycleFile, jobFile);
+					return BuildEngineOnly(cycleFile, dataWriter, sumWriter);
 				}
-				return BuildFullPowertrain(cycleFile, jobFile);
+				return BuildFullPowertrain(cycleFile, dataWriter, sumWriter);
+			}
+
+			private IVectoSimulator BuildFullPowertrain(string cycleFile, IModalDataWriter dataWriter,
+				SummaryFileWriter sumWriter)
+			{
+				//throw new NotImplementedException("FullPowertrain is not fully implemented yet.");
+				var cycleData = DrivingCycleData.ReadFromFileEngineOnly(cycleFile);
+				//todo: make distinction between time based and distance based driving cycle!
+				var cycle = new TimeBasedDrivingCycle(_container, cycleData);
+
+				_axleGear = null;
+				_wheels = null;
+
+				// connect cycle --> driver --> vehicle --> wheels --> axleGear --> gearBox --> retarder --> clutch
+				cycle.InShaft().Connect(_driver.OutShaft());
+				_driver.InShaft().Connect(_vehicle.OutShaft());
+				_vehicle.InShaft().Connect(_wheels.OutShaft());
+				_wheels.InShaft().Connect(_axleGear.OutShaft());
+				_axleGear.InShaft().Connect(_gearBox.OutShaft());
+				_gearBox.InShaft().Connect(_retarder.OutShaft());
+				_retarder.InShaft().Connect(_clutch.OutShaft());
+
+				// connect directAux --> engine
+				IAuxiliary directAux = new DirectAuxiliary(_container, new AuxiliaryCycleDataAdapter(cycleData));
+				directAux.InShaft().Connect(_engine.OutShaft());
+
+				// connect aux --> ... --> aux_XXX --> directAux
+				var previousAux = directAux;
+				foreach (var auxData in _auxDict) {
+					var auxCycleData = new AuxiliaryCycleDataAdapter(cycleData, auxData.Key);
+					IAuxiliary auxiliary = new MappingAuxiliary(_container, auxCycleData, auxData.Value);
+					auxiliary.InShaft().Connect(previousAux.OutShaft());
+					previousAux = auxiliary;
+				}
+
+				// connect clutch --> aux
+				_clutch.InShaft().Connect(previousAux.OutShaft());
+
+				var simulator = new VectoSimulator(_container, cycle, dataWriter, sumWriter);
+				return simulator;
+			}
+
+			private IVectoSimulator BuildEngineOnly(string cycleFile, IModalDataWriter dataWriter, SummaryFileWriter sumWriter)
+			{
+				var cycleData = DrivingCycleData.ReadFromFileEngineOnly(cycleFile);
+				var cycle = new EngineOnlyDrivingCycle(_container, cycleData);
+
+				IAuxiliary addAux = new DirectAuxiliary(_container, new AuxiliaryCycleDataAdapter(cycleData));
+				addAux.InShaft().Connect(_engine.OutShaft());
+
+				_gearBox.InShaft().Connect(addAux.OutShaft());
+
+				cycle.InShaft().Connect(_gearBox.OutShaft());
+
+				var simulator = new VectoSimulator(_container, cycle);
+				return simulator;
 			}
 
+
 			public void AddEngine(string engineFile)
 			{
 				var engineData = CombustionEngineData.ReadFromFile(engineFile);
@@ -126,67 +188,6 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				var retarderData = RetarderLossMap.ReadFromFile(retarderFile);
 				_retarder = new Retarder(_container, retarderData);
 			}
-
-			private IVectoSimulator BuildFullPowertrain(string cycleFile, string jobFile)
-			{
-				//throw new NotImplementedException("FullPowertrain is not fully implemented yet.");
-				var cycleData = DrivingCycleData.ReadFromFileEngineOnly(cycleFile);
-				//todo: make distinction between time based and distance based driving cycle!
-				var cycle = new TimeBasedDrivingCycle(_container, cycleData);
-
-				_axleGear = null;
-				_wheels = null;
-
-				// connect cycle --> driver --> vehicle --> wheels --> axleGear --> gearBox --> retarder --> clutch
-				cycle.InShaft().Connect(_driver.OutShaft());
-				_driver.InShaft().Connect(_vehicle.OutShaft());
-				_vehicle.InShaft().Connect(_wheels.OutShaft());
-				_wheels.InShaft().Connect(_axleGear.OutShaft());
-				_axleGear.InShaft().Connect(_gearBox.OutShaft());
-				_gearBox.InShaft().Connect(_retarder.OutShaft());
-				_retarder.InShaft().Connect(_clutch.OutShaft());
-
-				// connect directAux --> engine
-				IAuxiliary directAux = new DirectAuxiliary(_container, new AuxiliaryCycleDataAdapter(cycleData));
-				directAux.InShaft().Connect(_engine.OutShaft());
-
-				// connect aux --> ... --> aux_XXX --> directAux
-				var previousAux = directAux;
-				foreach (var auxData in _auxDict) {
-					var auxCycleData = new AuxiliaryCycleDataAdapter(cycleData, auxData.Key);
-					IAuxiliary auxiliary = new MappingAuxiliary(_container, auxCycleData, auxData.Value);
-					auxiliary.InShaft().Connect(previousAux.OutShaft());
-					previousAux = auxiliary;
-				}
-
-				// connect clutch --> aux
-				_clutch.InShaft().Connect(previousAux.OutShaft());
-
-				var dataWriter =
-					new ModalDataWriter(string.Format("{0}_{1}.vmod", Path.GetFileNameWithoutExtension(jobFile),
-						Path.GetFileNameWithoutExtension(cycleFile)));
-				var simulator = new VectoSimulator(Path.GetFileNameWithoutExtension(jobFile), jobFile, _container, cycle, dataWriter);
-				return simulator;
-			}
-
-			private IVectoSimulator BuildEngineOnly(string cycleFile, string jobFile)
-			{
-				var cycleData = DrivingCycleData.ReadFromFileEngineOnly(cycleFile);
-				var cycle = new EngineOnlyDrivingCycle(_container, cycleData);
-
-				IAuxiliary addAux = new DirectAuxiliary(_container, new AuxiliaryCycleDataAdapter(cycleData));
-				addAux.InShaft().Connect(_engine.OutShaft());
-
-				_gearBox.InShaft().Connect(addAux.OutShaft());
-
-				cycle.InShaft().Connect(_gearBox.OutShaft());
-
-				var dataWriter =
-					new ModalDataWriter(string.Format("{0}_{1}.vmod", Path.GetFileNameWithoutExtension(jobFile),
-						Path.GetFileNameWithoutExtension(cycleFile)));
-				var simulator = new VectoSimulator(Path.GetFileNameWithoutExtension(jobFile), jobFile, _container, cycle, dataWriter);
-				return simulator;
-			}
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/VectoSimulator.cs b/VectoCore/Models/Simulation/Impl/VectoSimulator.cs
index e1bb0f6755..7a260f5b85 100644
--- a/VectoCore/Models/Simulation/Impl/VectoSimulator.cs
+++ b/VectoCore/Models/Simulation/Impl/VectoSimulator.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Data;
+using System.IO;
 using Common.Logging;
 using TUGraz.VectoCore.Models.Connector.Ports;
 using TUGraz.VectoCore.Models.Connector.Ports.Impl;
@@ -15,17 +16,15 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 		private TimeSpan _absTime = new TimeSpan(seconds: 0, minutes: 0, hours: 0);
 		private TimeSpan _dt = new TimeSpan(seconds: 1, minutes: 0, hours: 0);
 
-		public VectoSimulator(string jobName, string jobFileName, IVehicleContainer container, IDrivingCycleOutPort cyclePort,
-			IModalDataWriter dataWriter)
+		public VectoSimulator(IVehicleContainer container, IDrivingCycleOutPort cyclePort)
 		{
-			JobName = jobName;
-			JobFileName = jobFileName;
 			Container = container;
 			CyclePort = cyclePort;
-			DataWriter = dataWriter;
 		}
 
-		public string JobFileName { get; set; }
+		protected SummaryFileWriter SumWriter { get; set; }
+
+		protected string JobFileName { get; set; }
 
 		protected string JobName { get; set; }
 
@@ -56,162 +55,16 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				DataWriter[ModalResultField.time] = (_absTime + TimeSpan.FromTicks(_dt.Ticks / 2)).TotalSeconds;
 				DataWriter[ModalResultField.simulationInterval] = _dt.TotalSeconds;
 
-				Container.CommitSimulationStep(DataWriter);
+				Container.CommitSimulationStep();
 
 				// set _dt to difference to next full second.
 				_absTime += _dt;
 				_dt = TimeSpan.FromSeconds(1) - TimeSpan.FromMilliseconds(_dt.Milliseconds);
 			} while (response is ResponseSuccess);
 
-			Container.FinishSimulation(DataWriter);
-
-
-			//todo: WriteSummary();
+			Container.FinishSimulation();
 
 			LogManager.GetLogger(GetType()).Info("VectoJob finished.");
 		}
-
-
-		/*
-        jobName	Unit	Description
-        Job	[-]	Job number. Format is "x-y" with x = file number and y = cycle number
-        Input File	[-]	jobName of the input file
-        Cycle	[-]	jobName of the cycle file
-        time	[s]	Total simulation time
-        distance	[km]	Total travelled distance
-        speed	[km/h]	Average vehicle speed
-        ∆altitude	[m]	Altitude difference between start and end of cycle
-        Ppos	[kW]	Average positive engine power
-        Pneg	[kW]	Average negative engine power
-        FC	[g/km]	Average fuel consumption
-        FC-AUXc	[g/km]	Fuel consumption after Auxiliary-Start/Stop Correction. (Based on FC.)
-        FC-WHTCc	[g/km]	Fuel consumption after WHTC Correction. (Based on FC-AUXc.)
-        Pbrake	[kW]	Average brake power (not including engine drag)
-        EposICE	[kWh]	Total positive engine work
-        EnegICE	[kWh]	Total negative engine work (engine brake)
-        Eair	[kWh]	Total work of air resistance
-        Eroll	[kWh]	Total work of rolling resistance
-        Egrad	[kWh]	Total work of gradient resistance
-        Eacc	[kWh]	Total work from accelerations (<0) / decelerations (>0) 
-        Eaux	[kWh]	Total energy demand of auxiliaries
-        Eaux_xxx	[kWh]	Energy demand of auxiliary with ID xxx. See also Aux Dialog and Driving Cycle.
-        Ebrake	[kWh]	Total work dissipated in mechanical braking (sum of service brakes, retader and additional engine exhaust brakes)
-        Etransm	[kWh]	Total work of transmission losses
-        Eretarder	[kWh]	Total retarder losses
-        Mass	[kg]	Vehicle mass (equals Curb Weight Vehicle plus Curb Weight Extra Trailer/Body, see Vehicle Editor)
-        Loading	[kg]	Vehicle loading (see Vehicle Editor)
-        a	[m/s2]	Average acceleration
-        a_pos	[m/s2]	Average acceleration in acceleration phases*
-        a_neg	[m/s2]	Average deceleration in deceleration phases*
-        Acc.Noise	[m/s2]	Acceleration noise
-        pAcc	[%]	Time share of acceleration phases*
-        pDec	[%]	Time share of deceleration phases*
-        pCruise	[%]	Time share of cruise phases*
-        pStop	[%]	Time share of stop phases*
-        */
-
-		private static class SummaryFile
-		{
-			private static DataTable table;
-
-			static SummaryFile()
-			{
-				table = new DataTable();
-				table.Columns.Add("Job [-]", typeof(string));
-				table.Columns.Add("Input File [-]", typeof(string));
-				table.Columns.Add("Cycle [-]", typeof(string));
-				table.Columns.Add("Time [s]", typeof(double));
-				table.Columns.Add("distance [km]", typeof(double));
-				table.Columns.Add("speed [km/h]", typeof(double));
-				table.Columns.Add("∆altitude [m]", typeof(double));
-				table.Columns.Add("Ppos [kw]", typeof(double));
-				table.Columns.Add("Pneg [kw]", typeof(double));
-				table.Columns.Add("FC [g/km]", typeof(double));
-				table.Columns.Add("FC-AUXc [g/km]", typeof(double));
-				table.Columns.Add("FC-WHTCc [g/km]", typeof(double));
-				table.Columns.Add("Pbrake [kw]", typeof(double));
-				table.Columns.Add("EposICE [kwh]", typeof(double));
-				table.Columns.Add("EnegICE [kwh]", typeof(double));
-				table.Columns.Add("Eair [kwh]", typeof(double));
-				table.Columns.Add("Eroll [kwh]", typeof(double));
-				table.Columns.Add("Egrad [kwh]", typeof(double));
-				table.Columns.Add("Eacc [kwh]", typeof(double));
-				table.Columns.Add("Eaux [kwh]", typeof(double));
-				table.Columns.Add("Eaux_xxx [kwh]", typeof(double));
-				table.Columns.Add("Ebrake [kwh]", typeof(double));
-				table.Columns.Add("Etransm [kwh]", typeof(double));
-				table.Columns.Add("Eretarder [kwh]", typeof(double));
-				table.Columns.Add("Mass [kg]", typeof(double));
-				table.Columns.Add("Loading [kg]", typeof(double));
-				table.Columns.Add("a [m/s2]", typeof(double));
-				table.Columns.Add("a_pos [m/s2]", typeof(double));
-				table.Columns.Add("a_neg [m/s2]", typeof(double));
-				table.Columns.Add("Acc.Noise [m/s2]", typeof(double));
-				table.Columns.Add("pAcc [%]", typeof(double));
-				table.Columns.Add("pDec [%]", typeof(double));
-				table.Columns.Add("pCruise [%]", typeof(double));
-				table.Columns.Add("pStop [%]", typeof(double));
-			}
-
-
-			private static void WriteSummary(ModalResults modData)
-			{
-				//var data = new ModalResults();
-
-				var row = table.NewRow();
-				//row["Job [-]"] = jobName;
-				//row["Input File [-]"] = jobFileName;
-				//row["Cycle [-]"] = Container.CycleFileName();
-				//row["time [s]"] = data.Compute("Max(time)", "");
-				//row["distance [km]"] = data.Compute("Max(distance)", "");
-				//row["speed [km/h]"] = data.Compute("Avg(speed)", "");
-				//row["∆altitude [m]"] = data.Rows[data.Rows.Count-1].Field<double>("altitude") - data.Rows[0].Field<double>("altitude");
-				//row["Ppos [kw]"] = data.Compute("Avg(Peng)", "Peng > 0");
-				//row["Pneg [kw]"] = data.Compute("Avg(Peng)", "Peng < 0");
-				//row["FC [g/km]"] = data.Compute("Avg(FC)", "");
-				//row["FC-AUXc [g/km]"] = data.Compute("Avg(FC-AUXc)", "");
-				//row["FC-WHTCc [g/km]"] = data.Compute("Avg(FC-WHTCc)", "");
-				//row["Pbrake [kw]"] = data.Compute("Avg(Pbrake)", "");
-				//row["EposICE [kwh]"] = data.Compute("Avg(pos)", "pos > 0");
-				//row["EnegICE [kwh]"] = data.Compute("Avg(pos)", "pos < 0");
-				//row["Eair [kwh]"] = data.Compute("Sum(air)", "");
-				//row["Eroll [kwh]"] = data.Compute("Sum(roll)", "");
-				//row["Egrad [kwh]"] = data.Compute("Sum(grad)", "");
-				//row["Eacc [kwh]"] = data.Compute("Sum(acc)", "");
-				//row["Eaux [kwh]"] = data.Compute("Sum(aux)", "");
-
-				//todo auxiliaries
-				//foreach (var auxCol in data.Auxiliaries) {
-				//    row["Eaux_" + auxCol.jobName + " [kwh]"] = data.Compute("Sum(aux_" + auxCol.jobName + ")", "");
-				//}
-
-
-				//row["Ebrake [kwh]"] = data.Compute("Sum(brake)", "");
-				//row["Etransm [kwh]"] = data.Compute("Sum(transm)", "");
-				//row["Eretarder [kwh]"] = data.Compute("Sum(retarder)", "");
-				//row["Mass [kg]"] = Container.VehicleMass();
-				//row["Loading [kg]"] = Container.LoadingMass();
-				//row["a [m/s2]"] = data.Compute("Avg(a)", "");
-
-				////todo: a3s = average over 3 seconds!!!
-				//row["a_pos [m/s2]"] = data.Compute("Avg(a)", "a > 0.125");
-				//row["a_neg [m/s2]"] = data.Compute("Avg(a)", "a < -0.125");
-
-				//// todo: is this really acc.noise?
-				//row["Acc.Noise [m/s2]"] = data.Compute("Sum(a)", "a < 0.125 and a > -0.125");
-
-				//row["pAcc [%]"] = (double) data.Compute("Sum(time_interval)", "a > 0.125") /
-				//                  (double) data.Compute("Sum(time_interval)", "");
-				//row["pDec [%]"] = (double) data.Compute("Sum(time_interval)", "a > 0.125") /
-				//                  (double) data.Compute("Sum(time_interval)", "");
-				//row["pCruise [%]"] = (double) data.Compute("Sum(time_interval)", "a > 0.125") /
-				//                     (double) data.Compute("Sum(time_interval)", "");
-				//row["pStop [%]"] = (double) data.Compute("Sum(time_interval)", "a < 0.125 and a > -0.125") /
-				//                   (double) data.Compute("Sum(time_interval)", "");
-
-				table.ImportRow(row);
-				//VectoCSVFile.Write(jobFileName, table);
-			}
-		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
index 7013a40b5a..597269ddc0 100644
--- a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
+++ b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
@@ -15,6 +15,10 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 		private IEngineCockpit _engine;
 		private IGearboxCockpit _gearbox;
 		private ILog _logger;
+		private SummaryFileWriter _sumWriter;
+		private IModalDataWriter _dataWriter;
+		private string _jobName;
+		private string _cycleFileName;
 
 		#region IGearCockpit
 
@@ -49,9 +53,13 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 
 		#endregion
 
-		public VehicleContainer()
+		public VehicleContainer(IModalDataWriter dataWriter, SummaryFileWriter sumWriter, string jobName, string cycleFileName)
 		{
 			_logger = LogManager.GetLogger(GetType());
+			_dataWriter = dataWriter;
+			_sumWriter = sumWriter;
+			_jobName = jobName;
+			_cycleFileName = cycleFileName;
 		}
 
 		#region IVehicleContainer
@@ -73,19 +81,21 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 		}
 
 
-		public void CommitSimulationStep(IModalDataWriter dataWriter)
+		public void CommitSimulationStep()
 		{
 			_logger.Info("VehicleContainer committing simulation.");
 			foreach (var component in _components) {
-				component.CommitSimulationStep(dataWriter);
+				component.CommitSimulationStep(_dataWriter);
 			}
-			dataWriter.CommitSimulationStep();
+			_dataWriter.CommitSimulationStep();
 		}
 
-		public void FinishSimulation(IModalDataWriter dataWriter)
+		public void FinishSimulation()
 		{
 			_logger.Info("VehicleContainer finishing simulation.");
-			dataWriter.Finish();
+			_dataWriter.Finish();
+
+			_sumWriter.Write(_dataWriter, _jobName, _cycleFileName);
 		}
 
 		#endregion
diff --git a/VectoCoreTest/Models/Simulation/SimulationTests.cs b/VectoCoreTest/Models/Simulation/SimulationTests.cs
index a11a76fb64..8655c0ecd4 100644
--- a/VectoCoreTest/Models/Simulation/SimulationTests.cs
+++ b/VectoCoreTest/Models/Simulation/SimulationTests.cs
@@ -118,12 +118,12 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation
 				@"TestData\Results\EngineOnlyCycles\24t Coach_Engine Only2.vmod",
 				@"TestData\Results\EngineOnlyCycles\24t Coach_Engine Only3.vmod"
 			};
-			var sumFile = @"24t Coach.vsum";
-			var expectedSumFile = "24t Coach-expected.vsum";
 
+			var expectedSumFile = @"TestData\Results\EngineOnlyCycles\24t Coach.vsum";
+			var sumFile = @"24t Coach.vsum";
 			var resultFiles = expectedResultFiles.Select(x => Path.GetFileName(x));
 
-			//Assert.IsTrue(File.Exists(sumFile), "sum file is missing: " + sumFile);
+			Assert.IsTrue(File.Exists(sumFile), "sum file is missing: " + sumFile);
 			foreach (var result in resultFiles) {
 				Assert.IsTrue(File.Exists(result), "vmod file is missing: " + result);
 			}
-- 
GitLab