Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS will be completely phased out by mid-2025. To see alternatives please check here

Skip to content
Snippets Groups Projects
Commit 7366ef3a authored by Markus Quaritsch's avatar Markus Quaritsch
Browse files

Merge pull request #239 in VECTO/vecto-sim from...

Merge pull request #239 in VECTO/vecto-sim from ~EMKRISPMI/vecto-sim:feature/VECTO-321-delaunay-triangulation-normalize to develop

* commit '8e6bf024':
  AssertHelper.AreRelativeEqual corrected bug
  ContextStopWatch: for easier debugging added
  AuxiliaryDataReader;: code formatting
  FuelConsumptionMapReader: code formatting
  TransmissionLossMap: removed ConvertTo of delaunay map, formatted code
  Check if delaunay map was triangulated before Interpolate was called
  DelaunayMapTests updated, new Test added
  AssertHelper accepts nullable double
  resharper code formatting
  Delaunay Map Normalization
  added missing AuxiliaryTypeHelper
parents d67e8a39 8e6bf024
No related branches found
No related tags found
No related merge requests found
......@@ -67,9 +67,9 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData
private static void FillFromColumnNames(DataTable table, DelaunayMap map)
{
var data = table.Rows.Cast<DataRow>().Select(row => new {
AuxiliarySpeed = DataTableExtensionMethods.ParseDouble(row, (string)Fields.AuxSpeed).RPMtoRad(),
MechanicalPower = DataTableExtensionMethods.ParseDouble(row, (string)Fields.MechPower).SI().Kilo.Watt.Cast<Watt>(),
SupplyPower = DataTableExtensionMethods.ParseDouble(row, (string)Fields.SupplyPower).SI().Kilo.Watt.Cast<Watt>()
AuxiliarySpeed = row.ParseDouble(Fields.AuxSpeed).RPMtoRad(),
MechanicalPower = row.ParseDouble(Fields.MechPower).SI().Kilo.Watt.Cast<Watt>(),
SupplyPower = row.ParseDouble(Fields.SupplyPower).SI().Kilo.Watt.Cast<Watt>()
});
foreach (var d in data) {
map.AddPoint(d.AuxiliarySpeed.Value(), d.SupplyPower.Value(), d.MechanicalPower.Value());
......
......@@ -8,7 +8,7 @@ using TUGraz.VectoCore.Utils;
namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
{
public class FuelConsumptionMapReader
public static class FuelConsumptionMapReader
{
public static FuelConsumptionMap ReadFromFile(string fileName)
{
......@@ -34,10 +34,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
foreach (DataRow row in data.Rows) {
try {
var entry = headerValid ? CreateFromColumNames(row) : CreateFromColumnIndizes(row);
// Delaunay map works only as expected, when the angularVelocity is in rpm.
delaunayMap.AddPoint(entry.Torque.Value(),
headerValid ? DataTableExtensionMethods.ParseDouble(row, (string)Fields.EngineSpeed) : row.ParseDouble(0),
delaunayMap.AddPoint(entry.Torque.Value(), headerValid ? row.ParseDouble(Fields.EngineSpeed) : row.ParseDouble(0),
entry.FuelConsumption.Value());
} catch (Exception e) {
throw new VectoException(string.Format("Line {0}: {1}", data.Rows.IndexOf(row), e.Message), e);
......@@ -67,10 +64,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
private static FuelConsumptionMap.FuelConsumptionEntry CreateFromColumNames(DataRow row)
{
return new FuelConsumptionMap.FuelConsumptionEntry(
engineSpeed: row.ParseDouble((string)Fields.EngineSpeed).SI().Rounds.Per.Minute.Cast<PerSecond>(),
torque: row.ParseDouble((string)Fields.Torque).SI<NewtonMeter>(),
engineSpeed: row.ParseDouble(Fields.EngineSpeed).SI().Rounds.Per.Minute.Cast<PerSecond>(),
torque: row.ParseDouble(Fields.Torque).SI<NewtonMeter>(),
fuelConsumption:
row.ParseDouble((string)Fields.FuelConsumption)
row.ParseDouble(Fields.FuelConsumption)
.SI()
.Gramm.Per.Hour.ConvertTo()
.Kilo.Gramm.Per.Second.Cast<KilogramPerSecond>()
......
......@@ -29,12 +29,9 @@
* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Diagnostics;
using System.Linq;
using TUGraz.VectoCommon.Exceptions;
using TUGraz.VectoCommon.Models;
using TUGraz.VectoCommon.Utils;
......@@ -69,10 +66,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox
_lossMap = new DelaunayMap("TransmissionLossMap " + GearName);
_invertedLossMap = new DelaunayMap("TransmissionLossMapInv. " + GearName);
foreach (var entry in _entries) {
_lossMap.AddPoint(entry.InputSpeed.ConvertTo().Rounds.Per.Minute.Value(),
(entry.InputTorque - entry.TorqueLoss).Value(), entry.TorqueLoss.Value());
_invertedLossMap.AddPoint(entry.InputSpeed.ConvertTo().Rounds.Per.Minute.Value(), entry.InputTorque.Value(),
entry.TorqueLoss.Value());
_lossMap.AddPoint(entry.InputSpeed.Value(), (entry.InputTorque - entry.TorqueLoss).Value(), entry.TorqueLoss.Value());
_invertedLossMap.AddPoint(entry.InputSpeed.Value(), entry.InputTorque.Value(), entry.TorqueLoss.Value());
}
_lossMap.Triangulate();
......@@ -88,12 +83,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox
public LossMapResult GetTorqueLoss(PerSecond outAngularVelocity, NewtonMeter outTorque)
{
var result = new LossMapResult();
var torqueLoss = _lossMap.Interpolate(outAngularVelocity.ConvertTo().Rounds.Per.Minute.Value() * _ratio,
outTorque.Value() / _ratio);
var torqueLoss = _lossMap.Interpolate(outAngularVelocity.Value() * _ratio, outTorque.Value() / _ratio);
if (!torqueLoss.HasValue) {
torqueLoss = _lossMap.Extrapolate(outAngularVelocity.ConvertTo().Rounds.Per.Minute.Value() * _ratio,
outTorque.Value() / _ratio);
torqueLoss = _lossMap.Extrapolate(outAngularVelocity.Value() * _ratio, outTorque.Value() / _ratio);
result.Extrapolated = true;
}
......@@ -120,14 +113,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox
/// <returns>Torque needed at output side (towards the wheels).</returns>
public NewtonMeter GetOutTorque(PerSecond inAngularVelocity, NewtonMeter inTorque, bool allowExtrapolation = false)
{
var torqueLoss = _invertedLossMap.Interpolate(inAngularVelocity.ConvertTo().Rounds.Per.Minute.Value(),
inTorque.Value());
var torqueLoss = _invertedLossMap.Interpolate(inAngularVelocity.Value(), inTorque.Value());
if (torqueLoss.HasValue) {
return (inTorque - torqueLoss.Value.SI<NewtonMeter>()) / _ratio;
}
if (allowExtrapolation) {
torqueLoss = _invertedLossMap.Extrapolate(inAngularVelocity.ConvertTo().Rounds.Per.Minute.Value(), inTorque.Value());
torqueLoss = _invertedLossMap.Extrapolate(inAngularVelocity.Value(), inTorque.Value());
return (inTorque - torqueLoss.Value.SI<NewtonMeter>()) / _ratio;
}
......
using System;
using System.Diagnostics;
namespace TUGraz.VectoCore.Utils
{
/// <summary>
/// StopWatch which works like an IDisposable-Context.
/// Usage: using(new ContextStopWatch("main")) { ... }
/// </summary>
public class ContextStopWatch : Stopwatch, IDisposable
{
private readonly string _name;
public ContextStopWatch(string name = null)
{
Start();
_name = name;
}
public void Dispose()
{
Stop();
if (_name != null)
Console.WriteLine("{0}: {1}", _name, Elapsed);
else
Console.WriteLine(Elapsed);
}
}
}
\ No newline at end of file
......@@ -45,11 +45,15 @@ namespace TUGraz.VectoCore.Utils
{
public sealed class DelaunayMap : LoggingObject
{
internal readonly ICollection<Point> Points = new HashSet<Point>();
internal ICollection<Point> Points = new HashSet<Point>();
private List<Triangle> _triangles = new List<Triangle>();
private Edge[] _convexHull;
private readonly string _mapName;
private double _minY;
private double _minX;
private double _maxY;
private double _maxX;
public DelaunayMap(string name)
{
......@@ -78,10 +82,14 @@ namespace TUGraz.VectoCore.Utils
SanitycheckInputPoints();
// The "supertriangle" encompasses all triangulation points.
// This is just a helper triangle which initializes the algorithm and will be removed later.
const int superTriangleScalingFactor = 10;
var max = Points.Max(point => Math.Max(Math.Abs(point.X), Math.Abs(point.Y))) * superTriangleScalingFactor;
var superTriangle = new Triangle(new Point(max, 0), new Point(0, max), new Point(-max, -max));
// This is just a helper triangle which initializes the algorithm and will be removed in the end of the algorithm.
_maxX = Points.Max(p => p.X);
_maxY = Points.Max(p => p.Y);
_minX = Points.Min(p => p.X);
_minY = Points.Min(p => p.Y);
Points =
Points.Select(p => new Point((p.X - _minX) / (_maxX - _minX), (p.Y - _minY) / (_maxY - _minY), p.Z)).ToList();
var superTriangle = new Triangle(new Point(-1, -1), new Point(4, -1), new Point(-1, 4));
var triangles = new List<Triangle> { superTriangle };
var pointCount = 0;
......@@ -146,8 +154,7 @@ namespace TUGraz.VectoCore.Utils
public void DrawGraph()
{
const int max = 100000;
var superTriangle = new Triangle(new Point(max, 0), new Point(0, max), new Point(-max, -max));
var superTriangle = new Triangle(new Point(-1, -1), new Point(4, -1), new Point(-1, 4));
DrawGraph(0, _triangles, superTriangle, Points.ToArray());
}
......@@ -215,6 +222,10 @@ namespace TUGraz.VectoCore.Utils
/// null if interpolation has failed.</returns>
public double? Interpolate(double x, double y)
{
if (!_triangles.Any())
throw new VectoException("Interpolation not possible. Call DelaunayMap.Triangulate first.");
x = (x - _minX) / (_maxX - _minX);
y = (y - _minY) / (_maxY - _minY);
var tr = _triangles.Find(triangle => triangle.IsInside(x, y, exact: true)) ??
_triangles.Find(triangle => triangle.IsInside(x, y, exact: false));
......@@ -234,6 +245,8 @@ namespace TUGraz.VectoCore.Utils
/// <returns></returns>
public double Extrapolate(double x, double y)
{
x = (x - _minX) / (_maxX - _minX);
y = (y - _minY) / (_maxY - _minY);
var point = new Point(x, y);
// get nearest point on convex hull
......
......@@ -29,8 +29,8 @@
* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology
*/
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using TUGraz.VectoCommon.Models;
using TUGraz.VectoCore.Configuration;
using TUGraz.VectoCore.Models.Declaration;
......
......@@ -29,10 +29,10 @@
* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology
*/
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Diagnostics;
using System.Globalization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TUGraz.VectoCommon.Utils;
namespace TUGraz.VectoCore.Tests.Utils
......@@ -73,29 +73,35 @@ namespace TUGraz.VectoCore.Tests.Utils
}
[DebuggerHidden]
public static void AreRelativeEqual(double expected, SI actual,
public static void AreRelativeEqual(double? expected, SI actual,
double toleranceFactor = DoubleExtensionMethods.ToleranceFactor)
{
AreRelativeEqual(expected, actual.Value(), toleranceFactor: toleranceFactor);
if (expected.HasValue) {
AreRelativeEqual(expected.Value, actual.Value(), toleranceFactor: toleranceFactor);
} else {
Assert.IsNull(actual, "Both Values have to be null or not null.");
}
}
[DebuggerHidden]
public static void AreRelativeEqual(double expected, double actual, string message = null,
public static void AreRelativeEqual(double? expected, double? actual, string message = null,
double toleranceFactor = DoubleExtensionMethods.ToleranceFactor)
{
if (!string.IsNullOrWhiteSpace(message)) {
message = "\n_eng_avg" + message;
message = "\n" + message;
} else {
message = "";
}
if (double.IsNaN(expected)) {
Assert.IsTrue(double.IsNaN(actual),
Assert.IsFalse(expected.HasValue ^ actual.HasValue, "Both Values have to be null or not null.");
if (double.IsNaN(expected.Value)) {
Assert.IsTrue(double.IsNaN(actual.Value),
string.Format("Actual value is not NaN. Expected: {0}, Actual: {1}{2}", expected, actual, message));
return;
}
var ratio = expected == 0 ? Math.Abs(actual) : Math.Abs(actual / expected - 1);
var ratio = expected == 0 ? Math.Abs(actual.Value) : Math.Abs(actual.Value / expected.Value - 1);
Assert.IsTrue(ratio < toleranceFactor, string.Format(CultureInfo.InvariantCulture,
"Given values are not equal. Expected: {0}, Actual: {1}, Difference: {3} (Tolerance Factor: {2}){4}",
expected, actual, toleranceFactor, expected - actual, message));
......
......@@ -29,9 +29,12 @@
* Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology
*/
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Linq;
using TUGraz.VectoCommon.Exceptions;
using TUGraz.VectoCommon.Utils;
using TUGraz.VectoCore.Utils;
namespace TUGraz.VectoCore.Tests.Utils
......@@ -51,7 +54,7 @@ namespace TUGraz.VectoCore.Tests.Utils
var result = map.Interpolate(0.25, 0.25);
AssertHelper.AreRelativeEqual(0, result.Value);
AssertHelper.AreRelativeEqual(0, result);
}
[TestMethod]
......@@ -65,21 +68,21 @@ namespace TUGraz.VectoCore.Tests.Utils
map.Triangulate();
// fixed points
AssertHelper.AreRelativeEqual(0, map.Interpolate(0, 0).Value);
AssertHelper.AreRelativeEqual(1, map.Interpolate(1, 0).Value);
AssertHelper.AreRelativeEqual(2, map.Interpolate(0, 1).Value);
AssertHelper.AreRelativeEqual(0, map.Interpolate(0, 0));
AssertHelper.AreRelativeEqual(1, map.Interpolate(1, 0));
AssertHelper.AreRelativeEqual(2, map.Interpolate(0, 1));
// interpolations
AssertHelper.AreRelativeEqual(0.5, map.Interpolate(0.5, 0).Value);
AssertHelper.AreRelativeEqual(1, map.Interpolate(0, 0.5).Value);
AssertHelper.AreRelativeEqual(1.5, map.Interpolate(0.5, 0.5).Value);
AssertHelper.AreRelativeEqual(0.5, map.Interpolate(0.5, 0));
AssertHelper.AreRelativeEqual(1, map.Interpolate(0, 0.5));
AssertHelper.AreRelativeEqual(1.5, map.Interpolate(0.5, 0.5));
AssertHelper.AreRelativeEqual(0.25, map.Interpolate(0.25, 0).Value);
AssertHelper.AreRelativeEqual(0.5, map.Interpolate(0, 0.25).Value);
AssertHelper.AreRelativeEqual(0.75, map.Interpolate(0.25, 0.25).Value);
AssertHelper.AreRelativeEqual(0.25, map.Interpolate(0.25, 0));
AssertHelper.AreRelativeEqual(0.5, map.Interpolate(0, 0.25));
AssertHelper.AreRelativeEqual(0.75, map.Interpolate(0.25, 0.25));
AssertHelper.AreRelativeEqual(0.75, map.Interpolate(0.75, 0).Value);
AssertHelper.AreRelativeEqual(1.5, map.Interpolate(0, 0.75).Value);
AssertHelper.AreRelativeEqual(0.75, map.Interpolate(0.75, 0));
AssertHelper.AreRelativeEqual(1.5, map.Interpolate(0, 0.75));
// extrapolation (should fail)
Assert.IsNull(map.Interpolate(1, 1));
......@@ -99,24 +102,24 @@ namespace TUGraz.VectoCore.Tests.Utils
map.Triangulate();
// fixed points
AssertHelper.AreRelativeEqual(0, map.Interpolate(0, 0).Value);
AssertHelper.AreRelativeEqual(1, map.Interpolate(1, 0).Value);
AssertHelper.AreRelativeEqual(2, map.Interpolate(0, 1).Value);
AssertHelper.AreRelativeEqual(3, map.Interpolate(1, 1).Value);
AssertHelper.AreRelativeEqual(0, map.Interpolate(0, 0));
AssertHelper.AreRelativeEqual(1, map.Interpolate(1, 0));
AssertHelper.AreRelativeEqual(2, map.Interpolate(0, 1));
AssertHelper.AreRelativeEqual(3, map.Interpolate(1, 1));
// interpolations
AssertHelper.AreRelativeEqual(0.5, map.Interpolate(0.5, 0).Value);
AssertHelper.AreRelativeEqual(1, map.Interpolate(0, 0.5).Value);
AssertHelper.AreRelativeEqual(2, map.Interpolate(1, 0.5).Value);
AssertHelper.AreRelativeEqual(2.5, map.Interpolate(0.5, 1).Value);
AssertHelper.AreRelativeEqual(0.5, map.Interpolate(0.5, 0));
AssertHelper.AreRelativeEqual(1, map.Interpolate(0, 0.5));
AssertHelper.AreRelativeEqual(2, map.Interpolate(1, 0.5));
AssertHelper.AreRelativeEqual(2.5, map.Interpolate(0.5, 1));
AssertHelper.AreRelativeEqual(1.5, map.Interpolate(0.5, 0.5).Value);
AssertHelper.AreRelativeEqual(1.5, map.Interpolate(0.5, 0.5));
AssertHelper.AreRelativeEqual(0.75, map.Interpolate(0.25, 0.25).Value);
AssertHelper.AreRelativeEqual(2.25, map.Interpolate(0.75, 0.75).Value);
AssertHelper.AreRelativeEqual(0.75, map.Interpolate(0.25, 0.25));
AssertHelper.AreRelativeEqual(2.25, map.Interpolate(0.75, 0.75));
AssertHelper.AreRelativeEqual(1.75, map.Interpolate(0.25, 0.75).Value);
AssertHelper.AreRelativeEqual(1.25, map.Interpolate(0.75, 0.25).Value);
AssertHelper.AreRelativeEqual(1.75, map.Interpolate(0.25, 0.75));
AssertHelper.AreRelativeEqual(1.25, map.Interpolate(0.75, 0.25));
// extrapolation (should fail)
AssertHelper.Exception<VectoException>(() => map.Interpolate(1.5, 0.5), "Interpolation failed.");
......@@ -168,5 +171,43 @@ namespace TUGraz.VectoCore.Tests.Utils
AssertHelper.Exception<VectoException>(() => { map.Triangulate(); },
"TEST: Input Data for Delaunay map contains duplicates! \n1 / 1");
}
[TestMethod]
public void Test_Delaunay_NormalOperation()
{
foreach (var factors in new[] {
Tuple.Create(1.0, 1.0),
Tuple.Create(1.0, 0.04),
Tuple.Create(1.0, 0.1),
Tuple.Create(1.0, 0.01),
Tuple.Create(1.0, 0.0001)
}) {
var xfactor = factors.Item1;
var yfactor = factors.Item2;
var map = new DelaunayMap("TEST");
var points =
File.ReadAllLines(@"TestData\Components\40t_Long_Haul_Truck.vmap")
.Skip(1)
.Select(s => {
var p = s.Split(',').ToDouble().ToList();
return new Point(p[0] * xfactor, p[1] * yfactor, p[2]);
})
.ToList();
points.ForEach(p => map.AddPoint(p.X, p.Y, p.Z));
map.Triangulate();
// test fixed points
foreach (var p in points) {
AssertHelper.AreRelativeEqual(p.Z, map.Interpolate(p.X, p.Y));
}
map.DrawGraph();
// test one arbitrary point in the middle
AssertHelper.AreRelativeEqual(37681, map.Interpolate(1500 * xfactor, 1300 * yfactor),
string.Format("{0}, {1}", xfactor, yfactor));
}
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment