From 7abff660a2789ce21cd3bb8d0f5d655c26274ef2 Mon Sep 17 00:00:00 2001
From: Michael Krisper <michael.krisper@gmail.com>
Date: Tue, 17 Mar 2015 14:06:09 +0100
Subject: [PATCH] added Vecto Simulator, Vecto Job and a Factory for Creating
 Vecto Jobs (Powertrain Components and Cycle)

---
 VectoCore/Exceptions/VectoExceptions.cs       |  2 +-
 .../Simulation/Data/IModalDataWriter.cs       |  2 +
 .../Models/Simulation/Data/ModalDataWriter.cs | 38 ++++++++++++++
 VectoCore/Models/Simulation/IVectoJob.cs      |  9 ++++
 .../Models/Simulation/IVectoSimulator.cs      |  6 +++
 .../Models/Simulation/IVehicleContainer.cs    |  1 -
 .../Impl/EngineOnlyTimeBasedVectoJob.cs       | 35 +++++++++++++
 .../Simulation/Impl/SimulationFactory.cs      | 29 +++++++++++
 VectoCore/Models/Simulation/Impl/VectoJob.cs  | 36 +++++++++++++
 .../Models/Simulation/Impl/VectoSimulator.cs  | 25 ++++++++++
 .../Simulation/Impl/VehicleContainer.cs       | 24 ++++++++-
 VectoCore/VectoCore.csproj                    |  7 +++
 .../Simulation/SimulationFactoryTests.cs      | 50 +++++++++++++++++++
 VectoCoreTest/Utils/TestModalDataWriter.cs    |  5 ++
 VectoCoreTest/VectoCoreTest.csproj            |  1 +
 15 files changed, 266 insertions(+), 4 deletions(-)
 create mode 100644 VectoCore/Models/Simulation/Data/ModalDataWriter.cs
 create mode 100644 VectoCore/Models/Simulation/IVectoJob.cs
 create mode 100644 VectoCore/Models/Simulation/IVectoSimulator.cs
 create mode 100644 VectoCore/Models/Simulation/Impl/EngineOnlyTimeBasedVectoJob.cs
 create mode 100644 VectoCore/Models/Simulation/Impl/SimulationFactory.cs
 create mode 100644 VectoCore/Models/Simulation/Impl/VectoJob.cs
 create mode 100644 VectoCore/Models/Simulation/Impl/VectoSimulator.cs
 create mode 100644 VectoCoreTest/Models/Simulation/SimulationFactoryTests.cs

diff --git a/VectoCore/Exceptions/VectoExceptions.cs b/VectoCore/Exceptions/VectoExceptions.cs
index 8501d66543..a3f8425f4a 100644
--- a/VectoCore/Exceptions/VectoExceptions.cs
+++ b/VectoCore/Exceptions/VectoExceptions.cs
@@ -2,7 +2,7 @@
 
 namespace TUGraz.VectoCore.Exceptions
 {
-    class VectoException : Exception
+    public class VectoException : Exception
     {
         public VectoException(string message) : base(message) { }
         public VectoException(string message, Exception innerException) : base(message, innerException) { }
diff --git a/VectoCore/Models/Simulation/Data/IModalDataWriter.cs b/VectoCore/Models/Simulation/Data/IModalDataWriter.cs
index fa70d9e9e4..d19bfb1f0a 100644
--- a/VectoCore/Models/Simulation/Data/IModalDataWriter.cs
+++ b/VectoCore/Models/Simulation/Data/IModalDataWriter.cs
@@ -13,5 +13,7 @@
         /// Commits the data of the current simulation step.
         /// </summary>
         void CommitSimulationStep();
+
+        void Finish();
     }
 }
diff --git a/VectoCore/Models/Simulation/Data/ModalDataWriter.cs b/VectoCore/Models/Simulation/Data/ModalDataWriter.cs
new file mode 100644
index 0000000000..1bf238d03d
--- /dev/null
+++ b/VectoCore/Models/Simulation/Data/ModalDataWriter.cs
@@ -0,0 +1,38 @@
+using System.Data;
+using TUGraz.VectoCore.Utils;
+
+namespace TUGraz.VectoCore.Models.Simulation.Data
+{
+    public class ModalDataWriter : IModalDataWriter
+    {
+        private ModalResults Data { get; set; }
+
+        private DataRow CurrentRow { get; set; }
+
+        public ModalDataWriter(string fileName)
+        {
+            FileName = fileName;
+            Data = new ModalResults();
+            CurrentRow = Data.NewRow();
+        }
+
+        public string FileName { get; set; }
+
+        public void CommitSimulationStep()
+        {
+            Data.Rows.Add(CurrentRow);
+            CurrentRow = Data.NewRow();
+        }
+
+        public void Finish()
+        {
+            VectoCSVFile.Write(FileName, Data);
+        }
+
+        public object this[ModalResultField key]
+        {
+            get { return CurrentRow[key.GetName()]; }
+            set { CurrentRow[key.GetName()] = value; }
+        }
+    }
+}
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/IVectoJob.cs b/VectoCore/Models/Simulation/IVectoJob.cs
new file mode 100644
index 0000000000..57b45c519d
--- /dev/null
+++ b/VectoCore/Models/Simulation/IVectoJob.cs
@@ -0,0 +1,9 @@
+namespace TUGraz.VectoCore.Models.Simulation
+{
+    public interface IVectoJob
+    {
+        void Run();
+
+        IVehicleContainer GetContainer();
+    }
+}
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/IVectoSimulator.cs b/VectoCore/Models/Simulation/IVectoSimulator.cs
new file mode 100644
index 0000000000..c07fb0bfc7
--- /dev/null
+++ b/VectoCore/Models/Simulation/IVectoSimulator.cs
@@ -0,0 +1,6 @@
+namespace TUGraz.VectoCore.Models.Simulation
+{
+    public interface IVectoSimulator
+    {
+    }
+}
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/IVehicleContainer.cs b/VectoCore/Models/Simulation/IVehicleContainer.cs
index 58f827591a..999e601ae6 100644
--- a/VectoCore/Models/Simulation/IVehicleContainer.cs
+++ b/VectoCore/Models/Simulation/IVehicleContainer.cs
@@ -6,6 +6,5 @@ namespace TUGraz.VectoCore.Models.Simulation
 	public interface IVehicleContainer : ICockpit
 	{
 		void AddComponent(VectoSimulationComponent component);
-
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/EngineOnlyTimeBasedVectoJob.cs b/VectoCore/Models/Simulation/Impl/EngineOnlyTimeBasedVectoJob.cs
new file mode 100644
index 0000000000..4d3160fe26
--- /dev/null
+++ b/VectoCore/Models/Simulation/Impl/EngineOnlyTimeBasedVectoJob.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using TUGraz.VectoCore.Models.Simulation.Data;
+
+namespace TUGraz.VectoCore.Models.Simulation.Impl
+{
+    public class EngineOnlyTimeBasedVectoJob : TimeBasedVectoJob
+    {
+        private List<EngineOnlyDrivingCycle> _cycles;
+        private IModalDataWriter _dataWriter;
+
+        public EngineOnlyTimeBasedVectoJob(VehicleContainer container, List<EngineOnlyDrivingCycle> cycles, IModalDataWriter dataWriter)
+            : base(container)
+        {
+            _cycles = cycles;
+            _dataWriter = dataWriter;
+        }
+
+        public override void Run()
+        {
+            var port = Container.GetEngineOnlyStartPort();
+            var absTime = new TimeSpan(seconds: 0, minutes: 0, hours: 0);
+            var dt = new TimeSpan(seconds: 1, minutes: 0, hours: 0);
+
+            foreach (var cycle in _cycles)
+            {
+                port.Request(absTime, dt, cycle.Torque, cycle.EngineSpeed);
+                Container.CommitSimulationStep(_dataWriter);
+
+                absTime += dt;
+            }
+            Container.FinishSimulation(_dataWriter);
+        }
+    }
+}
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/SimulationFactory.cs b/VectoCore/Models/Simulation/Impl/SimulationFactory.cs
new file mode 100644
index 0000000000..036f2868f1
--- /dev/null
+++ b/VectoCore/Models/Simulation/Impl/SimulationFactory.cs
@@ -0,0 +1,29 @@
+using TUGraz.VectoCore.Models.Simulation.Data;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.Models.SimulationComponent.Impl;
+
+namespace TUGraz.VectoCore.Models.Simulation.Impl
+{
+    public class SimulationFactory
+    {
+        public static IVectoJob CreateTimeBasedEngineOnlyJob(string engineFile, string cycleFile, string resultFile)
+        {
+            var container = new VehicleContainer();
+            var engineData = CombustionEngineData.ReadFromFile(engineFile);
+            var engine = new CombustionEngine(container, engineData);
+            var gearBox = new EngineOnlyGearbox(container);
+
+            var engineOutShaft = engine.OutShaft();
+            var gearBoxInShaft = gearBox.InShaft();
+
+            gearBoxInShaft.Connect(engineOutShaft);
+
+            var cycles = EngineOnlyDrivingCycle.ReadFromFile(cycleFile.ToString());
+            var dataWriter = new ModalDataWriter(resultFile);
+
+            var job = new EngineOnlyTimeBasedVectoJob(container, cycles, dataWriter);
+
+            return job;
+        }
+    }
+}
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/VectoJob.cs b/VectoCore/Models/Simulation/Impl/VectoJob.cs
new file mode 100644
index 0000000000..023bb5dec1
--- /dev/null
+++ b/VectoCore/Models/Simulation/Impl/VectoJob.cs
@@ -0,0 +1,36 @@
+namespace TUGraz.VectoCore.Models.Simulation.Impl
+{
+    public abstract class VectoJob : IVectoJob
+    {
+        protected VehicleContainer Container { get; set; }
+
+        protected VectoJob(VehicleContainer container)
+        {
+            Container = container;
+        }
+
+        public abstract void Run();
+        public IVehicleContainer GetContainer()
+        {
+            return Container;
+        }
+    }
+
+    public abstract class DistanceBasedVectoJob : VectoJob
+    {
+        protected DistanceBasedVectoJob(VehicleContainer container)
+            : base(container)
+        {
+
+        }
+
+    }
+
+    public abstract class TimeBasedVectoJob : VectoJob
+    {
+        protected TimeBasedVectoJob(VehicleContainer container)
+            : base(container)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/VectoSimulator.cs b/VectoCore/Models/Simulation/Impl/VectoSimulator.cs
new file mode 100644
index 0000000000..d73e3ebca7
--- /dev/null
+++ b/VectoCore/Models/Simulation/Impl/VectoSimulator.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace TUGraz.VectoCore.Models.Simulation.Impl
+{
+    public class VectoSimulator : IVectoSimulator
+    {
+        private List<IVectoJob> _jobs = new List<IVectoJob>();
+        private List<Task> _runningTasks = new List<Task>();
+
+        public void AddJob(IVectoJob job)
+        {
+            _jobs.Add(job);
+        }
+
+        public void RunSimulation()
+        {
+            foreach (var job in _jobs)
+            {
+                var task = Task.Factory.StartNew(() => job.Run());
+                _runningTasks.Add(task);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
index 01bd713b48..9fa4eb98a2 100644
--- a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
+++ b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs
@@ -1,7 +1,9 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using TUGraz.VectoCore.Exceptions;
+using TUGraz.VectoCore.Models.Connector.Ports;
 using TUGraz.VectoCore.Models.Simulation.Cockpit;
+using TUGraz.VectoCore.Models.Simulation.Data;
 using TUGraz.VectoCore.Models.SimulationComponent;
 
 namespace TUGraz.VectoCore.Models.Simulation.Impl
@@ -56,7 +58,25 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 		{
 			_components.Add(component);
 		}
-	
-	
+
+
+        public ITnOutPort GetEngineOnlyStartPort()
+	    {
+            //todo: find a better solution for getting the initial port in a powertrain
+	        return (_gearbox as IGearbox).OutShaft();
+	    }
+
+	    public void CommitSimulationStep(IModalDataWriter dataWriter)
+	    {
+            foreach (var c in _components)
+            {
+                c.CommitSimulationStep(dataWriter);
+            }
+	    }
+
+        public void FinishSimulation(IModalDataWriter dataWriter)
+        {
+            dataWriter.Finish();
+        }
 	}
 }
diff --git a/VectoCore/VectoCore.csproj b/VectoCore/VectoCore.csproj
index b8d6895b3a..6827b10477 100644
--- a/VectoCore/VectoCore.csproj
+++ b/VectoCore/VectoCore.csproj
@@ -87,6 +87,13 @@
     <Compile Include="Models\Simulation\Data\ModalResult.cs">
       <SubType>Component</SubType>
     </Compile>
+    <Compile Include="Models\Simulation\Impl\EngineOnlyTimeBasedVectoJob.cs" />
+    <Compile Include="Models\Simulation\IVectoJob.cs" />
+    <Compile Include="Models\Simulation\IVectoSimulator.cs" />
+    <Compile Include="Models\Simulation\Data\ModalDataWriter.cs" />
+    <Compile Include="Models\Simulation\Impl\SimulationFactory.cs" />
+    <Compile Include="Models\Simulation\Impl\VectoJob.cs" />
+    <Compile Include="Models\Simulation\Impl\VectoSimulator.cs" />
     <Compile Include="Models\Simulation\Impl\VehicleContainer.cs" />
     <Compile Include="Models\Simulation\Cockpit\ICockpit.cs" />
     <Compile Include="Models\Simulation\Cockpit\IEngineCockpit.cs" />
diff --git a/VectoCoreTest/Models/Simulation/SimulationFactoryTests.cs b/VectoCoreTest/Models/Simulation/SimulationFactoryTests.cs
new file mode 100644
index 0000000000..6f12d0aa7e
--- /dev/null
+++ b/VectoCoreTest/Models/Simulation/SimulationFactoryTests.cs
@@ -0,0 +1,50 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using TUGraz.VectoCore.Models.Simulation.Impl;
+using TUGraz.VectoCore.Exceptions;
+
+namespace TUGraz.VectoCore.Tests.Models.Simulation
+{
+    [TestClass]
+    public class SimulationFactoryTests
+    {
+        private const string EngineFile = @"TestData\EngineOnly\EngineMaps\24t Coach.veng";
+        private const string CycleFile = @"TestData\EngineOnly\Cycles\Coach Engine Only.vdri";
+
+        [TestMethod]
+        public void TestEngineOnly()
+        {
+            var job = SimulationFactory.CreateTimeBasedEngineOnlyJob(EngineFile, CycleFile,  "TestEngineOnly-result.vmod");
+
+            var container = job.GetContainer();
+
+            Assert.AreEqual(560, container.EngineSpeed(), "Engine Speed");
+            Assert.AreEqual(0U, container.Gear(), "Gear");
+
+            try
+            {
+                container.VehicleSpeed();
+                Assert.Fail("Access to Vehicle speed should fail, because there should be no vehicle in EngineOnly Mode.");
+            }
+            catch (VectoException ex)
+            {
+                Assert.AreEqual(ex.Message, "no vehicle available!", "Vehicle speed wrong exception message.");
+            }
+        }
+
+        [TestMethod]
+        public void TestEngineOnly_JobRun()
+        {
+            var job = SimulationFactory.CreateTimeBasedEngineOnlyJob(EngineFile, CycleFile, "TestEngineOnly-result.vmod");
+            job.Run();
+        }
+
+        [TestMethod]
+        public void TestEngineOnly_SimulatorRun()
+        {
+            var sim = new VectoSimulator();
+            var job = SimulationFactory.CreateTimeBasedEngineOnlyJob(EngineFile, CycleFile, "TestEngineOnly-result.vmod");
+            sim.AddJob(job);            
+            sim.RunSimulation();
+        }
+    }
+}
diff --git a/VectoCoreTest/Utils/TestModalDataWriter.cs b/VectoCoreTest/Utils/TestModalDataWriter.cs
index 1bab253151..4718d6e2e9 100644
--- a/VectoCoreTest/Utils/TestModalDataWriter.cs
+++ b/VectoCoreTest/Utils/TestModalDataWriter.cs
@@ -23,6 +23,11 @@ namespace TUGraz.VectoCore.Tests.Utils
             CurrentRow = Data.NewRow();
         }
 
+        public void Finish()
+        {
+            
+        }
+
         public object this[ModalResultField key]
         {
             get { return CurrentRow[key.GetName()]; }
diff --git a/VectoCoreTest/VectoCoreTest.csproj b/VectoCoreTest/VectoCoreTest.csproj
index 4483c5b508..6d25d04231 100644
--- a/VectoCoreTest/VectoCoreTest.csproj
+++ b/VectoCoreTest/VectoCoreTest.csproj
@@ -71,6 +71,7 @@
     <Compile Include="Models\SimulationComponent\CombustionEngineTest.cs" />
     <Compile Include="Models\SimulationComponent\GearboxTest.cs" />
     <Compile Include="Models\SimulationComponent\WheelTest.cs" />
+    <Compile Include="Models\Simulation\SimulationFactoryTests.cs" />
     <Compile Include="Models\Simulation\VechicleContainerTests.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\Settings.Designer.cs">
-- 
GitLab