diff --git a/VectoCommon/VectoHashingTest/VectoHashTest.cs b/VectoCommon/VectoHashingTest/VectoHashTest.cs index 2a6c5c43ea742558568b64662e0cb0bc01664fb7..a38bbeacaa4f12c341bbeb90019ade3c44ff749a 100644 --- a/VectoCommon/VectoHashingTest/VectoHashTest.cs +++ b/VectoCommon/VectoHashingTest/VectoHashTest.cs @@ -29,430 +29,430 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.IO; -using System.Linq; -using System.Text; -using System.Xml; -using System.Xml.Linq; -using System.Xml.Schema; -using NUnit.Framework; -using TUGraz.VectoCore.Utils; -using TUGraz.VectoHashing; -using VectoHashingTest.Utils; -using Assert = NUnit.Framework.Assert; - -namespace VectoHashingTest -{ - [TestFixture] - public class VectoHashTest - { - public const string ReferenceXMLEngine = @"Testdata\XML\Reference\vecto_engine-sample.xml"; - public const string ReferenceXMLVehicle = @"Testdata\XML\Reference\vecto_vehicle-sample_FULL.xml"; - - [TestCase] - public void TestComponentsEngineFile() - { - var h = VectoHash.Load(ReferenceXMLEngine); - var components = h.GetContainigComponents().ToList(); - - Assert.AreEqual(1, components.Count); - Assert.AreEqual(VectoComponents.Engine, components[0]); - } - - [TestCase] - public void TestComponentsVehicleFile() - { - var h = VectoHash.Load(ReferenceXMLVehicle); - var components = h.GetContainigComponents().ToList(); - - Assert.AreEqual(10, components.Count); - } - - [TestCase(ReferenceXMLEngine, VectoComponents.Engine, BasicHasingTests.HashEngineXML)] - public void TestHashComputationSelected(string file, VectoComponents component, string expectedHash) - { - var h = VectoHash.Load(file); - var hash = h.ComputeHash(component); - - Assert.AreEqual(expectedHash, hash); - } - - [TestCase(ReferenceXMLVehicle, BasicHasingTests.HashVehicleXML), - TestCase(ReferenceXMLEngine, BasicHasingTests.HashEngineXML)] - public void TestHashComputation(string file, string expectedHash) - { - var h = VectoHash.Load(file); - var hash = h.ComputeHash(); - - Assert.AreEqual(expectedHash, hash); - } - - [TestCase(ReferenceXMLEngine)] - public void TestHashComputationInvalidComponent(string file) - { - var h = VectoHash.Load(file); - AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Gearbox), "Component Gearbox not found"); - } - - [TestCase(ReferenceXMLEngine)] - public void TestReadHashInvalidComponent(string file) - { - var h = VectoHash.Load(file); - AssertHelper.Exception<Exception>(() => h.ReadHash(VectoComponents.Gearbox), "Component Gearbox not found"); - } - - [TestCase(ReferenceXMLVehicle, VectoComponents.Engine, "e0c253b643f7f8f09b963aca4a264d06fbfa599f"), - TestCase(ReferenceXMLVehicle, VectoComponents.Gearbox, "d14189366134120e08fa3f2c6e3328dd13c08a23")] - public void TestReadHash(string file, VectoComponents component, string expectedHash) - { - var h = VectoHash.Load(file); - var existingHash = h.ReadHash(component); - - Assert.AreEqual(expectedHash, existingHash); - } - - [TestCase(ReferenceXMLVehicle, VectoComponents.Tyre, 0, "5074334bb2c090c5e258e9a664f5d19689a3f13d"), - TestCase(ReferenceXMLVehicle, VectoComponents.Tyre, 1, "6074334bb2c090c5e258e9a664f5d19689a3f13d")] - public void TestReadHashIdx(string file, VectoComponents component, int index, string expectedHash) - { - var h = VectoHash.Load(file); - var existingHash = h.ReadHash(component, index); - - Assert.AreEqual(expectedHash, existingHash); - } - - [TestCase] - public void TestReadTyres1Index() - { - var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle1.xml"; - var h = VectoHash.Load(file); - var expectedHash = new[] { - "5074334bb2c090c5e258e9a664f5d19689a3f13d", - "6074334bb2c090c5e258e9a664f5d19689a3f13d", - "6074334bb2c090c5e258e9a664f5d19689a3f13d" - }; - - for (int i = 0; i < expectedHash.Length; i++) { - var existingHash = h.ReadHash(VectoComponents.Tyre, i); - - Assert.AreEqual(expectedHash[i], existingHash); - } - } - - [TestCase] - public void TestReadTyres2Index() - { - var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle2.xml"; - var h = VectoHash.Load(file); - var expectedHash = new[] { - "5074334bb2c090c5e258e9a664f5d19689a3f13d", - "5074334bb2c090c5e258e9a664f5d19689a3f13d", - "6074334bb2c090c5e258e9a664f5d19689a3f13d" - }; - - for (int i = 0; i < expectedHash.Length; i++) { - var existingHash = h.ReadHash(VectoComponents.Tyre, i); - - Assert.AreEqual(expectedHash[i], existingHash); - } - - AssertHelper.Exception<Exception>(() => h.ReadHash(VectoComponents.Tyre, 3), - "index exceeds number of components found! index: 3, #components: 3"); - } - - [TestCase] - public void TestComputeTyres1Index() - { - var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle1.xml"; - var h = VectoHash.Load(file); - - var hash1 = h.ComputeHash(VectoComponents.Tyre, 1); - var hash2 = h.ComputeHash(VectoComponents.Tyre, 2); - - Assert.AreEqual(hash1, hash2); - - AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Tyre, 3), - "index exceeds number of components found! index: 3, #components: 3"); - } - - [TestCase] - public void TestComputeTyres2Index() - { - var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle2.xml"; - var h = VectoHash.Load(file); - - var hash1 = h.ComputeHash(VectoComponents.Tyre, 0); - var hash2 = h.ComputeHash(VectoComponents.Tyre, 1); - - Assert.AreEqual(hash1, hash2); - - AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Tyre, 3), - "index exceeds number of components found! index: 3, #components: 3"); - } - - [TestCase("vecto_vehicle-sample_FULL_Comments.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_vehicle-sample_FULL_Entry_Order.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_vehicle-sample_FULL_Newlines_Linux_LF.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_vehicle-sample_FULL_Newlines_Mac_CR.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_vehicle-sample_FULL_Newlines_Windows_CRLF.xml", BasicHasingTests.HashVehicleXML), - TestCase("vecto_engine-sample Encoding ISO 8859-15.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding UTF-8 BOM.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding UTF-8.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding UTF-16 BE BOM.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding UTF-16 LE.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample Encoding windows-1292.xml", BasicHasingTests.HashEngineXML), - TestCase("vecto_engine-sample_Whitespaces.xml", BasicHasingTests.HashEngineXML), - ] - public void TestHashComputationVariations(string file, string expectedHash) - { - var h = VectoHash.Load(@"Testdata\XML\Variations\" + file); - var hash = h.ComputeHash(); - - Assert.AreEqual(expectedHash, hash); - } - - - [TestCase(@"Testdata\XML\Validation\vecto_engine_valid.xml"), - TestCase(@"Testdata\XML\Validation\vecto_gearbox_valid.xml")] - public void TestValidation(string file) - { - var h = VectoHash.Load(file); - Assert.IsTrue(h.ValidateHash()); - } - - [TestCase(@"Testdata\XML\Validation\vecto_engine_invalid.xml"), - TestCase(@"Testdata\XML\Validation\vecto_gearbox_invalid.xml")] - public void TestValidationInvalid(string file) - { - var h = VectoHash.Load(file); - Assert.IsFalse(h.ValidateHash()); - } - - [TestCase(VectoComponents.Engine), - TestCase(VectoComponents.Gearbox), - ] - public void TestValidationComponentValid(VectoComponents component) - { - var file = @"Testdata\XML\Validation\vecto_vehicle_components_valid-engine_gbx.xml"; - var h = VectoHash.Load(file); - - Assert.IsTrue(h.ValidateHash(component)); - } - - [TestCase(VectoComponents.Engine), - TestCase(VectoComponents.Gearbox), - TestCase(VectoComponents.Axlegear), - TestCase(VectoComponents.Angledrive), - TestCase(VectoComponents.Retarder), - TestCase(VectoComponents.TorqueConverter), - TestCase(VectoComponents.Tyre), - TestCase(VectoComponents.Airdrag), - ] - public void TestValidationComponentInvalid(VectoComponents component) - { - var file = @"Testdata\XML\Validation\vecto_vehicle_components_invalid.xml"; - var h = VectoHash.Load(file); - - Assert.IsFalse(h.ValidateHash(component)); - } - - [TestCase(@"Testdata\XML\ToHash\vecto_engine-input.xml"), - TestCase(@"Testdata\XML\ToHash\vecto_engine_withid-input.xml"), - TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input.xml")] - public void TestAddHash(string file) - { - var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; - - var h = VectoHash.Load(file); - var r = h.AddHash(); - - var writer = new XmlTextWriter(destination, Encoding.UTF8); - r.WriteTo(writer); - writer.Flush(); - writer.Close(); - - var h2 = VectoHash.Load(destination); - Assert.IsTrue(h2.ValidateHash()); - } - - [TestCase(@"Testdata\XML\ToHash\vecto_engine_withhash-input.xml", "input data already contains a signature element"), - TestCase(@"Testdata\XML\ToHash\vecto_vehicle-sample.xml", "adding hash for Vehicle is not supported"), - TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input_nodata.xml", "'Data' element for component 'Gearbox' not found!"), - TestCase(@"Testdata\XML\ToHash\multiple_components.xml", "input must not contain multiple components!"), - ] - public void TestAddHashException(string file, string expectedExceptionMsg) - { - var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; - - var h = VectoHash.Load(file); - AssertHelper.Exception<Exception>(() => { var r = h.AddHash(); }, expectedExceptionMsg); - } - - [TestCase] - public void TestDuplicateSigElement() - { - var filename = @"Testdata\XML\Invalid\duplicate-sig.xml"; - var h = VectoHash.Load(filename); - - AssertHelper.Exception<Exception>(() => { var r = h.ReadHash(); }, "Multiple DigestValue elements found!"); - } - - - [TestCase()] - public void TestLoadFromStream() - { - var fs = new FileStream(BasicHasingTests.ReferenceXMLVehicle, FileMode.Open); - var h = VectoHash.Load(fs); - - var hash = h.ComputeHash(); - Assert.AreEqual(BasicHasingTests.HashVehicleXML, hash); - fs.Close(); - } - - [TestCase(WhitespaceHandling.All), - TestCase(WhitespaceHandling.None), - TestCase(WhitespaceHandling.Significant)] - public void TestLoadXmlDocument(WhitespaceHandling whitespace) - { - var xml = new XmlDocument(); - var reader = new XmlTextReader(BasicHasingTests.ReferenceXMLVehicle); - reader.WhitespaceHandling = whitespace; - xml.Load(reader); - var h = VectoHash.Load(xml); - - var hash = h.ComputeHash(); - Assert.AreEqual(BasicHasingTests.HashVehicleXML, hash); - } - - [TestCase(@"Testdata\XML\ToHash\vecto_engine-input.xml"), - TestCase(@"Testdata\XML\ToHash\vecto_engine_withid-input.xml"), - TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input.xml")] - public void TestHashedComponentIsValid(string file) - { - var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; - - var h = VectoHash.Load(file); - var r = h.AddHash(); - - var writer = new XmlTextWriter(destination, Encoding.UTF8); - r.WriteTo(writer); - writer.Flush(); - writer.Close(); - - var h2 = VectoHash.Load(destination); - Assert.IsTrue(h2.ValidateHash()); - - // re-load generated XML and perform XSD validation - var settings = new XmlReaderSettings() { - ValidationType = ValidationType.Schema, - ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema | - //XmlSchemaValidationFlags.ProcessSchemaLocation | - XmlSchemaValidationFlags.ReportValidationWarnings - }; - settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack); - settings.Schemas.Add(GetXMLSchema(false)); - var xmlValidator = XmlReader.Create(destination, settings); - var xmlDoc = XDocument.Load(xmlValidator); - } - - - [TestCase("vecto_vehicle-namespace_prefix.xml", BasicHasingTests.HashVehicleXML)] - public void TestNamespacePrefixVariations(string file, string expectedHash) - { - var h = VectoHash.Load(@"Testdata\XML\Variations\" + file); - var hash = h.ComputeHash(); - - Assert.AreEqual(expectedHash, hash); - } - - [TestCase()] - public void TestInvalidXMLAsFile() - { - var file = @"Testdata\XML\Invalid\invalid-comp.xml"; - - AssertHelper.Exception<Exception>(() => VectoHash.Load(file), "failed to read XML document"); - } - - [TestCase()] - public void TestInvalidXMLAsStream() - { - var file = @"Testdata\XML\Invalid\invalid-comp.xml"; - var stream = File.Open(file, FileMode.Open); - AssertHelper.Exception<Exception>(() => VectoHash.Load(stream), "failed to read XML document"); - } - - [TestCase()] - public void TestComputeHashNoComponentInXML() - { - var xml = @"<VectoInputDeclaration/>"; - var stream = new MemoryStream(); - var writer = new StreamWriter(stream); - writer.Write(xml); - writer.Flush(); - stream.Seek(0, SeekOrigin.Begin); - - var h = VectoHash.Load(stream); - AssertHelper.Exception<Exception>(() => h.ComputeHash(), "No component found"); - } - - [TestCase()] - public void TestReadHashNoComponentInXML() - { - var xml = @"<VectoInputDeclaration/>"; - var stream = new MemoryStream(); - var writer = new StreamWriter(stream); - writer.Write(xml); - writer.Flush(); - stream.Seek(0, SeekOrigin.Begin); - - var h = VectoHash.Load(stream); - AssertHelper.Exception<Exception>(() => h.ReadHash(), "No component found"); - } - - [TestCase(VectoComponents.Engine, "ENG-"), - TestCase(VectoComponents.Gearbox, "GBX-"), - TestCase(VectoComponents.Axlegear, "AXL-"), - TestCase(VectoComponents.Retarder, "RET-"), - TestCase(VectoComponents.TorqueConverter, "TC-"), - TestCase(VectoComponents.Angledrive, "ANGL-"), - TestCase(VectoComponents.Airdrag, "AD-"), - TestCase(VectoComponents.Tyre, "TYRE-"), - ] - public void TestIdPrefix(VectoComponents component, string expectedPrefix) - { - Assert.AreEqual(expectedPrefix, component.HashIdPrefix()); - } - - [TestCase()] - public void TestInvalidComponentXMLName() - { - AssertHelper.Exception<ArgumentOutOfRangeException>(() => ((VectoComponents)9999).XMLElementName()); - } - - [TestCase()] - public void TestInvalidComponentPrefix() - { - AssertHelper.Exception<ArgumentOutOfRangeException>(() => ((VectoComponents)9999).HashIdPrefix()); - } - - private static XmlSchemaSet GetXMLSchema(bool job) - { - var resource = RessourceHelper.LoadResourceAsStream(RessourceHelper.ResourceType.XMLSchema, - job ? "VectoInput.xsd" : "VectoComponent.xsd"); - var xset = new XmlSchemaSet() { XmlResolver = new XmlResourceResolver() }; - var reader = XmlReader.Create(resource, new XmlReaderSettings(), "schema://"); - xset.Add(XmlSchema.Read(reader, null)); - xset.Compile(); - return xset; - } - - private static void ValidationCallBack(object sender, ValidationEventArgs args) - { - if (args.Severity == XmlSeverityType.Error) { - throw new Exception(string.Format("Validation error: {0}" + Environment.NewLine + - "Line: {1}", args.Message, args.Exception.LineNumber)); - } - } - } +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; +using System.Xml.Linq; +using System.Xml.Schema; +using NUnit.Framework; +using TUGraz.VectoCore.Utils; +using TUGraz.VectoHashing; +using VectoHashingTest.Utils; +using Assert = NUnit.Framework.Assert; + +namespace VectoHashingTest +{ + [TestFixture] + public class VectoHashTest + { + public const string ReferenceXMLEngine = @"Testdata\XML\Reference\vecto_engine-sample.xml"; + public const string ReferenceXMLVehicle = @"Testdata\XML\Reference\vecto_vehicle-sample_FULL.xml"; + + [TestCase] + public void TestComponentsEngineFile() + { + var h = VectoHash.Load(ReferenceXMLEngine); + var components = h.GetContainigComponents().ToList(); + + Assert.AreEqual(1, components.Count); + Assert.AreEqual(VectoComponents.Engine, components[0]); + } + + [TestCase] + public void TestComponentsVehicleFile() + { + var h = VectoHash.Load(ReferenceXMLVehicle); + var components = h.GetContainigComponents().ToList(); + + Assert.AreEqual(10, components.Count); + } + + [TestCase(ReferenceXMLEngine, VectoComponents.Engine, BasicHasingTests.HashEngineXML)] + public void TestHashComputationSelected(string file, VectoComponents component, string expectedHash) + { + var h = VectoHash.Load(file); + var hash = h.ComputeHash(component); + + Assert.AreEqual(expectedHash, hash); + } + + [TestCase(ReferenceXMLVehicle, BasicHasingTests.HashVehicleXML), + TestCase(ReferenceXMLEngine, BasicHasingTests.HashEngineXML)] + public void TestHashComputation(string file, string expectedHash) + { + var h = VectoHash.Load(file); + var hash = h.ComputeHash(); + + Assert.AreEqual(expectedHash, hash); + } + + [TestCase(ReferenceXMLEngine)] + public void TestHashComputationInvalidComponent(string file) + { + var h = VectoHash.Load(file); + AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Gearbox), "Component Gearbox not found"); + } + + [TestCase(ReferenceXMLEngine)] + public void TestReadHashInvalidComponent(string file) + { + var h = VectoHash.Load(file); + AssertHelper.Exception<Exception>(() => h.ReadHash(VectoComponents.Gearbox), "Component Gearbox not found"); + } + + [TestCase(ReferenceXMLVehicle, VectoComponents.Engine, "e0c253b643f7f8f09b963aca4a264d06fbfa599f"), + TestCase(ReferenceXMLVehicle, VectoComponents.Gearbox, "d14189366134120e08fa3f2c6e3328dd13c08a23")] + public void TestReadHash(string file, VectoComponents component, string expectedHash) + { + var h = VectoHash.Load(file); + var existingHash = h.ReadHash(component); + + Assert.AreEqual(expectedHash, existingHash); + } + + [TestCase(ReferenceXMLVehicle, VectoComponents.Tyre, 0, "5074334bb2c090c5e258e9a664f5d19689a3f13d"), + TestCase(ReferenceXMLVehicle, VectoComponents.Tyre, 1, "6074334bb2c090c5e258e9a664f5d19689a3f13d")] + public void TestReadHashIdx(string file, VectoComponents component, int index, string expectedHash) + { + var h = VectoHash.Load(file); + var existingHash = h.ReadHash(component, index); + + Assert.AreEqual(expectedHash, existingHash); + } + + [TestCase] + public void TestReadTyres1Index() + { + var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle1.xml"; + var h = VectoHash.Load(file); + var expectedHash = new[] { + "5074334bb2c090c5e258e9a664f5d19689a3f13d", + "6074334bb2c090c5e258e9a664f5d19689a3f13d", + "6074334bb2c090c5e258e9a664f5d19689a3f13d" + }; + + for (int i = 0; i < expectedHash.Length; i++) { + var existingHash = h.ReadHash(VectoComponents.Tyre, i); + + Assert.AreEqual(expectedHash[i], existingHash); + } + } + + [TestCase] + public void TestReadTyres2Index() + { + var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle2.xml"; + var h = VectoHash.Load(file); + var expectedHash = new[] { + "5074334bb2c090c5e258e9a664f5d19689a3f13d", + "5074334bb2c090c5e258e9a664f5d19689a3f13d", + "6074334bb2c090c5e258e9a664f5d19689a3f13d" + }; + + for (int i = 0; i < expectedHash.Length; i++) { + var existingHash = h.ReadHash(VectoComponents.Tyre, i); + + Assert.AreEqual(expectedHash[i], existingHash); + } + + AssertHelper.Exception<Exception>(() => h.ReadHash(VectoComponents.Tyre, 3), + "index exceeds number of components found! index: 3, #components: 3"); + } + + [TestCase] + public void TestComputeTyres1Index() + { + var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle1.xml"; + var h = VectoHash.Load(file); + + var hash1 = h.ComputeHash(VectoComponents.Tyre, 1); + var hash2 = h.ComputeHash(VectoComponents.Tyre, 2); + + Assert.AreEqual(hash1, hash2); + + AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Tyre, 3), + "index exceeds number of components found! index: 3, #components: 3"); + } + + [TestCase] + public void TestComputeTyres2Index() + { + var file = @"Testdata\XML\ToHash\vecto_vehicle-sample_3axle2.xml"; + var h = VectoHash.Load(file); + + var hash1 = h.ComputeHash(VectoComponents.Tyre, 0); + var hash2 = h.ComputeHash(VectoComponents.Tyre, 1); + + Assert.AreEqual(hash1, hash2); + + AssertHelper.Exception<Exception>(() => h.ComputeHash(VectoComponents.Tyre, 3), + "index exceeds number of components found! index: 3, #components: 3"); + } + + [TestCase("vecto_vehicle-sample_FULL_Comments.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_vehicle-sample_FULL_Entry_Order.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_vehicle-sample_FULL_Newlines_Linux_LF.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_vehicle-sample_FULL_Newlines_Mac_CR.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_vehicle-sample_FULL_Newlines_Windows_CRLF.xml", BasicHasingTests.HashVehicleXML), + TestCase("vecto_engine-sample Encoding ISO 8859-15.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding UTF-8 BOM.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding UTF-8.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding UTF-16 BE BOM.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding UTF-16 LE.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample Encoding windows-1292.xml", BasicHasingTests.HashEngineXML), + TestCase("vecto_engine-sample_Whitespaces.xml", BasicHasingTests.HashEngineXML), + ] + public void TestHashComputationVariations(string file, string expectedHash) + { + var h = VectoHash.Load(@"Testdata\XML\Variations\" + file); + var hash = h.ComputeHash(); + + Assert.AreEqual(expectedHash, hash); + } + + + [TestCase(@"Testdata\XML\Validation\vecto_engine_valid.xml"), + TestCase(@"Testdata\XML\Validation\vecto_gearbox_valid.xml")] + public void TestValidation(string file) + { + var h = VectoHash.Load(file); + Assert.IsTrue(h.ValidateHash()); + } + + [TestCase(@"Testdata\XML\Validation\vecto_engine_invalid.xml"), + TestCase(@"Testdata\XML\Validation\vecto_gearbox_invalid.xml")] + public void TestValidationInvalid(string file) + { + var h = VectoHash.Load(file); + Assert.IsFalse(h.ValidateHash()); + } + + [TestCase(VectoComponents.Engine), + TestCase(VectoComponents.Gearbox), + ] + public void TestValidationComponentValid(VectoComponents component) + { + var file = @"Testdata\XML\Validation\vecto_vehicle_components_valid-engine_gbx.xml"; + var h = VectoHash.Load(file); + + Assert.IsTrue(h.ValidateHash(component)); + } + + [TestCase(VectoComponents.Engine), + TestCase(VectoComponents.Gearbox), + TestCase(VectoComponents.Axlegear), + TestCase(VectoComponents.Angledrive), + TestCase(VectoComponents.Retarder), + TestCase(VectoComponents.TorqueConverter), + TestCase(VectoComponents.Tyre), + TestCase(VectoComponents.Airdrag), + ] + public void TestValidationComponentInvalid(VectoComponents component) + { + var file = @"Testdata\XML\Validation\vecto_vehicle_components_invalid.xml"; + var h = VectoHash.Load(file); + + Assert.IsFalse(h.ValidateHash(component)); + } + + [TestCase(@"Testdata\XML\ToHash\vecto_engine-input.xml"), + TestCase(@"Testdata\XML\ToHash\vecto_engine_withid-input.xml"), + TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input.xml")] + public void TestAddHash(string file) + { + var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; + + var h = VectoHash.Load(file); + var r = h.AddHash(); + + var writer = new XmlTextWriter(destination, Encoding.UTF8); + r.WriteTo(writer); + writer.Flush(); + writer.Close(); + + var h2 = VectoHash.Load(destination); + Assert.IsTrue(h2.ValidateHash()); + } + + [TestCase(@"Testdata\XML\ToHash\vecto_engine_withhash-input.xml", "input data already contains a signature element"), + TestCase(@"Testdata\XML\ToHash\vecto_vehicle-sample.xml", "adding hash for Vehicle is not supported"), + TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input_nodata.xml", "'Data' element for component 'Gearbox' not found!"), + TestCase(@"Testdata\XML\ToHash\multiple_components.xml", "input must not contain multiple components!"), + ] + public void TestAddHashException(string file, string expectedExceptionMsg) + { + var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; + + var h = VectoHash.Load(file); + AssertHelper.Exception<Exception>(() => { var r = h.AddHash(); }, expectedExceptionMsg); + } + + [TestCase] + public void TestDuplicateSigElement() + { + var filename = @"Testdata\XML\Invalid\duplicate-sig.xml"; + var h = VectoHash.Load(filename); + + AssertHelper.Exception<Exception>(() => { var r = h.ReadHash(); }, "Multiple DigestValue elements found!"); + } + + + [TestCase()] + public void TestLoadFromStream() + { + var fs = new FileStream(BasicHasingTests.ReferenceXMLVehicle, FileMode.Open); + var h = VectoHash.Load(fs); + + var hash = h.ComputeHash(); + Assert.AreEqual(BasicHasingTests.HashVehicleXML, hash); + fs.Close(); + } + + [TestCase(WhitespaceHandling.All), + TestCase(WhitespaceHandling.None), + TestCase(WhitespaceHandling.Significant)] + public void TestLoadXmlDocument(WhitespaceHandling whitespace) + { + var xml = new XmlDocument(); + var reader = new XmlTextReader(BasicHasingTests.ReferenceXMLVehicle); + reader.WhitespaceHandling = whitespace; + xml.Load(reader); + var h = VectoHash.Load(xml); + + var hash = h.ComputeHash(); + Assert.AreEqual(BasicHasingTests.HashVehicleXML, hash); + } + + [TestCase(@"Testdata\XML\ToHash\vecto_engine-input.xml"), + TestCase(@"Testdata\XML\ToHash\vecto_engine_withid-input.xml"), + TestCase(@"Testdata\XML\ToHash\vecto_gearbox-input.xml")] + public void TestHashedComponentIsValid(string file) + { + var destination = Path.GetFileNameWithoutExtension(file) + "_hashed.xml"; + + var h = VectoHash.Load(file); + var r = h.AddHash(); + + var writer = new XmlTextWriter(destination, Encoding.UTF8); + r.WriteTo(writer); + writer.Flush(); + writer.Close(); + + var h2 = VectoHash.Load(destination); + Assert.IsTrue(h2.ValidateHash()); + + // re-load generated XML and perform XSD validation + var settings = new XmlReaderSettings() { + ValidationType = ValidationType.Schema, + ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema | + //XmlSchemaValidationFlags.ProcessSchemaLocation | + XmlSchemaValidationFlags.ReportValidationWarnings + }; + settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack); + settings.Schemas.Add(GetXMLSchema(false)); + var xmlValidator = XmlReader.Create(destination, settings); + var xmlDoc = XDocument.Load(xmlValidator); + } + + + [TestCase("vecto_vehicle-namespace_prefix.xml", BasicHasingTests.HashVehicleXML)] + public void TestNamespacePrefixVariations(string file, string expectedHash) + { + var h = VectoHash.Load(@"Testdata\XML\Variations\" + file); + var hash = h.ComputeHash(); + + Assert.AreEqual(expectedHash, hash); + } + + [TestCase()] + public void TestInvalidXMLAsFile() + { + var file = @"Testdata\XML\Invalid\invalid-comp.xml"; + + AssertHelper.Exception<Exception>(() => VectoHash.Load(file), "failed to read XML document"); + } + + [TestCase()] + public void TestInvalidXMLAsStream() + { + var file = @"Testdata\XML\Invalid\invalid-comp.xml"; + var stream = File.Open(file, FileMode.Open); + AssertHelper.Exception<Exception>(() => VectoHash.Load(stream), "failed to read XML document"); + } + + [TestCase()] + public void TestComputeHashNoComponentInXML() + { + var xml = @"<VectoInputDeclaration/>"; + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(xml); + writer.Flush(); + stream.Seek(0, SeekOrigin.Begin); + + var h = VectoHash.Load(stream); + AssertHelper.Exception<Exception>(() => h.ComputeHash(), "No component found"); + } + + [TestCase()] + public void TestReadHashNoComponentInXML() + { + var xml = @"<VectoInputDeclaration/>"; + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(xml); + writer.Flush(); + stream.Seek(0, SeekOrigin.Begin); + + var h = VectoHash.Load(stream); + AssertHelper.Exception<Exception>(() => h.ReadHash(), "No component found"); + } + + [TestCase(VectoComponents.Engine, "ENG-"), + TestCase(VectoComponents.Gearbox, "GBX-"), + TestCase(VectoComponents.Axlegear, "AXL-"), + TestCase(VectoComponents.Retarder, "RET-"), + TestCase(VectoComponents.TorqueConverter, "TC-"), + TestCase(VectoComponents.Angledrive, "ANGL-"), + TestCase(VectoComponents.Airdrag, "AD-"), + TestCase(VectoComponents.Tyre, "TYRE-"), + ] + public void TestIdPrefix(VectoComponents component, string expectedPrefix) + { + Assert.AreEqual(expectedPrefix, component.HashIdPrefix()); + } + + [TestCase()] + public void TestInvalidComponentXMLName() + { + AssertHelper.Exception<ArgumentOutOfRangeException>(() => ((VectoComponents)9999).XMLElementName()); + } + + [TestCase()] + public void TestInvalidComponentPrefix() + { + AssertHelper.Exception<ArgumentOutOfRangeException>(() => ((VectoComponents)9999).HashIdPrefix()); + } + + private static XmlSchemaSet GetXMLSchema(bool job) + { + var resource = RessourceHelper.LoadResourceAsStream(RessourceHelper.ResourceType.XMLSchema, + job ? "VectoInput.xsd" : "VectoComponent.xsd"); + var xset = new XmlSchemaSet() { XmlResolver = new XmlResourceResolver() }; + var reader = XmlReader.Create(resource, new XmlReaderSettings(), "schema://"); + xset.Add(XmlSchema.Read(reader, null)); + xset.Compile(); + return xset; + } + + private static void ValidationCallBack(object sender, ValidationEventArgs args) + { + if (args.Severity == XmlSeverityType.Error) { + throw new Exception(string.Format("Validation error: {0}" + Environment.NewLine + + "Line: {1}", args.Message, args.Exception.LineNumber)); + } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs index 207f17c59015785251f2b258189b341a30a84534..dbae9245a3542a478016f308e9015468cad9c090 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs @@ -29,525 +29,527 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Models.Connector.Ports; -using TUGraz.VectoCore.Models.Connector.Ports.Impl; -using TUGraz.VectoCore.Models.Simulation; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - /// <summary> - /// Class representing one Distance Based Driving Cycle - /// </summary> - public sealed class DistanceBasedDrivingCycle : StatefulProviderComponent - <DistanceBasedDrivingCycle.DrivingCycleState, ISimulationOutPort, IDrivingCycleInPort, IDrivingCycleOutPort>, - IDrivingCycle, ISimulationOutPort, IDrivingCycleInPort, IDisposable - { - private const double LookaheadTimeSafetyMargin = 1.5; - internal readonly IDrivingCycleData Data; - internal readonly DrivingCycleEnumerator CycleIntervalIterator; - private bool _intervalProlonged; - internal IdleControllerSwitcher IdleController; - - private DrivingCycleData.DrivingCycleEntry Left - { - get { return CycleIntervalIterator.LeftSample; } - } - - private DrivingCycleData.DrivingCycleEntry Right - { - get { return CycleIntervalIterator.RightSample; } - } - - public DistanceBasedDrivingCycle(IVehicleContainer container, IDrivingCycleData cycle) : base(container) - { - Data = cycle; - CycleIntervalIterator = new DrivingCycleEnumerator(Data); - CycleStartDistance = Data.Entries.Count > 0 ? Data.Entries.First().Distance : 0.SI<Meter>(); - - var first = Data.Entries.First(); - PreviousState = new DrivingCycleState { - AbsTime = 0.SI<Second>(), - WaitTime = 0.SI<Second>(), - Distance = first.Distance, - Altitude = first.Altitude, - }; - CurrentState = PreviousState.Clone(); - } - - public IResponse Initialize() - { - if (Left.VehicleTargetSpeed.IsEqual(0)) { - var retVal = NextComponent.Initialize(DataBus.StartSpeed, - Left.RoadGradient, DataBus.StartAcceleration); - if (!(retVal is ResponseSuccess)) { - throw new UnexpectedResponseException("DistanceBasedDrivingCycle.Initialize: Couldn't find start gear.", retVal); - } - } - - return NextComponent.Initialize(Left.VehicleTargetSpeed, - Left.RoadGradient); - } - - public IResponse Request(Second absTime, Second dt) - { - throw new NotImplementedException("Distance Based Driving Cycle does not support time requests."); - } - - public IResponse Request(Second absTime, Meter ds) - { - if (Left.Distance.IsEqual(PreviousState.Distance.Value())) { - // we are exactly on an entry in the cycle. - var stopTime = Left.PTOActive && IdleController != null - ? Left.StoppingTime + IdleController.Duration - : Left.StoppingTime; - - if (stopTime.IsGreater(0) && PreviousState.WaitTime.IsSmaller(stopTime)) { - // stop for certain time unless we've already waited long enough ... - - // we are stopping: ensure that velocity is 0. - if (!Left.VehicleTargetSpeed.IsEqual(0)) { - Log.Warn("Stopping Time requested in cycle but target-velocity not zero. distance: {0}, target speed: {1}", - Left.StoppingTime, Left.VehicleTargetSpeed); - throw new VectoSimulationException("Stopping Time only allowed when target speed is zero!"); - } - var dt = GetStopTimeInterval(); - if (dt == null) { - CurrentState.WaitPhase++; - dt = GetStopTimeInterval(); - } - CurrentState.Response = DriveTimeInterval(absTime, dt); - return CurrentState.Response; - } - } - if (CycleIntervalIterator.LastEntry && PreviousState.Distance.IsEqual(Right.Distance)) { - CurrentState.Response = new ResponseCycleFinished(); - return CurrentState.Response; - } - - var nextSpeedChange = GetSpeedChangeWithinSimulationInterval(ds); - if (nextSpeedChange == null || ds.IsSmallerOrEqual(nextSpeedChange - PreviousState.Distance)) { - if (nextSpeedChange == null || DataBus.VehicleSpeed.IsEqual(0.SI<MeterPerSecond>())) { - CurrentState.Response = DriveDistance(absTime, ds); - return CurrentState.Response; - } - var remainingDistance = nextSpeedChange - PreviousState.Distance - ds; - var estimatedRemainingTime = remainingDistance / DataBus.VehicleSpeed; - if (_intervalProlonged || remainingDistance.IsEqual(0.SI<Meter>()) || - estimatedRemainingTime.IsGreater(Constants.SimulationSettings.LowerBoundTimeInterval)) { - CurrentState.Response = DriveDistance(absTime, ds); - return CurrentState.Response; - } - Log.Debug("Extending distance by {0} to next sample point. ds: {1} new ds: {2}", remainingDistance, ds, - nextSpeedChange - PreviousState.Distance); - _intervalProlonged = true; - CurrentState.Response = new ResponseDrivingCycleDistanceExceeded { - Source = this, - MaxDistance = nextSpeedChange - PreviousState.Distance - }; - return CurrentState.Response; - } - // only drive until next sample point in cycle with speed change - Log.Debug("Limiting distance to next sample point {0}", - Right.Distance - PreviousState.Distance); - CurrentState.Response = new ResponseDrivingCycleDistanceExceeded { - Source = this, - MaxDistance = nextSpeedChange - PreviousState.Distance - }; - return CurrentState.Response; - } - - private Second GetStopTimeInterval() - { - if (!Left.PTOActive || IdleController == null) { - return Left.StoppingTime.IsGreater(3 * Constants.SimulationSettings.TargetTimeInterval) - ? GetStopTimeIntervalThreePhases() - : Left.StoppingTime; - } - if (Left.StoppingTime.IsGreater(6 * Constants.SimulationSettings.TargetTimeInterval)) { - // 7 phases - return GetStopTimeIntervalSevenPhasesPTO(); - } - if (Left.StoppingTime.IsGreater(0)) { - // 3 phases - return GetStopTimeIntervalThreePhasesPTO(); - } - // we have a pto cycle without stopping time. - IdleController.ActivatePTO(); - return IdleController.GetNextCycleTime(); - } - - private Second GetStopTimeIntervalThreePhases() - { - switch (CurrentState.WaitPhase) { - case 1: - case 3: - CurrentState.WaitPhase++; - return Constants.SimulationSettings.TargetTimeInterval; - case 2: - CurrentState.WaitPhase++; - return Left.StoppingTime - 2 * Constants.SimulationSettings.TargetTimeInterval; - } - return null; - } - - private Second GetStopTimeIntervalThreePhasesPTO() - { - switch (CurrentState.WaitPhase) { - case 1: - case 3: - CurrentState.WaitPhase++; - IdleController.ActivateIdle(); - PTOActive = false; - return Left.StoppingTime / 2; - case 2: - PTOActive = true; - IdleController.ActivatePTO(); - return IdleController.GetNextCycleTime(); - } - return null; - } - - private Second GetStopTimeIntervalSevenPhasesPTO() - { - switch (CurrentState.WaitPhase) { - case 1: - case 5: - CurrentState.WaitPhase++; - IdleController.ActivateIdle(); - PTOActive = false; - return Constants.SimulationSettings.TargetTimeInterval; - case 3: - case 7: - CurrentState.WaitPhase++; - return Constants.SimulationSettings.TargetTimeInterval; - case 2: - case 6: - CurrentState.WaitPhase++; - return Left.StoppingTime / 2 - 2 * Constants.SimulationSettings.TargetTimeInterval; - case 4: - PTOActive = true; - IdleController.ActivatePTO(); - return IdleController.GetNextCycleTime(); - } - return null; - } - - private IResponse DriveTimeInterval(Second absTime, Second dt) - { - CurrentState.AbsTime = absTime; - CurrentState.WaitTime = PreviousState.WaitTime + dt; - CurrentState.Gradient = ComputeGradient(0.SI<Meter>()); - CurrentState.VehicleTargetSpeed = Left.VehicleTargetSpeed; - - return NextComponent.Request(absTime, dt, Left.VehicleTargetSpeed, CurrentState.Gradient); - } - - private IResponse DriveDistance(Second absTime, Meter ds) - { - var nextSpeedChanges = LookAhead(Constants.SimulationSettings.BrakeNextTargetDistance); - if (nextSpeedChanges.Count > 0 && !CurrentState.RequestToNextSamplePointDone) { - CurrentState.RequestToNextSamplePointDone = true; - Log.Debug("current distance is close to the next speed change: {0}", - nextSpeedChanges.First().Distance - PreviousState.Distance); - return new ResponseDrivingCycleDistanceExceeded { - Source = this, - MaxDistance = Constants.SimulationSettings.BrakeNextTargetDistance - }; - } - - CurrentState.WaitPhase = 0; - //CurrentState.Distance = PreviousState.Distance + ds; - CurrentState.SimulationDistance = ds; - CurrentState.VehicleTargetSpeed = Left.VehicleTargetSpeed; - CurrentState.Gradient = ComputeGradient(ds); - - var retVal = NextComponent.Request(absTime, ds, CurrentState.VehicleTargetSpeed, CurrentState.Gradient); - retVal.Switch() - .Case<ResponseFailTimeInterval>( - r => { - retVal = NextComponent.Request(absTime, r.DeltaT, 0.SI<MeterPerSecond>(), CurrentState.Gradient); - retVal = NextComponent.Request(absTime, ds, CurrentState.VehicleTargetSpeed, CurrentState.Gradient); - }); - CurrentState.AbsTime = absTime; - if (retVal is ResponseSuccess) { - CurrentState.Distance = PreviousState.Distance + retVal.SimulationDistance; - } - return retVal; - } - - protected override void DoWriteModalResults(IModalDataContainer container) - { - container[ModalResultField.dist] = CurrentState.Distance; // (CurrentState.Distance + PreviousState.Distance) / 2.0; - container[ModalResultField.simulationDistance] = CurrentState.SimulationDistance; - container[ModalResultField.v_targ] = CurrentState.VehicleTargetSpeed; - container[ModalResultField.grad] = (Math.Tan(CurrentState.Gradient.Value()) * 100).SI<Scalar>(); - container[ModalResultField.altitude] = CurrentState.Altitude; - - if (IdleController != null) { - IdleController.CommitSimulationStep(container); - } - } - - protected override void DoCommitSimulationStep() - { - if (!(CurrentState.Response is ResponseSuccess)) { - throw new VectoSimulationException("Previous request did not succeed!"); - } - - PreviousState = CurrentState; - CurrentState = CurrentState.Clone(); - _intervalProlonged = false; - - var stopTime = Left.PTOActive && IdleController != null - ? Left.StoppingTime + IdleController.Duration - : Left.StoppingTime; - - if (!stopTime.IsEqual(0) && stopTime.IsEqual(PreviousState.WaitTime)) { - // we needed to stop at the current interval in the cycle and have already waited enough time, move on.. - if (IdleController != null) { - IdleController.ActivateIdle(); - } - CycleIntervalIterator.MoveNext(); - } - - stopTime = Left.PTOActive && IdleController != null ? Left.StoppingTime + IdleController.Duration : Left.StoppingTime; - - // separately test for equality and greater than to have tolerance for equality comparison - if (stopTime.IsEqual(0)) { - while (stopTime.IsEqual(0) && CurrentState.Distance.IsGreaterOrEqual(Right.Distance) && - !CycleIntervalIterator.LastEntry) { - // we have reached the end of the current interval in the cycle, move on... - CycleIntervalIterator.MoveNext(); - - stopTime = Left.PTOActive && IdleController != null - ? Left.StoppingTime + IdleController.Duration - : Left.StoppingTime; - } - } else { - if (stopTime.IsEqual(PreviousState.WaitTime)) { - // we needed to stop at the current interval in the cycle and have already waited enough time, move on.. - if (IdleController != null) { - IdleController.ActivateIdle(); - } - CycleIntervalIterator.MoveNext(); - } - } - } - - private Radian ComputeGradient(Meter ds) - { - var cycleIterator = CycleIntervalIterator.Clone(); - while (cycleIterator.RightSample.Distance < PreviousState.Distance + ds && !cycleIterator.LastEntry) { - cycleIterator.MoveNext(); - } - var leftSamplePoint = cycleIterator.LeftSample; - var rightSamplePoint = cycleIterator.RightSample; - - if (leftSamplePoint.Distance.IsEqual(rightSamplePoint.Distance)) { - return leftSamplePoint.RoadGradient; - } - if (ds.IsEqual(0.SI<Meter>())) { - return leftSamplePoint.RoadGradient; - } - CurrentState.Altitude = VectoMath.Interpolate(leftSamplePoint.Distance, rightSamplePoint.Distance, - leftSamplePoint.Altitude, rightSamplePoint.Altitude, PreviousState.Distance + ds); - - var gradient = VectoMath.InclinationToAngle(((CurrentState.Altitude - PreviousState.Altitude) / - ds).Value()); - //return 0.SI<Radian>(); - return gradient; - } - - private Meter GetSpeedChangeWithinSimulationInterval(Meter ds) - { - var leftSamplePoint = Left; - var cycleIterator = CycleIntervalIterator.Clone(); - - do { - if (!leftSamplePoint.VehicleTargetSpeed.IsEqual(cycleIterator.RightSample.VehicleTargetSpeed)) { - return cycleIterator.RightSample.Distance; - } - } while (cycleIterator.RightSample.Distance < PreviousState.Distance + ds && cycleIterator.MoveNext()); - if (cycleIterator.LastEntry) { - return cycleIterator.RightSample.Distance; - } - return null; - } - - /// <summary> - /// Progress of the distance in the driving cycle. - /// </summary> - public double Progress - { - get { - return Data.Entries.Count > 0 - ? (CurrentState.Distance.Value() - Data.Entries.First().Distance.Value()) / - (Data.Entries.Last().Distance.Value() - Data.Entries.First().Distance.Value()) - : 0; - } - } - - public Meter CycleStartDistance { get; internal set; } - - public IReadOnlyList<DrivingCycleData.DrivingCycleEntry> LookAhead(Meter lookaheadDistance) - { - var retVal = new List<DrivingCycleData.DrivingCycleEntry>(); - - var cycleIterator = CycleIntervalIterator.Clone(); - var velocity = cycleIterator.LeftSample.VehicleTargetSpeed; - - do { - if (cycleIterator.RightSample.VehicleTargetSpeed.IsEqual(velocity)) { - continue; - } - var lookaheadEntry = retVal.Find(x => x.Distance == cycleIterator.RightSample.Distance); - if (lookaheadEntry != null) { - // an entry may occur twice when vehicle stops (one entry with v=0 and the other with drive on after stop) - // only use the one with min. speed - if (cycleIterator.RightSample.VehicleTargetSpeed < lookaheadEntry.VehicleTargetSpeed) { - retVal.Remove(lookaheadEntry); - retVal.Add(cycleIterator.RightSample); // TODO: MQ 2016-05-13: use clone of iterator here? - } - } else { - retVal.Add(cycleIterator.RightSample); // TODO: MQ 2016-05-13: use clone of iterator here? - } - velocity = cycleIterator.RightSample.VehicleTargetSpeed; - if (velocity.IsEqual(0.KMPHtoMeterPerSecond())) { - // do not look beyond vehicle stop - break; - } - } while (cycleIterator.MoveNext() && cycleIterator.RightSample.Distance < PreviousState.Distance + lookaheadDistance); - if (retVal.Count > 0) { - retVal = retVal.Where(x => x.Distance <= PreviousState.Distance + lookaheadDistance).ToList(); - retVal.Sort((x, y) => x.Distance.CompareTo(y.Distance)); - } - return retVal; - } - - public IReadOnlyList<DrivingCycleData.DrivingCycleEntry> LookAhead(Second time) - { - return LookAhead(LookaheadTimeSafetyMargin * DataBus.VehicleSpeed * time); - } - - public void FinishSimulation() - { - Data.Finish(); - } - - public CycleData CycleData - { - get { - return new CycleData { - AbsTime = CurrentState.AbsTime, - AbsDistance = CurrentState.Distance, - LeftSample = Left, - RightSample = CycleIntervalIterator.RightSample - }; - } - } - - public bool PTOActive { get; private set; } - - public DrivingCycleData.DrivingCycleEntry CycleLookAhead(Meter distance) - { - var absDistance = CurrentState.Distance + distance; - var myIterator = CycleIntervalIterator.Clone(); - - if (absDistance > Data.Entries.Last().Distance) { - return ExtrapolateCycleEntry(absDistance, Data.Entries.Last()); - } - while (myIterator.RightSample.Distance < absDistance) { - myIterator.MoveNext(); - } - - return InterpolateCycleEntry(absDistance, myIterator.RightSample); - } - - private DrivingCycleData.DrivingCycleEntry InterpolateCycleEntry(Meter absDistance, - DrivingCycleData.DrivingCycleEntry lookahead) - { - var retVal = new DrivingCycleData.DrivingCycleEntry(lookahead) { - Distance = absDistance, - Altitude = VectoMath.Interpolate(CurrentState.Distance, lookahead.Distance, CurrentState.Altitude, - lookahead.Altitude, absDistance) - }; - - retVal.RoadGradient = - ((retVal.Altitude - CurrentState.Altitude) / (absDistance - CurrentState.Distance)).Value().SI<Radian>(); - - return retVal; - } - - private DrivingCycleData.DrivingCycleEntry ExtrapolateCycleEntry(Meter absDistance, - DrivingCycleData.DrivingCycleEntry lookahead) - { - var retVal = new DrivingCycleData.DrivingCycleEntry(lookahead) { - Distance = absDistance, - Altitude = lookahead.Altitude + lookahead.RoadGradient * (absDistance - lookahead.Distance), - }; - - retVal.RoadGradient = - ((retVal.Altitude - CurrentState.Altitude) / (absDistance - CurrentState.Distance)).Value().SI<Radian>(); - - return retVal; - } - - public Meter Altitude - { - get { return PreviousState.Altitude; } - } - - public sealed class DrivingCycleState - { - public DrivingCycleState Clone() - { - return new DrivingCycleState { - AbsTime = AbsTime, - Distance = Distance, - VehicleTargetSpeed = VehicleTargetSpeed, - Altitude = Altitude, - WaitPhase = WaitPhase, - // WaitTime is not cloned on purpose! - WaitTime = 0.SI<Second>(), - Response = null - }; - } - - public Second AbsTime; - - public Meter Distance; - - public Second WaitTime; - - public uint WaitPhase; - - public MeterPerSecond VehicleTargetSpeed; - - public Meter Altitude; - - public Radian Gradient; - - public IResponse Response; - - public bool RequestToNextSamplePointDone; - - public Meter SimulationDistance; - } - - public void Dispose() - { - CycleIntervalIterator.Dispose(); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + /// <summary> + /// Class representing one Distance Based Driving Cycle + /// </summary> + public sealed class DistanceBasedDrivingCycle : StatefulProviderComponent + <DistanceBasedDrivingCycle.DrivingCycleState, ISimulationOutPort, IDrivingCycleInPort, IDrivingCycleOutPort>, + IDrivingCycle, ISimulationOutPort, IDrivingCycleInPort, IDisposable + { + private const double LookaheadTimeSafetyMargin = 1.5; + internal readonly IDrivingCycleData Data; + internal readonly DrivingCycleEnumerator CycleIntervalIterator; + private bool _intervalProlonged; + internal IdleControllerSwitcher IdleController; + + private DrivingCycleData.DrivingCycleEntry Left + { + get { return CycleIntervalIterator.LeftSample; } + } + + private DrivingCycleData.DrivingCycleEntry Right + { + get { return CycleIntervalIterator.RightSample; } + } + + public DistanceBasedDrivingCycle(IVehicleContainer container, IDrivingCycleData cycle) : base(container) + { + Data = cycle; + CycleIntervalIterator = new DrivingCycleEnumerator(Data); + CycleStartDistance = Data.Entries.Count > 0 ? Data.Entries.First().Distance : 0.SI<Meter>(); + + var first = Data.Entries.First(); + PreviousState = new DrivingCycleState { + AbsTime = 0.SI<Second>(), + WaitTime = 0.SI<Second>(), + Distance = first.Distance, + Altitude = first.Altitude, + }; + CurrentState = PreviousState.Clone(); + } + + public IResponse Initialize() + { + if (Left.VehicleTargetSpeed.IsEqual(0)) { + var retVal = NextComponent.Initialize(DataBus.StartSpeed, + Left.RoadGradient, DataBus.StartAcceleration); + if (!(retVal is ResponseSuccess)) { + throw new UnexpectedResponseException("DistanceBasedDrivingCycle.Initialize: Couldn't find start gear.", retVal); + } + } + + return NextComponent.Initialize(Left.VehicleTargetSpeed, + Left.RoadGradient); + } + + public IResponse Request(Second absTime, Second dt) + { + throw new NotImplementedException("Distance Based Driving Cycle does not support time requests."); + } + + public IResponse Request(Second absTime, Meter ds) + { + if (Left.Distance.IsEqual(PreviousState.Distance.Value())) { + // we are exactly on an entry in the cycle. + var stopTime = Left.PTOActive && IdleController != null + ? Left.StoppingTime + IdleController.Duration + : Left.StoppingTime; + + if (stopTime.IsGreater(0) && PreviousState.WaitTime.IsSmaller(stopTime)) { + // stop for certain time unless we've already waited long enough ... + + // we are stopping: ensure that velocity is 0. + if (!Left.VehicleTargetSpeed.IsEqual(0)) { + Log.Warn("Stopping Time requested in cycle but target-velocity not zero. distance: {0}, target speed: {1}", + Left.StoppingTime, Left.VehicleTargetSpeed); + throw new VectoSimulationException("Stopping Time only allowed when target speed is zero!"); + } + var dt = GetStopTimeInterval(); + if (dt == null) { + CurrentState.WaitPhase++; + dt = GetStopTimeInterval(); + } + CurrentState.Response = DriveTimeInterval(absTime, dt); + return CurrentState.Response; + } + } + if (CycleIntervalIterator.LastEntry && PreviousState.Distance.IsEqual(Right.Distance)) { + CurrentState.Response = new ResponseCycleFinished(); + return CurrentState.Response; + } + + var nextSpeedChange = GetSpeedChangeWithinSimulationInterval(ds); + if (nextSpeedChange == null || ds.IsSmallerOrEqual(nextSpeedChange - PreviousState.Distance)) { + if (nextSpeedChange == null || DataBus.VehicleSpeed.IsEqual(0.SI<MeterPerSecond>())) { + CurrentState.Response = DriveDistance(absTime, ds); + return CurrentState.Response; + } + var remainingDistance = nextSpeedChange - PreviousState.Distance - ds; + var estimatedRemainingTime = remainingDistance / DataBus.VehicleSpeed; + if (_intervalProlonged || remainingDistance.IsEqual(0.SI<Meter>()) || + estimatedRemainingTime.IsGreater(Constants.SimulationSettings.LowerBoundTimeInterval)) { + CurrentState.Response = DriveDistance(absTime, ds); + return CurrentState.Response; + } + Log.Debug("Extending distance by {0} to next sample point. ds: {1} new ds: {2}", remainingDistance, ds, + nextSpeedChange - PreviousState.Distance); + _intervalProlonged = true; + CurrentState.Response = new ResponseDrivingCycleDistanceExceeded { + Source = this, + MaxDistance = nextSpeedChange - PreviousState.Distance + }; + return CurrentState.Response; + } + // only drive until next sample point in cycle with speed change + Log.Debug("Limiting distance to next sample point {0}", + Right.Distance - PreviousState.Distance); + CurrentState.Response = new ResponseDrivingCycleDistanceExceeded { + Source = this, + MaxDistance = nextSpeedChange - PreviousState.Distance + }; + return CurrentState.Response; + } + + private Second GetStopTimeInterval() + { + if (!Left.PTOActive || IdleController == null) { + return Left.StoppingTime.IsGreater(3 * Constants.SimulationSettings.TargetTimeInterval) + ? GetStopTimeIntervalThreePhases() + : Left.StoppingTime; + } + if (Left.StoppingTime.IsGreater(6 * Constants.SimulationSettings.TargetTimeInterval)) { + // 7 phases + return GetStopTimeIntervalSevenPhasesPTO(); + } + if (Left.StoppingTime.IsGreater(0)) { + // 3 phases + return GetStopTimeIntervalThreePhasesPTO(); + } + // we have a pto cycle without stopping time. + IdleController.ActivatePTO(); + return IdleController.GetNextCycleTime(); + } + + private Second GetStopTimeIntervalThreePhases() + { + switch (CurrentState.WaitPhase) { + case 1: + case 3: + CurrentState.WaitPhase++; + return Constants.SimulationSettings.TargetTimeInterval; + case 2: + CurrentState.WaitPhase++; + return Left.StoppingTime - 2 * Constants.SimulationSettings.TargetTimeInterval; + } + return null; + } + + private Second GetStopTimeIntervalThreePhasesPTO() + { + switch (CurrentState.WaitPhase) { + case 1: + case 3: + CurrentState.WaitPhase++; + IdleController.ActivateIdle(); + PTOActive = false; + return Left.StoppingTime / 2; + case 2: + PTOActive = true; + IdleController.ActivatePTO(); + return IdleController.GetNextCycleTime(); + } + return null; + } + + private Second GetStopTimeIntervalSevenPhasesPTO() + { + switch (CurrentState.WaitPhase) { + case 1: + case 5: + CurrentState.WaitPhase++; + IdleController.ActivateIdle(); + PTOActive = false; + return Constants.SimulationSettings.TargetTimeInterval; + case 3: + case 7: + CurrentState.WaitPhase++; + return Constants.SimulationSettings.TargetTimeInterval; + case 2: + case 6: + CurrentState.WaitPhase++; + return Left.StoppingTime / 2 - 2 * Constants.SimulationSettings.TargetTimeInterval; + case 4: + PTOActive = true; + IdleController.ActivatePTO(); + return IdleController.GetNextCycleTime(); + } + return null; + } + + private IResponse DriveTimeInterval(Second absTime, Second dt) + { + CurrentState.AbsTime = absTime; + CurrentState.WaitTime = PreviousState.WaitTime + dt; + CurrentState.Gradient = ComputeGradient(0.SI<Meter>()); + CurrentState.VehicleTargetSpeed = Left.VehicleTargetSpeed; + + return NextComponent.Request(absTime, dt, Left.VehicleTargetSpeed, CurrentState.Gradient); + } + + private IResponse DriveDistance(Second absTime, Meter ds) + { + var nextSpeedChanges = LookAhead(Constants.SimulationSettings.BrakeNextTargetDistance); + if (nextSpeedChanges.Count > 0 && !CurrentState.RequestToNextSamplePointDone) { + CurrentState.RequestToNextSamplePointDone = true; + Log.Debug("current distance is close to the next speed change: {0}", + nextSpeedChanges.First().Distance - PreviousState.Distance); + return new ResponseDrivingCycleDistanceExceeded { + Source = this, + MaxDistance = Constants.SimulationSettings.BrakeNextTargetDistance + }; + } + + CurrentState.WaitPhase = 0; + //CurrentState.Distance = PreviousState.Distance + ds; + CurrentState.SimulationDistance = ds; + CurrentState.VehicleTargetSpeed = Left.VehicleTargetSpeed; + CurrentState.Gradient = ComputeGradient(ds); + + var retVal = NextComponent.Request(absTime, ds, CurrentState.VehicleTargetSpeed, CurrentState.Gradient); + retVal.Switch() + .Case<ResponseFailTimeInterval>( + r => { + retVal = NextComponent.Request(absTime, r.DeltaT, 0.SI<MeterPerSecond>(), CurrentState.Gradient); + retVal = NextComponent.Request(absTime, ds, CurrentState.VehicleTargetSpeed, CurrentState.Gradient); + }); + CurrentState.AbsTime = absTime; + if (retVal is ResponseSuccess) { + CurrentState.Distance = PreviousState.Distance + retVal.SimulationDistance; + } + return retVal; + } + + protected override void DoWriteModalResults(IModalDataContainer container) + { + container[ModalResultField.dist] = CurrentState.Distance; // (CurrentState.Distance + PreviousState.Distance) / 2.0; + container[ModalResultField.simulationDistance] = CurrentState.SimulationDistance; + container[ModalResultField.v_targ] = CurrentState.VehicleTargetSpeed; + container[ModalResultField.grad] = (Math.Tan(CurrentState.Gradient.Value()) * 100).SI<Scalar>(); + container[ModalResultField.altitude] = CurrentState.Altitude; + + if (IdleController != null) { + IdleController.CommitSimulationStep(container); + } + } + + protected override void DoCommitSimulationStep() + { + if (!(CurrentState.Response is ResponseSuccess)) { + throw new VectoSimulationException("Previous request did not succeed!"); + } + + PreviousState = CurrentState; + CurrentState = CurrentState.Clone(); + _intervalProlonged = false; + + //var stopTime = Left.PTOActive && IdleController != null + // ? Left.StoppingTime + IdleController.Duration + // : Left.StoppingTime; + + //if (!stopTime.IsEqual(0) && stopTime.IsEqual(PreviousState.WaitTime)) { + // // we needed to stop at the current interval in the cycle and have already waited enough time, move on.. + // if (IdleController != null) { + // IdleController.ActivateIdle(); + // } + // CycleIntervalIterator.MoveNext(); + //} + + var stopTime = Left.PTOActive && IdleController != null + ? Left.StoppingTime + IdleController.Duration + : Left.StoppingTime; + + // separately test for equality and greater than to have tolerance for equality comparison + if (stopTime.IsEqual(0)) { + while (stopTime.IsEqual(0) && CurrentState.Distance.IsGreaterOrEqual(Right.Distance) && + !CycleIntervalIterator.LastEntry) { + // we have reached the end of the current interval in the cycle, move on... + CycleIntervalIterator.MoveNext(); + + stopTime = Left.PTOActive && IdleController != null + ? Left.StoppingTime + IdleController.Duration + : Left.StoppingTime; + } + } else { + if (stopTime.IsEqual(PreviousState.WaitTime)) { + // we needed to stop at the current interval in the cycle and have already waited enough time, move on.. + if (IdleController != null) { + IdleController.ActivateIdle(); + } + CycleIntervalIterator.MoveNext(); + } + } + } + + private Radian ComputeGradient(Meter ds) + { + var cycleIterator = CycleIntervalIterator.Clone(); + while (cycleIterator.RightSample.Distance < PreviousState.Distance + ds && !cycleIterator.LastEntry) { + cycleIterator.MoveNext(); + } + var leftSamplePoint = cycleIterator.LeftSample; + var rightSamplePoint = cycleIterator.RightSample; + + if (leftSamplePoint.Distance.IsEqual(rightSamplePoint.Distance)) { + return leftSamplePoint.RoadGradient; + } + if (ds.IsEqual(0.SI<Meter>())) { + return leftSamplePoint.RoadGradient; + } + CurrentState.Altitude = VectoMath.Interpolate(leftSamplePoint.Distance, rightSamplePoint.Distance, + leftSamplePoint.Altitude, rightSamplePoint.Altitude, PreviousState.Distance + ds); + + var gradient = VectoMath.InclinationToAngle(((CurrentState.Altitude - PreviousState.Altitude) / + ds).Value()); + //return 0.SI<Radian>(); + return gradient; + } + + private Meter GetSpeedChangeWithinSimulationInterval(Meter ds) + { + var leftSamplePoint = Left; + var cycleIterator = CycleIntervalIterator.Clone(); + + do { + if (!leftSamplePoint.VehicleTargetSpeed.IsEqual(cycleIterator.RightSample.VehicleTargetSpeed)) { + return cycleIterator.RightSample.Distance; + } + } while (cycleIterator.RightSample.Distance < PreviousState.Distance + ds && cycleIterator.MoveNext()); + if (cycleIterator.LastEntry) { + return cycleIterator.RightSample.Distance; + } + return null; + } + + /// <summary> + /// Progress of the distance in the driving cycle. + /// </summary> + public double Progress + { + get { + return Data.Entries.Count > 0 + ? (CurrentState.Distance.Value() - Data.Entries.First().Distance.Value()) / + (Data.Entries.Last().Distance.Value() - Data.Entries.First().Distance.Value()) + : 0; + } + } + + public Meter CycleStartDistance { get; internal set; } + + public IReadOnlyList<DrivingCycleData.DrivingCycleEntry> LookAhead(Meter lookaheadDistance) + { + var retVal = new List<DrivingCycleData.DrivingCycleEntry>(); + + var cycleIterator = CycleIntervalIterator.Clone(); + var velocity = cycleIterator.LeftSample.VehicleTargetSpeed; + + do { + if (cycleIterator.RightSample.VehicleTargetSpeed.IsEqual(velocity)) { + continue; + } + var lookaheadEntry = retVal.Find(x => x.Distance == cycleIterator.RightSample.Distance); + if (lookaheadEntry != null) { + // an entry may occur twice when vehicle stops (one entry with v=0 and the other with drive on after stop) + // only use the one with min. speed + if (cycleIterator.RightSample.VehicleTargetSpeed < lookaheadEntry.VehicleTargetSpeed) { + retVal.Remove(lookaheadEntry); + retVal.Add(cycleIterator.RightSample); // TODO: MQ 2016-05-13: use clone of iterator here? + } + } else { + retVal.Add(cycleIterator.RightSample); // TODO: MQ 2016-05-13: use clone of iterator here? + } + velocity = cycleIterator.RightSample.VehicleTargetSpeed; + if (velocity.IsEqual(0.KMPHtoMeterPerSecond())) { + // do not look beyond vehicle stop + break; + } + } while (cycleIterator.MoveNext() && cycleIterator.RightSample.Distance < PreviousState.Distance + lookaheadDistance); + if (retVal.Count > 0) { + retVal = retVal.Where(x => x.Distance <= PreviousState.Distance + lookaheadDistance).ToList(); + retVal.Sort((x, y) => x.Distance.CompareTo(y.Distance)); + } + return retVal; + } + + public IReadOnlyList<DrivingCycleData.DrivingCycleEntry> LookAhead(Second time) + { + return LookAhead(LookaheadTimeSafetyMargin * DataBus.VehicleSpeed * time); + } + + public void FinishSimulation() + { + Data.Finish(); + } + + public CycleData CycleData + { + get { + return new CycleData { + AbsTime = CurrentState.AbsTime, + AbsDistance = CurrentState.Distance, + LeftSample = Left, + RightSample = CycleIntervalIterator.RightSample + }; + } + } + + public bool PTOActive { get; private set; } + + public DrivingCycleData.DrivingCycleEntry CycleLookAhead(Meter distance) + { + var absDistance = CurrentState.Distance + distance; + var myIterator = CycleIntervalIterator.Clone(); + + if (absDistance > Data.Entries.Last().Distance) { + return ExtrapolateCycleEntry(absDistance, Data.Entries.Last()); + } + while (myIterator.RightSample.Distance < absDistance) { + myIterator.MoveNext(); + } + + return InterpolateCycleEntry(absDistance, myIterator.RightSample); + } + + private DrivingCycleData.DrivingCycleEntry InterpolateCycleEntry(Meter absDistance, + DrivingCycleData.DrivingCycleEntry lookahead) + { + var retVal = new DrivingCycleData.DrivingCycleEntry(lookahead) { + Distance = absDistance, + Altitude = VectoMath.Interpolate(CurrentState.Distance, lookahead.Distance, CurrentState.Altitude, + lookahead.Altitude, absDistance) + }; + + retVal.RoadGradient = + ((retVal.Altitude - CurrentState.Altitude) / (absDistance - CurrentState.Distance)).Value().SI<Radian>(); + + return retVal; + } + + private DrivingCycleData.DrivingCycleEntry ExtrapolateCycleEntry(Meter absDistance, + DrivingCycleData.DrivingCycleEntry lookahead) + { + var retVal = new DrivingCycleData.DrivingCycleEntry(lookahead) { + Distance = absDistance, + Altitude = lookahead.Altitude + lookahead.RoadGradient * (absDistance - lookahead.Distance), + }; + + retVal.RoadGradient = + ((retVal.Altitude - CurrentState.Altitude) / (absDistance - CurrentState.Distance)).Value().SI<Radian>(); + + return retVal; + } + + public Meter Altitude + { + get { return PreviousState.Altitude; } + } + + public sealed class DrivingCycleState + { + public DrivingCycleState Clone() + { + return new DrivingCycleState { + AbsTime = AbsTime, + Distance = Distance, + VehicleTargetSpeed = VehicleTargetSpeed, + Altitude = Altitude, + WaitPhase = WaitPhase, + // WaitTime is not cloned on purpose! + WaitTime = 0.SI<Second>(), + Response = null + }; + } + + public Second AbsTime; + + public Meter Distance; + + public Second WaitTime; + + public uint WaitPhase; + + public MeterPerSecond VehicleTargetSpeed; + + public Meter Altitude; + + public Radian Gradient; + + public IResponse Response; + + public bool RequestToNextSamplePointDone; + + public Meter SimulationDistance; + } + + public void Dispose() + { + CycleIntervalIterator.Dispose(); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs index 622d04724afe278f28bc7f2c170bcca68dc41f9a..d58d0a42cb7b122f4016ac40b118223eb777387f 100644 --- a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs +++ b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs @@ -29,529 +29,529 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.Models.Simulation.Impl; - -namespace TUGraz.VectoCore.OutputData -{ - public interface IModalDataFilter - { - ModalResults Filter(ModalResults data); - string ID { get; } - } - - public interface IModalDataContainer - { - /// <summary> - /// Indexer for fields of the DataWriter. Accesses the data of the current step. - /// </summary> - /// <param name="key"></param> - /// <returns></returns> - object this[ModalResultField key] { get; set; } - - /// <summary> - /// Indexer for auxiliary fields of the DataWriter. - /// </summary> - /// <param name="auxId"></param> - /// <returns></returns> - object this[string auxId] { get; set; } - - bool HasTorqueConverter { set; } - - /// <summary> - /// Commits the data of the current simulation step. - /// </summary> - void CommitSimulationStep(); - - FuelData.Entry FuelData { get; } - - VectoRun.Status RunStatus { get; } - - string Error { get; } - - string StackTrace { get; } - - /// <summary> - /// Finishes the writing of the DataWriter. - /// </summary> - void Finish(VectoRun.Status runStatus); - - IEnumerable<T> GetValues<T>(ModalResultField key); - - IEnumerable<T> GetValues<T>(DataColumn col); - - IEnumerable<T> GetValues<T>(Func<DataRow, T> selectorFunc); - - Dictionary<string, DataColumn> Auxiliaries { get; } - - T TimeIntegral<T>(ModalResultField field, Func<SI, bool> filter = null) where T : SIBase<T>; - - void SetDataValue(string fieldName, object value); - - void AddAuxiliary(string id, string columnName = null); - - /// <summary> - /// clear the modal data after the simulation - /// called after the simulation is finished and the sum-entries have been written - /// </summary> - /// <param name="exception"></param> - void FinishSimulation(Exception exception = null); - } - - public static class ModalDataContainerExtensions - { - public static T Max<T>(this IModalDataContainer data, ModalResultField field) - { - return data.GetValues<T>(field).Max(); - } - - public static T Min<T>(this IModalDataContainer data, ModalResultField field) - { - return data.GetValues<T>(field).Min(); - } - - /// <summary> - /// Returns a default value if the SI object is null. - /// </summary> - /// <typeparam name="T">The SI Type.</typeparam> - /// <param name="self">The SI Instance.</param> - /// <param name="defaultValue">The default value.</param> - /// <returns>If self is null, the default value as SI-Type is returned. Otherwise self is returned.</returns> - /// <code> - /// NewtonMeter t = null; - /// var x = t.DefaultIfNull(0); - /// </code> - public static T DefaultIfNull<T>(this T self, double defaultValue) where T : SIBase<T> - { - return self ?? defaultValue.SI<T>(); - } - - public static MeterPerSquareSecond AccelerationsPositive(this IModalDataContainer data) - { - return data.GetValues<MeterPerSquareSecond>(ModalResultField.acc) - .Where(x => x > 0.125) - .DefaultIfEmpty(0.SI<MeterPerSquareSecond>()) - .Average(); - } - - public static MeterPerSquareSecond AccelerationsNegative(this IModalDataContainer data) - { - return data.GetValues<MeterPerSquareSecond>(ModalResultField.acc) - .Where(x => x < -0.125) - .DefaultIfEmpty(0.SI<MeterPerSquareSecond>()) - .Average(); - } - - public static Scalar AccelerationTimeShare(this IModalDataContainer data) - { - var accelerationTimeShare = data.GetValues(x => new { - a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.a > 0.125 ? x.dt : 0.SI<Second>()).DefaultIfNull(0); - return 100 * (accelerationTimeShare / data.Duration()).Cast<Scalar>(); - } - - public static Scalar DecelerationTimeShare(this IModalDataContainer data) - { - var decelerationTimeShare = data.GetValues(x => new { - a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.a < -0.125 ? x.dt : 0.SI<Second>()).DefaultIfNull(0); - return 100 * (decelerationTimeShare / data.Duration()).Cast<Scalar>(); - } - - public static Scalar CruiseTimeShare(this IModalDataContainer data) - { - var cruiseTime = data.GetValues(x => new { - v = x.Field<MeterPerSecond>((int)ModalResultField.v_act).DefaultIfNull(0), - a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.v >= 0.1.KMPHtoMeterPerSecond() && x.a.IsBetween(-0.125, 0.125) ? x.dt : 0.SI<Second>()) - .DefaultIfNull(0); - return 100 * (cruiseTime / data.Duration()).Cast<Scalar>(); - } - - public static Scalar StopTimeShare(this IModalDataContainer data) - { - var stopTime = data.GetValues(x => new { - v = x.Field<MeterPerSecond>((int)ModalResultField.v_act).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.v < 0.1.KMPHtoMeterPerSecond() ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); - return 100 * (stopTime / data.Duration()).Cast<Scalar>(); - } - - public static MeterPerSquareSecond AccelerationAverage(this IModalDataContainer data) - { - return data.TimeIntegral<MeterPerSecond>(ModalResultField.acc) / data.Duration(); - } - - public static Meter AltitudeDelta(this IModalDataContainer data) - { - var altitudes = data.GetValues<Meter>(ModalResultField.altitude).ToList(); - var first = altitudes.First(); - var last = altitudes.Last(); - return first == null || last == null ? null : last - first; - } - - public static WattSecond PowerAccelerations(this IModalDataContainer data) - { - var paEngine = data.TimeIntegral<WattSecond>(ModalResultField.P_eng_inertia); - var paGearbox = data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_inertia); - return paEngine + paGearbox; - } - - public static WattSecond WorkClutch(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_clutch_loss); - } - - public static WattSecond WorkGearshift(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_shift_loss); - } - - public static WattSecond WorkGearbox(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_loss); - } - - public static WattSecond WorkAxlegear(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_axle_loss); - } - - public static WattSecond WorkRetarder(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_ret_loss); - } - - public static WattSecond WorkAngledrive(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_angle_loss); - } - - public static WattSecond WorkTorqueConverter(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_TC_loss); - } - - public static Second Duration(this IModalDataContainer data) - { - var time = data.GetValues<Second>(ModalResultField.time).ToList(); - var dt = data.GetValues<Second>(ModalResultField.simulationInterval).ToList(); - if (time.Count == 1) { - return time.First(); - } - return time.Max() - time.Min() + dt.First() / 2 + dt.Last() / 2; - } - - public static Meter Distance(this IModalDataContainer data) - { - var max = data.Max<Meter>(ModalResultField.dist); - var min = data.Min<Meter>(ModalResultField.dist); - return max == null || min == null ? null : max - min; - } - - public static WattSecond WorkTotalMechanicalBrake(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_brake_loss); - } - - public static WattSecond WorkVehicleInertia(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_veh_inertia) + - data.TimeIntegral<WattSecond>(ModalResultField.P_wheel_inertia); - } - - public static WattSecond WorkAuxiliaries(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_aux); - } - - public static WattSecond WorkRoadGradientResistance(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_slope); - } - - public static WattSecond WorkRollingResistance(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_roll); - } - - public static WattSecond WorkAirResistance(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_air); - } - - - public static WattSecond TotalEngineWorkPositive(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_eng_fcmap, x => x > 0); - } - - public static WattSecond TotalEngineWorkNegative(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_eng_fcmap, x => x < 0); - } - - public static Watt PowerWheelPositive(this IModalDataContainer data) - { - return data.TimeIntegral<WattSecond>(ModalResultField.P_wheel_in, x => x > 0) / data.Duration(); - } - - public static KilogramPerMeter FuelConsumptionWHTC(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCWHTCc) / distance; - } - - public static KilogramPerSecond FuelConsumptionWHTCPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCWHTCc) / data.Duration(); - } - - public static KilogramPerMeter FuelConsumptionAuxStartStop(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCAUXc) / distance; - } - - public static KilogramPerSecond FuelConsumptionAAUXPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCAAUX) / data.Duration(); - } - - public static KilogramPerMeter FuelConsumptionAAUX(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCAAUX) / distance; - } - - public static KilogramPerSecond FuelConsumptionAuxStartStopPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCAUXc) / data.Duration(); - } - - public static KilogramPerSecond FuelConsumptionFinalPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) / data.Duration(); - } - - public static KilogramPerMeter FuelConsumptionFinal(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) / distance; - } - - public static SI FuelConsumptionFinalLiterPer100Kilometer(this IModalDataContainer data) - { - var fuelConsumptionFinal = data.FuelConsumptionFinal(); - if (fuelConsumptionFinal == null || data.FuelData.FuelDensity == null) { - return null; - } - - var fcVolumePerMeter = fuelConsumptionFinal / data.FuelData.FuelDensity; - return fcVolumePerMeter.ConvertTo().Cubic.Dezi.Meter * 100.SI().Kilo.Meter; - } - - public static KilogramPerMeter CO2PerMeter(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) * data.FuelData.CO2PerFuelWeight / distance; - } - - public static JoulePerMeter EnergyPerMeter(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) * data.FuelData.LowerHeatingValue / distance; - } - - public static KilogramPerSecond FCMapPerSecond(this IModalDataContainer data) - { - return data.TimeIntegral<Kilogram>(ModalResultField.FCMap) / data.Duration(); - } - - public static KilogramPerMeter FCMapPerMeter(this IModalDataContainer data) - { - var distance = data.Distance(); - if (distance == null || distance.IsEqual(0)) { - return null; - } - return data.TimeIntegral<Kilogram>(ModalResultField.FCMap) / distance; - } - - - public static Watt TotalPowerEnginePositiveAverage(this IModalDataContainer data) - { - var simulationIntervals = data.GetValues<Second>(ModalResultField.simulationInterval); - var values = data.GetValues<Watt>(ModalResultField.P_eng_fcmap) - .Zip(simulationIntervals, (value, dt) => new { Dt = dt, Value = value * dt }) - .Where(v => v.Value > 0).ToList(); - if (values.Any()) { - return values.Sum(v => v.Value) / Duration(data); - } - return 0.SI<Watt>(); - } - - public static MeterPerSecond Speed(this IModalDataContainer data) - { - var distance = Distance(data); - var duration = Duration(data); - if (distance == null || duration == null || duration.IsEqual(0)) { - return null; - } - return distance / duration; - } - - public static WattSecond AuxiliaryWork(this IModalDataContainer data, DataColumn auxCol) - { - var simulationIntervals = data.GetValues<Second>(ModalResultField.simulationInterval).ToArray(); - var auxValues = data.GetValues<Watt>(auxCol).ToArray(); - var sum = 0.SI<WattSecond>(); - for (var i = 0; i < simulationIntervals.Length; i++) { - if (auxValues[i] != null && simulationIntervals[i] != null) { - sum += auxValues[i] * simulationIntervals[i]; - } - } - return sum; - } - - - public static MeterPerSecond MaxSpeed(this IModalDataContainer data) - { - return data.Max<MeterPerSecond>(ModalResultField.v_act).DefaultIfNull(0); - } - - public static MeterPerSecond MinSpeed(this IModalDataContainer data) - { - return data.Min<MeterPerSecond>(ModalResultField.v_act).DefaultIfNull(0); - } - - public static MeterPerSquareSecond MaxAcceleration(this IModalDataContainer data) - { - return data.Max<MeterPerSquareSecond>(ModalResultField.acc).DefaultIfNull(0); - } - - public static MeterPerSquareSecond MaxDeceleration(this IModalDataContainer data) - { - return -data.Min<MeterPerSquareSecond>(ModalResultField.acc).DefaultIfNull(0); - } - - public static PerSecond AvgEngineSpeed(this IModalDataContainer data) - { - var integral = data.GetValues(x => x.Field<PerSecond>((int)ModalResultField.n_eng_avg).Value() * - x.Field<Second>((int)ModalResultField.simulationInterval).Value()).Sum(); - return (integral / Duration(data).Value()).SI<PerSecond>(); - } - - public static PerSecond MaxEngineSpeed(this IModalDataContainer data) - { - return data.Max<PerSecond>(ModalResultField.n_eng_avg); - } - - public static Scalar EngineMaxLoadTimeShare(this IModalDataContainer data) - { - var sum = data.GetValues(x => new { - tMax = x.Field<NewtonMeter>((int)ModalResultField.Tq_full).DefaultIfNull(-1), - tEng = x.Field<NewtonMeter>((int)ModalResultField.T_eng_fcmap).DefaultIfNull(0), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }).Sum(x => x.tMax.IsEqual(x.tEng, 5.SI<NewtonMeter>()) ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); - return 100 * sum / Duration(data); - } - - public static Scalar GearshiftCount(this IModalDataContainer data) - { - var prevGear = data.GetValues<uint>(ModalResultField.Gear).First(); - var gearCount = 0; - - data.GetValues(x => { - var gear = x.Field<uint>((int)ModalResultField.Gear); - var speed = x.Field<MeterPerSecond>((int)ModalResultField.v_act); - if (speed != null && speed.IsSmallerOrEqual(0.1)) { - prevGear = 0; - gearCount++; - return gear; // not used - } - if (gear == 0 || gear == prevGear) { - return gear; // not used - } - gearCount++; - prevGear = gear; - return gear; // not used - }); - return gearCount.SI<Scalar>(); - } - - public static Scalar CoastingTimeShare(this IModalDataContainer data) - { - var sum = data.GetValues(x => new { - DrivingBehavior = x.Field<DrivingBehavior>((int)ModalResultField.drivingBehavior), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.DrivingBehavior == DrivingBehavior.Coasting ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); - return 100 * sum / Duration(data); - } - - public static Scalar BrakingTimeShare(this IModalDataContainer data) - { - var sum = data.GetValues(x => new { - DrivingBehavior = x.Field<DrivingBehavior>((int)ModalResultField.drivingBehavior), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }) - .Sum(x => x.DrivingBehavior == DrivingBehavior.Braking ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); - return 100 * sum / Duration(data); - } - - public static Dictionary<uint, Scalar> TimeSharePerGear(this IModalDataContainer data, uint gearCount) - { - var retVal = new Dictionary<uint, Scalar>(); - for (uint i = 0; i <= gearCount; i++) { - retVal[i] = 0.SI<Scalar>(); - } - - var gearData = data.GetValues(x => new { - Gear = x.Field<uint>((int)ModalResultField.Gear), - dt = x.Field<Second>((int)ModalResultField.simulationInterval) - }); - - foreach (var entry in gearData) { - retVal[entry.Gear] += entry.dt.Value(); - } - - var duration = Duration(data).Value(); - for (uint i = 0; i <= gearCount; i++) { - retVal[i] = 100 * retVal[i] / duration; - } - return retVal; - } - } +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.Simulation.Impl; + +namespace TUGraz.VectoCore.OutputData +{ + public interface IModalDataFilter + { + ModalResults Filter(ModalResults data); + string ID { get; } + } + + public interface IModalDataContainer + { + /// <summary> + /// Indexer for fields of the DataWriter. Accesses the data of the current step. + /// </summary> + /// <param name="key"></param> + /// <returns></returns> + object this[ModalResultField key] { get; set; } + + /// <summary> + /// Indexer for auxiliary fields of the DataWriter. + /// </summary> + /// <param name="auxId"></param> + /// <returns></returns> + object this[string auxId] { get; set; } + + bool HasTorqueConverter { set; } + + /// <summary> + /// Commits the data of the current simulation step. + /// </summary> + void CommitSimulationStep(); + + FuelData.Entry FuelData { get; } + + VectoRun.Status RunStatus { get; } + + string Error { get; } + + string StackTrace { get; } + + /// <summary> + /// Finishes the writing of the DataWriter. + /// </summary> + void Finish(VectoRun.Status runStatus); + + IEnumerable<T> GetValues<T>(ModalResultField key); + + IEnumerable<T> GetValues<T>(DataColumn col); + + IEnumerable<T> GetValues<T>(Func<DataRow, T> selectorFunc); + + Dictionary<string, DataColumn> Auxiliaries { get; } + + T TimeIntegral<T>(ModalResultField field, Func<SI, bool> filter = null) where T : SIBase<T>; + + void SetDataValue(string fieldName, object value); + + void AddAuxiliary(string id, string columnName = null); + + /// <summary> + /// clear the modal data after the simulation + /// called after the simulation is finished and the sum-entries have been written + /// </summary> + /// <param name="exception"></param> + void FinishSimulation(Exception exception = null); + } + + public static class ModalDataContainerExtensions + { + public static T Max<T>(this IModalDataContainer data, ModalResultField field) + { + return data.GetValues<T>(field).Max(); + } + + public static T Min<T>(this IModalDataContainer data, ModalResultField field) + { + return data.GetValues<T>(field).Min(); + } + + /// <summary> + /// Returns a default value if the SI object is null. + /// </summary> + /// <typeparam name="T">The SI Type.</typeparam> + /// <param name="self">The SI Instance.</param> + /// <param name="defaultValue">The default value.</param> + /// <returns>If self is null, the default value as SI-Type is returned. Otherwise self is returned.</returns> + /// <code> + /// NewtonMeter t = null; + /// var x = t.DefaultIfNull(0); + /// </code> + public static T DefaultIfNull<T>(this T self, double defaultValue) where T : SIBase<T> + { + return self ?? defaultValue.SI<T>(); + } + + public static MeterPerSquareSecond AccelerationsPositive(this IModalDataContainer data) + { + return data.GetValues<MeterPerSquareSecond>(ModalResultField.acc) + .Where(x => x > 0.125) + .DefaultIfEmpty(0.SI<MeterPerSquareSecond>()) + .Average(); + } + + public static MeterPerSquareSecond AccelerationsNegative(this IModalDataContainer data) + { + return data.GetValues<MeterPerSquareSecond>(ModalResultField.acc) + .Where(x => x < -0.125) + .DefaultIfEmpty(0.SI<MeterPerSquareSecond>()) + .Average(); + } + + public static Scalar AccelerationTimeShare(this IModalDataContainer data) + { + var accelerationTimeShare = data.GetValues(x => new { + a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.a > 0.125 ? x.dt : 0.SI<Second>()).DefaultIfNull(0); + return 100 * (accelerationTimeShare / data.Duration()).Cast<Scalar>(); + } + + public static Scalar DecelerationTimeShare(this IModalDataContainer data) + { + var decelerationTimeShare = data.GetValues(x => new { + a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.a < -0.125 ? x.dt : 0.SI<Second>()).DefaultIfNull(0); + return 100 * (decelerationTimeShare / data.Duration()).Cast<Scalar>(); + } + + public static Scalar CruiseTimeShare(this IModalDataContainer data) + { + var cruiseTime = data.GetValues(x => new { + v = x.Field<MeterPerSecond>((int)ModalResultField.v_act).DefaultIfNull(0), + a = x.Field<MeterPerSquareSecond>((int)ModalResultField.acc).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.v >= 0.1.KMPHtoMeterPerSecond() && x.a.IsBetween(-0.125, 0.125) ? x.dt : 0.SI<Second>()) + .DefaultIfNull(0); + return 100 * (cruiseTime / data.Duration()).Cast<Scalar>(); + } + + public static Scalar StopTimeShare(this IModalDataContainer data) + { + var stopTime = data.GetValues(x => new { + v = x.Field<MeterPerSecond>((int)ModalResultField.v_act).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.v < 0.1.KMPHtoMeterPerSecond() ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); + return 100 * (stopTime / data.Duration()).Cast<Scalar>(); + } + + public static MeterPerSquareSecond AccelerationAverage(this IModalDataContainer data) + { + return data.TimeIntegral<MeterPerSecond>(ModalResultField.acc) / data.Duration(); + } + + public static Meter AltitudeDelta(this IModalDataContainer data) + { + var altitudes = data.GetValues<Meter>(ModalResultField.altitude).ToList(); + var first = altitudes.First(); + var last = altitudes.Last(); + return first == null || last == null ? null : last - first; + } + + public static WattSecond PowerAccelerations(this IModalDataContainer data) + { + var paEngine = data.TimeIntegral<WattSecond>(ModalResultField.P_eng_inertia); + var paGearbox = data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_inertia); + return paEngine + paGearbox; + } + + public static WattSecond WorkClutch(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_clutch_loss); + } + + public static WattSecond WorkGearshift(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_shift_loss); + } + + public static WattSecond WorkGearbox(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_gbx_loss); + } + + public static WattSecond WorkAxlegear(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_axle_loss); + } + + public static WattSecond WorkRetarder(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_ret_loss); + } + + public static WattSecond WorkAngledrive(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_angle_loss); + } + + public static WattSecond WorkTorqueConverter(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_TC_loss); + } + + public static Second Duration(this IModalDataContainer data) + { + var time = data.GetValues<Second>(ModalResultField.time).ToList(); + var dt = data.GetValues<Second>(ModalResultField.simulationInterval).ToList(); + if (time.Count == 1) { + return time.First(); + } + return time.Max() - time.Min() + dt.First() / 2 + dt.Last() / 2; + } + + public static Meter Distance(this IModalDataContainer data) + { + var max = data.Max<Meter>(ModalResultField.dist); + var min = data.Min<Meter>(ModalResultField.dist); + return max == null || min == null ? null : max - min; + } + + public static WattSecond WorkTotalMechanicalBrake(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_brake_loss); + } + + public static WattSecond WorkVehicleInertia(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_veh_inertia) + + data.TimeIntegral<WattSecond>(ModalResultField.P_wheel_inertia); + } + + public static WattSecond WorkAuxiliaries(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_aux); + } + + public static WattSecond WorkRoadGradientResistance(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_slope); + } + + public static WattSecond WorkRollingResistance(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_roll); + } + + public static WattSecond WorkAirResistance(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_air); + } + + + public static WattSecond TotalEngineWorkPositive(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_eng_fcmap, x => x > 0); + } + + public static WattSecond TotalEngineWorkNegative(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_eng_fcmap, x => x < 0); + } + + public static Watt PowerWheelPositive(this IModalDataContainer data) + { + return data.TimeIntegral<WattSecond>(ModalResultField.P_wheel_in, x => x > 0) / data.Duration(); + } + + public static KilogramPerMeter FuelConsumptionWHTC(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCWHTCc) / distance; + } + + public static KilogramPerSecond FuelConsumptionWHTCPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCWHTCc) / data.Duration(); + } + + public static KilogramPerMeter FuelConsumptionAuxStartStop(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCAUXc) / distance; + } + + public static KilogramPerSecond FuelConsumptionAAUXPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCAAUX) / data.Duration(); + } + + public static KilogramPerMeter FuelConsumptionAAUX(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCAAUX) / distance; + } + + public static KilogramPerSecond FuelConsumptionAuxStartStopPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCAUXc) / data.Duration(); + } + + public static KilogramPerSecond FuelConsumptionFinalPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) / data.Duration(); + } + + public static KilogramPerMeter FuelConsumptionFinal(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) / distance; + } + + public static SI FuelConsumptionFinalLiterPer100Kilometer(this IModalDataContainer data) + { + var fuelConsumptionFinal = data.FuelConsumptionFinal(); + if (fuelConsumptionFinal == null || data.FuelData.FuelDensity == null) { + return null; + } + + var fcVolumePerMeter = fuelConsumptionFinal / data.FuelData.FuelDensity; + return fcVolumePerMeter.ConvertTo().Cubic.Dezi.Meter * 100.SI().Kilo.Meter; + } + + public static KilogramPerMeter CO2PerMeter(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) * data.FuelData.CO2PerFuelWeight / distance; + } + + public static JoulePerMeter EnergyPerMeter(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) * data.FuelData.LowerHeatingValue / distance; + } + + public static KilogramPerSecond FCMapPerSecond(this IModalDataContainer data) + { + return data.TimeIntegral<Kilogram>(ModalResultField.FCMap) / data.Duration(); + } + + public static KilogramPerMeter FCMapPerMeter(this IModalDataContainer data) + { + var distance = data.Distance(); + if (distance == null || distance.IsEqual(0)) { + return null; + } + return data.TimeIntegral<Kilogram>(ModalResultField.FCMap) / distance; + } + + + public static Watt TotalPowerEnginePositiveAverage(this IModalDataContainer data) + { + var simulationIntervals = data.GetValues<Second>(ModalResultField.simulationInterval); + var values = data.GetValues<Watt>(ModalResultField.P_eng_fcmap) + .Zip(simulationIntervals, (value, dt) => new { Dt = dt, Value = value * dt }) + .Where(v => v.Value > 0).ToList(); + if (values.Any()) { + return values.Sum(v => v.Value) / Duration(data); + } + return 0.SI<Watt>(); + } + + public static MeterPerSecond Speed(this IModalDataContainer data) + { + var distance = Distance(data); + var duration = Duration(data); + if (distance == null || duration == null || duration.IsEqual(0)) { + return null; + } + return distance / duration; + } + + public static WattSecond AuxiliaryWork(this IModalDataContainer data, DataColumn auxCol) + { + var simulationIntervals = data.GetValues<Second>(ModalResultField.simulationInterval).ToArray(); + var auxValues = data.GetValues<Watt>(auxCol).ToArray(); + var sum = 0.SI<WattSecond>(); + for (var i = 0; i < simulationIntervals.Length; i++) { + if (auxValues[i] != null && simulationIntervals[i] != null) { + sum += auxValues[i] * simulationIntervals[i]; + } + } + return sum; + } + + + public static MeterPerSecond MaxSpeed(this IModalDataContainer data) + { + return data.Max<MeterPerSecond>(ModalResultField.v_act).DefaultIfNull(0); + } + + public static MeterPerSecond MinSpeed(this IModalDataContainer data) + { + return data.Min<MeterPerSecond>(ModalResultField.v_act).DefaultIfNull(0); + } + + public static MeterPerSquareSecond MaxAcceleration(this IModalDataContainer data) + { + return data.Max<MeterPerSquareSecond>(ModalResultField.acc).DefaultIfNull(0); + } + + public static MeterPerSquareSecond MaxDeceleration(this IModalDataContainer data) + { + return -data.Min<MeterPerSquareSecond>(ModalResultField.acc).DefaultIfNull(0); + } + + public static PerSecond AvgEngineSpeed(this IModalDataContainer data) + { + var integral = data.GetValues(x => x.Field<PerSecond>((int)ModalResultField.n_eng_avg).Value() * + x.Field<Second>((int)ModalResultField.simulationInterval).Value()).Sum(); + return (integral / Duration(data).Value()).SI<PerSecond>(); + } + + public static PerSecond MaxEngineSpeed(this IModalDataContainer data) + { + return data.Max<PerSecond>(ModalResultField.n_eng_avg); + } + + public static Scalar EngineMaxLoadTimeShare(this IModalDataContainer data) + { + var sum = data.GetValues(x => new { + tMax = x.Field<NewtonMeter>((int)ModalResultField.Tq_full).DefaultIfNull(-1), + tEng = x.Field<NewtonMeter>((int)ModalResultField.T_eng_fcmap).DefaultIfNull(0), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }).Sum(x => x.tMax.IsEqual(x.tEng, 5.SI<NewtonMeter>()) ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); + return 100 * sum / Duration(data); + } + + public static Scalar GearshiftCount(this IModalDataContainer data) + { + var prevGear = data.GetValues<uint>(ModalResultField.Gear).First(); + var gearCount = 0; + + var shifts = data.GetValues(x => new { + Gear = x.Field<uint>((int)ModalResultField.Gear), + Speed = x.Field<MeterPerSecond>((int)ModalResultField.v_act) + }); + foreach (var entry in shifts) { + if (entry.Speed != null && entry.Speed.IsSmallerOrEqual(0.1)) { + prevGear = 0; + gearCount++; + } + if (entry.Gear == 0 || entry.Gear == prevGear) { + continue; + } + gearCount++; + prevGear = entry.Gear; + } + return gearCount.SI<Scalar>(); + } + + public static Scalar CoastingTimeShare(this IModalDataContainer data) + { + var sum = data.GetValues(x => new { + DrivingBehavior = x.Field<DrivingBehavior>((int)ModalResultField.drivingBehavior), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.DrivingBehavior == DrivingBehavior.Coasting ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); + return 100 * sum / Duration(data); + } + + public static Scalar BrakingTimeShare(this IModalDataContainer data) + { + var sum = data.GetValues(x => new { + DrivingBehavior = x.Field<DrivingBehavior>((int)ModalResultField.drivingBehavior), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }) + .Sum(x => x.DrivingBehavior == DrivingBehavior.Braking ? x.dt : 0.SI<Second>()) ?? 0.SI<Second>(); + return 100 * sum / Duration(data); + } + + public static Dictionary<uint, Scalar> TimeSharePerGear(this IModalDataContainer data, uint gearCount) + { + var retVal = new Dictionary<uint, Scalar>(); + for (uint i = 0; i <= gearCount; i++) { + retVal[i] = 0.SI<Scalar>(); + } + + var gearData = data.GetValues(x => new { + Gear = x.Field<uint>((int)ModalResultField.Gear), + dt = x.Field<Second>((int)ModalResultField.simulationInterval) + }); + + foreach (var entry in gearData) { + retVal[entry.Gear] += entry.dt.Value(); + } + + var duration = Duration(data).Value(); + for (uint i = 0; i <= gearCount; i++) { + retVal[i] = 100 * retVal[i] / duration; + } + return retVal; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/OutputData/SummaryDataContainer.cs b/VectoCore/VectoCore/OutputData/SummaryDataContainer.cs index 7a69faf093e6c94035e30fd0dcd67f9ff55a6667..10c29e57190056f883d4a4147a85447b36f5b292 100644 --- a/VectoCore/VectoCore/OutputData/SummaryDataContainer.cs +++ b/VectoCore/VectoCore/OutputData/SummaryDataContainer.cs @@ -29,566 +29,566 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Data; -using System.Linq; -using System.Runtime.CompilerServices; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data; - -// ReSharper disable MemberCanBePrivate.Global -- used by API! - -namespace TUGraz.VectoCore.OutputData -{ - public delegate void WriteSumData(IModalDataContainer data); - - /// <summary> - /// Class for the sum file in vecto. - /// </summary> - public class SummaryDataContainer : LoggingObject, IDisposable - { - // ReSharper disable InconsistentNaming - public const string INTERNAL_PREFIX = "INTERNAL"; - public const string SORT = INTERNAL_PREFIX + " Sorting"; - public const string JOB = "Job [-]"; - public const string INPUTFILE = "Input File [-]"; - public const string CYCLE = "Cycle [-]"; - public const string STATUS = "Status"; - public const string CURB_MASS = "Chassis curb mass [kg]"; - public const string LOADING = "Loading [kg]"; - - public const string VEHICLE_MANUFACTURER = "Vehicle manufacturer [-]"; - public const string VIN_NUMBER = "VIN number"; - public const string VEHICLE_MODEL = "Vehicle model [-]"; - - public const string ENGINE_MANUFACTURER = "Engine manufacturer [-]"; - public const string ENGINE_MODEL = "Engine model [-]"; - public const string ENGINE_FUEL_TYPE = "Engine fuel type [-]"; - public const string ENGINE_WHTC_URBAN = "Engine WHTCUrban"; - public const string ENGINE_WHTC_RURAL = "Engine WHTCRural"; - public const string ENGINE_WHTC_MOTORWAY = "Engine WHTCMotorway"; - public const string ENGINE_BF_COLD_HOT = "Engine BFColdHot"; - public const string ENGINE_CF_REG_PER = "Engine CFRegPer"; - public const string ENGINE_ACTUAL_CORRECTION_FACTOR = "Engine actual CF"; - public const string ENGINE_RATED_POWER = "Engine rated power [kW]"; - public const string ENGINE_IDLING_SPEED = "Engine idling speed [rpm]"; - public const string ENGINE_RATED_SPEED = "Engine rated speed [rpm]"; - public const string ENGINE_DISPLACEMENT = "Engine displacement [ccm]"; - - public const string ROLLING_RESISTANCE_COEFFICIENT_W_TRAILER = "total RRC [-]"; - public const string ROLLING_RESISTANCE_COEFFICIENT_WO_TRAILER = "weighted RRC w/o trailer [-]"; - - public const string GEARBOX_MANUFACTURER = "Gearbox manufacturer [-]"; - public const string GEARBOX_MODEL = "Gearbox model [-]"; - public const string GEARBOX_TYPE = "Gearbox type [-]"; - public const string GEAR_RATIO_FIRST_GEAR = "Gear ratio first gear [-]"; - public const string GEAR_RATIO_LAST_GEAR = "Gear ratio last gear [-]"; - - public const string TORQUECONVERTER_MANUFACTURER = "Torque converter manufacturer [-]"; - public const string TORQUECONVERTER_MODEL = "Torque converter model [-]"; - - public const string RETARDER_MANUFACTURER = "Retarder manufacturer [-]"; - public const string RETARDER_MODEL = "Retarder model [-]"; - public const string RETARDER_TYPE = "Retarder type [-]"; - - public const string ANGLEDRIVE_MANUFACTURER = "Angledrive manufacturer [-]"; - public const string ANGLEDRIVE_MODEL = "Angledrive model [-]"; - public const string ANGLEDRIVE_RATIO = "Angledrive ratio [-]"; - - public const string AXLE_MANUFACTURER = "Axle manufacturer [-]"; - public const string AXLE_MODEL = "Axle model [-]"; - public const string AXLE_RATIO = "Axle gear ratio [-]"; - - public const string AUX_TECH_FORMAT = "Auxiliary technology {0} [-]"; - - public const string HDV_CO2_VEHICLE_CLASS = "HDV CO2 vehicle class [-]"; - public const string TOTAL_VEHICLE_MASS = "Total vehicle mass [kg]"; - public const string CD_x_A = "CdxA [m²]"; - //public const string ROLLING_RESISTANCE_COEFFICIENT = "weighed RRC [-]"; - public const string R_DYN = "r_dyn [m]"; - - public const string CARGO_VOLUME = "Cargo Volume [m³]"; - public const string TIME = "time [s]"; - public const string DISTANCE = "distance [km]"; - public const string SPEED = "speed [km/h]"; - public const string ALTITUDE_DELTA = "altitudeDelta [m]"; - - public const string FCMAP_H = "FC-Map [g/h]"; - public const string FCMAP_KM = "FC-Map [g/km]"; - public const string FCAUXC_H = "FC-AUXc [g/h]"; - public const string FCAUXC_KM = "FC-AUXc [g/km]"; - public const string FCWHTCC_H = "FC-WHTCc [g/h]"; - public const string FCWHTCC_KM = "FC-WHTCc [g/km]"; - public const string FCAAUX_H = "FC-AAUX [g/h]"; - public const string FCAAUX_KM = "FC-AAUX [g/km]"; - - public const string FCFINAL_H = "FC-Final [g/h]"; - public const string FCFINAL_KM = "FC-Final [g/km]"; - public const string FCFINAL_LITERPER100KM = "FC-Final [l/100km]"; - public const string FCFINAL_LITERPER100TKM = "FC-Final [l/100tkm]"; - public const string FCFINAL_LiterPer100M3KM = "FC-Final [l/100m³km]"; - - public const string CO2_KM = "CO2 [g/km]"; - public const string CO2_TKM = "CO2 [g/tkm]"; - public const string CO2_M3KM = "CO2 [g/m³km]"; - - public const string P_WHEEL_POS = "P_wheel_in_pos [kW]"; - public const string P_FCMAP_POS = "P_fcmap_pos [kW]"; - - public const string E_FORMAT = "E_{0} [kWh]"; - public const string E_AUX_FORMAT = "E_aux_{0} [kWh]"; - public const string E_AUX = "E_aux_sum [kWh]"; - - public const string E_AIR = "E_air [kWh]"; - public const string E_ROLL = "E_roll [kWh]"; - public const string E_GRAD = "E_grad [kWh]"; - public const string E_VEHICLE_INERTIA = "E_vehi_inertia [kWh]"; - public const string E_POWERTRAIN_INERTIA = "E_powertrain_inertia [kWh]"; - public const string E_BRAKE = "E_brake [kWh]"; - public const string E_GBX_LOSS = "E_gbx_loss [kWh]"; - public const string E_SHIFT_LOSS = "E_shift_loss [kWh]"; - public const string E_AXL_LOSS = "E_axl_loss [kWh]"; - public const string E_RET_LOSS = "E_ret_loss [kWh]"; - public const string E_TC_LOSS = "E_tc_loss [kWh]"; - public const string E_ANGLE_LOSS = "E_angle_loss [kWh]"; - public const string E_CLUTCH_LOSS = "E_clutch_loss [kWh]"; - public const string E_FCMAP_POS = "E_fcmap_pos [kWh]"; - public const string E_FCMAP_NEG = "E_fcmap_neg [kWh]"; - - public const string ACC = "a [m/s^2]"; - public const string ACC_POS = "a_pos [m/s^2]"; - public const string ACC_NEG = "a_neg [m/s^2]"; - - public const string ACC_TIMESHARE = "AccelerationTimeShare [%]"; - public const string DEC_TIMESHARE = "DecelerationTimeShare [%]"; - public const string CRUISE_TIMESHARE = "CruiseTimeShare [%]"; - public const string STOP_TIMESHARE = "StopTimeShare [%]"; - - public const string MAX_SPEED = "max. speed [km/h"; - public const string MAX_ACCELERATION = "max. acc [m/s²]"; - public const string MAX_DECELERATION = "max. dec [m/s²]"; - public const string AVG_ENGINE_SPEED = "n_eng_avg [rpm]"; - public const string MAX_ENGINE_SPEED = "n_eng_max [rpm]"; - public const string NUM_GEARSHIFTS = "gear shifts [-]"; - public const string ENGINE_FULL_LOAD_TIME_SHARE = "Engine max. Load time share [%]"; - public const string COASTING_TIME_SHARE = "CoastingTimeShare [%]"; - public const string BRAKING_TIME_SHARE = "BrakingTImeShare [%]"; - - public const string TIME_SHARE_PER_GEAR_FORMAT = "Gear {0} TimeShare [%]"; - - // ReSharper restore InconsistentNaming - - internal readonly DataTable Table; - private readonly ISummaryWriter _sumWriter; - - - protected SummaryDataContainer() {} - - /// <summary> - /// Initializes a new instance of the <see cref="SummaryDataContainer"/> class. - /// </summary> - /// <param name="writer"></param> - public SummaryDataContainer(ISummaryWriter writer) - { - _sumWriter = writer; - - Table = new DataTable(); - - Table.Columns.AddRange(new[] { - Tuple.Create(SORT, typeof(int)), - Tuple.Create(JOB, typeof(string)), - Tuple.Create(INPUTFILE, typeof(string)), - Tuple.Create(CYCLE, typeof(string)), - Tuple.Create(STATUS, typeof(string)), - Tuple.Create(VEHICLE_MANUFACTURER, typeof(string)), - Tuple.Create(VIN_NUMBER, typeof(string)), - Tuple.Create(VEHICLE_MODEL, typeof(string)), - Tuple.Create(HDV_CO2_VEHICLE_CLASS, typeof(string)), - Tuple.Create(CURB_MASS, typeof(SI)), - Tuple.Create(LOADING, typeof(SI)), - Tuple.Create(TOTAL_VEHICLE_MASS, typeof(SI)), - Tuple.Create(ENGINE_MANUFACTURER, typeof(string)), - Tuple.Create(ENGINE_MODEL, typeof(string)), - Tuple.Create(ENGINE_FUEL_TYPE, typeof(string)), - Tuple.Create(ENGINE_RATED_POWER, typeof(SI)), - Tuple.Create(ENGINE_IDLING_SPEED, typeof(SI)), - Tuple.Create(ENGINE_RATED_SPEED, typeof(SI)), - Tuple.Create(ENGINE_DISPLACEMENT, typeof(SI)), - Tuple.Create(ENGINE_WHTC_URBAN, typeof(double)), - Tuple.Create(ENGINE_WHTC_RURAL, typeof(double)), - Tuple.Create(ENGINE_WHTC_MOTORWAY, typeof(double)), - Tuple.Create(ENGINE_BF_COLD_HOT, typeof(double)), - Tuple.Create(ENGINE_CF_REG_PER, typeof(double)), - Tuple.Create(ENGINE_ACTUAL_CORRECTION_FACTOR, typeof(double)), - Tuple.Create(CD_x_A, typeof(SI)), - Tuple.Create(ROLLING_RESISTANCE_COEFFICIENT_W_TRAILER, typeof(double)), - Tuple.Create(ROLLING_RESISTANCE_COEFFICIENT_WO_TRAILER, typeof(double)), - Tuple.Create(R_DYN, typeof(SI)), - Tuple.Create(GEARBOX_MANUFACTURER, typeof(string)), - Tuple.Create(GEARBOX_MODEL, typeof(string)), - Tuple.Create(GEARBOX_TYPE, typeof(string)), - Tuple.Create(GEAR_RATIO_FIRST_GEAR, typeof(SI)), - Tuple.Create(GEAR_RATIO_LAST_GEAR, typeof(SI)), - Tuple.Create(TORQUECONVERTER_MANUFACTURER, typeof(string)), - Tuple.Create(TORQUECONVERTER_MODEL, typeof(string)), - Tuple.Create(RETARDER_MANUFACTURER, typeof(string)), - Tuple.Create(RETARDER_MODEL, typeof(string)), - Tuple.Create(RETARDER_TYPE, typeof(string)), - Tuple.Create(ANGLEDRIVE_MANUFACTURER, typeof(string)), - Tuple.Create(ANGLEDRIVE_MODEL, typeof(string)), - Tuple.Create(ANGLEDRIVE_RATIO, typeof(string)), - Tuple.Create(AXLE_MANUFACTURER, typeof(string)), - Tuple.Create(AXLE_MODEL, typeof(string)), - Tuple.Create(AXLE_RATIO, typeof(SI)), - Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.SteeringPump), typeof(string)), - Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.Fan), typeof(string)), - Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.HeatingVentilationAirCondition), - typeof(string)), - Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.PneumaticSystem), typeof(string)), - Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.ElectricSystem), typeof(string)), - }.Select(x => new DataColumn(x.Item1, x.Item2)).ToArray()); - - Table.Columns.AddRange(new[] { - CARGO_VOLUME, - TIME, DISTANCE, - SPEED, ALTITUDE_DELTA, - FCMAP_H, FCMAP_KM, - FCAUXC_H, FCAUXC_KM, - FCWHTCC_H, FCWHTCC_KM, - FCAAUX_H, FCAAUX_KM, - FCFINAL_H, FCFINAL_KM, - FCFINAL_LITERPER100KM, FCFINAL_LITERPER100TKM, FCFINAL_LiterPer100M3KM, - CO2_KM, CO2_TKM, CO2_M3KM, - P_WHEEL_POS, P_FCMAP_POS, - E_FCMAP_POS, E_FCMAP_NEG, E_POWERTRAIN_INERTIA, - E_AUX, E_CLUTCH_LOSS, E_TC_LOSS, E_SHIFT_LOSS, E_GBX_LOSS, - E_RET_LOSS, E_ANGLE_LOSS, E_AXL_LOSS, E_BRAKE, E_VEHICLE_INERTIA, E_AIR, E_ROLL, E_GRAD, - ACC, ACC_POS, ACC_NEG, ACC_TIMESHARE, DEC_TIMESHARE, CRUISE_TIMESHARE, STOP_TIMESHARE, - MAX_SPEED, MAX_ACCELERATION, MAX_DECELERATION, AVG_ENGINE_SPEED, MAX_ENGINE_SPEED, NUM_GEARSHIFTS, - ENGINE_FULL_LOAD_TIME_SHARE, COASTING_TIME_SHARE, BRAKING_TIME_SHARE - }.Select(x => new DataColumn(x, typeof(SI))).ToArray()); - } - - /// <summary> - /// Finishes the summary data container (writes the data to the sumWriter). - /// </summary> - public virtual void Finish() - { - if (_sumWriter != null) { - var view = new DataView(Table, "", SORT, DataViewRowState.CurrentRows).ToTable(); - var toRemove = - view.Columns.Cast<DataColumn>().Where(column => column.ColumnName.StartsWith(INTERNAL_PREFIX)).ToList(); - foreach (var dataColumn in toRemove) { - view.Columns.Remove(dataColumn); - } - _sumWriter.WriteSumData(view); - } - } - - /// <summary> - /// Writes the result of one run into the summary data container. - /// </summary> - [MethodImpl(MethodImplOptions.Synchronized)] - //public virtual void Write(IModalDataContainer modData, string jobFileName, string jobName, string cycleFileName, - // Kilogram vehicleMass, Kilogram vehicleLoading, CubicMeter cargoVolume, uint gearCount) - public virtual void Write(IModalDataContainer modData, int jobNr, int runNr, VectoRunData runData) - { - var row = Table.NewRow(); - Table.Rows.Add(row); - - row[SORT] = jobNr * 1000 + runNr; - row[JOB] = string.Format("{0}-{1}", jobNr, runNr); //ReplaceNotAllowedCharacters(current); - row[INPUTFILE] = ReplaceNotAllowedCharacters(runData.JobName); - row[CYCLE] = ReplaceNotAllowedCharacters(runData.Cycle.Name + Constants.FileExtensions.CycleFile); - - row[STATUS] = modData.RunStatus; - - var vehicleLoading = 0.SI<Kilogram>(); - var cargoVolume = 0.SI<CubicMeter>(); - uint gearCount = 0u; - if (runData.Cycle.CycleType != CycleType.EngineOnly) { - row[VEHICLE_MANUFACTURER] = runData.VehicleData.Manufacturer; - row[VIN_NUMBER] = runData.VehicleData.VIN; - row[VEHICLE_MODEL] = runData.VehicleData.ModelName; - - row[HDV_CO2_VEHICLE_CLASS] = runData.VehicleData.VehicleClass.GetClassNumber(); - row[CURB_MASS] = runData.VehicleData.CurbWeight; - // - (runData.VehicleData.BodyAndTrailerWeight ?? 0.SI<Kilogram>()); - row[LOADING] = runData.VehicleData.Loading; - row[CARGO_VOLUME] = runData.VehicleData.CargoVolume; - - row[TOTAL_VEHICLE_MASS] = runData.VehicleData.TotalVehicleWeight; - row[ENGINE_MANUFACTURER] = runData.EngineData.Manufacturer; - row[ENGINE_MODEL] = runData.EngineData.ModelName; - row[ENGINE_FUEL_TYPE] = runData.EngineData.FuelType.GetLabel(); - row[ENGINE_RATED_POWER] = runData.EngineData.RatedPowerDeclared != null - ? runData.EngineData.RatedPowerDeclared.ConvertTo().Kilo.Watt - : runData.EngineData.FullLoadCurves[0].MaxPower.ConvertTo().Kilo.Watt; - row[ENGINE_IDLING_SPEED] = runData.EngineData.IdleSpeed.AsRPM.SI<Scalar>(); - row[ENGINE_RATED_SPEED] = runData.EngineData.RatedSpeedDeclared != null - ? runData.EngineData.RatedSpeedDeclared.AsRPM.SI<Scalar>() - : runData.EngineData.FullLoadCurves[0].RatedSpeed.AsRPM.SI<Scalar>(); - row[ENGINE_DISPLACEMENT] = runData.EngineData.Displacement.ConvertTo().Cubic.Centi.Meter; - - row[ENGINE_WHTC_URBAN] = runData.EngineData.WHTCUrban; - row[ENGINE_WHTC_RURAL] = runData.EngineData.WHTCRural; - row[ENGINE_WHTC_MOTORWAY] = runData.EngineData.WHTCMotorway; - row[ENGINE_BF_COLD_HOT] = runData.EngineData.ColdHotCorrectionFactor; - row[ENGINE_CF_REG_PER] = runData.EngineData.CorrectionFactorRegPer; - row[ENGINE_ACTUAL_CORRECTION_FACTOR] = runData.EngineData.FuelConsumptionCorrectionFactor; - - row[CD_x_A] = runData.AirdragData.CrossWindCorrectionCurve.AirDragArea; - - row[ROLLING_RESISTANCE_COEFFICIENT_WO_TRAILER] = - runData.VehicleData.RollResistanceCoefficientWithoutTrailer; - row[ROLLING_RESISTANCE_COEFFICIENT_W_TRAILER] = - runData.VehicleData.TotalRollResistanceCoefficient; - - row[R_DYN] = runData.VehicleData.DynamicTyreRadius; - - row[GEARBOX_MANUFACTURER] = runData.GearboxData.Manufacturer; - row[GEARBOX_MODEL] = runData.GearboxData.ModelName; - row[GEARBOX_TYPE] = runData.GearboxData.Type; - if (runData.GearboxData.Type.AutomaticTransmission()) { - row[GEAR_RATIO_FIRST_GEAR] = runData.GearboxData.Gears.Count > 0 - ? (double.IsNaN(runData.GearboxData.Gears.First().Value.Ratio) - ? runData.GearboxData.Gears.First().Value.TorqueConverterRatio.SI<Scalar>() - : runData.GearboxData.Gears.First().Value.Ratio.SI<Scalar>()) - : 0.SI<Scalar>(); - row[GEAR_RATIO_LAST_GEAR] = runData.GearboxData.Gears.Count > 0 - ? runData.GearboxData.Gears.Last().Value.Ratio.SI<Scalar>() - : 0.SI<Scalar>(); - row[TORQUECONVERTER_MANUFACTURER] = runData.GearboxData.TorqueConverterData.Manufacturer; - row[TORQUECONVERTER_MODEL] = runData.GearboxData.TorqueConverterData.ModelName; - } else { - row[GEAR_RATIO_FIRST_GEAR] = runData.GearboxData.Gears.Count > 0 - ? runData.GearboxData.Gears.First().Value.Ratio.SI<Scalar>() - : 0.SI<Scalar>(); - row[GEAR_RATIO_LAST_GEAR] = runData.GearboxData.Gears.Count > 0 - ? runData.GearboxData.Gears.Last().Value.Ratio.SI<Scalar>() - : 0.SI<Scalar>(); - row[TORQUECONVERTER_MANUFACTURER] = "n.a."; - row[TORQUECONVERTER_MODEL] = "n.a."; - } - row[RETARDER_TYPE] = runData.Retarder.Type.GetLabel(); - if (runData.Retarder.Type.IsDedicatedComponent()) { - row[RETARDER_MANUFACTURER] = runData.Retarder.Manufacturer; - row[RETARDER_MODEL] = runData.Retarder.ModelName; - } else { - row[RETARDER_MANUFACTURER] = "n.a."; - row[RETARDER_MODEL] = "n.a."; - } - - if (runData.AngledriveData != null) { - row[ANGLEDRIVE_MANUFACTURER] = runData.AngledriveData.Manufacturer; - row[ANGLEDRIVE_MODEL] = runData.AngledriveData.ModelName; - row[ANGLEDRIVE_RATIO] = runData.AngledriveData.Angledrive.Ratio; - } else { - row[ANGLEDRIVE_MANUFACTURER] = "n.a."; - row[ANGLEDRIVE_MODEL] = "n.a."; - row[ANGLEDRIVE_RATIO] = "n.a."; - } - - row[AXLE_MANUFACTURER] = runData.AxleGearData.Manufacturer; - row[AXLE_MODEL] = runData.AxleGearData.ModelName; - row[AXLE_RATIO] = runData.AxleGearData.AxleGear.Ratio.SI<Scalar>(); - - foreach (var aux in runData.Aux) { - if (aux.ID == Constants.Auxiliaries.IDs.PTOConsumer || aux.ID == Constants.Auxiliaries.IDs.PTOTransmission) { - continue; - } - var colName = string.Format(AUX_TECH_FORMAT, aux.ID); - - if (!Table.Columns.Contains(colName)) { - var col = Table.Columns.Add(colName, typeof(string)); - // move the new column to correct position - col.SetOrdinal(Table.Columns[CARGO_VOLUME].Ordinal); - } - - row[colName] = aux.Technology == null ? "" : string.Join("; ", aux.Technology); - } - - cargoVolume = runData.VehicleData.CargoVolume; - vehicleLoading = runData.VehicleData.Loading; - gearCount = (uint)runData.GearboxData.Gears.Count; - } - - - var totalTime = modData.Duration(); - row[TIME] = totalTime; - - var distance = modData.Distance(); - if (distance != null) { - row[DISTANCE] = distance.ConvertTo().Kilo.Meter; - } - - var speed = modData.Speed(); - if (speed != null) { - row[SPEED] = speed.ConvertTo().Kilo.Meter.Per.Hour; - } - - row[ALTITUDE_DELTA] = modData.AltitudeDelta(); - - row[FCMAP_H] = modData.FCMapPerSecond().ConvertTo().Gramm.Per.Hour; - var fcMapPerMeter = modData.FCMapPerMeter(); - if (fcMapPerMeter != null) { - row[FCMAP_KM] = fcMapPerMeter.ConvertTo().Gramm.Per.Kilo.Meter; - } - - row[FCAUXC_H] = modData.FuelConsumptionAuxStartStopPerSecond().ConvertTo().Gramm.Per.Hour; - var fuelConsumptionAuxStartStopCorrected = modData.FuelConsumptionAuxStartStop(); - if (fuelConsumptionAuxStartStopCorrected != null) { - row[FCAUXC_KM] = fuelConsumptionAuxStartStopCorrected.ConvertTo().Gramm.Per.Kilo.Meter; - } - - row[FCWHTCC_H] = modData.FuelConsumptionWHTCPerSecond().ConvertTo().Gramm.Per.Hour; - var fuelConsumptionWHTCCorrected = modData.FuelConsumptionWHTC(); - if (fuelConsumptionWHTCCorrected != null) { - row[FCWHTCC_KM] = fuelConsumptionWHTCCorrected.ConvertTo().Gramm.Per.Kilo.Meter; - } - - row[FCAAUX_H] = modData.FuelConsumptionAAUXPerSecond().ConvertTo().Gramm.Per.Hour; - var fuelConsumptionAaux = modData.FuelConsumptionAAUX(); - if (fuelConsumptionAaux != null) { - row[FCAAUX_KM] = fuelConsumptionAaux.ConvertTo().Gramm.Per.Kilo.Meter; - } - - row[FCFINAL_H] = modData.FuelConsumptionFinalPerSecond().ConvertTo().Gramm.Per.Hour; - var fcfinal = modData.FuelConsumptionFinal(); - if (fcfinal != null) { - row[FCFINAL_KM] = fcfinal.ConvertTo().Gramm.Per.Kilo.Meter; - } - - var fcPer100lkm = modData.FuelConsumptionFinalLiterPer100Kilometer(); - row[FCFINAL_LITERPER100KM] = fcPer100lkm; - if (vehicleLoading != null && !vehicleLoading.IsEqual(0) && fcPer100lkm != null) { - row[FCFINAL_LITERPER100TKM] = fcPer100lkm / - vehicleLoading.ConvertTo().Ton; - } - if (cargoVolume > 0 && fcPer100lkm != null) { - row[FCFINAL_LiterPer100M3KM] = fcPer100lkm / cargoVolume; - } - - var kilogramPerMeter = modData.CO2PerMeter(); - if (kilogramPerMeter != null) { - row[CO2_KM] = kilogramPerMeter.ConvertTo().Gramm.Per.Kilo.Meter; - if (vehicleLoading != null && !vehicleLoading.IsEqual(0)) { - row[CO2_TKM] = kilogramPerMeter.ConvertTo().Gramm.Per.Kilo.Meter / vehicleLoading.ConvertTo().Ton; - } - if (cargoVolume > 0) { - row[CO2_M3KM] = kilogramPerMeter.ConvertTo().Gramm.Per.Kilo.Meter / cargoVolume; - } - } - - row[P_WHEEL_POS] = modData.PowerWheelPositive().ConvertTo().Kilo.Watt; - - row[P_FCMAP_POS] = modData.TotalPowerEnginePositiveAverage().ConvertTo().Kilo.Watt; - - foreach (var aux in modData.Auxiliaries) { - string colName; - if (aux.Key == Constants.Auxiliaries.IDs.PTOConsumer || aux.Key == Constants.Auxiliaries.IDs.PTOTransmission) { - colName = string.Format(E_FORMAT, aux.Key); - } else { - colName = string.Format(E_AUX_FORMAT, aux.Key); - } - - if (!Table.Columns.Contains(colName)) { - var col = Table.Columns.Add(colName, typeof(SI)); - // move the new column to correct position - col.SetOrdinal(Table.Columns[E_AUX].Ordinal); - } - - row[colName] = modData.AuxiliaryWork(aux.Value).ConvertTo().Kilo.Watt.Hour; - } - - row[E_FCMAP_POS] = modData.TotalEngineWorkPositive().ConvertTo().Kilo.Watt.Hour; - row[E_FCMAP_NEG] = -modData.TotalEngineWorkNegative().ConvertTo().Kilo.Watt.Hour; - row[E_POWERTRAIN_INERTIA] = modData.PowerAccelerations().ConvertTo().Kilo.Watt.Hour; - row[E_AUX] = modData.WorkAuxiliaries().ConvertTo().Kilo.Watt.Hour; - row[E_CLUTCH_LOSS] = modData.WorkClutch().ConvertTo().Kilo.Watt.Hour; - row[E_TC_LOSS] = modData.WorkTorqueConverter().ConvertTo().Kilo.Watt.Hour; - row[E_SHIFT_LOSS] = modData.WorkGearshift().ConvertTo().Kilo.Watt.Hour; - row[E_GBX_LOSS] = modData.WorkGearbox().ConvertTo().Kilo.Watt.Hour; - row[E_RET_LOSS] = modData.WorkRetarder().ConvertTo().Kilo.Watt.Hour; - row[E_AXL_LOSS] = modData.WorkAxlegear().ConvertTo().Kilo.Watt.Hour; - row[E_ANGLE_LOSS] = modData.WorkAngledrive().ConvertTo().Kilo.Watt.Hour; - row[E_BRAKE] = modData.WorkTotalMechanicalBrake().ConvertTo().Kilo.Watt.Hour; - row[E_VEHICLE_INERTIA] = modData.WorkVehicleInertia().ConvertTo().Kilo.Watt.Hour; - row[E_AIR] = modData.WorkAirResistance().ConvertTo().Kilo.Watt.Hour; - row[E_ROLL] = modData.WorkRollingResistance().ConvertTo().Kilo.Watt.Hour; - row[E_GRAD] = modData.WorkRoadGradientResistance().ConvertTo().Kilo.Watt.Hour; - - //var acc = modData.AccelerationPer3Seconds(); - - - row[ACC] = modData.AccelerationAverage(); - row[ACC_POS] = modData.AccelerationsPositive(); - row[ACC_NEG] = modData.AccelerationsNegative(); - var accTimeShare = modData.AccelerationTimeShare(); - row[ACC_TIMESHARE] = accTimeShare; - var decTimeShare = modData.DecelerationTimeShare(); - row[DEC_TIMESHARE] = decTimeShare; - var cruiseTimeShare = modData.CruiseTimeShare(); - row[CRUISE_TIMESHARE] = cruiseTimeShare; - var stopTimeShare = modData.StopTimeShare(); - row[STOP_TIMESHARE] = stopTimeShare; - - row[MAX_SPEED] = modData.MaxSpeed().AsKmph.SI<Scalar>(); - row[MAX_ACCELERATION] = modData.MaxAcceleration(); - row[MAX_DECELERATION] = modData.MaxDeceleration(); - row[AVG_ENGINE_SPEED] = modData.AvgEngineSpeed().AsRPM.SI<Scalar>(); - row[MAX_ENGINE_SPEED] = modData.MaxEngineSpeed().AsRPM.SI<Scalar>(); - - row[ENGINE_FULL_LOAD_TIME_SHARE] = modData.EngineMaxLoadTimeShare(); - row[COASTING_TIME_SHARE] = modData.CoastingTimeShare(); - row[BRAKING_TIME_SHARE] = modData.BrakingTimeShare(); - - if (gearCount <= 0) { - return; - } - - row[NUM_GEARSHIFTS] = modData.GearshiftCount(); - var timeSharePerGear = modData.TimeSharePerGear(gearCount); - - for (uint i = 0; i <= gearCount; i++) { - var colName = string.Format(TIME_SHARE_PER_GEAR_FORMAT, i); - if (!Table.Columns.Contains(colName)) { - Table.Columns.Add(colName, typeof(SI)); - } - row[colName] = timeSharePerGear[i]; - } - if (accTimeShare != null && decTimeShare != null && cruiseTimeShare != null) { - var shareSum = accTimeShare + decTimeShare + cruiseTimeShare + stopTimeShare; - if (!shareSum.IsEqual(100)) { - Log.Error( - "Sumfile Error: driving behavior timeshares must sum up to 100%: acc: {0}%, dec: {1}%, cruise: {2}%, stop: {3}%, sum: {4}%", - accTimeShare.ToOutputFormat(1, null, false), decTimeShare.ToOutputFormat(1, null, false), - cruiseTimeShare.ToOutputFormat(1, null, false), stopTimeShare.ToOutputFormat(1, null, false), - shareSum.ToOutputFormat(1, null, false)); - } - } - } - - private static string ReplaceNotAllowedCharacters(string text) - { - return text.Replace('#', '_').Replace(',', '_').Replace('\n', '_').Replace('\r', '_'); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected void Dispose(bool disposing) - { - if (disposing) { - Table.Dispose(); - } - } - } +using System; +using System.Data; +using System.Linq; +using System.Runtime.CompilerServices; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data; + +// ReSharper disable MemberCanBePrivate.Global -- used by API! + +namespace TUGraz.VectoCore.OutputData +{ + public delegate void WriteSumData(IModalDataContainer data); + + /// <summary> + /// Class for the sum file in vecto. + /// </summary> + public class SummaryDataContainer : LoggingObject, IDisposable + { + // ReSharper disable InconsistentNaming + public const string INTERNAL_PREFIX = "INTERNAL"; + public const string SORT = INTERNAL_PREFIX + " Sorting"; + public const string JOB = "Job [-]"; + public const string INPUTFILE = "Input File [-]"; + public const string CYCLE = "Cycle [-]"; + public const string STATUS = "Status"; + public const string CURB_MASS = "Chassis curb mass [kg]"; + public const string LOADING = "Loading [kg]"; + + public const string VEHICLE_MANUFACTURER = "Vehicle manufacturer [-]"; + public const string VIN_NUMBER = "VIN number"; + public const string VEHICLE_MODEL = "Vehicle model [-]"; + + public const string ENGINE_MANUFACTURER = "Engine manufacturer [-]"; + public const string ENGINE_MODEL = "Engine model [-]"; + public const string ENGINE_FUEL_TYPE = "Engine fuel type [-]"; + public const string ENGINE_WHTC_URBAN = "Engine WHTCUrban"; + public const string ENGINE_WHTC_RURAL = "Engine WHTCRural"; + public const string ENGINE_WHTC_MOTORWAY = "Engine WHTCMotorway"; + public const string ENGINE_BF_COLD_HOT = "Engine BFColdHot"; + public const string ENGINE_CF_REG_PER = "Engine CFRegPer"; + public const string ENGINE_ACTUAL_CORRECTION_FACTOR = "Engine actual CF"; + public const string ENGINE_RATED_POWER = "Engine rated power [kW]"; + public const string ENGINE_IDLING_SPEED = "Engine idling speed [rpm]"; + public const string ENGINE_RATED_SPEED = "Engine rated speed [rpm]"; + public const string ENGINE_DISPLACEMENT = "Engine displacement [ccm]"; + + public const string ROLLING_RESISTANCE_COEFFICIENT_W_TRAILER = "total RRC [-]"; + public const string ROLLING_RESISTANCE_COEFFICIENT_WO_TRAILER = "weighted RRC w/o trailer [-]"; + + public const string GEARBOX_MANUFACTURER = "Gearbox manufacturer [-]"; + public const string GEARBOX_MODEL = "Gearbox model [-]"; + public const string GEARBOX_TYPE = "Gearbox type [-]"; + public const string GEAR_RATIO_FIRST_GEAR = "Gear ratio first gear [-]"; + public const string GEAR_RATIO_LAST_GEAR = "Gear ratio last gear [-]"; + + public const string TORQUECONVERTER_MANUFACTURER = "Torque converter manufacturer [-]"; + public const string TORQUECONVERTER_MODEL = "Torque converter model [-]"; + + public const string RETARDER_MANUFACTURER = "Retarder manufacturer [-]"; + public const string RETARDER_MODEL = "Retarder model [-]"; + public const string RETARDER_TYPE = "Retarder type [-]"; + + public const string ANGLEDRIVE_MANUFACTURER = "Angledrive manufacturer [-]"; + public const string ANGLEDRIVE_MODEL = "Angledrive model [-]"; + public const string ANGLEDRIVE_RATIO = "Angledrive ratio [-]"; + + public const string AXLE_MANUFACTURER = "Axle manufacturer [-]"; + public const string AXLE_MODEL = "Axle model [-]"; + public const string AXLE_RATIO = "Axle gear ratio [-]"; + + public const string AUX_TECH_FORMAT = "Auxiliary technology {0} [-]"; + + public const string HDV_CO2_VEHICLE_CLASS = "HDV CO2 vehicle class [-]"; + public const string TOTAL_VEHICLE_MASS = "Total vehicle mass [kg]"; + public const string CD_x_A = "CdxA [m²]"; + //public const string ROLLING_RESISTANCE_COEFFICIENT = "weighed RRC [-]"; + public const string R_DYN = "r_dyn [m]"; + + public const string CARGO_VOLUME = "Cargo Volume [m³]"; + public const string TIME = "time [s]"; + public const string DISTANCE = "distance [km]"; + public const string SPEED = "speed [km/h]"; + public const string ALTITUDE_DELTA = "altitudeDelta [m]"; + + public const string FCMAP_H = "FC-Map [g/h]"; + public const string FCMAP_KM = "FC-Map [g/km]"; + public const string FCAUXC_H = "FC-AUXc [g/h]"; + public const string FCAUXC_KM = "FC-AUXc [g/km]"; + public const string FCWHTCC_H = "FC-WHTCc [g/h]"; + public const string FCWHTCC_KM = "FC-WHTCc [g/km]"; + public const string FCAAUX_H = "FC-AAUX [g/h]"; + public const string FCAAUX_KM = "FC-AAUX [g/km]"; + + public const string FCFINAL_H = "FC-Final [g/h]"; + public const string FCFINAL_KM = "FC-Final [g/km]"; + public const string FCFINAL_LITERPER100KM = "FC-Final [l/100km]"; + public const string FCFINAL_LITERPER100TKM = "FC-Final [l/100tkm]"; + public const string FCFINAL_LiterPer100M3KM = "FC-Final [l/100m³km]"; + + public const string CO2_KM = "CO2 [g/km]"; + public const string CO2_TKM = "CO2 [g/tkm]"; + public const string CO2_M3KM = "CO2 [g/m³km]"; + + public const string P_WHEEL_POS = "P_wheel_in_pos [kW]"; + public const string P_FCMAP_POS = "P_fcmap_pos [kW]"; + + public const string E_FORMAT = "E_{0} [kWh]"; + public const string E_AUX_FORMAT = "E_aux_{0} [kWh]"; + public const string E_AUX = "E_aux_sum [kWh]"; + + public const string E_AIR = "E_air [kWh]"; + public const string E_ROLL = "E_roll [kWh]"; + public const string E_GRAD = "E_grad [kWh]"; + public const string E_VEHICLE_INERTIA = "E_vehi_inertia [kWh]"; + public const string E_POWERTRAIN_INERTIA = "E_powertrain_inertia [kWh]"; + public const string E_BRAKE = "E_brake [kWh]"; + public const string E_GBX_LOSS = "E_gbx_loss [kWh]"; + public const string E_SHIFT_LOSS = "E_shift_loss [kWh]"; + public const string E_AXL_LOSS = "E_axl_loss [kWh]"; + public const string E_RET_LOSS = "E_ret_loss [kWh]"; + public const string E_TC_LOSS = "E_tc_loss [kWh]"; + public const string E_ANGLE_LOSS = "E_angle_loss [kWh]"; + public const string E_CLUTCH_LOSS = "E_clutch_loss [kWh]"; + public const string E_FCMAP_POS = "E_fcmap_pos [kWh]"; + public const string E_FCMAP_NEG = "E_fcmap_neg [kWh]"; + + public const string ACC = "a [m/s^2]"; + public const string ACC_POS = "a_pos [m/s^2]"; + public const string ACC_NEG = "a_neg [m/s^2]"; + + public const string ACC_TIMESHARE = "AccelerationTimeShare [%]"; + public const string DEC_TIMESHARE = "DecelerationTimeShare [%]"; + public const string CRUISE_TIMESHARE = "CruiseTimeShare [%]"; + public const string STOP_TIMESHARE = "StopTimeShare [%]"; + + public const string MAX_SPEED = "max. speed [km/h"; + public const string MAX_ACCELERATION = "max. acc [m/s²]"; + public const string MAX_DECELERATION = "max. dec [m/s²]"; + public const string AVG_ENGINE_SPEED = "n_eng_avg [rpm]"; + public const string MAX_ENGINE_SPEED = "n_eng_max [rpm]"; + public const string NUM_GEARSHIFTS = "gear shifts [-]"; + public const string ENGINE_FULL_LOAD_TIME_SHARE = "Engine max. Load time share [%]"; + public const string COASTING_TIME_SHARE = "CoastingTimeShare [%]"; + public const string BRAKING_TIME_SHARE = "BrakingTImeShare [%]"; + + public const string TIME_SHARE_PER_GEAR_FORMAT = "Gear {0} TimeShare [%]"; + + // ReSharper restore InconsistentNaming + + internal readonly DataTable Table; + private readonly ISummaryWriter _sumWriter; + + + protected SummaryDataContainer() {} + + /// <summary> + /// Initializes a new instance of the <see cref="SummaryDataContainer"/> class. + /// </summary> + /// <param name="writer"></param> + public SummaryDataContainer(ISummaryWriter writer) + { + _sumWriter = writer; + + Table = new DataTable(); + + Table.Columns.AddRange(new[] { + Tuple.Create(SORT, typeof(int)), + Tuple.Create(JOB, typeof(string)), + Tuple.Create(INPUTFILE, typeof(string)), + Tuple.Create(CYCLE, typeof(string)), + Tuple.Create(STATUS, typeof(string)), + Tuple.Create(VEHICLE_MANUFACTURER, typeof(string)), + Tuple.Create(VIN_NUMBER, typeof(string)), + Tuple.Create(VEHICLE_MODEL, typeof(string)), + Tuple.Create(HDV_CO2_VEHICLE_CLASS, typeof(string)), + Tuple.Create(CURB_MASS, typeof(SI)), + Tuple.Create(LOADING, typeof(SI)), + Tuple.Create(TOTAL_VEHICLE_MASS, typeof(SI)), + Tuple.Create(ENGINE_MANUFACTURER, typeof(string)), + Tuple.Create(ENGINE_MODEL, typeof(string)), + Tuple.Create(ENGINE_FUEL_TYPE, typeof(string)), + Tuple.Create(ENGINE_RATED_POWER, typeof(SI)), + Tuple.Create(ENGINE_IDLING_SPEED, typeof(SI)), + Tuple.Create(ENGINE_RATED_SPEED, typeof(SI)), + Tuple.Create(ENGINE_DISPLACEMENT, typeof(SI)), + Tuple.Create(ENGINE_WHTC_URBAN, typeof(double)), + Tuple.Create(ENGINE_WHTC_RURAL, typeof(double)), + Tuple.Create(ENGINE_WHTC_MOTORWAY, typeof(double)), + Tuple.Create(ENGINE_BF_COLD_HOT, typeof(double)), + Tuple.Create(ENGINE_CF_REG_PER, typeof(double)), + Tuple.Create(ENGINE_ACTUAL_CORRECTION_FACTOR, typeof(double)), + Tuple.Create(CD_x_A, typeof(SI)), + Tuple.Create(ROLLING_RESISTANCE_COEFFICIENT_W_TRAILER, typeof(double)), + Tuple.Create(ROLLING_RESISTANCE_COEFFICIENT_WO_TRAILER, typeof(double)), + Tuple.Create(R_DYN, typeof(SI)), + Tuple.Create(GEARBOX_MANUFACTURER, typeof(string)), + Tuple.Create(GEARBOX_MODEL, typeof(string)), + Tuple.Create(GEARBOX_TYPE, typeof(string)), + Tuple.Create(GEAR_RATIO_FIRST_GEAR, typeof(SI)), + Tuple.Create(GEAR_RATIO_LAST_GEAR, typeof(SI)), + Tuple.Create(TORQUECONVERTER_MANUFACTURER, typeof(string)), + Tuple.Create(TORQUECONVERTER_MODEL, typeof(string)), + Tuple.Create(RETARDER_MANUFACTURER, typeof(string)), + Tuple.Create(RETARDER_MODEL, typeof(string)), + Tuple.Create(RETARDER_TYPE, typeof(string)), + Tuple.Create(ANGLEDRIVE_MANUFACTURER, typeof(string)), + Tuple.Create(ANGLEDRIVE_MODEL, typeof(string)), + Tuple.Create(ANGLEDRIVE_RATIO, typeof(string)), + Tuple.Create(AXLE_MANUFACTURER, typeof(string)), + Tuple.Create(AXLE_MODEL, typeof(string)), + Tuple.Create(AXLE_RATIO, typeof(SI)), + Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.SteeringPump), typeof(string)), + Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.Fan), typeof(string)), + Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.HeatingVentilationAirCondition), + typeof(string)), + Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.PneumaticSystem), typeof(string)), + Tuple.Create(string.Format(AUX_TECH_FORMAT, Constants.Auxiliaries.IDs.ElectricSystem), typeof(string)), + }.Select(x => new DataColumn(x.Item1, x.Item2)).ToArray()); + + Table.Columns.AddRange(new[] { + CARGO_VOLUME, + TIME, DISTANCE, + SPEED, ALTITUDE_DELTA, + FCMAP_H, FCMAP_KM, + FCAUXC_H, FCAUXC_KM, + FCWHTCC_H, FCWHTCC_KM, + FCAAUX_H, FCAAUX_KM, + FCFINAL_H, FCFINAL_KM, + FCFINAL_LITERPER100KM, FCFINAL_LITERPER100TKM, FCFINAL_LiterPer100M3KM, + CO2_KM, CO2_TKM, CO2_M3KM, + P_WHEEL_POS, P_FCMAP_POS, + E_FCMAP_POS, E_FCMAP_NEG, E_POWERTRAIN_INERTIA, + E_AUX, E_CLUTCH_LOSS, E_TC_LOSS, E_SHIFT_LOSS, E_GBX_LOSS, + E_RET_LOSS, E_ANGLE_LOSS, E_AXL_LOSS, E_BRAKE, E_VEHICLE_INERTIA, E_AIR, E_ROLL, E_GRAD, + ACC, ACC_POS, ACC_NEG, ACC_TIMESHARE, DEC_TIMESHARE, CRUISE_TIMESHARE, STOP_TIMESHARE, + MAX_SPEED, MAX_ACCELERATION, MAX_DECELERATION, AVG_ENGINE_SPEED, MAX_ENGINE_SPEED, NUM_GEARSHIFTS, + ENGINE_FULL_LOAD_TIME_SHARE, COASTING_TIME_SHARE, BRAKING_TIME_SHARE + }.Select(x => new DataColumn(x, typeof(SI))).ToArray()); + } + + /// <summary> + /// Finishes the summary data container (writes the data to the sumWriter). + /// </summary> + public virtual void Finish() + { + if (_sumWriter != null) { + var view = new DataView(Table, "", SORT, DataViewRowState.CurrentRows).ToTable(); + var toRemove = + view.Columns.Cast<DataColumn>().Where(column => column.ColumnName.StartsWith(INTERNAL_PREFIX)).ToList(); + foreach (var dataColumn in toRemove) { + view.Columns.Remove(dataColumn); + } + _sumWriter.WriteSumData(view); + } + } + + /// <summary> + /// Writes the result of one run into the summary data container. + /// </summary> + [MethodImpl(MethodImplOptions.Synchronized)] + //public virtual void Write(IModalDataContainer modData, string jobFileName, string jobName, string cycleFileName, + // Kilogram vehicleMass, Kilogram vehicleLoading, CubicMeter cargoVolume, uint gearCount) + public virtual void Write(IModalDataContainer modData, int jobNr, int runNr, VectoRunData runData) + { + var row = Table.NewRow(); + Table.Rows.Add(row); + + row[SORT] = jobNr * 1000 + runNr; + row[JOB] = string.Format("{0}-{1}", jobNr, runNr); //ReplaceNotAllowedCharacters(current); + row[INPUTFILE] = ReplaceNotAllowedCharacters(runData.JobName); + row[CYCLE] = ReplaceNotAllowedCharacters(runData.Cycle.Name + Constants.FileExtensions.CycleFile); + + row[STATUS] = modData.RunStatus; + + var vehicleLoading = 0.SI<Kilogram>(); + var cargoVolume = 0.SI<CubicMeter>(); + uint gearCount = 0u; + if (runData.Cycle.CycleType != CycleType.EngineOnly) { + row[VEHICLE_MANUFACTURER] = runData.VehicleData.Manufacturer; + row[VIN_NUMBER] = runData.VehicleData.VIN; + row[VEHICLE_MODEL] = runData.VehicleData.ModelName; + + row[HDV_CO2_VEHICLE_CLASS] = runData.VehicleData.VehicleClass.GetClassNumber(); + row[CURB_MASS] = runData.VehicleData.CurbWeight; + // - (runData.VehicleData.BodyAndTrailerWeight ?? 0.SI<Kilogram>()); + row[LOADING] = runData.VehicleData.Loading; + row[CARGO_VOLUME] = runData.VehicleData.CargoVolume; + + row[TOTAL_VEHICLE_MASS] = runData.VehicleData.TotalVehicleWeight; + row[ENGINE_MANUFACTURER] = runData.EngineData.Manufacturer; + row[ENGINE_MODEL] = runData.EngineData.ModelName; + row[ENGINE_FUEL_TYPE] = runData.EngineData.FuelType.GetLabel(); + row[ENGINE_RATED_POWER] = runData.EngineData.RatedPowerDeclared != null + ? runData.EngineData.RatedPowerDeclared.ConvertTo().Kilo.Watt + : runData.EngineData.FullLoadCurves[0].MaxPower.ConvertTo().Kilo.Watt; + row[ENGINE_IDLING_SPEED] = runData.EngineData.IdleSpeed.AsRPM.SI<Scalar>(); + row[ENGINE_RATED_SPEED] = runData.EngineData.RatedSpeedDeclared != null + ? runData.EngineData.RatedSpeedDeclared.AsRPM.SI<Scalar>() + : runData.EngineData.FullLoadCurves[0].RatedSpeed.AsRPM.SI<Scalar>(); + row[ENGINE_DISPLACEMENT] = runData.EngineData.Displacement.ConvertTo().Cubic.Centi.Meter; + + row[ENGINE_WHTC_URBAN] = runData.EngineData.WHTCUrban; + row[ENGINE_WHTC_RURAL] = runData.EngineData.WHTCRural; + row[ENGINE_WHTC_MOTORWAY] = runData.EngineData.WHTCMotorway; + row[ENGINE_BF_COLD_HOT] = runData.EngineData.ColdHotCorrectionFactor; + row[ENGINE_CF_REG_PER] = runData.EngineData.CorrectionFactorRegPer; + row[ENGINE_ACTUAL_CORRECTION_FACTOR] = runData.EngineData.FuelConsumptionCorrectionFactor; + + row[CD_x_A] = runData.AirdragData.CrossWindCorrectionCurve.AirDragArea; + + row[ROLLING_RESISTANCE_COEFFICIENT_WO_TRAILER] = + runData.VehicleData.RollResistanceCoefficientWithoutTrailer; + row[ROLLING_RESISTANCE_COEFFICIENT_W_TRAILER] = + runData.VehicleData.TotalRollResistanceCoefficient; + + row[R_DYN] = runData.VehicleData.DynamicTyreRadius; + + row[GEARBOX_MANUFACTURER] = runData.GearboxData.Manufacturer; + row[GEARBOX_MODEL] = runData.GearboxData.ModelName; + row[GEARBOX_TYPE] = runData.GearboxData.Type; + if (runData.GearboxData.Type.AutomaticTransmission()) { + row[GEAR_RATIO_FIRST_GEAR] = runData.GearboxData.Gears.Count > 0 + ? (double.IsNaN(runData.GearboxData.Gears.First().Value.Ratio) + ? runData.GearboxData.Gears.First().Value.TorqueConverterRatio.SI<Scalar>() + : runData.GearboxData.Gears.First().Value.Ratio.SI<Scalar>()) + : 0.SI<Scalar>(); + row[GEAR_RATIO_LAST_GEAR] = runData.GearboxData.Gears.Count > 0 + ? runData.GearboxData.Gears.Last().Value.Ratio.SI<Scalar>() + : 0.SI<Scalar>(); + row[TORQUECONVERTER_MANUFACTURER] = runData.GearboxData.TorqueConverterData.Manufacturer; + row[TORQUECONVERTER_MODEL] = runData.GearboxData.TorqueConverterData.ModelName; + } else { + row[GEAR_RATIO_FIRST_GEAR] = runData.GearboxData.Gears.Count > 0 + ? runData.GearboxData.Gears.First().Value.Ratio.SI<Scalar>() + : 0.SI<Scalar>(); + row[GEAR_RATIO_LAST_GEAR] = runData.GearboxData.Gears.Count > 0 + ? runData.GearboxData.Gears.Last().Value.Ratio.SI<Scalar>() + : 0.SI<Scalar>(); + row[TORQUECONVERTER_MANUFACTURER] = "n.a."; + row[TORQUECONVERTER_MODEL] = "n.a."; + } + row[RETARDER_TYPE] = runData.Retarder.Type.GetLabel(); + if (runData.Retarder.Type.IsDedicatedComponent()) { + row[RETARDER_MANUFACTURER] = runData.Retarder.Manufacturer; + row[RETARDER_MODEL] = runData.Retarder.ModelName; + } else { + row[RETARDER_MANUFACTURER] = "n.a."; + row[RETARDER_MODEL] = "n.a."; + } + + if (runData.AngledriveData != null) { + row[ANGLEDRIVE_MANUFACTURER] = runData.AngledriveData.Manufacturer; + row[ANGLEDRIVE_MODEL] = runData.AngledriveData.ModelName; + row[ANGLEDRIVE_RATIO] = runData.AngledriveData.Angledrive.Ratio; + } else { + row[ANGLEDRIVE_MANUFACTURER] = "n.a."; + row[ANGLEDRIVE_MODEL] = "n.a."; + row[ANGLEDRIVE_RATIO] = "n.a."; + } + + row[AXLE_MANUFACTURER] = runData.AxleGearData.Manufacturer; + row[AXLE_MODEL] = runData.AxleGearData.ModelName; + row[AXLE_RATIO] = runData.AxleGearData.AxleGear.Ratio.SI<Scalar>(); + + foreach (var aux in runData.Aux) { + if (aux.ID == Constants.Auxiliaries.IDs.PTOConsumer || aux.ID == Constants.Auxiliaries.IDs.PTOTransmission) { + continue; + } + var colName = string.Format(AUX_TECH_FORMAT, aux.ID); + + if (!Table.Columns.Contains(colName)) { + var col = Table.Columns.Add(colName, typeof(string)); + // move the new column to correct position + col.SetOrdinal(Table.Columns[CARGO_VOLUME].Ordinal); + } + + row[colName] = aux.Technology == null ? "" : string.Join("; ", aux.Technology); + } + + cargoVolume = runData.VehicleData.CargoVolume; + vehicleLoading = runData.VehicleData.Loading; + gearCount = (uint)runData.GearboxData.Gears.Count; + } + + + var totalTime = modData.Duration(); + row[TIME] = totalTime; + + var distance = modData.Distance(); + if (distance != null) { + row[DISTANCE] = distance.ConvertTo().Kilo.Meter; + } + + var speed = modData.Speed(); + if (speed != null) { + row[SPEED] = speed.ConvertTo().Kilo.Meter.Per.Hour; + } + + row[ALTITUDE_DELTA] = modData.AltitudeDelta(); + + row[FCMAP_H] = modData.FCMapPerSecond().ConvertTo().Gramm.Per.Hour; + var fcMapPerMeter = modData.FCMapPerMeter(); + if (fcMapPerMeter != null) { + row[FCMAP_KM] = fcMapPerMeter.ConvertTo().Gramm.Per.Kilo.Meter; + } + + row[FCAUXC_H] = modData.FuelConsumptionAuxStartStopPerSecond().ConvertTo().Gramm.Per.Hour; + var fuelConsumptionAuxStartStopCorrected = modData.FuelConsumptionAuxStartStop(); + if (fuelConsumptionAuxStartStopCorrected != null) { + row[FCAUXC_KM] = fuelConsumptionAuxStartStopCorrected.ConvertTo().Gramm.Per.Kilo.Meter; + } + + row[FCWHTCC_H] = modData.FuelConsumptionWHTCPerSecond().ConvertTo().Gramm.Per.Hour; + var fuelConsumptionWHTCCorrected = modData.FuelConsumptionWHTC(); + if (fuelConsumptionWHTCCorrected != null) { + row[FCWHTCC_KM] = fuelConsumptionWHTCCorrected.ConvertTo().Gramm.Per.Kilo.Meter; + } + + row[FCAAUX_H] = modData.FuelConsumptionAAUXPerSecond().ConvertTo().Gramm.Per.Hour; + var fuelConsumptionAaux = modData.FuelConsumptionAAUX(); + if (fuelConsumptionAaux != null) { + row[FCAAUX_KM] = fuelConsumptionAaux.ConvertTo().Gramm.Per.Kilo.Meter; + } + + row[FCFINAL_H] = modData.FuelConsumptionFinalPerSecond().ConvertTo().Gramm.Per.Hour; + var fcfinal = modData.FuelConsumptionFinal(); + if (fcfinal != null) { + row[FCFINAL_KM] = fcfinal.ConvertTo().Gramm.Per.Kilo.Meter; + } + + var fcPer100lkm = modData.FuelConsumptionFinalLiterPer100Kilometer(); + row[FCFINAL_LITERPER100KM] = fcPer100lkm; + if (vehicleLoading != null && !vehicleLoading.IsEqual(0) && fcPer100lkm != null) { + row[FCFINAL_LITERPER100TKM] = fcPer100lkm / + vehicleLoading.ConvertTo().Ton; + } + if (cargoVolume > 0 && fcPer100lkm != null) { + row[FCFINAL_LiterPer100M3KM] = fcPer100lkm / cargoVolume; + } + + var kilogramPerMeter = modData.CO2PerMeter(); + if (kilogramPerMeter != null) { + row[CO2_KM] = kilogramPerMeter.ConvertTo().Gramm.Per.Kilo.Meter; + if (vehicleLoading != null && !vehicleLoading.IsEqual(0)) { + row[CO2_TKM] = kilogramPerMeter.ConvertTo().Gramm.Per.Kilo.Meter / vehicleLoading.ConvertTo().Ton; + } + if (cargoVolume > 0) { + row[CO2_M3KM] = kilogramPerMeter.ConvertTo().Gramm.Per.Kilo.Meter / cargoVolume; + } + } + + row[P_WHEEL_POS] = modData.PowerWheelPositive().ConvertTo().Kilo.Watt; + + row[P_FCMAP_POS] = modData.TotalPowerEnginePositiveAverage().ConvertTo().Kilo.Watt; + + foreach (var aux in modData.Auxiliaries) { + string colName; + if (aux.Key == Constants.Auxiliaries.IDs.PTOConsumer || aux.Key == Constants.Auxiliaries.IDs.PTOTransmission) { + colName = string.Format(E_FORMAT, aux.Key); + } else { + colName = string.Format(E_AUX_FORMAT, aux.Key); + } + + if (!Table.Columns.Contains(colName)) { + var col = Table.Columns.Add(colName, typeof(SI)); + // move the new column to correct position + col.SetOrdinal(Table.Columns[E_AUX].Ordinal); + } + + row[colName] = modData.AuxiliaryWork(aux.Value).ConvertTo().Kilo.Watt.Hour; + } + + row[E_FCMAP_POS] = modData.TotalEngineWorkPositive().ConvertTo().Kilo.Watt.Hour; + row[E_FCMAP_NEG] = -modData.TotalEngineWorkNegative().ConvertTo().Kilo.Watt.Hour; + row[E_POWERTRAIN_INERTIA] = modData.PowerAccelerations().ConvertTo().Kilo.Watt.Hour; + row[E_AUX] = modData.WorkAuxiliaries().ConvertTo().Kilo.Watt.Hour; + row[E_CLUTCH_LOSS] = modData.WorkClutch().ConvertTo().Kilo.Watt.Hour; + row[E_TC_LOSS] = modData.WorkTorqueConverter().ConvertTo().Kilo.Watt.Hour; + row[E_SHIFT_LOSS] = modData.WorkGearshift().ConvertTo().Kilo.Watt.Hour; + row[E_GBX_LOSS] = modData.WorkGearbox().ConvertTo().Kilo.Watt.Hour; + row[E_RET_LOSS] = modData.WorkRetarder().ConvertTo().Kilo.Watt.Hour; + row[E_AXL_LOSS] = modData.WorkAxlegear().ConvertTo().Kilo.Watt.Hour; + row[E_ANGLE_LOSS] = modData.WorkAngledrive().ConvertTo().Kilo.Watt.Hour; + row[E_BRAKE] = modData.WorkTotalMechanicalBrake().ConvertTo().Kilo.Watt.Hour; + row[E_VEHICLE_INERTIA] = modData.WorkVehicleInertia().ConvertTo().Kilo.Watt.Hour; + row[E_AIR] = modData.WorkAirResistance().ConvertTo().Kilo.Watt.Hour; + row[E_ROLL] = modData.WorkRollingResistance().ConvertTo().Kilo.Watt.Hour; + row[E_GRAD] = modData.WorkRoadGradientResistance().ConvertTo().Kilo.Watt.Hour; + + //var acc = modData.AccelerationPer3Seconds(); + + + row[ACC] = modData.AccelerationAverage(); + row[ACC_POS] = modData.AccelerationsPositive(); + row[ACC_NEG] = modData.AccelerationsNegative(); + var accTimeShare = modData.AccelerationTimeShare(); + row[ACC_TIMESHARE] = accTimeShare; + var decTimeShare = modData.DecelerationTimeShare(); + row[DEC_TIMESHARE] = decTimeShare; + var cruiseTimeShare = modData.CruiseTimeShare(); + row[CRUISE_TIMESHARE] = cruiseTimeShare; + var stopTimeShare = modData.StopTimeShare(); + row[STOP_TIMESHARE] = stopTimeShare; + + row[MAX_SPEED] = modData.MaxSpeed().AsKmph.SI<Scalar>(); + row[MAX_ACCELERATION] = modData.MaxAcceleration(); + row[MAX_DECELERATION] = modData.MaxDeceleration(); + row[AVG_ENGINE_SPEED] = modData.AvgEngineSpeed().AsRPM.SI<Scalar>(); + row[MAX_ENGINE_SPEED] = modData.MaxEngineSpeed().AsRPM.SI<Scalar>(); + + row[ENGINE_FULL_LOAD_TIME_SHARE] = modData.EngineMaxLoadTimeShare(); + row[COASTING_TIME_SHARE] = modData.CoastingTimeShare(); + row[BRAKING_TIME_SHARE] = modData.BrakingTimeShare(); + + if (gearCount <= 0) { + return; + } + + row[NUM_GEARSHIFTS] = modData.GearshiftCount(); + var timeSharePerGear = modData.TimeSharePerGear(gearCount); + + for (uint i = 0; i <= gearCount; i++) { + var colName = string.Format(TIME_SHARE_PER_GEAR_FORMAT, i); + if (!Table.Columns.Contains(colName)) { + Table.Columns.Add(colName, typeof(SI)); + } + row[colName] = timeSharePerGear[i]; + } + if (accTimeShare != null && decTimeShare != null && cruiseTimeShare != null) { + var shareSum = accTimeShare + decTimeShare + cruiseTimeShare + stopTimeShare; + if (!shareSum.IsEqual(100)) { + Log.Error( + "Sumfile Error: driving behavior timeshares must sum up to 100%: acc: {0}%, dec: {1}%, cruise: {2}%, stop: {3}%, sum: {4}%", + accTimeShare.ToOutputFormat(1, null, false), decTimeShare.ToOutputFormat(1, null, false), + cruiseTimeShare.ToOutputFormat(1, null, false), stopTimeShare.ToOutputFormat(1, null, false), + shareSum.ToOutputFormat(1, null, false)); + } + } + } + + private static string ReplaceNotAllowedCharacters(string text) + { + return text.Replace('#', '_').Replace(',', '_').Replace('\n', '_').Replace('\r', '_'); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + if (disposing) { + Table.Dispose(); + } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Reports/ModDataTest.cs b/VectoCore/VectoCoreTest/Reports/ModDataTest.cs index 5ed3af872f8f3e5b03d2f8f18c1ea0d7d75a19d0..660c3311774a1ec69c9a3647edf6765bd8c858cb 100644 --- a/VectoCore/VectoCoreTest/Reports/ModDataTest.cs +++ b/VectoCore/VectoCoreTest/Reports/ModDataTest.cs @@ -29,475 +29,480 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using NUnit.Framework; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.InputData.FileIO.JSON; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.Impl; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; -using TUGraz.VectoCore.Models.SimulationComponent.Impl; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.OutputData.FileIO; -using TUGraz.VectoCore.Tests.Integration; -using TUGraz.VectoCore.Tests.Utils; -using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert; - -namespace TUGraz.VectoCore.Tests.Reports -{ - [TestFixture] - public class ModDataTest - { - [TestCase()] - public void ModDataIntegritySimpleTest() - { - var cycleData = new[] { - // <s>,<v>,<grad>,<stop> - " 0, 20, 0, 0", - " 100, 60, 0, 0", - "1000, 60, 0, 0", - "1500, 40, 1, 0", - "2000, 50,-1, 0", - "2500, 0, 0, 2" - }; - var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); - var sumData = new SummaryDataContainer(null); - var run = Truck40tPowerTrain.CreateEngineeringRun(cycle, "Truck_ModDataIntegrity.vmod"); - - var engineData = MockSimulationDataFactory.CreateEngineDataFromFile(Truck40tPowerTrain.EngineFile, 0); - - // get a reference to the mod-data because the modaldata container clears it after simulation - var modData = ((ModalDataContainer)run.GetContainer().ModalData).Data; - var auxKeys = ((ModalDataContainer)run.GetContainer().ModalData).Auxiliaries; - - run.Run(); - Assert.IsTrue(run.FinishedWithoutErrors); - - AssertModDataIntegrity(modData, auxKeys, cycle.Entries.Last().Distance, engineData.ConsumptionMap); - } - - [TestCase(@"TestData\Integration\DeclarationMode\Class2_RigidTruck_4x2\Class2_RigidTruck_DECL.vecto")] - public void TestFullCycleModDataIntegrityDeclMT(string jobName) - { - RunSimulation(jobName, ExecutionMode.Declaration); - } - - [TestCase(@"TestData\Integration\EngineeringMode\Class2_RigidTruck_4x2\Class2_RigidTruck_ENG.vecto"), - TestCase(@"TestData\Integration\EngineeringMode\Class5_Tractor_4x2\Class5_Tractor_ENG.vecto"), - TestCase(@"TestData\Integration\EngineeringMode\Class9_RigidTruck_6x2_PTO\Class9_RigidTruck_ENG_PTO.vecto"),] - public void TestFullCycleModDataIntegrityMT(string jobName) - { - RunSimulation(jobName, ExecutionMode.Engineering); - } - - private static void RunSimulation(string jobName, ExecutionMode mode) - { - var fileWriter = new FileOutputWriter(jobName); - var sumData = new SummaryDataContainer(fileWriter); - - var jobContainer = new JobContainer(sumData); - var inputData = JSONInputDataFactory.ReadJsonJob(jobName); - - var runsFactory = new SimulatorFactory(mode, inputData, fileWriter) { WriteModalResults = true }; - - jobContainer.AddRuns(runsFactory); - var modData = new List<Tuple<ModalResults, Meter>>(); - foreach (var run in jobContainer.Runs) { - modData.Add(Tuple.Create(((ModalDataContainer)run.Run.GetContainer().ModalData).Data, - ((DistanceBasedDrivingCycle)((VehicleContainer)run.Run.GetContainer()).DrivingCycle).Data.Entries.Last() - .Distance)); - } - var auxKeys = - new Dictionary<string, DataColumn>( - ((ModalDataContainer)jobContainer.Runs.First().Run.GetContainer().ModalData).Auxiliaries); - jobContainer.Execute(); - jobContainer.WaitFinished(); - - // mod files will be stored in e.g. - // VectoCoreTest\bin\Debug\TestData\Integration\EngineeringMode\Class2_RigidTruck_4x2\Class2_RigidTruck_ENG.vecto_00.vmod - //fileWriter.WriteModData(Path.GetFileName(jobName), "0", "0", modData[0].Item1); - //fileWriter.WriteModData(Path.GetFileName(jobName), "1", "1", modData[1].Item1); - - foreach (var modalResults in modData) { - AssertModDataIntegrity(modalResults.Item1, auxKeys, modalResults.Item2, - FuelConsumptionMapReader.Create(((IEngineeringInputDataProvider)inputData).EngineInputData.FuelConsumptionMap)); - } - - AssertSumDataIntegrity(sumData, mode); - } - - private static void AssertSumDataIntegrity(SummaryDataContainer sumData, ExecutionMode mode) - { - Assert.IsTrue(sumData.Table.Rows.Count > 0); - - var ptoTransmissionColumn = - sumData.Table.Columns.Contains(string.Format(SummaryDataContainer.E_FORMAT, - Constants.Auxiliaries.IDs.PTOTransmission)) - ? string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOTransmission) - : null; - var ptoConsumerColumn = - sumData.Table.Columns.Contains(string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOConsumer)) - ? string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOConsumer) - : null; - - foreach (DataRow row in sumData.Table.Rows) { - var inputFile = row[SummaryDataContainer.INPUTFILE].ToString(); - var cycle = row[SummaryDataContainer.CYCLE].ToString(); - var loading = row[SummaryDataContainer.LOADING].ToString(); - var eFcMapPos = ((SI)row[SummaryDataContainer.E_FCMAP_POS]).Value(); - var eFcMapNeg = ((SI)row[SummaryDataContainer.E_FCMAP_NEG]).Value(); - var ePowertrainInertia = ((SI)row[SummaryDataContainer.E_POWERTRAIN_INERTIA]).Value(); - var eAux = ((SI)row[SummaryDataContainer.E_AUX]).Value(); - var eClutchLoss = ((SI)row[SummaryDataContainer.E_CLUTCH_LOSS]).Value(); - var eTcLoss = ((SI)row[SummaryDataContainer.E_TC_LOSS]).Value(); - //var eShiftLoss = ((SI)row[SummaryDataContainer.E_SHIFT_LOSS]).Value(); - var eGbxLoss = ((SI)row[SummaryDataContainer.E_GBX_LOSS]).Value(); - var eRetLoss = ((SI)row[SummaryDataContainer.E_RET_LOSS]).Value(); - var eAngleLoss = ((SI)row[SummaryDataContainer.E_ANGLE_LOSS]).Value(); - var eAxlLoss = ((SI)row[SummaryDataContainer.E_AXL_LOSS]).Value(); - var eBrakeLoss = ((SI)row[SummaryDataContainer.E_BRAKE]).Value(); - var eVehInertia = ((SI)row[SummaryDataContainer.E_VEHICLE_INERTIA]).Value(); - var eAir = ((SI)row[SummaryDataContainer.E_AIR]).Value(); - var eRoll = ((SI)row[SummaryDataContainer.E_ROLL]).Value(); - var eGrad = ((SI)row[SummaryDataContainer.E_GRAD]).Value(); - var cargoVolume = mode == ExecutionMode.Engineering ? 0 : ((SI)row[SummaryDataContainer.CARGO_VOLUME]).Value(); - - var loadingValue = ((SI)row[SummaryDataContainer.LOADING]).Value() / 1000; - var fcPer100km = ((SI)row[SummaryDataContainer.FCFINAL_LITERPER100KM]).Value(); - var fcPerVolume = mode == ExecutionMode.Engineering - ? 0 - : ((SI)row[SummaryDataContainer.FCFINAL_LiterPer100M3KM]).Value(); - var fcPerLoad = loadingValue > 0 ? ((SI)row[SummaryDataContainer.FCFINAL_LITERPER100TKM]).Value() : 0; - var co2Per100km = ((SI)row[SummaryDataContainer.CO2_KM]).Value(); - var co2PerVolume = mode == ExecutionMode.Engineering ? 0 : ((SI)row[SummaryDataContainer.CO2_M3KM]).Value(); - var co2PerLoad = loadingValue > 0 ? ((SI)row[SummaryDataContainer.CO2_TKM]).Value() : 0; - - var ePTOtransm = ptoTransmissionColumn != null ? ((SI)row[ptoTransmissionColumn]).Value() : 0; - var ePTOconsumer = ptoConsumerColumn != null ? ((SI)row[ptoConsumerColumn]).Value() : 0; - - // E_fcmap_pos = E_fcmap_neg + E_powertrain_inertia + E_aux_xxx + E_aux_sum + E_clutch_loss + E_tc_loss + E_gbx_loss + E_shift_loss + E_ret_loss + E_angle_loss + E_axl_loss + E_brake + E_vehicle_inertia + E_air + E_roll + E_grad + E_PTO_CONSUM + E_PTO_TRANSM - Assert.AreEqual(eFcMapPos, - eFcMapNeg + ePowertrainInertia + eAux + eClutchLoss + eTcLoss + eGbxLoss + eRetLoss + eAngleLoss + - eAxlLoss + eBrakeLoss + eVehInertia + eAir + eRoll + eGrad + ePTOconsumer + ePTOtransm, 1e-5, - "input file: {0} cycle: {1} loading: {2}", - inputFile, cycle, loading); - - var pFcmapPos = ((SI)row[SummaryDataContainer.P_FCMAP_POS]).Value(); - var time = ((SI)row[SummaryDataContainer.TIME]).Value(); - - // E_fcmap_pos = P_fcmap_pos * t - Assert.AreEqual(eFcMapPos, pFcmapPos * (time / 3600), 1e-3, "input file: {0} cycle: {1} loading: {2}", inputFile, - cycle, loading); - - if (cargoVolume > 0) { - Assert.AreEqual(fcPerVolume, fcPer100km / cargoVolume, 1e-3, "input file: {0} cycle: {1} loading: {2}", inputFile, - cycle, loading); - - Assert.AreEqual(co2PerVolume, co2Per100km / cargoVolume, 1e-3, "input file: {0} cycle: {1} loading: {2}", - inputFile, - cycle, loading); - } - - if (loadingValue > 0) { - Assert.AreEqual(co2PerLoad, co2Per100km / loadingValue, 1e-3, "input file: {0} cycle: {1} loading: {2}", - inputFile, cycle, loading); - Assert.AreEqual(fcPerLoad, fcPer100km / loadingValue, 1e-3, "input file: {0} cycle: {1} loading: {2}", - inputFile, cycle, loading); - } - - var stopTimeShare = ((SI)row[SummaryDataContainer.STOP_TIMESHARE]).Value(); - var accTimeShare = ((SI)row[SummaryDataContainer.ACC_TIMESHARE]).Value(); - var decTimeShare = ((SI)row[SummaryDataContainer.DEC_TIMESHARE]).Value(); - var cruiseTimeShare = ((SI)row[SummaryDataContainer.CRUISE_TIMESHARE]).Value(); - - Assert.AreEqual(100, stopTimeShare + accTimeShare + decTimeShare + cruiseTimeShare, 1e-3, - "input file: {0} cycle: {1} loading: {2}", inputFile, cycle, loading); - - Assert.IsTrue(((SI)row[SummaryDataContainer.ACC_POS]).Value() > 0); - Assert.IsTrue(((SI)row[SummaryDataContainer.ACC_NEG]).Value() < 0); - } - } - - private static void AssertModDataIntegrity(ModalResults modData, Dictionary<string, DataColumn> auxKeys, - Meter totalDistance, FuelConsumptionMap consumptionMap) - { - Assert.IsTrue(modData.Rows.Count > 0); - - var ptoTransmissionColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOTransmission) - ? auxKeys[Constants.Auxiliaries.IDs.PTOTransmission] - : null; - var ptoConsumerColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOConsumer) - ? auxKeys[Constants.Auxiliaries.IDs.PTOConsumer] - : null; - foreach (DataRow row in modData.Rows) { - if (totalDistance.IsEqual(((Meter)row[(int)ModalResultField.dist]))) { - continue; - } - var gear = (uint)row[(int)ModalResultField.Gear]; - var time = (Second)row[(int)ModalResultField.time]; - - var distance = (Meter)row[(int)ModalResultField.dist]; - var tqEngFcmap = (NewtonMeter)row[(int)ModalResultField.T_eng_fcmap]; - var nEngFcMap = (PerSecond)row[(int)ModalResultField.n_eng_avg]; - - // check fuel consumption interpolation - var fuelConsumption = (SI)row[(int)ModalResultField.FCMap]; - Assert.AreEqual(fuelConsumption.Value(), - consumptionMap.GetFuelConsumption(tqEngFcmap, nEngFcMap).Value.Value(), 1E-3, "time: {0} distance: {1}", - time, distance); - - // check P_eng_FCmap = T_eng_fcmap * n_eng - var pEngFcmap = (SI)row[(int)ModalResultField.P_eng_fcmap]; - Assert.AreEqual(pEngFcmap.Value(), (tqEngFcmap * nEngFcMap).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - var pWheelIn = (Watt)row[(int)ModalResultField.P_wheel_in]; - var pAir = (Watt)row[(int)ModalResultField.P_air]; - var pRoll = (Watt)row[(int)ModalResultField.P_roll]; - var pGrad = (Watt)row[(int)ModalResultField.P_slope]; - var pVehInertia = (Watt)row[(int)ModalResultField.P_veh_inertia]; - var pTrac = (Watt)row[(int)ModalResultField.P_trac]; - - // P_eng_out = P_wheel + P_lossgearbox + P_lossaxle + P_lossretarder + P_agbx + Pa_eng + P_aux - P_brake_loss - var pEngOut = (Watt)row[(int)ModalResultField.P_eng_out]; - var pLossGbx = (Watt)row[(int)ModalResultField.P_gbx_loss]; - var pGbxIn = (Watt)row[(int)ModalResultField.P_gbx_in]; - var pLossAxle = (Watt)row[(int)ModalResultField.P_axle_loss]; - var pLossAngle = row[(int)ModalResultField.P_angle_loss] is DBNull - ? 0.SI<Watt>() - : (Watt)row[(int)ModalResultField.P_angle_loss]; - var pAxleIn = (Watt)row[(int)ModalResultField.P_axle_in]; - var pLossRet = (Watt)row[(int)ModalResultField.P_ret_loss]; - var pRetIn = (Watt)row[(int)ModalResultField.P_retarder_in]; - var pGbxInertia = (Watt)row[(int)ModalResultField.P_gbx_inertia]; - var pShiftLoss = row[(int)ModalResultField.P_gbx_shift_loss] is DBNull - ? 0.SI<Watt>() - : (Watt)row[(int)ModalResultField.P_gbx_shift_loss]; - var pEngInertia = (Watt)row[(int)ModalResultField.P_eng_inertia]; - var pAux = - (Watt)(row[(int)ModalResultField.P_aux] != DBNull.Value ? row[(int)ModalResultField.P_aux] : 0.SI<Watt>()); - var pBrakeLoss = (Watt)row[(int)ModalResultField.P_brake_loss]; - var pBrakeIn = (Watt)row[(int)ModalResultField.P_brake_in]; - - var pWheelInertia = (Watt)row[(int)ModalResultField.P_wheel_inertia]; - var pPTOconsumer = ptoConsumerColumn == null || row[ptoConsumerColumn.ColumnName] is DBNull - ? 0.SI<Watt>() - : (Watt)row[ptoConsumerColumn.ColumnName]; - var pPTOtransm = ptoTransmissionColumn == null || row[ptoTransmissionColumn.ColumnName] is DBNull - ? 0.SI<Watt>() - : (Watt)row[ptoTransmissionColumn.ColumnName]; - // P_trac = P_veh_inertia + P_roll + P_air + P_slope - Assert.AreEqual(pTrac.Value(), (pAir + pRoll + pGrad + pVehInertia).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - // P_wheel_in = P_trac + P_wheel_inertia - Assert.AreEqual(pWheelIn.Value(), (pTrac + pWheelInertia).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pBrakeIn.Value(), (pWheelIn + pBrakeLoss).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pAxleIn.Value(), (pBrakeIn + pLossAxle).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pRetIn.Value(), (pAxleIn + pLossRet).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - var pClutchLoss = (Watt)(row[(int)ModalResultField.P_clutch_loss] != DBNull.Value - ? row[(int)ModalResultField.P_clutch_loss] - : 0.SI<Watt>()); - - var pClutchOut = row[(int)ModalResultField.P_clutch_out]; - if (pClutchOut != DBNull.Value) { - Assert.AreEqual(pGbxIn.Value(), (pClutchOut as Watt).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - Assert.AreEqual(pEngOut.Value(), (pClutchOut as Watt + pClutchLoss).Value(), 1E-3, "time: {0} distance: {1}", - time, distance); - } - - var pTC_Loss = (Watt)(row[(int)ModalResultField.P_TC_loss] != DBNull.Value - ? row[(int)ModalResultField.P_TC_loss] - : 0.SI<Watt>()); - - var pTCOut = row[(int)ModalResultField.P_clutch_out]; - if (pTCOut != DBNull.Value) { - Assert.AreEqual(pGbxIn.Value(), (pTCOut as Watt).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - //Assert.AreEqual(pEngOut.Value(), (pTCOut as Watt + pTC_Loss).Value(), 1E-3, "time: {0} distance: {1}", - // time, distance); - } - - Assert.IsTrue(pLossGbx.IsGreaterOrEqual(pShiftLoss + pGbxInertia), "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pGbxIn.Value(), (pRetIn + pLossGbx + pGbxInertia).Value(), gear != 0 ? 1E-3 : 0.5, - "time: {0} distance: {1}", time, - distance); - - // P_eng_fcmap = P_eng_out + P_AUX + P_eng_inertia ( + P_PTO_Transm + P_PTO_Consumer ) - Assert.AreEqual(pEngFcmap.Value(), (pEngOut + pAux + pEngInertia + pPTOtransm + pPTOconsumer).Value(), 0.5, - "time: {0} distance: {1}", time, distance); - - // P_eng_fcmap = sum(Losses Powertrain) - var pLossTot = pClutchLoss + pTC_Loss + pLossGbx + pLossRet + pGbxInertia + pLossAngle + pLossAxle + pBrakeLoss + - pWheelInertia + pAir + pRoll + pGrad + pVehInertia + pPTOconsumer + pPTOtransm; - var pEngFcmapCalc = (pLossTot + pEngInertia + pAux).Value(); - Assert.AreEqual(pEngFcmap.Value(), pEngFcmapCalc, 0.5, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pEngFcmap.Value(), - (pTrac + pWheelInertia + pBrakeLoss + pLossAxle + pLossRet + pLossGbx + pGbxInertia + pEngInertia + pAux + - pClutchLoss + pTC_Loss + pPTOtransm + pPTOconsumer).Value(), 0.5, "time: {0} distance: {1}", time, distance); - } - } - - [ - TestCase(@"TestData\Integration\EngineeringMode\CityBus_AT\CityBus_AT_Ser.vecto"), - TestCase(@"TestData\Integration\EngineeringMode\CityBus_AT\CityBus_AT_PS.vecto")] - public void TestFullCycleModDataIntegrityAT(string jobName) - { - var fileWriter = new FileOutputWriter(jobName); - var sumData = new SummaryDataContainer(fileWriter); - - var jobContainer = new JobContainer(sumData); - var inputData = JSONInputDataFactory.ReadJsonJob(jobName); - - var runsFactory = - new SimulatorFactory(ExecutionMode.Engineering, inputData, fileWriter) { WriteModalResults = true }; - - jobContainer.AddRuns(runsFactory); - var modData = new List<Tuple<ModalResults, Meter>>(); - foreach (var run in jobContainer.Runs) { - modData.Add(Tuple.Create(((ModalDataContainer)run.Run.GetContainer().ModalData).Data, - ((DistanceBasedDrivingCycle)((VehicleContainer)run.Run.GetContainer()).DrivingCycle).Data.Entries.Last() - .Distance)); - } - var auxKeys = - new Dictionary<string, DataColumn>( - ((ModalDataContainer)jobContainer.Runs.First().Run.GetContainer().ModalData).Auxiliaries); - jobContainer.Execute(); - jobContainer.WaitFinished(); - - foreach (var modalResults in modData) { - AssertModDataIntegrityAT(modalResults.Item1, auxKeys, modalResults.Item2, - FuelConsumptionMapReader.Create(((IEngineeringInputDataProvider)inputData).EngineInputData.FuelConsumptionMap)); - } - - AssertSumDataIntegrity(sumData, ExecutionMode.Engineering); - } - - private static void AssertModDataIntegrityAT(ModalResults modData, Dictionary<string, DataColumn> auxKeys, - Meter totalDistance, FuelConsumptionMap consumptionMap) - { - Assert.IsTrue(modData.Rows.Count > 0); - - var ptoTransmissionColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOTransmission) - ? auxKeys[Constants.Auxiliaries.IDs.PTOTransmission] - : null; - var ptoConsumerColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOConsumer) - ? auxKeys[Constants.Auxiliaries.IDs.PTOConsumer] - : null; - foreach (DataRow row in modData.Rows) { - if (totalDistance.IsEqual(((Meter)row[(int)ModalResultField.dist]))) { - continue; - } - var gear = (uint)row[(int)ModalResultField.Gear]; - var time = (Second)row[(int)ModalResultField.time]; - - var distance = (Meter)row[(int)ModalResultField.dist]; - var tqEngFcmap = (NewtonMeter)row[(int)ModalResultField.T_eng_fcmap]; - var nEngFcMap = (PerSecond)row[(int)ModalResultField.n_eng_avg]; - - // check fuel consumption interpolation - var fuelConsumption = (SI)row[(int)ModalResultField.FCMap]; - Assert.AreEqual(fuelConsumption.Value(), - consumptionMap.GetFuelConsumption(tqEngFcmap, nEngFcMap).Value.Value(), 1E-3, "time: {0} distance: {1}", - time, distance); - - // check P_eng_FCmap = T_eng_fcmap * n_eng - var pEngFcmap = (SI)row[(int)ModalResultField.P_eng_fcmap]; - Assert.AreEqual(pEngFcmap.Value(), (tqEngFcmap * nEngFcMap).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - var pWheelIn = (Watt)row[(int)ModalResultField.P_wheel_in]; - var pAir = (Watt)row[(int)ModalResultField.P_air]; - var pRoll = (Watt)row[(int)ModalResultField.P_roll]; - var pGrad = (Watt)row[(int)ModalResultField.P_slope]; - var pVehInertia = (Watt)row[(int)ModalResultField.P_veh_inertia]; - var pTrac = (Watt)row[(int)ModalResultField.P_trac]; - - // Pe_eng = P_wheel + P_lossgearbox + P_lossaxle + P_lossretarder + P_agbx + Pa_eng + P_aux - P_brake_loss - var pEngOut = (Watt)row[(int)ModalResultField.P_eng_out]; - var pLossGbx = (Watt)row[(int)ModalResultField.P_gbx_loss]; - var pGbxIn = (Watt)row[(int)ModalResultField.P_gbx_in]; - var pLossAxle = (Watt)row[(int)ModalResultField.P_axle_loss]; - var pLossAngle = row[(int)ModalResultField.P_angle_loss] is DBNull - ? 0.SI<Watt>() - : (Watt)row[(int)ModalResultField.P_angle_loss]; - var pAxleIn = (Watt)row[(int)ModalResultField.P_axle_in]; - var pLossRet = (Watt)row[(int)ModalResultField.P_ret_loss]; - var pRetIn = (Watt)row[(int)ModalResultField.P_retarder_in]; - var pGbxInertia = (Watt)row[(int)ModalResultField.P_gbx_inertia]; - var pShiftLoss = row[(int)ModalResultField.P_gbx_shift_loss] is DBNull - ? 0.SI<Watt>() - : (Watt)row[(int)ModalResultField.P_gbx_shift_loss]; - var pEngInertia = (Watt)row[(int)ModalResultField.P_eng_inertia]; - var pAux = - (Watt)(row[(int)ModalResultField.P_aux] != DBNull.Value ? row[(int)ModalResultField.P_aux] : 0.SI<Watt>()); - var pBrakeLoss = (Watt)row[(int)ModalResultField.P_brake_loss]; - var pBrakeIn = (Watt)row[(int)ModalResultField.P_brake_in]; - var pTcLoss = (Watt)row[(int)ModalResultField.P_TC_loss]; - var pTcOut = (Watt)row[(int)ModalResultField.P_TC_out]; - var pWheelInertia = (Watt)row[(int)ModalResultField.P_wheel_inertia]; - var pPTOconsumer = ptoConsumerColumn == null || row[ptoConsumerColumn] is DBNull - ? 0.SI<Watt>() - : (Watt)row[ptoConsumerColumn]; - var pPTOtransm = ptoTransmissionColumn == null || row[ptoTransmissionColumn] is DBNull - ? 0.SI<Watt>() - : (Watt)row[ptoTransmissionColumn]; - // P_trac = P_veh_inertia + P_roll + P_air + P_slope - Assert.AreEqual(pTrac.Value(), (pAir + pRoll + pGrad + pVehInertia).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - // P_wheel_in = P_trac + P_wheel_inertia - Assert.AreEqual(pWheelIn.Value(), (pTrac + pWheelInertia).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pBrakeIn.Value(), (pWheelIn + pBrakeLoss).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pAxleIn.Value(), (pBrakeIn + pLossAxle).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pRetIn.Value(), (pAxleIn + pLossRet).Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pGbxIn.Value(), pTcOut.Value(), 1E-3, "time: {0} distance: {1}", time, distance); - - Assert.AreEqual(pEngOut.Value(), (pTcOut + pTcLoss).Value(), 1E-3, - "time: {0} distance: {1}", time, distance); - - // P_eng_fcmap = P_eng_out + P_AUX + P_eng_inertia ( + P_PTO_Transm + P_PTO_Consumer ) - Assert.AreEqual(pEngFcmap.Value(), (pEngOut + pAux + pEngInertia + pPTOtransm + pPTOconsumer).Value(), 1E-3, - "time: {0} distance: {1}", time, - distance); - - // P_eng_fcmap = sum(Losses Powertrain) - var pLossTot = pTcLoss + pLossGbx + pLossRet + pGbxInertia + pLossAngle + pLossAxle + pBrakeLoss + - pWheelInertia + pAir + pRoll + pGrad + pVehInertia + pPTOconsumer + pPTOtransm; - - Assert.AreEqual(pEngFcmap.Value(), (pLossTot + pEngInertia + pAux).Value(), 1E-3, "time: {0} distance: {1}", time, - distance); - - Assert.IsTrue(pLossGbx.IsGreaterOrEqual(pShiftLoss + pGbxInertia), "time: {0} distance: {1}", time, - distance); - - Assert.AreEqual(pGbxIn.Value(), (pRetIn + pLossGbx + pGbxInertia).Value(), gear != 0 ? 1E-3 : 0.5, - "time: {0} distance: {1}", time, - distance); - Assert.AreEqual(pEngFcmap.Value(), - (pTrac + pWheelInertia + pBrakeLoss + pLossAxle + pLossRet + pLossGbx + pGbxInertia + pEngInertia + pAux + - pTcLoss + pPTOtransm + pPTOconsumer).Value(), 0.5, "time: {0} distance: {1}", time, distance); - } - } - } +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using NUnit.Framework; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.InputData.FileIO.JSON; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.OutputData.FileIO; +using TUGraz.VectoCore.Tests.Integration; +using TUGraz.VectoCore.Tests.Utils; +using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert; + +namespace TUGraz.VectoCore.Tests.Reports +{ + [TestFixture] + public class ModDataTest + { + [TestCase()] + public void ModDataIntegritySimpleTest() + { + var cycleData = new[] { + // <s>,<v>,<grad>,<stop> + " 0, 20, 0, 0", + " 100, 60, 0, 0", + "1000, 60, 0, 0", + "1500, 40, 1, 0", + "2000, 50,-1, 0", + "2500, 0, 0, 2" + }; + var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); + var sumData = new SummaryDataContainer(null); + var run = Truck40tPowerTrain.CreateEngineeringRun(cycle, "Truck_ModDataIntegrity.vmod"); + + var engineData = MockSimulationDataFactory.CreateEngineDataFromFile(Truck40tPowerTrain.EngineFile, 0); + + // get a reference to the mod-data because the modaldata container clears it after simulation + var modData = ((ModalDataContainer)run.GetContainer().ModalData).Data; + var auxKeys = ((ModalDataContainer)run.GetContainer().ModalData).Auxiliaries; + + run.Run(); + Assert.IsTrue(run.FinishedWithoutErrors); + + AssertModDataIntegrity(modData, auxKeys, cycle.Entries.Last().Distance, engineData.ConsumptionMap); + } + + [TestCase(@"TestData\Integration\DeclarationMode\Class2_RigidTruck_4x2\Class2_RigidTruck_DECL.vecto")] + public void TestFullCycleModDataIntegrityDeclMT(string jobName) + { + RunSimulation(jobName, ExecutionMode.Declaration); + } + + [TestCase(@"TestData\Integration\EngineeringMode\Class2_RigidTruck_4x2\Class2_RigidTruck_ENG.vecto"), + TestCase(@"TestData\Integration\EngineeringMode\Class5_Tractor_4x2\Class5_Tractor_ENG.vecto"), + TestCase(@"TestData\Integration\EngineeringMode\Class9_RigidTruck_6x2_PTO\Class9_RigidTruck_ENG_PTO.vecto"),] + public void TestFullCycleModDataIntegrityMT(string jobName) + { + RunSimulation(jobName, ExecutionMode.Engineering); + } + + private static void RunSimulation(string jobName, ExecutionMode mode) + { + var fileWriter = new FileOutputWriter(jobName); + var sumData = new SummaryDataContainer(fileWriter); + + var jobContainer = new JobContainer(sumData); + var inputData = JSONInputDataFactory.ReadJsonJob(jobName); + + var runsFactory = new SimulatorFactory(mode, inputData, fileWriter) { WriteModalResults = true }; + + jobContainer.AddRuns(runsFactory); + var modData = new List<Tuple<ModalResults, Meter>>(); + foreach (var run in jobContainer.Runs) { + modData.Add(Tuple.Create(((ModalDataContainer)run.Run.GetContainer().ModalData).Data, + ((DistanceBasedDrivingCycle)((VehicleContainer)run.Run.GetContainer()).DrivingCycle).Data.Entries.Last() + .Distance)); + } + var auxKeys = + new Dictionary<string, DataColumn>( + ((ModalDataContainer)jobContainer.Runs.First().Run.GetContainer().ModalData).Auxiliaries); + jobContainer.Execute(); + jobContainer.WaitFinished(); + + // mod files will be stored in e.g. + // VectoCoreTest\bin\Debug\TestData\Integration\EngineeringMode\Class2_RigidTruck_4x2\Class2_RigidTruck_ENG.vecto_00.vmod + //fileWriter.WriteModData(Path.GetFileName(jobName), "0", "0", modData[0].Item1); + //fileWriter.WriteModData(Path.GetFileName(jobName), "1", "1", modData[1].Item1); + + foreach (var modalResults in modData) { + AssertModDataIntegrity(modalResults.Item1, auxKeys, modalResults.Item2, + FuelConsumptionMapReader.Create(((IEngineeringInputDataProvider)inputData).EngineInputData.FuelConsumptionMap)); + } + + AssertSumDataIntegrity(sumData, mode); + } + + private static void AssertSumDataIntegrity(SummaryDataContainer sumData, ExecutionMode mode) + { + Assert.IsTrue(sumData.Table.Rows.Count > 0); + + var ptoTransmissionColumn = + sumData.Table.Columns.Contains(string.Format(SummaryDataContainer.E_FORMAT, + Constants.Auxiliaries.IDs.PTOTransmission)) + ? string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOTransmission) + : null; + var ptoConsumerColumn = + sumData.Table.Columns.Contains(string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOConsumer)) + ? string.Format(SummaryDataContainer.E_FORMAT, Constants.Auxiliaries.IDs.PTOConsumer) + : null; + + foreach (DataRow row in sumData.Table.Rows) { + var inputFile = row[SummaryDataContainer.INPUTFILE].ToString(); + var cycle = row[SummaryDataContainer.CYCLE].ToString(); + var loading = row[SummaryDataContainer.LOADING].ToString(); + var eFcMapPos = ((SI)row[SummaryDataContainer.E_FCMAP_POS]).Value(); + var eFcMapNeg = ((SI)row[SummaryDataContainer.E_FCMAP_NEG]).Value(); + var ePowertrainInertia = ((SI)row[SummaryDataContainer.E_POWERTRAIN_INERTIA]).Value(); + var eAux = ((SI)row[SummaryDataContainer.E_AUX]).Value(); + var eClutchLoss = ((SI)row[SummaryDataContainer.E_CLUTCH_LOSS]).Value(); + var eTcLoss = ((SI)row[SummaryDataContainer.E_TC_LOSS]).Value(); + //var eShiftLoss = ((SI)row[SummaryDataContainer.E_SHIFT_LOSS]).Value(); + var eGbxLoss = ((SI)row[SummaryDataContainer.E_GBX_LOSS]).Value(); + var eRetLoss = ((SI)row[SummaryDataContainer.E_RET_LOSS]).Value(); + var eAngleLoss = ((SI)row[SummaryDataContainer.E_ANGLE_LOSS]).Value(); + var eAxlLoss = ((SI)row[SummaryDataContainer.E_AXL_LOSS]).Value(); + var eBrakeLoss = ((SI)row[SummaryDataContainer.E_BRAKE]).Value(); + var eVehInertia = ((SI)row[SummaryDataContainer.E_VEHICLE_INERTIA]).Value(); + var eAir = ((SI)row[SummaryDataContainer.E_AIR]).Value(); + var eRoll = ((SI)row[SummaryDataContainer.E_ROLL]).Value(); + var eGrad = ((SI)row[SummaryDataContainer.E_GRAD]).Value(); + var cargoVolume = mode == ExecutionMode.Engineering ? 0 : ((SI)row[SummaryDataContainer.CARGO_VOLUME]).Value(); + + var loadingValue = ((SI)row[SummaryDataContainer.LOADING]).Value() / 1000; + var fcPer100km = ((SI)row[SummaryDataContainer.FCFINAL_LITERPER100KM]).Value(); + var fcPerVolume = mode == ExecutionMode.Engineering + ? 0 + : ((SI)row[SummaryDataContainer.FCFINAL_LiterPer100M3KM]).Value(); + var fcPerLoad = loadingValue > 0 ? ((SI)row[SummaryDataContainer.FCFINAL_LITERPER100TKM]).Value() : 0; + var co2Per100km = ((SI)row[SummaryDataContainer.CO2_KM]).Value(); + var co2PerVolume = mode == ExecutionMode.Engineering ? 0 : ((SI)row[SummaryDataContainer.CO2_M3KM]).Value(); + var co2PerLoad = loadingValue > 0 ? ((SI)row[SummaryDataContainer.CO2_TKM]).Value() : 0; + + var ePTOtransm = ptoTransmissionColumn != null ? ((SI)row[ptoTransmissionColumn]).Value() : 0; + var ePTOconsumer = ptoConsumerColumn != null ? ((SI)row[ptoConsumerColumn]).Value() : 0; + + // E_fcmap_pos = E_fcmap_neg + E_powertrain_inertia + E_aux_xxx + E_aux_sum + E_clutch_loss + E_tc_loss + E_gbx_loss + E_shift_loss + E_ret_loss + E_angle_loss + E_axl_loss + E_brake + E_vehicle_inertia + E_air + E_roll + E_grad + E_PTO_CONSUM + E_PTO_TRANSM + Assert.AreEqual(eFcMapPos, + eFcMapNeg + ePowertrainInertia + eAux + eClutchLoss + eTcLoss + eGbxLoss + eRetLoss + eAngleLoss + + eAxlLoss + eBrakeLoss + eVehInertia + eAir + eRoll + eGrad + ePTOconsumer + ePTOtransm, 1e-5, + "input file: {0} cycle: {1} loading: {2}", + inputFile, cycle, loading); + + var pFcmapPos = ((SI)row[SummaryDataContainer.P_FCMAP_POS]).Value(); + var time = ((SI)row[SummaryDataContainer.TIME]).Value(); + + // E_fcmap_pos = P_fcmap_pos * t + Assert.AreEqual(eFcMapPos, pFcmapPos * (time / 3600), 1e-3, "input file: {0} cycle: {1} loading: {2}", inputFile, + cycle, loading); + + if (cargoVolume > 0) { + Assert.AreEqual(fcPerVolume, fcPer100km / cargoVolume, 1e-3, "input file: {0} cycle: {1} loading: {2}", inputFile, + cycle, loading); + + Assert.AreEqual(co2PerVolume, co2Per100km / cargoVolume, 1e-3, "input file: {0} cycle: {1} loading: {2}", + inputFile, + cycle, loading); + } + + if (loadingValue > 0) { + Assert.AreEqual(co2PerLoad, co2Per100km / loadingValue, 1e-3, "input file: {0} cycle: {1} loading: {2}", + inputFile, cycle, loading); + Assert.AreEqual(fcPerLoad, fcPer100km / loadingValue, 1e-3, "input file: {0} cycle: {1} loading: {2}", + inputFile, cycle, loading); + } + + var stopTimeShare = ((SI)row[SummaryDataContainer.STOP_TIMESHARE]).Value(); + var accTimeShare = ((SI)row[SummaryDataContainer.ACC_TIMESHARE]).Value(); + var decTimeShare = ((SI)row[SummaryDataContainer.DEC_TIMESHARE]).Value(); + var cruiseTimeShare = ((SI)row[SummaryDataContainer.CRUISE_TIMESHARE]).Value(); + + Assert.AreEqual(100, stopTimeShare + accTimeShare + decTimeShare + cruiseTimeShare, 1e-3, + "input file: {0} cycle: {1} loading: {2}", inputFile, cycle, loading); + + Assert.IsTrue(((SI)row[SummaryDataContainer.ACC_POS]).Value() > 0); + Assert.IsTrue(((SI)row[SummaryDataContainer.ACC_NEG]).Value() < 0); + + var gearshifts = ((SI)row[SummaryDataContainer.NUM_GEARSHIFTS]).Value(); + Assert.IsTrue(gearshifts > 0); + + //var acc = ((SI)row[SummaryDataContainer.ACC]).Value(); + } + } + + private static void AssertModDataIntegrity(ModalResults modData, Dictionary<string, DataColumn> auxKeys, + Meter totalDistance, FuelConsumptionMap consumptionMap) + { + Assert.IsTrue(modData.Rows.Count > 0); + + var ptoTransmissionColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOTransmission) + ? auxKeys[Constants.Auxiliaries.IDs.PTOTransmission] + : null; + var ptoConsumerColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOConsumer) + ? auxKeys[Constants.Auxiliaries.IDs.PTOConsumer] + : null; + foreach (DataRow row in modData.Rows) { + if (totalDistance.IsEqual(((Meter)row[(int)ModalResultField.dist]))) { + continue; + } + var gear = (uint)row[(int)ModalResultField.Gear]; + var time = (Second)row[(int)ModalResultField.time]; + + var distance = (Meter)row[(int)ModalResultField.dist]; + var tqEngFcmap = (NewtonMeter)row[(int)ModalResultField.T_eng_fcmap]; + var nEngFcMap = (PerSecond)row[(int)ModalResultField.n_eng_avg]; + + // check fuel consumption interpolation + var fuelConsumption = (SI)row[(int)ModalResultField.FCMap]; + Assert.AreEqual(fuelConsumption.Value(), + consumptionMap.GetFuelConsumption(tqEngFcmap, nEngFcMap).Value.Value(), 1E-3, "time: {0} distance: {1}", + time, distance); + + // check P_eng_FCmap = T_eng_fcmap * n_eng + var pEngFcmap = (SI)row[(int)ModalResultField.P_eng_fcmap]; + Assert.AreEqual(pEngFcmap.Value(), (tqEngFcmap * nEngFcMap).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + var pWheelIn = (Watt)row[(int)ModalResultField.P_wheel_in]; + var pAir = (Watt)row[(int)ModalResultField.P_air]; + var pRoll = (Watt)row[(int)ModalResultField.P_roll]; + var pGrad = (Watt)row[(int)ModalResultField.P_slope]; + var pVehInertia = (Watt)row[(int)ModalResultField.P_veh_inertia]; + var pTrac = (Watt)row[(int)ModalResultField.P_trac]; + + // P_eng_out = P_wheel + P_lossgearbox + P_lossaxle + P_lossretarder + P_agbx + Pa_eng + P_aux - P_brake_loss + var pEngOut = (Watt)row[(int)ModalResultField.P_eng_out]; + var pLossGbx = (Watt)row[(int)ModalResultField.P_gbx_loss]; + var pGbxIn = (Watt)row[(int)ModalResultField.P_gbx_in]; + var pLossAxle = (Watt)row[(int)ModalResultField.P_axle_loss]; + var pLossAngle = row[(int)ModalResultField.P_angle_loss] is DBNull + ? 0.SI<Watt>() + : (Watt)row[(int)ModalResultField.P_angle_loss]; + var pAxleIn = (Watt)row[(int)ModalResultField.P_axle_in]; + var pLossRet = (Watt)row[(int)ModalResultField.P_ret_loss]; + var pRetIn = (Watt)row[(int)ModalResultField.P_retarder_in]; + var pGbxInertia = (Watt)row[(int)ModalResultField.P_gbx_inertia]; + var pShiftLoss = row[(int)ModalResultField.P_gbx_shift_loss] is DBNull + ? 0.SI<Watt>() + : (Watt)row[(int)ModalResultField.P_gbx_shift_loss]; + var pEngInertia = (Watt)row[(int)ModalResultField.P_eng_inertia]; + var pAux = + (Watt)(row[(int)ModalResultField.P_aux] != DBNull.Value ? row[(int)ModalResultField.P_aux] : 0.SI<Watt>()); + var pBrakeLoss = (Watt)row[(int)ModalResultField.P_brake_loss]; + var pBrakeIn = (Watt)row[(int)ModalResultField.P_brake_in]; + + var pWheelInertia = (Watt)row[(int)ModalResultField.P_wheel_inertia]; + var pPTOconsumer = ptoConsumerColumn == null || row[ptoConsumerColumn.ColumnName] is DBNull + ? 0.SI<Watt>() + : (Watt)row[ptoConsumerColumn.ColumnName]; + var pPTOtransm = ptoTransmissionColumn == null || row[ptoTransmissionColumn.ColumnName] is DBNull + ? 0.SI<Watt>() + : (Watt)row[ptoTransmissionColumn.ColumnName]; + // P_trac = P_veh_inertia + P_roll + P_air + P_slope + Assert.AreEqual(pTrac.Value(), (pAir + pRoll + pGrad + pVehInertia).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + // P_wheel_in = P_trac + P_wheel_inertia + Assert.AreEqual(pWheelIn.Value(), (pTrac + pWheelInertia).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pBrakeIn.Value(), (pWheelIn + pBrakeLoss).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pAxleIn.Value(), (pBrakeIn + pLossAxle).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pRetIn.Value(), (pAxleIn + pLossRet).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + var pClutchLoss = (Watt)(row[(int)ModalResultField.P_clutch_loss] != DBNull.Value + ? row[(int)ModalResultField.P_clutch_loss] + : 0.SI<Watt>()); + + var pClutchOut = row[(int)ModalResultField.P_clutch_out]; + if (pClutchOut != DBNull.Value) { + Assert.AreEqual(pGbxIn.Value(), (pClutchOut as Watt).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + Assert.AreEqual(pEngOut.Value(), (pClutchOut as Watt + pClutchLoss).Value(), 1E-3, "time: {0} distance: {1}", + time, distance); + } + + var pTC_Loss = (Watt)(row[(int)ModalResultField.P_TC_loss] != DBNull.Value + ? row[(int)ModalResultField.P_TC_loss] + : 0.SI<Watt>()); + + var pTCOut = row[(int)ModalResultField.P_clutch_out]; + if (pTCOut != DBNull.Value) { + Assert.AreEqual(pGbxIn.Value(), (pTCOut as Watt).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + //Assert.AreEqual(pEngOut.Value(), (pTCOut as Watt + pTC_Loss).Value(), 1E-3, "time: {0} distance: {1}", + // time, distance); + } + + Assert.IsTrue(pLossGbx.IsGreaterOrEqual(pShiftLoss + pGbxInertia), "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pGbxIn.Value(), (pRetIn + pLossGbx + pGbxInertia).Value(), gear != 0 ? 1E-3 : 0.5, + "time: {0} distance: {1}", time, + distance); + + // P_eng_fcmap = P_eng_out + P_AUX + P_eng_inertia ( + P_PTO_Transm + P_PTO_Consumer ) + Assert.AreEqual(pEngFcmap.Value(), (pEngOut + pAux + pEngInertia + pPTOtransm + pPTOconsumer).Value(), 0.5, + "time: {0} distance: {1}", time, distance); + + // P_eng_fcmap = sum(Losses Powertrain) + var pLossTot = pClutchLoss + pTC_Loss + pLossGbx + pLossRet + pGbxInertia + pLossAngle + pLossAxle + pBrakeLoss + + pWheelInertia + pAir + pRoll + pGrad + pVehInertia + pPTOconsumer + pPTOtransm; + var pEngFcmapCalc = (pLossTot + pEngInertia + pAux).Value(); + Assert.AreEqual(pEngFcmap.Value(), pEngFcmapCalc, 0.5, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pEngFcmap.Value(), + (pTrac + pWheelInertia + pBrakeLoss + pLossAxle + pLossRet + pLossGbx + pGbxInertia + pEngInertia + pAux + + pClutchLoss + pTC_Loss + pPTOtransm + pPTOconsumer).Value(), 0.5, "time: {0} distance: {1}", time, distance); + } + } + + [ + TestCase(@"TestData\Integration\EngineeringMode\CityBus_AT\CityBus_AT_Ser.vecto"), + TestCase(@"TestData\Integration\EngineeringMode\CityBus_AT\CityBus_AT_PS.vecto")] + public void TestFullCycleModDataIntegrityAT(string jobName) + { + var fileWriter = new FileOutputWriter(jobName); + var sumData = new SummaryDataContainer(fileWriter); + + var jobContainer = new JobContainer(sumData); + var inputData = JSONInputDataFactory.ReadJsonJob(jobName); + + var runsFactory = + new SimulatorFactory(ExecutionMode.Engineering, inputData, fileWriter) { WriteModalResults = true }; + + jobContainer.AddRuns(runsFactory); + var modData = new List<Tuple<ModalResults, Meter>>(); + foreach (var run in jobContainer.Runs) { + modData.Add(Tuple.Create(((ModalDataContainer)run.Run.GetContainer().ModalData).Data, + ((DistanceBasedDrivingCycle)((VehicleContainer)run.Run.GetContainer()).DrivingCycle).Data.Entries.Last() + .Distance)); + } + var auxKeys = + new Dictionary<string, DataColumn>( + ((ModalDataContainer)jobContainer.Runs.First().Run.GetContainer().ModalData).Auxiliaries); + jobContainer.Execute(); + jobContainer.WaitFinished(); + + foreach (var modalResults in modData) { + AssertModDataIntegrityAT(modalResults.Item1, auxKeys, modalResults.Item2, + FuelConsumptionMapReader.Create(((IEngineeringInputDataProvider)inputData).EngineInputData.FuelConsumptionMap)); + } + + AssertSumDataIntegrity(sumData, ExecutionMode.Engineering); + } + + private static void AssertModDataIntegrityAT(ModalResults modData, Dictionary<string, DataColumn> auxKeys, + Meter totalDistance, FuelConsumptionMap consumptionMap) + { + Assert.IsTrue(modData.Rows.Count > 0); + + var ptoTransmissionColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOTransmission) + ? auxKeys[Constants.Auxiliaries.IDs.PTOTransmission] + : null; + var ptoConsumerColumn = auxKeys.ContainsKey(Constants.Auxiliaries.IDs.PTOConsumer) + ? auxKeys[Constants.Auxiliaries.IDs.PTOConsumer] + : null; + foreach (DataRow row in modData.Rows) { + if (totalDistance.IsEqual(((Meter)row[(int)ModalResultField.dist]))) { + continue; + } + var gear = (uint)row[(int)ModalResultField.Gear]; + var time = (Second)row[(int)ModalResultField.time]; + + var distance = (Meter)row[(int)ModalResultField.dist]; + var tqEngFcmap = (NewtonMeter)row[(int)ModalResultField.T_eng_fcmap]; + var nEngFcMap = (PerSecond)row[(int)ModalResultField.n_eng_avg]; + + // check fuel consumption interpolation + var fuelConsumption = (SI)row[(int)ModalResultField.FCMap]; + Assert.AreEqual(fuelConsumption.Value(), + consumptionMap.GetFuelConsumption(tqEngFcmap, nEngFcMap).Value.Value(), 1E-3, "time: {0} distance: {1}", + time, distance); + + // check P_eng_FCmap = T_eng_fcmap * n_eng + var pEngFcmap = (SI)row[(int)ModalResultField.P_eng_fcmap]; + Assert.AreEqual(pEngFcmap.Value(), (tqEngFcmap * nEngFcMap).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + var pWheelIn = (Watt)row[(int)ModalResultField.P_wheel_in]; + var pAir = (Watt)row[(int)ModalResultField.P_air]; + var pRoll = (Watt)row[(int)ModalResultField.P_roll]; + var pGrad = (Watt)row[(int)ModalResultField.P_slope]; + var pVehInertia = (Watt)row[(int)ModalResultField.P_veh_inertia]; + var pTrac = (Watt)row[(int)ModalResultField.P_trac]; + + // Pe_eng = P_wheel + P_lossgearbox + P_lossaxle + P_lossretarder + P_agbx + Pa_eng + P_aux - P_brake_loss + var pEngOut = (Watt)row[(int)ModalResultField.P_eng_out]; + var pLossGbx = (Watt)row[(int)ModalResultField.P_gbx_loss]; + var pGbxIn = (Watt)row[(int)ModalResultField.P_gbx_in]; + var pLossAxle = (Watt)row[(int)ModalResultField.P_axle_loss]; + var pLossAngle = row[(int)ModalResultField.P_angle_loss] is DBNull + ? 0.SI<Watt>() + : (Watt)row[(int)ModalResultField.P_angle_loss]; + var pAxleIn = (Watt)row[(int)ModalResultField.P_axle_in]; + var pLossRet = (Watt)row[(int)ModalResultField.P_ret_loss]; + var pRetIn = (Watt)row[(int)ModalResultField.P_retarder_in]; + var pGbxInertia = (Watt)row[(int)ModalResultField.P_gbx_inertia]; + var pShiftLoss = row[(int)ModalResultField.P_gbx_shift_loss] is DBNull + ? 0.SI<Watt>() + : (Watt)row[(int)ModalResultField.P_gbx_shift_loss]; + var pEngInertia = (Watt)row[(int)ModalResultField.P_eng_inertia]; + var pAux = + (Watt)(row[(int)ModalResultField.P_aux] != DBNull.Value ? row[(int)ModalResultField.P_aux] : 0.SI<Watt>()); + var pBrakeLoss = (Watt)row[(int)ModalResultField.P_brake_loss]; + var pBrakeIn = (Watt)row[(int)ModalResultField.P_brake_in]; + var pTcLoss = (Watt)row[(int)ModalResultField.P_TC_loss]; + var pTcOut = (Watt)row[(int)ModalResultField.P_TC_out]; + var pWheelInertia = (Watt)row[(int)ModalResultField.P_wheel_inertia]; + var pPTOconsumer = ptoConsumerColumn == null || row[ptoConsumerColumn] is DBNull + ? 0.SI<Watt>() + : (Watt)row[ptoConsumerColumn]; + var pPTOtransm = ptoTransmissionColumn == null || row[ptoTransmissionColumn] is DBNull + ? 0.SI<Watt>() + : (Watt)row[ptoTransmissionColumn]; + // P_trac = P_veh_inertia + P_roll + P_air + P_slope + Assert.AreEqual(pTrac.Value(), (pAir + pRoll + pGrad + pVehInertia).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + // P_wheel_in = P_trac + P_wheel_inertia + Assert.AreEqual(pWheelIn.Value(), (pTrac + pWheelInertia).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pBrakeIn.Value(), (pWheelIn + pBrakeLoss).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pAxleIn.Value(), (pBrakeIn + pLossAxle).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pRetIn.Value(), (pAxleIn + pLossRet).Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pGbxIn.Value(), pTcOut.Value(), 1E-3, "time: {0} distance: {1}", time, distance); + + Assert.AreEqual(pEngOut.Value(), (pTcOut + pTcLoss).Value(), 1E-3, + "time: {0} distance: {1}", time, distance); + + // P_eng_fcmap = P_eng_out + P_AUX + P_eng_inertia ( + P_PTO_Transm + P_PTO_Consumer ) + Assert.AreEqual(pEngFcmap.Value(), (pEngOut + pAux + pEngInertia + pPTOtransm + pPTOconsumer).Value(), 1E-3, + "time: {0} distance: {1}", time, + distance); + + // P_eng_fcmap = sum(Losses Powertrain) + var pLossTot = pTcLoss + pLossGbx + pLossRet + pGbxInertia + pLossAngle + pLossAxle + pBrakeLoss + + pWheelInertia + pAir + pRoll + pGrad + pVehInertia + pPTOconsumer + pPTOtransm; + + Assert.AreEqual(pEngFcmap.Value(), (pLossTot + pEngInertia + pAux).Value(), 1E-3, "time: {0} distance: {1}", time, + distance); + + Assert.IsTrue(pLossGbx.IsGreaterOrEqual(pShiftLoss + pGbxInertia), "time: {0} distance: {1}", time, + distance); + + Assert.AreEqual(pGbxIn.Value(), (pRetIn + pLossGbx + pGbxInertia).Value(), gear != 0 ? 1E-3 : 0.5, + "time: {0} distance: {1}", time, + distance); + Assert.AreEqual(pEngFcmap.Value(), + (pTrac + pWheelInertia + pBrakeLoss + pLossAxle + pLossRet + pLossGbx + pGbxInertia + pEngInertia + pAux + + pTcLoss + pPTOtransm + pPTOconsumer).Value(), 0.5, "time: {0} distance: {1}", time, distance); + } + } + } } \ No newline at end of file