From a62cdb396685949cb0d38b8035239ec178449403 Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <markus.quaritsch@tugraz.at> Date: Wed, 15 Nov 2017 17:57:39 +0100 Subject: [PATCH] additional SI classes for 'special' units, extensive tests for all conversion methods --- VectoCommon/VectoCommon/Utils/SI.cs | 69 +++++- .../Utils/SIConvertExtensionMethods.cs | 29 +-- .../OutputData/IModalDataContainer.cs | 4 +- VectoCore/VectoCoreTest/Utils/SITest.cs | 213 +++++++++++++++++- 4 files changed, 277 insertions(+), 38 deletions(-) diff --git a/VectoCommon/VectoCommon/Utils/SI.cs b/VectoCommon/VectoCommon/Utils/SI.cs index 1cf8a45a81..344db00e28 100644 --- a/VectoCommon/VectoCommon/Utils/SI.cs +++ b/VectoCommon/VectoCommon/Utils/SI.cs @@ -223,7 +223,17 @@ namespace TUGraz.VectoCommon.Utils [DebuggerHidden] private KilogramPerMeter(double val) : base(val, Units) { } - } + + public static KilogramPerMeterMass operator /(KilogramPerMeter kpm, Kilogram kg) + { + return SIBase<KilogramPerMeterMass>.Create(kpm.Val / kg.Value()); + } + + public static KilogramPerMeterCubicMeter operator /(KilogramPerMeter kpm, CubicMeter vol) + { + return SIBase<KilogramPerMeterCubicMeter>.Create(kpm.Val / vol.Value()); + } + } /// <summary> /// SI Class for Liter per Second [l/s]. @@ -787,12 +797,57 @@ namespace TUGraz.VectoCommon.Utils } } - /// <summary> - /// Base Class for all special SI Classes. Not intended to be used directly. - /// Implements templated operators for type safety and convenience. - /// </summary> - /// <typeparam name="T"></typeparam> - public abstract class SIBase<T> : SI where T : SIBase<T> + public class VolumePerMeter : SIBase<VolumePerMeter> + { + private static readonly int[] Units = { 0, 2, 0, 0, 0, 0, 0 }; + private VolumePerMeter(double val) : base(val, Units) { } + + public static VolumePerMeterMass operator /(VolumePerMeter vpm, Kilogram kg) + { + return SIBase<VolumePerMeterMass>.Create(vpm.Val / kg.Value()); + } + + public static VolumePerMeterVolume operator /(VolumePerMeter vpm, CubicMeter vol) + { + return SIBase<VolumePerMeterVolume>.Create(vpm.Val / vol.Value()); + } + + } + + public class VolumePerMeterMass : SIBase<VolumePerMeterMass> + { + private static readonly int[] Units = { -1, 2, 0, 0, 0, 0, 0 }; + + private VolumePerMeterMass(double val) : base (val, Units) { } + } + + public class VolumePerMeterVolume : SIBase<VolumePerMeterVolume> + { + private static readonly int[] Units = { 0, -1, 0, 0, 0, 0, 0 }; + + private VolumePerMeterVolume(double val) : base (val, Units) { } + } + + public class KilogramPerMeterCubicMeter : SIBase<KilogramPerMeterCubicMeter> + { + private static readonly int[] Units = { 1, -4, 0, 0, 0, 0, 0 }; + + private KilogramPerMeterCubicMeter(double val) : base(val, Units) { } + } + + public class KilogramPerMeterMass : SIBase<KilogramPerMeterMass> + { + private static readonly int[] Units = { 0, -1, 0, 0, 0, 0, 0 }; + + private KilogramPerMeterMass(double val) : base(val, Units) { } + } + + /// <summary> + /// Base Class for all special SI Classes. Not intended to be used directly. + /// Implements templated operators for type safety and convenience. + /// </summary> + /// <typeparam name="T"></typeparam> + public abstract class SIBase<T> : SI where T : SIBase<T> { private static readonly T ZeroPrototype; diff --git a/VectoCommon/VectoCommon/Utils/SIConvertExtensionMethods.cs b/VectoCommon/VectoCommon/Utils/SIConvertExtensionMethods.cs index 7a910a2ac6..3f7a0d65c0 100644 --- a/VectoCommon/VectoCommon/Utils/SIConvertExtensionMethods.cs +++ b/VectoCommon/VectoCommon/Utils/SIConvertExtensionMethods.cs @@ -6,17 +6,17 @@ namespace TUGraz.VectoCommon.Utils public class ConvertedSI { private readonly double _value; - private readonly string _units; + public string Units { get; } public ConvertedSI(double value, string units) { _value = value; - _units = units; + Units = units; } protected bool Equals(ConvertedSI other) { - return _value.Equals(other._value) && string.Equals(_units, other._units); + return _value.Equals(other._value) && string.Equals(Units, other.Units); } public override bool Equals(object obj) @@ -33,7 +33,7 @@ namespace TUGraz.VectoCommon.Utils public override int GetHashCode() { unchecked { - return (_value.GetHashCode() * 397) ^ (_units != null ? _units.GetHashCode() : 0); + return (_value.GetHashCode() * 397) ^ (Units != null ? Units.GetHashCode() : 0); } } @@ -66,7 +66,7 @@ namespace TUGraz.VectoCommon.Utils if (showUnit.Value) { return (_value * outputFactor.Value).ToString("F" + decimals.Value, CultureInfo.InvariantCulture) + " [" + - _units + "]"; + Units + "]"; } return (_value * outputFactor.Value).ToString("F" + decimals.Value, CultureInfo.InvariantCulture); @@ -84,7 +84,7 @@ namespace TUGraz.VectoCommon.Utils } public static ConvertedSI ConvertToTon(this Kilogram value) { - return new ConvertedSI(value.Value() / Kilo, "Ton"); + return new ConvertedSI(value.Value() / Kilo, "t"); } public static ConvertedSI ConvertToKiloMeterPerHour(this MeterPerSecond value) { @@ -95,12 +95,12 @@ namespace TUGraz.VectoCommon.Utils return value == null ? null : new ConvertedSI(value.Value() * Kilo * Kilo, "g/km"); } - public static ConvertedSI ConvertToLiterPer100Kilometer(this SI value) + public static ConvertedSI ConvertToLiterPer100Kilometer(this VolumePerMeter value) { return value == null ? null : new ConvertedSI(value.Value() * (10*10*10) * (100*1000), "l/100km"); } - public static ConvertedSI ConvertToLiterPer100TonKiloMeter(this SI value) + public static ConvertedSI ConvertToLiterPer100TonKiloMeter(this VolumePerMeterMass value) { const int CubicMeterToLiter = 10 * 10 * 10; const int MeterTo100KiloMeter = 100 * Kilo; @@ -109,7 +109,7 @@ namespace TUGraz.VectoCommon.Utils return value == null ? null : new ConvertedSI(value.Value() * CubicMeterToLiter * (MeterTo100KiloMeter * KilogrammToTon), "l/100tkm"); } - public static ConvertedSI ConvertToLiterPerCubicMeter100KiloMeter(this SI value) + public static ConvertedSI ConvertToLiterPerCubicMeter100KiloMeter(this VolumePerMeterVolume value) { const int CubicMeterToLiter = 10 * 10 * 10; const int MeterTo100KiloMeter = 100 * Kilo; @@ -131,20 +131,15 @@ namespace TUGraz.VectoCommon.Utils return new ConvertedSI(value.Value() * 100 * 100 * 100, "cm^3"); } - public static ConvertedSI ConvertToGrammPerCubicMeterKiloMeter(this SI value) + public static ConvertedSI ConvertToGrammPerCubicMeterKiloMeter(this KilogramPerMeterCubicMeter value) { return new ConvertedSI(value.Value() * Kilo * Kilo, "g/m^3km"); } - public static ConvertedSI ConvertToGrammPerTonKilometer(this SI value) + public static ConvertedSI ConvertToGrammPerTonKilometer(this KilogramPerMeterMass value) { return new ConvertedSI(value.Value() * Kilo * Kilo * Kilo, "g/tkm"); } - - public static ConvertedSI ConvertToLiterPer100KiloMeter(this SI value) - { - return new ConvertedSI(value.Value() * 10 * 10 * 10 * 100 * Kilo, "l/100km"); - } public static ConvertedSI ConvertToKiloWattHour(this WattSecond value) { @@ -157,7 +152,7 @@ namespace TUGraz.VectoCommon.Utils public static ConvertedSI ConvertToRoundsPerMinute(this PerSecond value) { - return new ConvertedSI(value.Value() * 2 * Math.PI / 60, "rpm"); + return new ConvertedSI(value.AsRPM, "rpm"); } public static ConvertedSI ConvertToCubicDeziMeter(this CubicMeter value) { diff --git a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs index 6bdc2259ea..43f16c5b77 100644 --- a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs +++ b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs @@ -365,7 +365,7 @@ namespace TUGraz.VectoCore.OutputData return data.TimeIntegral<Kilogram>(ModalResultField.FCFinal) / distance; } - public static SquareMeter FuelConsumptionFinalVolumePerMeter(this IModalDataContainer data) + public static VolumePerMeter FuelConsumptionFinalVolumePerMeter(this IModalDataContainer data) { var fuelConsumptionFinal = data.FuelConsumptionFinal(); if (fuelConsumptionFinal == null || data.FuelData.FuelDensity == null) { @@ -373,7 +373,7 @@ namespace TUGraz.VectoCore.OutputData } var fcVolumePerMeter = fuelConsumptionFinal / data.FuelData.FuelDensity; - return fcVolumePerMeter.Cast<SquareMeter>(); + return fcVolumePerMeter.Cast<VolumePerMeter>(); } public static KilogramPerMeter CO2PerMeter(this IModalDataContainer data) diff --git a/VectoCore/VectoCoreTest/Utils/SITest.cs b/VectoCore/VectoCoreTest/Utils/SITest.cs index 31c01ccfcf..5d384d4bef 100644 --- a/VectoCore/VectoCoreTest/Utils/SITest.cs +++ b/VectoCore/VectoCoreTest/Utils/SITest.cs @@ -571,22 +571,211 @@ namespace TUGraz.VectoCore.Tests.Utils Assert.AreEqual("m^3", 2.13093.SI(Unit.SI.Liter).GetUnitString()); } - [TestCase] - public void SI_ConvertValues() - { - var sig1 = 5.SI(Unit.SI.Gramm); - Assert.AreEqual(0.005, sig1.Value()); + //[TestCase] + // public void SI_ConvertValues() + // { + // var sig1 = 5.SI(Unit.SI.Gramm); + // Assert.AreEqual(0.005, sig1.Value()); + + // var val2 = 7.SI(Unit.SI.Cubic.Dezi.Meter).Cast<CubicMeter>().ConvertToCubicDeziMeter(); + // AssertHelper.AreRelativeEqual(7, val2); + + // var val3 = 5.SI(Unit.SI.Cubic.Dezi.Meter).Cast<CubicMeter>().ConvertToCubicCentiMeter(); + // AssertHelper.AreRelativeEqual(5000, val3); // 5000 cm^3 + + // var val4 = 5.SI(Unit.SI.Cubic.Centi.Meter).Cast<CubicMeter>().ConvertToCubicDeziMeter(); + // AssertHelper.AreRelativeEqual(0.005, val4); // 0.005 dm^3 + //} + + [TestCase(1, 1000), + TestCase(1e-3, 1), + TestCase(2.65344, 2653.44)] + public void SI_Convert_ConvertToGramm(double val, double converted) + { + var siVal = val.SI<Kilogram>(); + var siConv = siVal.ConvertToGramm(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("g", siConv.Units); + } - var val2 = 7.SI(Unit.SI.Cubic.Dezi.Meter).Cast<CubicMeter>().ConvertToCubicDeziMeter(); - AssertHelper.AreRelativeEqual(7, val2); + [TestCase(1000, 1), + TestCase(1, 1e-3), + TestCase(5243, 5.243)] + public void SI_Convert_ConvertToTon(double val, double converted) + { + var siVal = val.SI<Kilogram>(); + var siConv = siVal.ConvertToTon(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("t", siConv.Units); + } - var val3 = 5.SI(Unit.SI.Cubic.Dezi.Meter).Cast<CubicMeter>().ConvertToCubicCentiMeter(); - AssertHelper.AreRelativeEqual(5000, val3); // 5000 cm^3 + [TestCase(1, 3.6), + TestCase(0.2777777777777777, 1), + TestCase(13.7603, 49.53708)] + public void SI_Convert_ConvertToKiloMeterPerHour(double val, double converted) + { + var siVal = val.SI<MeterPerSecond>(); + var siConv = siVal.ConvertToKiloMeterPerHour(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("km/h", siConv.Units); + } + + [TestCase(1, 1e6), + TestCase(1e-6, 1), + TestCase(7.54214451, 7542144.51)] + public void SI_Convert_ConvertToGrammPerKiloMeter(double val, double converted) + { + var siVal = val.SI<KilogramPerMeter>(); + var siConv = siVal.ConvertToGrammPerKiloMeter(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("g/km", siConv.Units); + } - var val4 = 5.SI(Unit.SI.Cubic.Centi.Meter).Cast<CubicMeter>().ConvertToCubicDeziMeter(); - AssertHelper.AreRelativeEqual(0.005, val4); // 0.005 dm^3 + [TestCase(1, 1e8), + TestCase(1e-8, 1), + TestCase(0.00935934235, 935934.235)] + public void SI_Convert_ConvertToLiterPer100Kilometer(double val, double converted) + { + var siVal = val.SI<VolumePerMeter>(); + var siConv = siVal.ConvertToLiterPer100Kilometer(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("l/100km", siConv.Units); } - } + [TestCase(1, 1e11), + TestCase(1e-11, 1), + TestCase(0.00013243241234, 13243241.234)] + public void SI_Convert_ConvertToLiterPer100TonKiloMeter(double val, double converted) + { + var siVal = val.SI<VolumePerMeterMass>(); + var siConv = siVal.ConvertToLiterPer100TonKiloMeter(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("l/100tkm", siConv.Units); + } + + [TestCase(1, 1e8), + TestCase(1e-8, 1), + TestCase(0.13243241234, 13243241.234)] + public void SI_Convert_ConvertToLiterPerCubicMeter100KiloMeter(double val, double converted) + { + var siVal = val.SI<VolumePerMeterVolume>(); + var siConv = siVal.ConvertToLiterPerCubicMeter100KiloMeter(); + Assert.AreEqual(converted, siConv, 1e-6); + Assert.AreEqual("l/100m^3km", siConv.Units); + } + + [TestCase(1,3.6e6), + TestCase(0.277777777777777777e-6,1), + TestCase(0.0135897845, 13589.7845*3.6)] + public void SI_Convert_ConvertToGrammPerHour(double val, double converted) + { + var siVal = val.SI<KilogramPerSecond>(); + var siConv = siVal.ConvertToGrammPerHour(); + Assert.AreEqual(converted, siConv, 1e-6); + Assert.AreEqual("g/h", siConv.Units); + } + + [TestCase(1, 1e-3), + TestCase(1e3, 1), + TestCase(4353.32, 4.35332)] + public void SI_Convert_ConvertToKiloMeter(double val, double converted) + { + var siVal = val.SI<Meter>(); + var siConv = siVal.ConvertToKiloMeter(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("km", siConv.Units); + } + + [TestCase(1, 1e6), + TestCase(1e-6, 1), + TestCase(0.053798513789, 53798.513789)] + public void SI_Convert_ConvertToCubicCentiMeter(double val, double converted) + { + var siVal = val.SI<CubicMeter>(); + var siConv = siVal.ConvertToCubicCentiMeter(); + Assert.AreEqual(converted, siConv, 1e-6); + Assert.AreEqual("cm^3", siConv.Units); + } + + [TestCase(1, 1e6), + TestCase(1e-6, 1), + TestCase(7.54214451, 7542144.51)] + public void SI_Convert_ConvertToGrammPerCubicMeterKiloMeter(double val, double converted) + { + var siVal = val.SI<KilogramPerMeterCubicMeter>(); + var siConv = siVal.ConvertToGrammPerCubicMeterKiloMeter(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("g/m^3km", siConv.Units); + } + + [TestCase(1, 1e9), + TestCase(1e-9, 1), + TestCase(7.54214451, 7542144510)] + public void SI_Convert_ConvertToGrammPerTonKilometer(double val, double converted) + { + var siVal = val.SI<KilogramPerMeterMass>(); + var siConv = siVal.ConvertToGrammPerTonKilometer(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("g/tkm", siConv.Units); + } + + [TestCase(1, 0.277777777777e-6), + TestCase(3600e3, 1), + TestCase(135890, 0.0377472222)] + public void SI_Convert_ConvertToKiloWattHour(double val, double converted) + { + var siVal = val.SI<WattSecond>(); + var siConv = siVal.ConvertToKiloWattHour(); + Assert.AreEqual(converted, siConv, 1e-6); + Assert.AreEqual("kWh", siConv.Units); + } + + [TestCase(1, 1e-3), + TestCase(1e3, 1), + TestCase(23453, 23.453)] + public void SI_Convert_ConvertToKiloWatt(double val, double converted) + { + var siVal = val.SI<Watt>(); + var siConv = siVal.ConvertToKiloWatt(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("kW", siConv.Units); + } + + [TestCase(1, 9.549296586), + TestCase(0.104719755, 1), + TestCase(62.83185307, 600)] + public void SI_Convert_ConvertToRoundsPerMinute(double val, double converted) + { + var siVal = val.SI<PerSecond>(); + var siConv = siVal.ConvertToRoundsPerMinute(); + Assert.AreEqual(converted, siConv, 1e-6); + Assert.AreEqual(siVal.Value(), ((double)siConv).RPMtoRad().Value()); + Assert.AreEqual("rpm", siConv.Units); + } + + [TestCase(1, 1e3), + TestCase(1e-3, 1), + TestCase(123.780, 123780)] + public void SI_Convert_ConvertToCubicDeziMeter(double val, double converted) + { + var siVal = val.SI<CubicMeter>(); + var siConv = siVal.ConvertToCubicDeziMeter(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("dm^3", siConv.Units); + } + + [TestCase(1, 1e3), + TestCase(1e-3, 1), + TestCase(0.255, 255)] + public void SI_Convert_ConvertToMilliMeter(double val, double converted) + { + var siVal = val.SI<Meter>(); + var siConv = siVal.ConvertToMilliMeter(); + Assert.AreEqual(converted, siConv, 1e-12); + Assert.AreEqual("mm", siConv.Units); + } + + + } } \ No newline at end of file -- GitLab