diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs index fb3702ba23ee5b202ef6ddbbf0bfbf8bc5d45f19..cb343eb7da69507fb28805d5cbcacfcf5de47191 100644 --- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs +++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs @@ -57,7 +57,7 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter } var lookAheadData = new DriverData.LACData { Enabled = DeclarationData.Driver.LookAhead.Enabled, - //Deceleration = DeclarationData.Driver.LookAhead.Deceleration, + //Deceleration = DeclarationData.Driver.LookAhead.Deceleration, MinSpeed = DeclarationData.Driver.LookAhead.MinimumSpeed, LookAheadDecisionFactor = new LACDecisionFactor(), LookAheadDistanceFactor = DeclarationData.Driver.LookAhead.LookAheadDistanceFactor, diff --git a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs index ea3022adb098538243405eca1eef263087ba8440..2f4f41999a2b25a96fbde71eba1faa5e8b4f8f99 100644 --- a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs +++ b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs @@ -177,7 +177,7 @@ namespace TUGraz.VectoCore.Models.Declaration //public static readonly PerSecond TorqueConverterSpeedLimit = 1600.RPMtoRad(); public static double TorqueConverterSecondGearThreshold(VehicleCategory category) { - return category.IsTruck() ? 1.8 : 1.9; + return category.IsTruck() ? 1.8 : 1.85; } public static readonly Second PowershiftShiftTime = 0.8.SI<Second>(); diff --git a/VectoCore/VectoCore/Models/Declaration/Mission.cs b/VectoCore/VectoCore/Models/Declaration/Mission.cs index 2e1fac83d741e53777a232c965a96af38d1b904b..e0b15c2687297f5b417dfe312170a5adc512a945 100644 --- a/VectoCore/VectoCore/Models/Declaration/Mission.cs +++ b/VectoCore/VectoCore/Models/Declaration/Mission.cs @@ -29,79 +29,79 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.IO; -using TUGraz.VectoCommon.Utils; - -namespace TUGraz.VectoCore.Models.Declaration -{ - public enum LoadingType - { - FullLoading, - ReferenceLoad, - LowLoading, - EmptyLoading, - } - - public class Mission - { - public MissionType MissionType; - public string CrossWindCorrectionParameters; - public double[] AxleWeightDistribution; - - public Kilogram BodyCurbWeight; - - public Stream CycleFile; - - public List<MissionTrailer> Trailer; - - public Kilogram MinLoad; - public Kilogram LowLoad; - public Kilogram RefLoad; - public Kilogram MaxLoad; - - public CubicMeter TotalCargoVolume; - - public Dictionary<LoadingType, Kilogram> Loadings - { - get { - return new Dictionary<LoadingType, Kilogram> { - { LoadingType.LowLoading, LowLoad }, - { LoadingType.ReferenceLoad, RefLoad }, - }; - } - } - } - - public class MissionTrailer - { - public TrailerType TrailerType; - public Kilogram TrailerCurbWeight; - public Kilogram TrailerGrossVehicleWeight; - public List<Wheels.Entry> TrailerWheels; - public double TrailerAxleWeightShare; - public SquareMeter DeltaCdA; - public CubicMeter CargoVolume; - } - - public enum TrailerType - { - //None, - T1, - T2, - ST1, - Dolly - } - - public static class TrailterTypeHelper - { - public static TrailerType Parse(string trailer) - { - if ("d".Equals(trailer, StringComparison.InvariantCultureIgnoreCase)) { - return TrailerType.Dolly; - } - return trailer.ParseEnum<TrailerType>(); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.Models.Declaration +{ + public enum LoadingType + { + FullLoading, + ReferenceLoad, + LowLoading, + EmptyLoading, + } + + public class Mission + { + public MissionType MissionType; + public string CrossWindCorrectionParameters; + public double[] AxleWeightDistribution; + + public Kilogram BodyCurbWeight; + + public Stream CycleFile; + + public List<MissionTrailer> Trailer; + + public Kilogram MinLoad; + public Kilogram LowLoad; + public Kilogram RefLoad; + public Kilogram MaxLoad; + + public CubicMeter TotalCargoVolume; + + public Dictionary<LoadingType, Kilogram> Loadings + { + get { + return new Dictionary<LoadingType, Kilogram> { + { LoadingType.LowLoading, LowLoad }, + { LoadingType.ReferenceLoad, RefLoad }, + }; + } + } + } + + public class MissionTrailer + { + public TrailerType TrailerType; + public Kilogram TrailerCurbWeight; + public Kilogram TrailerGrossVehicleWeight; + public List<Wheels.Entry> TrailerWheels; + public double TrailerAxleWeightShare; + public SquareMeter DeltaCdA; + public CubicMeter CargoVolume; + } + + public enum TrailerType + { + //None, + T1, + T2, + ST1, + Dolly + } + + public static class TrailterTypeHelper + { + public static TrailerType Parse(string trailer) + { + if ("d".Equals(trailer, StringComparison.InvariantCultureIgnoreCase)) { + return TrailerType.Dolly; + } + return trailer.ParseEnum<TrailerType>(); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Declaration/Segment.cs b/VectoCore/VectoCore/Models/Declaration/Segment.cs index 16abc25895037280bf41566fa923085da223b0e7..aa0627c1736abbd73aa7e080d42a234e0c493a4c 100644 --- a/VectoCore/VectoCore/Models/Declaration/Segment.cs +++ b/VectoCore/VectoCore/Models/Declaration/Segment.cs @@ -29,38 +29,38 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.IO; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; - -namespace TUGraz.VectoCore.Models.Declaration -{ - public class Segment - { - public VehicleClass VehicleClass { get; internal set; } - - public VehicleCategory VehicleCategory { get; set; } - - public AxleConfiguration AxleConfiguration { get; set; } - - public Kilogram GrossVehicleWeightMin { get; set; } - - public Kilogram GrossVehicleWeightMax { get; set; } - - public Kilogram GrossVehicleMassRating { get; set; } - - public Stream AccelerationFile { get; internal set; } - - public Mission[] Missions { get; internal set; } - - public Meter VehicleHeight { get; internal set; } - - public MeterPerSecond DesignSpeed { get; internal set; } - - public SquareMeter CdADefault { get; internal set; } - - public SquareMeter CdAConstruction { get; internal set; } - - public Kilogram MunicipalBodyWeight { get; internal set; } - } +using System.IO; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.Models.Declaration +{ + public class Segment + { + public VehicleClass VehicleClass { get; internal set; } + + public VehicleCategory VehicleCategory { get; set; } + + public AxleConfiguration AxleConfiguration { get; set; } + + public Kilogram GrossVehicleWeightMin { get; set; } + + public Kilogram GrossVehicleWeightMax { get; set; } + + public Kilogram GrossVehicleMassRating { get; set; } + + public Stream AccelerationFile { get; internal set; } + + public Mission[] Missions { get; internal set; } + + public Meter VehicleHeight { get; internal set; } + + public MeterPerSecond DesignSpeed { get; internal set; } + + public SquareMeter CdADefault { get; internal set; } + + public SquareMeter CdAConstruction { get; internal set; } + + public Kilogram MunicipalBodyWeight { get; internal set; } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Declaration/Segments.cs b/VectoCore/VectoCore/Models/Declaration/Segments.cs index 1d6997e14eb7ddfd5db7cb1ef874ac3d7c56497a..f070c9e29b1c41c2d2131dc48e2165dbcc551461 100644 --- a/VectoCore/VectoCore/Models/Declaration/Segments.cs +++ b/VectoCore/VectoCore/Models/Declaration/Segments.cs @@ -29,132 +29,132 @@ * 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.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.Declaration -{ - public sealed class Segments : LookupData<VehicleCategory, AxleConfiguration, Kilogram, Kilogram, Segment> - { - private DataTable _segmentTable; - - protected override string ResourceId - { - get { return DeclarationData.DeclarationDataResourcePrefix + ".SegmentTable.csv"; } - } - - protected override string ErrorMessage - { - get { - return - "ERROR: Could not find the declaration segment for vehicle. Category: {0}, AxleConfiguration: {1}, GrossVehicleWeight: {2}"; - } - } - - protected override void ParseData(DataTable table) - { - _segmentTable = table.Copy(); - } - - public override Segment Lookup(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, - Kilogram grossVehicleMassRating, Kilogram curbWeight) - { - return Lookup(vehicleCategory, axleConfiguration, grossVehicleMassRating, curbWeight, false); - } - - public Segment Lookup(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, - Kilogram grossVehicleMassRating, Kilogram curbWeight, bool considerInvalid) - { - if (grossVehicleMassRating == null || grossVehicleMassRating < 7.5.SI().Ton) { - throw new VectoException("Gross vehicle mass must be greater than 7.5 tons"); - } - - var row = GetSegmentDataRow(vehicleCategory, axleConfiguration, grossVehicleMassRating, considerInvalid); - - var segment = new Segment { - GrossVehicleWeightMin = row.ParseDouble("gvw_min").SI().Ton.Cast<Kilogram>(), - GrossVehicleWeightMax = row.ParseDouble("gvw_max").SI().Ton.Cast<Kilogram>(), - VehicleCategory = vehicleCategory, - AxleConfiguration = axleConfiguration, - VehicleClass = VehicleClassHelper.Parse(row.Field<string>("hdvclass")), - AccelerationFile = - RessourceHelper.ReadStream(DeclarationData.DeclarationDataResourcePrefix + ".VACC." + - row.Field<string>(".vaccfile")), - Missions = CreateMissions(ref grossVehicleMassRating, curbWeight, row), - VehicleHeight = LookupHeight(vehicleCategory, axleConfiguration, grossVehicleMassRating), - DesignSpeed = row.ParseDouble("designspeed").KMPHtoMeterPerSecond(), - GrossVehicleMassRating = grossVehicleMassRating, - CdADefault = row.ParseDouble("cdxa_default").SI<SquareMeter>(), - CdAConstruction = string.IsNullOrEmpty(row["cdxa_construction"].ToString()) - ? null - : row.ParseDouble("cdxa_construction").SI<SquareMeter>(), - MunicipalBodyWeight = string.IsNullOrEmpty(row["bodyweight_municipalutility"].ToString()) - ? null - : row.ParseDouble("bodyweight_municipalutility").SI<Kilogram>() - }; - - return segment; - } - - private DataRow GetSegmentDataRow(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, - Kilogram grossVehicleMassRating, bool considerInvalid) - { - DataRow row; - try { - row = _segmentTable.AsEnumerable().First(r => { - var isValid = r.Field<string>("valid"); - var category = r.Field<string>("vehiclecategory"); - var axleConf = r.Field<string>("axleconf."); - var massMin = r.ParseDouble("gvw_min").SI().Ton; - var massMax = r.ParseDouble("gvw_max").SI().Ton; - return (considerInvalid || isValid == "1") - && category == vehicleCategory.ToString() - && axleConf == axleConfiguration.GetName() - // MK 2016-06-07: normally the next condition should be "mass > massMin", except for 7.5t where is should be ">=" - // in any case ">=" is also correct, because the segment table is sorted by weight. - && massMin <= grossVehicleMassRating && grossVehicleMassRating <= massMax; - }); - } catch (InvalidOperationException e) { - var errorMessage = string.Format(ErrorMessage, vehicleCategory, axleConfiguration.GetName(), - grossVehicleMassRating); - Log.Fatal(errorMessage); - throw new VectoException(errorMessage, e); - } - return row; - } - - public Meter LookupHeight(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, - Kilogram grossVehicleMassRating) - { - var row = GetSegmentDataRow(vehicleCategory, axleConfiguration, grossVehicleMassRating, true); - - var vehicleHeight = row.ParseDouble("height").SI<Meter>(); - var vehicleClass = VehicleClassHelper.Parse(row.Field<string>("hdvclass")); - - if (vehicleClass == VehicleClass.Class9) { - // VECTO-471: for class 9 take similar height than rigid with same maximum gross vehicle weight (class 1, 2, 3 or 4). - var rigidGVWrow = _segmentTable.AsEnumerable().FirstOrDefault(r => { - var massMin = r.ParseDouble("gvw_min").SI().Ton; - var massMax = r.ParseDouble("gvw_max").SI().Ton; - return new[] { "1", "2", "3", "4" }.Contains(r.Field<string>("hdvclass")) - && massMin <= grossVehicleMassRating && grossVehicleMassRating <= massMax; - }); - if (rigidGVWrow != null) { - vehicleHeight = rigidGVWrow.ParseDouble("height").SI<Meter>(); - } - } - - return vehicleHeight; - } - +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.Declaration +{ + public sealed class Segments : LookupData<VehicleCategory, AxleConfiguration, Kilogram, Kilogram, Segment> + { + private DataTable _segmentTable; + + protected override string ResourceId + { + get { return DeclarationData.DeclarationDataResourcePrefix + ".SegmentTable.csv"; } + } + + protected override string ErrorMessage + { + get { + return + "ERROR: Could not find the declaration segment for vehicle. Category: {0}, AxleConfiguration: {1}, GrossVehicleWeight: {2}"; + } + } + + protected override void ParseData(DataTable table) + { + _segmentTable = table.Copy(); + } + + public override Segment Lookup(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, + Kilogram grossVehicleMassRating, Kilogram curbWeight) + { + return Lookup(vehicleCategory, axleConfiguration, grossVehicleMassRating, curbWeight, false); + } + + public Segment Lookup(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, + Kilogram grossVehicleMassRating, Kilogram curbWeight, bool considerInvalid) + { + if (grossVehicleMassRating == null || grossVehicleMassRating < 7.5.SI().Ton) { + throw new VectoException("Gross vehicle mass must be greater than 7.5 tons"); + } + + var row = GetSegmentDataRow(vehicleCategory, axleConfiguration, grossVehicleMassRating, considerInvalid); + + var segment = new Segment { + GrossVehicleWeightMin = row.ParseDouble("gvw_min").SI().Ton.Cast<Kilogram>(), + GrossVehicleWeightMax = row.ParseDouble("gvw_max").SI().Ton.Cast<Kilogram>(), + VehicleCategory = vehicleCategory, + AxleConfiguration = axleConfiguration, + VehicleClass = VehicleClassHelper.Parse(row.Field<string>("hdvclass")), + AccelerationFile = + RessourceHelper.ReadStream(DeclarationData.DeclarationDataResourcePrefix + ".VACC." + + row.Field<string>(".vaccfile")), + Missions = CreateMissions(ref grossVehicleMassRating, curbWeight, row), + VehicleHeight = LookupHeight(vehicleCategory, axleConfiguration, grossVehicleMassRating), + DesignSpeed = row.ParseDouble("designspeed").KMPHtoMeterPerSecond(), + GrossVehicleMassRating = grossVehicleMassRating, + CdADefault = row.ParseDouble("cdxa_default").SI<SquareMeter>(), + CdAConstruction = string.IsNullOrEmpty(row["cdxa_construction"].ToString()) + ? null + : row.ParseDouble("cdxa_construction").SI<SquareMeter>(), + MunicipalBodyWeight = string.IsNullOrEmpty(row["bodyweight_municipalutility"].ToString()) + ? null + : row.ParseDouble("bodyweight_municipalutility").SI<Kilogram>() + }; + + return segment; + } + + private DataRow GetSegmentDataRow(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, + Kilogram grossVehicleMassRating, bool considerInvalid) + { + DataRow row; + try { + row = _segmentTable.AsEnumerable().First(r => { + var isValid = r.Field<string>("valid"); + var category = r.Field<string>("vehiclecategory"); + var axleConf = r.Field<string>("axleconf."); + var massMin = r.ParseDouble("gvw_min").SI().Ton; + var massMax = r.ParseDouble("gvw_max").SI().Ton; + return (considerInvalid || isValid == "1") + && category == vehicleCategory.ToString() + && axleConf == axleConfiguration.GetName() + // MK 2016-06-07: normally the next condition should be "mass > massMin", except for 7.5t where is should be ">=" + // in any case ">=" is also correct, because the segment table is sorted by weight. + && massMin <= grossVehicleMassRating && grossVehicleMassRating <= massMax; + }); + } catch (InvalidOperationException e) { + var errorMessage = string.Format(ErrorMessage, vehicleCategory, axleConfiguration.GetName(), + grossVehicleMassRating); + Log.Fatal(errorMessage); + throw new VectoException(errorMessage, e); + } + return row; + } + + public Meter LookupHeight(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, + Kilogram grossVehicleMassRating) + { + var row = GetSegmentDataRow(vehicleCategory, axleConfiguration, grossVehicleMassRating, true); + + var vehicleHeight = row.ParseDouble("height").SI<Meter>(); + var vehicleClass = VehicleClassHelper.Parse(row.Field<string>("hdvclass")); + + if (vehicleClass == VehicleClass.Class9) { + // VECTO-471: for class 9 take similar height than rigid with same maximum gross vehicle weight (class 1, 2, 3 or 4). + var rigidGVWrow = _segmentTable.AsEnumerable().FirstOrDefault(r => { + var massMin = r.ParseDouble("gvw_min").SI().Ton; + var massMax = r.ParseDouble("gvw_max").SI().Ton; + return new[] { "1", "2", "3", "4" }.Contains(r.Field<string>("hdvclass")) + && massMin <= grossVehicleMassRating && grossVehicleMassRating <= massMax; + }); + if (rigidGVWrow != null) { + vehicleHeight = rigidGVWrow.ParseDouble("height").SI<Meter>(); + } + } + + return vehicleHeight; + } + /// <summary> /// Looks up the default CdxA value for the cross wind correction. /// </summary> @@ -165,143 +165,143 @@ namespace TUGraz.VectoCore.Models.Declaration return row.SI<SquareMeter>("cdxa_default"); } - private static Mission[] CreateMissions(ref Kilogram grossVehicleWeight, Kilogram curbWeight, DataRow row) - { - var missionTypes = Enum.GetValues(typeof(MissionType)).Cast<MissionType>(); - var missions = new List<Mission>(); - foreach (var missionType in missionTypes.Where(m => row.Field<string>(m.ToString()) != "-")) { - var body = DeclarationData.StandardBodies.Lookup(row.Field<string>("body")); - - var maxGVW = Constants.SimulationSettings.MaximumGrossVehicleWeight; - var trailers = new List<MissionTrailer>(); - if (missionType.IsEMS()) { - maxGVW = Constants.SimulationSettings.MaximumGrossVehicleWeightEMS; - var trailerList = row.Field<string>("ems").Split('+'); - var trailerWeightShares = row.Field<string>("traileraxles" + GetMissionSuffix(missionType)).Split('/'); - if (trailerList.Length != trailerWeightShares.Length) { - throw new VectoException( - "Error in segmentation table: number of trailers and list of weight shares does not match!"); - } - trailers.AddRange( - trailerWeightShares.Select((t, i) => CreateTrailer(trailerList[i], t.ToDouble() / 100.0, i == 0))); - } else { - if (ShouldTrailerBeUsed(row, missionType)) { - var trailerValue = row.Field<string>("trailer"); - if (string.IsNullOrWhiteSpace(trailerValue)) { - throw new VectoException("Error in segmentation table: trailer weight share is defined but not trailer type!"); - } - trailers.Add(CreateTrailer(trailerValue, GetTrailerAxleWeightDistribution(row, missionType), true)); - } - } - - //var semiTrailerField = row.Field<string>("semitrailer"); - //var semiTrailer = !string.IsNullOrWhiteSpace(semiTrailerField) - // ? DeclarationData.StandardBodies.Lookup(semiTrailerField) - // : StandardBodies.Empty; - - //trailer += semiTrailer; - - // limit gvw to MaxGVW (40t) - var gvw = - VectoMath.Min( - grossVehicleWeight + trailers.Sum(t => t.TrailerGrossVehicleWeight).DefaultIfNull(0), - maxGVW); - var maxLoad = gvw - curbWeight - body.CurbWeight - - trailers.Sum(t => t.TrailerCurbWeight).DefaultIfNull(0); - - var payloads = row.Field<string>(missionType.ToString()).Split('/'); - Kilogram refLoad, lowLoad = 0.SI<Kilogram>(); - if (payloads.Length == 2) { - lowLoad = GetLoading(payloads[0], grossVehicleWeight, trailers, true); - refLoad = GetLoading(payloads[1], grossVehicleWeight, trailers, false); - } else { - refLoad = GetLoading(row.Field<string>(missionType.ToString()), grossVehicleWeight, trailers, false); - } - - refLoad = refLoad.LimitTo(0.SI<Kilogram>(), maxLoad); - lowLoad = lowLoad.LimitTo(0.SI<Kilogram>(), maxLoad); - - var mission = new Mission { - MissionType = missionType, - CrossWindCorrectionParameters = row.Field<string>("crosswindcorrection" + GetMissionSuffix(missionType, true)), - CycleFile = - RessourceHelper.ReadStream(DeclarationData.DeclarationDataResourcePrefix + ".MissionCycles." + - missionType.ToString().Replace("EMS", "") + - Constants.FileExtensions.CycleFile), - AxleWeightDistribution = GetAxleWeightDistribution(row, missionType), - BodyCurbWeight = body.CurbWeight, - Trailer = trailers, - MinLoad = 0.SI<Kilogram>(), - MaxLoad = maxLoad, - RefLoad = refLoad, - LowLoad = lowLoad, - TotalCargoVolume = body.CargoVolume + trailers.Sum(t => t.CargoVolume).DefaultIfNull(0), - }; - missions.Add(mission); - } - return missions.ToArray(); - } - - private static Kilogram GetLoading(string payloadStr, Kilogram grossVehicleWeight, - IEnumerable<MissionTrailer> trailers, bool lowLoading) - { - var refLoadValue = payloadStr.ToDouble(double.NaN); - if (double.IsNaN(refLoadValue)) { - return DeclarationData.GetPayloadForGrossVehicleWeight(grossVehicleWeight, payloadStr) + - trailers.Sum( - t => DeclarationData.GetPayloadForTrailerWeight(t.TrailerGrossVehicleWeight, t.TrailerCurbWeight, lowLoading)) - .DefaultIfNull(0); - } - return refLoadValue.SI<Kilogram>(); - } - - /// <summary> - /// Checks if a trailer should be used for the current missionType. - /// </summary> - private static bool ShouldTrailerBeUsed(DataRow row, MissionType missionType) - { - return !string.IsNullOrWhiteSpace(row.Field<string>("traileraxles" + GetMissionSuffix(missionType))); - } - - private static double GetTrailerAxleWeightDistribution(DataRow row, MissionType missionType) - { - var trailerAxles = - row.Field<string>("traileraxles" + GetMissionSuffix(missionType)); - if (!string.IsNullOrWhiteSpace(trailerAxles)) { - return trailerAxles.ToDouble() / 100.0; - } - return 0; - } - - private static double[] GetAxleWeightDistribution(DataRow row, MissionType missionType) - { - return - row.Field<string>("truckaxles" + GetMissionSuffix(missionType)) - .Split('/').ToDouble().Select(x => x / 100.0).ToArray(); - } - - private static string GetMissionSuffix(MissionType missionType, bool ignoreEMS = false) - { - return "-" + - (missionType.IsEMS() && ignoreEMS - ? "" - : (missionType.GetNonEMSMissionType() == MissionType.LongHaul ? "longhaul" : "other")) + - (missionType.IsEMS() ? "ems" : ""); - } - - private static MissionTrailer CreateTrailer(string trailerValue, double axleWeightShare, bool firstTrailer) - { - var trailerType = TrailterTypeHelper.Parse(trailerValue); - var trailer = DeclarationData.StandardBodies.Lookup(trailerType.ToString()); - return new MissionTrailer { - TrailerType = trailerType, - TrailerWheels = trailer.Wheels, - TrailerAxleWeightShare = axleWeightShare, - TrailerCurbWeight = trailer.CurbWeight, - TrailerGrossVehicleWeight = trailer.GrossVehicleWeight, - DeltaCdA = trailer.DeltaCrossWindArea[firstTrailer ? 0 : 1], - CargoVolume = trailer.CargoVolume - }; - } - } + private static Mission[] CreateMissions(ref Kilogram grossVehicleWeight, Kilogram curbWeight, DataRow row) + { + var missionTypes = Enum.GetValues(typeof(MissionType)).Cast<MissionType>(); + var missions = new List<Mission>(); + foreach (var missionType in missionTypes.Where(m => row.Field<string>(m.ToString()) != "-")) { + var body = DeclarationData.StandardBodies.Lookup(row.Field<string>("body")); + + var maxGVW = Constants.SimulationSettings.MaximumGrossVehicleWeight; + var trailers = new List<MissionTrailer>(); + if (missionType.IsEMS()) { + maxGVW = Constants.SimulationSettings.MaximumGrossVehicleWeightEMS; + var trailerList = row.Field<string>("ems").Split('+'); + var trailerWeightShares = row.Field<string>("traileraxles" + GetMissionSuffix(missionType)).Split('/'); + if (trailerList.Length != trailerWeightShares.Length) { + throw new VectoException( + "Error in segmentation table: number of trailers and list of weight shares does not match!"); + } + trailers.AddRange( + trailerWeightShares.Select((t, i) => CreateTrailer(trailerList[i], t.ToDouble() / 100.0, i == 0))); + } else { + if (ShouldTrailerBeUsed(row, missionType)) { + var trailerValue = row.Field<string>("trailer"); + if (string.IsNullOrWhiteSpace(trailerValue)) { + throw new VectoException("Error in segmentation table: trailer weight share is defined but not trailer type!"); + } + trailers.Add(CreateTrailer(trailerValue, GetTrailerAxleWeightDistribution(row, missionType), true)); + } + } + + //var semiTrailerField = row.Field<string>("semitrailer"); + //var semiTrailer = !string.IsNullOrWhiteSpace(semiTrailerField) + // ? DeclarationData.StandardBodies.Lookup(semiTrailerField) + // : StandardBodies.Empty; + + //trailer += semiTrailer; + + // limit gvw to MaxGVW (40t) + var gvw = + VectoMath.Min( + grossVehicleWeight + trailers.Sum(t => t.TrailerGrossVehicleWeight).DefaultIfNull(0), + maxGVW); + var maxLoad = gvw - curbWeight - body.CurbWeight - + trailers.Sum(t => t.TrailerCurbWeight).DefaultIfNull(0); + + var payloads = row.Field<string>(missionType.ToString()).Split('/'); + Kilogram refLoad, lowLoad = 0.SI<Kilogram>(); + if (payloads.Length == 2) { + lowLoad = GetLoading(payloads[0], grossVehicleWeight, trailers, true); + refLoad = GetLoading(payloads[1], grossVehicleWeight, trailers, false); + } else { + refLoad = GetLoading(row.Field<string>(missionType.ToString()), grossVehicleWeight, trailers, false); + } + + refLoad = refLoad.LimitTo(0.SI<Kilogram>(), maxLoad); + lowLoad = lowLoad.LimitTo(0.SI<Kilogram>(), maxLoad); + + var mission = new Mission { + MissionType = missionType, + CrossWindCorrectionParameters = row.Field<string>("crosswindcorrection" + GetMissionSuffix(missionType, true)), + CycleFile = + RessourceHelper.ReadStream(DeclarationData.DeclarationDataResourcePrefix + ".MissionCycles." + + missionType.ToString().Replace("EMS", "") + + Constants.FileExtensions.CycleFile), + AxleWeightDistribution = GetAxleWeightDistribution(row, missionType), + BodyCurbWeight = body.CurbWeight, + Trailer = trailers, + MinLoad = 0.SI<Kilogram>(), + MaxLoad = maxLoad, + RefLoad = refLoad, + LowLoad = lowLoad, + TotalCargoVolume = body.CargoVolume + trailers.Sum(t => t.CargoVolume).DefaultIfNull(0), + }; + missions.Add(mission); + } + return missions.ToArray(); + } + + private static Kilogram GetLoading(string payloadStr, Kilogram grossVehicleWeight, + IEnumerable<MissionTrailer> trailers, bool lowLoading) + { + var refLoadValue = payloadStr.ToDouble(double.NaN); + if (double.IsNaN(refLoadValue)) { + return DeclarationData.GetPayloadForGrossVehicleWeight(grossVehicleWeight, payloadStr) + + trailers.Sum( + t => DeclarationData.GetPayloadForTrailerWeight(t.TrailerGrossVehicleWeight, t.TrailerCurbWeight, lowLoading)) + .DefaultIfNull(0); + } + return refLoadValue.SI<Kilogram>(); + } + + /// <summary> + /// Checks if a trailer should be used for the current missionType. + /// </summary> + private static bool ShouldTrailerBeUsed(DataRow row, MissionType missionType) + { + return !string.IsNullOrWhiteSpace(row.Field<string>("traileraxles" + GetMissionSuffix(missionType))); + } + + private static double GetTrailerAxleWeightDistribution(DataRow row, MissionType missionType) + { + var trailerAxles = + row.Field<string>("traileraxles" + GetMissionSuffix(missionType)); + if (!string.IsNullOrWhiteSpace(trailerAxles)) { + return trailerAxles.ToDouble() / 100.0; + } + return 0; + } + + private static double[] GetAxleWeightDistribution(DataRow row, MissionType missionType) + { + return + row.Field<string>("truckaxles" + GetMissionSuffix(missionType)) + .Split('/').ToDouble().Select(x => x / 100.0).ToArray(); + } + + private static string GetMissionSuffix(MissionType missionType, bool ignoreEMS = false) + { + return "-" + + (missionType.IsEMS() && ignoreEMS + ? "" + : (missionType.GetNonEMSMissionType() == MissionType.LongHaul ? "longhaul" : "other")) + + (missionType.IsEMS() ? "ems" : ""); + } + + private static MissionTrailer CreateTrailer(string trailerValue, double axleWeightShare, bool firstTrailer) + { + var trailerType = TrailterTypeHelper.Parse(trailerValue); + var trailer = DeclarationData.StandardBodies.Lookup(trailerType.ToString()); + return new MissionTrailer { + TrailerType = trailerType, + TrailerWheels = trailer.Wheels, + TrailerAxleWeightShare = axleWeightShare, + TrailerCurbWeight = trailer.CurbWeight, + TrailerGrossVehicleWeight = trailer.GrossVehicleWeight, + DeltaCdA = trailer.DeltaCrossWindArea[firstTrailer ? 0 : 1], + CargoVolume = trailer.CargoVolume + }; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/VehicleData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/VehicleData.cs index 49bcd6c601efeb2f4f8142e03cfe32712afa8bee..1d688b2e734e64862d201e3aba535b0a44a9427e 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/VehicleData.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/VehicleData.cs @@ -29,28 +29,28 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Data -{ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Data +{ [CustomValidation(typeof(AirdragData), "ValidateAirDragData")] - public class AirdragData : SimulationComponentData - { - public CrossWindCorrectionMode CrossWindCorrectionMode { get; set; } - - [Required, ValidateObject] - public ICrossWindCorrection CrossWindCorrectionCurve { get; internal set; } - - public SquareMeter DeclaredAirdragArea { get; internal set; } + public class AirdragData : SimulationComponentData + { + public CrossWindCorrectionMode CrossWindCorrectionMode { get; set; } + + [Required, ValidateObject] + public ICrossWindCorrection CrossWindCorrectionCurve { get; internal set; } + + public SquareMeter DeclaredAirdragArea { get; internal set; } // ReSharper disable once UnusedMember.Global -- used via Validation public static ValidationResult ValidateAirDragData(AirdragData airDragData, ValidationContext validationContext) @@ -62,229 +62,229 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data return ValidationResult.Success; } - } - - /// <summary> - /// Data Class for the Vehicle - /// </summary> - [CustomValidation(typeof(VehicleData), "ValidateVehicleData")] - public class VehicleData : SimulationComponentData - { - public string VIN { get; internal set; } - - public string LegislativeClass { get; internal set; } - - public VehicleCategory VehicleCategory { get; internal set; } - - public VehicleClass VehicleClass { get; internal set; } - - public AxleConfiguration AxleConfiguration { get; internal set; } - - public string ManufacturerAddress { get; internal set; } - - - [Required, ValidateObject] private List<Axle> _axleData; - - private KilogramSquareMeter _wheelsInertia; - private double? _totalRollResistanceCoefficient; - private double? _rollResistanceCoefficientWithoutTrailer; - - public List<Axle> AxleData - { - get { return _axleData; } - internal set { - _axleData = value; - _wheelsInertia = null; - _totalRollResistanceCoefficient = null; - } - } - - /// <summary> - /// The Curb Weight of the vehicle - /// (+ Curb Weight of Standard-Body if it has one) - /// (+ Curb Weight of Trailer if it has one) - /// </summary> - [Required, SIRange(500, 40000, emsMission: false), - SIRange(0, 60000, emsMission: true)] - public Kilogram CurbWeight { get; internal set; } - - /// <summary> - /// Curb Weight of Standard-Body (if it has one) - /// + Curb Weight of Trailer (if it has one) - /// </summary> - public Kilogram BodyAndTrailerWeight { get; internal set; } - - [Required, SIRange(0, 40000, emsMission: false), - SIRange(0, 60000, emsMission: true)] - public Kilogram Loading { get; internal set; } - - [SIRange(0, 500)] - public CubicMeter CargoVolume { get; internal set; } - - /// <summary> - /// The Gross Vehicle Weight of the Vehicle. - /// </summary> - [Required, - SIRange(3500, 40000, ExecutionMode.Declaration, emsMission: false), - SIRange(0, 60000, ExecutionMode.Declaration, emsMission: true), - SIRange(0, 1000000, ExecutionMode.Engineering)] - public Kilogram GrossVehicleWeight { get; internal set; } - - /// <summary> - /// The Gross Vehicle Weight of the Trailer (if the vehicle has one). - /// </summary> - [Required, SIRange(0, 40000, emsMission: false), - SIRange(0, 60000, emsMission: true)] - public Kilogram TrailerGrossVehicleWeight { get; internal set; } - - [Required, SIRange(0.1, 0.7)] - public Meter DynamicTyreRadius { get; internal set; } - - public KilogramSquareMeter WheelsInertia - { - get { - if (_wheelsInertia == null) { - ComputeRollResistanceAndReducedMassWheels(); - } - return _wheelsInertia; - } - internal set { _wheelsInertia = value; } - } - - //[Required, SIRange(0, 1E12)] - public double TotalRollResistanceCoefficient - { - get { - if (_totalRollResistanceCoefficient == null) { - ComputeRollResistanceAndReducedMassWheels(); - } - return _totalRollResistanceCoefficient.GetValueOrDefault(); - } - protected internal set { _totalRollResistanceCoefficient = value; } - } - - public double RollResistanceCoefficientWithoutTrailer - { - get { - if (_rollResistanceCoefficientWithoutTrailer == null) { - ComputeRollResistanceAndReducedMassWheels(); - } - return _rollResistanceCoefficientWithoutTrailer.GetValueOrDefault(); - } - protected internal set { _rollResistanceCoefficientWithoutTrailer = value; } - } - - public Kilogram TotalVehicleWeight - { - get { - var retVal = 0.0.SI<Kilogram>(); - retVal += CurbWeight ?? 0.SI<Kilogram>(); - retVal += BodyAndTrailerWeight ?? 0.SI<Kilogram>(); - retVal += Loading ?? 0.SI<Kilogram>(); - return retVal; - } - } - - public Kilogram TotalCurbWeight - { - get { return (CurbWeight ?? 0.SI<Kilogram>()) + (BodyAndTrailerWeight ?? 0.SI<Kilogram>()); } - } - - protected void ComputeRollResistanceAndReducedMassWheels() - { - if (TotalVehicleWeight == 0.SI<Kilogram>()) { - throw new VectoException("Total vehicle weight must be greater than 0! Set CurbWeight and Loading before!"); - } - if (DynamicTyreRadius == null) { - throw new VectoException("Dynamic tyre radius must be set before axles!"); - } - - var g = Physics.GravityAccelleration; - - var rrc = 0.0.SI<Scalar>(); - var rrcVehicle = 0.0.SI<Scalar>(); - - var wheelsInertia = 0.0.SI<KilogramSquareMeter>(); - var vehicleWeightShare = 0.0; - foreach (var axle in _axleData) { - if (axle.AxleWeightShare.IsEqual(0, 1e-12)) { - continue; - } - var nrWheels = axle.TwinTyres ? 4 : 2; - var baseValue = (axle.AxleWeightShare * TotalVehicleWeight * g / axle.TyreTestLoad / nrWheels).Value(); - - var rrcShare = axle.AxleWeightShare * axle.RollResistanceCoefficient * - Math.Pow(baseValue, Physics.RollResistanceExponent - 1); - - if (axle.AxleType != AxleType.Trailer) { - rrcVehicle += rrcShare; - vehicleWeightShare += axle.AxleWeightShare; - } - rrc += rrcShare; - wheelsInertia += nrWheels * axle.Inertia; - } - RollResistanceCoefficientWithoutTrailer = rrcVehicle / vehicleWeightShare; - TotalRollResistanceCoefficient = rrc; - WheelsInertia = wheelsInertia; - } - - // ReSharper disable once UnusedMember.Global -- used via Validation - public static ValidationResult ValidateVehicleData(VehicleData vehicleData, ValidationContext validationContext) - { - var mode = GetExecutionMode(validationContext); - var emsCycle = GetEmsMode(validationContext); - - if (vehicleData.AxleData.Count < 1) { - return new ValidationResult("At least two axles need to be specified"); - } - - var weightShareSum = vehicleData.AxleData.Sum(axle => axle.AxleWeightShare); - if (!weightShareSum.IsEqual(1.0, 1E-10)) { - return new ValidationResult( - string.Format("Sum of axle weight share is not 1! sum: {0}, difference: {1}", - weightShareSum, 1 - weightShareSum)); - } - for (var i = 0; i < vehicleData.AxleData.Count; i++) { - if (vehicleData.AxleData[i].TyreTestLoad.IsSmallerOrEqual(0)) { - return new ValidationResult(string.Format("Tyre test load (FzISO) for axle {0} must be greater than 0.", i)); - } - } - - if (vehicleData.TotalRollResistanceCoefficient <= 0) { - return - new ValidationResult(string.Format("Total rolling resistance must be greater than 0! {0}", - vehicleData.TotalRollResistanceCoefficient)); - } - - // total gvw is limited by max gvw (40t) - var gvwTotal = VectoMath.Min(vehicleData.GrossVehicleWeight + vehicleData.TrailerGrossVehicleWeight, - emsCycle - ? Constants.SimulationSettings.MaximumGrossVehicleWeightEMS - : Constants.SimulationSettings.MaximumGrossVehicleWeight); - if (mode != ExecutionMode.Declaration) { - return ValidationResult.Success; - } - // vvvvvvv these checks apply only for declaration mode! vvvvvv - - //if (vehicleData.AxleConfiguration.NumAxles() != vehicleData.AxleData.Count) { - // return - // new ValidationResult( - // string.Format("For a {0} type vehicle exactly {1} number of axles have to pe specified. Found {2}", - // vehicleData.AxleConfiguration.GetName(), vehicleData.AxleConfiguration.NumAxles(), vehicleData.AxleData.Count)); - //} - - if (vehicleData.TotalVehicleWeight > gvwTotal) { - return new ValidationResult( - string.Format("Total Vehicle Weight is greater than GrossVehicleWeight! Weight: {0}, GVW: {1}", - vehicleData.TotalVehicleWeight, gvwTotal)); - } - - var numDrivenAxles = vehicleData._axleData.Count(x => x.AxleType == AxleType.VehicleDriven); - if (numDrivenAxles != 1) { - return new ValidationResult("Exactly one axle has to be defined as driven!"); - } - - return ValidationResult.Success; - } - } + } + + /// <summary> + /// Data Class for the Vehicle + /// </summary> + [CustomValidation(typeof(VehicleData), "ValidateVehicleData")] + public class VehicleData : SimulationComponentData + { + public string VIN { get; internal set; } + + public string LegislativeClass { get; internal set; } + + public VehicleCategory VehicleCategory { get; internal set; } + + public VehicleClass VehicleClass { get; internal set; } + + public AxleConfiguration AxleConfiguration { get; internal set; } + + public string ManufacturerAddress { get; internal set; } + + + [Required, ValidateObject] private List<Axle> _axleData; + + private KilogramSquareMeter _wheelsInertia; + private double? _totalRollResistanceCoefficient; + private double? _rollResistanceCoefficientWithoutTrailer; + + public List<Axle> AxleData + { + get { return _axleData; } + internal set { + _axleData = value; + _wheelsInertia = null; + _totalRollResistanceCoefficient = null; + } + } + + /// <summary> + /// The Curb Weight of the vehicle + /// (+ Curb Weight of Standard-Body if it has one) + /// (+ Curb Weight of Trailer if it has one) + /// </summary> + [Required, SIRange(500, 40000, emsMission: false), + SIRange(0, 60000, emsMission: true)] + public Kilogram CurbWeight { get; internal set; } + + /// <summary> + /// Curb Weight of Standard-Body (if it has one) + /// + Curb Weight of Trailer (if it has one) + /// </summary> + public Kilogram BodyAndTrailerWeight { get; internal set; } + + [Required, SIRange(0, 40000, emsMission: false), + SIRange(0, 60000, emsMission: true)] + public Kilogram Loading { get; internal set; } + + [SIRange(0, 500)] + public CubicMeter CargoVolume { get; internal set; } + + /// <summary> + /// The Gross Vehicle Weight of the Vehicle. + /// </summary> + [Required, + SIRange(3500, 40000, ExecutionMode.Declaration, emsMission: false), + SIRange(0, 60000, ExecutionMode.Declaration, emsMission: true), + SIRange(0, 1000000, ExecutionMode.Engineering)] + public Kilogram GrossVehicleWeight { get; internal set; } + + /// <summary> + /// The Gross Vehicle Weight of the Trailer (if the vehicle has one). + /// </summary> + [Required, SIRange(0, 40000, emsMission: false), + SIRange(0, 60000, emsMission: true)] + public Kilogram TrailerGrossVehicleWeight { get; internal set; } + + [Required, SIRange(0.1, 0.7)] + public Meter DynamicTyreRadius { get; internal set; } + + public KilogramSquareMeter WheelsInertia + { + get { + if (_wheelsInertia == null) { + ComputeRollResistanceAndReducedMassWheels(); + } + return _wheelsInertia; + } + internal set { _wheelsInertia = value; } + } + + //[Required, SIRange(0, 1E12)] + public double TotalRollResistanceCoefficient + { + get { + if (_totalRollResistanceCoefficient == null) { + ComputeRollResistanceAndReducedMassWheels(); + } + return _totalRollResistanceCoefficient.GetValueOrDefault(); + } + protected internal set { _totalRollResistanceCoefficient = value; } + } + + public double RollResistanceCoefficientWithoutTrailer + { + get { + if (_rollResistanceCoefficientWithoutTrailer == null) { + ComputeRollResistanceAndReducedMassWheels(); + } + return _rollResistanceCoefficientWithoutTrailer.GetValueOrDefault(); + } + protected internal set { _rollResistanceCoefficientWithoutTrailer = value; } + } + + public Kilogram TotalVehicleWeight + { + get { + var retVal = 0.0.SI<Kilogram>(); + retVal += CurbWeight ?? 0.SI<Kilogram>(); + retVal += BodyAndTrailerWeight ?? 0.SI<Kilogram>(); + retVal += Loading ?? 0.SI<Kilogram>(); + return retVal; + } + } + + public Kilogram TotalCurbWeight + { + get { return (CurbWeight ?? 0.SI<Kilogram>()) + (BodyAndTrailerWeight ?? 0.SI<Kilogram>()); } + } + + protected void ComputeRollResistanceAndReducedMassWheels() + { + if (TotalVehicleWeight == 0.SI<Kilogram>()) { + throw new VectoException("Total vehicle weight must be greater than 0! Set CurbWeight and Loading before!"); + } + if (DynamicTyreRadius == null) { + throw new VectoException("Dynamic tyre radius must be set before axles!"); + } + + var g = Physics.GravityAccelleration; + + var rrc = 0.0.SI<Scalar>(); + var rrcVehicle = 0.0.SI<Scalar>(); + + var wheelsInertia = 0.0.SI<KilogramSquareMeter>(); + var vehicleWeightShare = 0.0; + foreach (var axle in _axleData) { + if (axle.AxleWeightShare.IsEqual(0, 1e-12)) { + continue; + } + var nrWheels = axle.TwinTyres ? 4 : 2; + var baseValue = (axle.AxleWeightShare * TotalVehicleWeight * g / axle.TyreTestLoad / nrWheels).Value(); + + var rrcShare = axle.AxleWeightShare * axle.RollResistanceCoefficient * + Math.Pow(baseValue, Physics.RollResistanceExponent - 1); + + if (axle.AxleType != AxleType.Trailer) { + rrcVehicle += rrcShare; + vehicleWeightShare += axle.AxleWeightShare; + } + rrc += rrcShare; + wheelsInertia += nrWheels * axle.Inertia; + } + RollResistanceCoefficientWithoutTrailer = rrcVehicle / vehicleWeightShare; + TotalRollResistanceCoefficient = rrc; + WheelsInertia = wheelsInertia; + } + + // ReSharper disable once UnusedMember.Global -- used via Validation + public static ValidationResult ValidateVehicleData(VehicleData vehicleData, ValidationContext validationContext) + { + var mode = GetExecutionMode(validationContext); + var emsCycle = GetEmsMode(validationContext); + + if (vehicleData.AxleData.Count < 1) { + return new ValidationResult("At least two axles need to be specified"); + } + + var weightShareSum = vehicleData.AxleData.Sum(axle => axle.AxleWeightShare); + if (!weightShareSum.IsEqual(1.0, 1E-10)) { + return new ValidationResult( + string.Format("Sum of axle weight share is not 1! sum: {0}, difference: {1}", + weightShareSum, 1 - weightShareSum)); + } + for (var i = 0; i < vehicleData.AxleData.Count; i++) { + if (vehicleData.AxleData[i].TyreTestLoad.IsSmallerOrEqual(0)) { + return new ValidationResult(string.Format("Tyre test load (FzISO) for axle {0} must be greater than 0.", i)); + } + } + + if (vehicleData.TotalRollResistanceCoefficient <= 0) { + return + new ValidationResult(string.Format("Total rolling resistance must be greater than 0! {0}", + vehicleData.TotalRollResistanceCoefficient)); + } + + // total gvw is limited by max gvw (40t) + var gvwTotal = VectoMath.Min(vehicleData.GrossVehicleWeight + vehicleData.TrailerGrossVehicleWeight, + emsCycle + ? Constants.SimulationSettings.MaximumGrossVehicleWeightEMS + : Constants.SimulationSettings.MaximumGrossVehicleWeight); + if (mode != ExecutionMode.Declaration) { + return ValidationResult.Success; + } + // vvvvvvv these checks apply only for declaration mode! vvvvvv + + //if (vehicleData.AxleConfiguration.NumAxles() != vehicleData.AxleData.Count) { + // return + // new ValidationResult( + // string.Format("For a {0} type vehicle exactly {1} number of axles have to pe specified. Found {2}", + // vehicleData.AxleConfiguration.GetName(), vehicleData.AxleConfiguration.NumAxles(), vehicleData.AxleData.Count)); + //} + + if (vehicleData.TotalVehicleWeight > gvwTotal) { + return new ValidationResult( + string.Format("Total Vehicle Weight is greater than GrossVehicleWeight! Weight: {0}, GVW: {1}", + vehicleData.TotalVehicleWeight, gvwTotal)); + } + + var numDrivenAxles = vehicleData._axleData.Count(x => x.AxleType == AxleType.VehicleDriven); + if (numDrivenAxles != 1) { + return new ValidationResult("Exactly one axle has to be defined as driven!"); + } + + return ValidationResult.Success; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs index 5a749e071ff0aa74a8cd1115e933cf0b33739515..57cdd58380c2ac56974b0496f08e483539a41728 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs @@ -29,228 +29,228 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -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.Simulation; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - public class Vehicle : StatefulProviderComponent<Vehicle.VehicleState, IDriverDemandOutPort, IFvInPort, IFvOutPort>, - IVehicle, IMileageCounter, IFvInPort, - IDriverDemandOutPort - { - internal readonly VehicleData ModelData; - - public readonly AirdragData AirdragData; - - - public Vehicle(IVehicleContainer container, VehicleData modelData, AirdragData airdrag) : base(container) - { - ModelData = modelData; - AirdragData = airdrag; - if (AirdragData.CrossWindCorrectionCurve != null) { - AirdragData.CrossWindCorrectionCurve.SetDataBus(container); - } - } - - - public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient) - { - PreviousState = new VehicleState { - Distance = DataBus.CycleStartDistance, - Velocity = vehicleSpeed, - RollingResistance = RollingResistance(roadGradient), - SlopeResistance = SlopeResistance(roadGradient), - AirDragResistance = AirDragResistance(vehicleSpeed, vehicleSpeed), - }; - PreviousState.VehicleTractionForce = PreviousState.RollingResistance - + PreviousState.AirDragResistance - + PreviousState.SlopeResistance; - - return NextComponent.Initialize(PreviousState.VehicleTractionForce, vehicleSpeed); - } - - public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient, MeterPerSquareSecond startAcceleration) - { - //CurrentState.Velocity = vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval; - var vehicleAccelerationForce = DriverAcceleration(startAcceleration) - + RollingResistance(roadGradient) - + - AirDragResistance(vehicleSpeed, - vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval) - + SlopeResistance(roadGradient); - - var retVal = NextComponent.Initialize(vehicleAccelerationForce, vehicleSpeed); - return retVal; - } - - public IResponse Request(Second absTime, Second dt, MeterPerSquareSecond acceleration, Radian gradient, - bool dryRun = false) - { - Log.Debug("Vehicle: acceleration: {0}", acceleration); - CurrentState.SimulationInterval = dt; - CurrentState.Acceleration = acceleration; - CurrentState.Velocity = PreviousState.Velocity + acceleration * dt; - if (CurrentState.Velocity.IsEqual(0.SI<MeterPerSecond>(), - Constants.SimulationSettings.VehicleSpeedHaltTolerance)) { - CurrentState.Velocity = 0.SI<MeterPerSecond>(); - } - CurrentState.Distance = PreviousState.Distance + PreviousState.Velocity * dt + acceleration * dt * dt / 2; - - CurrentState.DriverAcceleration = DriverAcceleration(acceleration); - CurrentState.RollingResistance = RollingResistance(gradient); - try { - CurrentState.AirDragResistance = AirDragResistance(PreviousState.Velocity, CurrentState.Velocity); - } catch (VectoException ex) { - Log.Warn("Exception during calculation of AirDragResistance: absTime: {0}, dist: {1}, v: {2}. {3}", absTime, - CurrentState.Distance, CurrentState.Velocity, ex); - CurrentState.AirDragResistance = AirDragResistance(VectoMath.Max(0, PreviousState.Velocity), - VectoMath.Max(0, CurrentState.Velocity)); - } - CurrentState.SlopeResistance = SlopeResistance(gradient); - - // DriverAcceleration = vehicleTractionForce - RollingResistance - AirDragResistance - SlopeResistance - CurrentState.VehicleTractionForce = CurrentState.DriverAcceleration - + CurrentState.RollingResistance - + CurrentState.AirDragResistance - + CurrentState.SlopeResistance; - - var retval = NextComponent.Request(absTime, dt, CurrentState.VehicleTractionForce, - CurrentState.Velocity, dryRun); - return retval; - } - - protected override void DoWriteModalResults(IModalDataContainer container) - { - var averageVelocity = (PreviousState.Velocity + CurrentState.Velocity) / 2.0; - - container[ModalResultField.v_act] = averageVelocity; - - container[ModalResultField.P_veh_inertia] = CurrentState.DriverAcceleration * averageVelocity; - container[ModalResultField.P_roll] = CurrentState.RollingResistance * averageVelocity; - container[ModalResultField.P_air] = CurrentState.AirDragResistance * averageVelocity; - container[ModalResultField.P_slope] = CurrentState.SlopeResistance * averageVelocity; - container[ModalResultField.P_trac] = CurrentState.VehicleTractionForce * averageVelocity; - - // sanity check: is the vehicle in step with the cycle? - if (container[ModalResultField.dist] == DBNull.Value) { - Log.Warn("Distance field is not set!"); - } else { - var distance = (SI)container[ModalResultField.dist]; - if (!distance.IsEqual(CurrentState.Distance)) { - Log.Warn("Vehicle Distance diverges from Cycle by {0} [m]. Distance: {1}", - (distance - CurrentState.Distance).Value(), distance); - } - } - } - - public Newton RollingResistance(Radian gradient) - { - var weight = ModelData.TotalVehicleWeight; - var gravity = Physics.GravityAccelleration; - var rollCoefficient = ModelData.TotalRollResistanceCoefficient; - - var retVal = Math.Cos(gradient.Value()) * weight * gravity * rollCoefficient; - Log.Debug("RollingResistance: {0}", retVal); - return retVal; - } - - protected internal Newton DriverAcceleration(MeterPerSquareSecond accelleration) - { - var retVal = ModelData.TotalVehicleWeight * accelleration; - Log.Debug("DriverAcceleration: {0}", retVal); - return retVal; - } - - public Newton SlopeResistance(Radian gradient) - { - var retVal = ModelData.TotalVehicleWeight * Physics.GravityAccelleration * Math.Sin(gradient.Value()); - Log.Debug("SlopeResistance: {0}", retVal); - return retVal; - } - - public Newton AirDragResistance(MeterPerSecond previousVelocity, MeterPerSecond nextVelocity) - { - var vAverage = (previousVelocity + nextVelocity) / 2; - if (vAverage.IsEqual(0)) { - return 0.SI<Newton>(); - } - var result = ComputeAirDragPowerLoss(previousVelocity, nextVelocity) / vAverage; - - Log.Debug("AirDragResistance: {0}", result); - return result; - } - - private Watt ComputeAirDragPowerLoss(MeterPerSecond v1, MeterPerSecond v2) - { - return AirdragData.CrossWindCorrectionCurve.AverageAirDragPowerLoss(v1, v2); - } - - public Meter Distance - { - get { return PreviousState.Distance; } - } - - public MeterPerSecond VehicleSpeed - { - get { return PreviousState.Velocity; } - } - - public bool VehicleStopped - { - get { return PreviousState.Velocity.IsEqual(0.SI<MeterPerSecond>(), 0.01.SI<MeterPerSecond>()); } - } - - public Kilogram VehicleMass - { - get { return ModelData.TotalCurbWeight; } - } - - public Kilogram VehicleLoading - { - get { return ModelData.Loading; } - } - - public Kilogram TotalMass - { - get { return ModelData.TotalVehicleWeight; } - } - - public CubicMeter CargoVolume - { - get { return ModelData.CargoVolume; } - } - - public class VehicleState - { - public Meter Distance = 0.SI<Meter>(); - public Second SimulationInterval = 0.SI<Second>(); - public Newton AirDragResistance = 0.SI<Newton>(); - public Newton DriverAcceleration = 0.SI<Newton>(); - public Newton RollingResistance = 0.SI<Newton>(); - public Newton SlopeResistance = 0.SI<Newton>(); - public Newton VehicleTractionForce = 0.SI<Newton>(); - public MeterPerSecond Velocity = 0.SI<MeterPerSecond>(); - public MeterPerSquareSecond Acceleration = 0.SI<MeterPerSquareSecond>(); - - public override string ToString() - { - return - string.Format( - "v: {0} a: {1}, dt: {2}, driver_acc: {3}, roll_res: {4}, slope_res: {5}, air_drag: {6}, traction force: {7}", - Velocity, Acceleration, SimulationInterval, DriverAcceleration, RollingResistance, SlopeResistance, - AirDragResistance, - VehicleTractionForce); - } - } - } +using System; +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.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public class Vehicle : StatefulProviderComponent<Vehicle.VehicleState, IDriverDemandOutPort, IFvInPort, IFvOutPort>, + IVehicle, IMileageCounter, IFvInPort, + IDriverDemandOutPort + { + internal readonly VehicleData ModelData; + + public readonly AirdragData AirdragData; + + + public Vehicle(IVehicleContainer container, VehicleData modelData, AirdragData airdrag) : base(container) + { + ModelData = modelData; + AirdragData = airdrag; + if (AirdragData.CrossWindCorrectionCurve != null) { + AirdragData.CrossWindCorrectionCurve.SetDataBus(container); + } + } + + + public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient) + { + PreviousState = new VehicleState { + Distance = DataBus.CycleStartDistance, + Velocity = vehicleSpeed, + RollingResistance = RollingResistance(roadGradient), + SlopeResistance = SlopeResistance(roadGradient), + AirDragResistance = AirDragResistance(vehicleSpeed, vehicleSpeed), + }; + PreviousState.VehicleTractionForce = PreviousState.RollingResistance + + PreviousState.AirDragResistance + + PreviousState.SlopeResistance; + + return NextComponent.Initialize(PreviousState.VehicleTractionForce, vehicleSpeed); + } + + public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient, MeterPerSquareSecond startAcceleration) + { + //CurrentState.Velocity = vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval; + var vehicleAccelerationForce = DriverAcceleration(startAcceleration) + + RollingResistance(roadGradient) + + + AirDragResistance(vehicleSpeed, + vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval) + + SlopeResistance(roadGradient); + + var retVal = NextComponent.Initialize(vehicleAccelerationForce, vehicleSpeed); + return retVal; + } + + public IResponse Request(Second absTime, Second dt, MeterPerSquareSecond acceleration, Radian gradient, + bool dryRun = false) + { + Log.Debug("Vehicle: acceleration: {0}", acceleration); + CurrentState.SimulationInterval = dt; + CurrentState.Acceleration = acceleration; + CurrentState.Velocity = PreviousState.Velocity + acceleration * dt; + if (CurrentState.Velocity.IsEqual(0.SI<MeterPerSecond>(), + Constants.SimulationSettings.VehicleSpeedHaltTolerance)) { + CurrentState.Velocity = 0.SI<MeterPerSecond>(); + } + CurrentState.Distance = PreviousState.Distance + PreviousState.Velocity * dt + acceleration * dt * dt / 2; + + CurrentState.DriverAcceleration = DriverAcceleration(acceleration); + CurrentState.RollingResistance = RollingResistance(gradient); + try { + CurrentState.AirDragResistance = AirDragResistance(PreviousState.Velocity, CurrentState.Velocity); + } catch (VectoException ex) { + Log.Warn("Exception during calculation of AirDragResistance: absTime: {0}, dist: {1}, v: {2}. {3}", absTime, + CurrentState.Distance, CurrentState.Velocity, ex); + CurrentState.AirDragResistance = AirDragResistance(VectoMath.Max(0, PreviousState.Velocity), + VectoMath.Max(0, CurrentState.Velocity)); + } + CurrentState.SlopeResistance = SlopeResistance(gradient); + + // DriverAcceleration = vehicleTractionForce - RollingResistance - AirDragResistance - SlopeResistance + CurrentState.VehicleTractionForce = CurrentState.DriverAcceleration + + CurrentState.RollingResistance + + CurrentState.AirDragResistance + + CurrentState.SlopeResistance; + + var retval = NextComponent.Request(absTime, dt, CurrentState.VehicleTractionForce, + CurrentState.Velocity, dryRun); + return retval; + } + + protected override void DoWriteModalResults(IModalDataContainer container) + { + var averageVelocity = (PreviousState.Velocity + CurrentState.Velocity) / 2.0; + + container[ModalResultField.v_act] = averageVelocity; + + container[ModalResultField.P_veh_inertia] = CurrentState.DriverAcceleration * averageVelocity; + container[ModalResultField.P_roll] = CurrentState.RollingResistance * averageVelocity; + container[ModalResultField.P_air] = CurrentState.AirDragResistance * averageVelocity; + container[ModalResultField.P_slope] = CurrentState.SlopeResistance * averageVelocity; + container[ModalResultField.P_trac] = CurrentState.VehicleTractionForce * averageVelocity; + + // sanity check: is the vehicle in step with the cycle? + if (container[ModalResultField.dist] == DBNull.Value) { + Log.Warn("Distance field is not set!"); + } else { + var distance = (SI)container[ModalResultField.dist]; + if (!distance.IsEqual(CurrentState.Distance)) { + Log.Warn("Vehicle Distance diverges from Cycle by {0} [m]. Distance: {1}", + (distance - CurrentState.Distance).Value(), distance); + } + } + } + + public Newton RollingResistance(Radian gradient) + { + var weight = ModelData.TotalVehicleWeight; + var gravity = Physics.GravityAccelleration; + var rollCoefficient = ModelData.TotalRollResistanceCoefficient; + + var retVal = Math.Cos(gradient.Value()) * weight * gravity * rollCoefficient; + Log.Debug("RollingResistance: {0}", retVal); + return retVal; + } + + protected internal Newton DriverAcceleration(MeterPerSquareSecond accelleration) + { + var retVal = ModelData.TotalVehicleWeight * accelleration; + Log.Debug("DriverAcceleration: {0}", retVal); + return retVal; + } + + public Newton SlopeResistance(Radian gradient) + { + var retVal = ModelData.TotalVehicleWeight * Physics.GravityAccelleration * Math.Sin(gradient.Value()); + Log.Debug("SlopeResistance: {0}", retVal); + return retVal; + } + + public Newton AirDragResistance(MeterPerSecond previousVelocity, MeterPerSecond nextVelocity) + { + var vAverage = (previousVelocity + nextVelocity) / 2; + if (vAverage.IsEqual(0)) { + return 0.SI<Newton>(); + } + var result = ComputeAirDragPowerLoss(previousVelocity, nextVelocity) / vAverage; + + Log.Debug("AirDragResistance: {0}", result); + return result; + } + + private Watt ComputeAirDragPowerLoss(MeterPerSecond v1, MeterPerSecond v2) + { + return AirdragData.CrossWindCorrectionCurve.AverageAirDragPowerLoss(v1, v2); + } + + public Meter Distance + { + get { return PreviousState.Distance; } + } + + public MeterPerSecond VehicleSpeed + { + get { return PreviousState.Velocity; } + } + + public bool VehicleStopped + { + get { return PreviousState.Velocity.IsEqual(0.SI<MeterPerSecond>(), 0.01.SI<MeterPerSecond>()); } + } + + public Kilogram VehicleMass + { + get { return ModelData.TotalCurbWeight; } + } + + public Kilogram VehicleLoading + { + get { return ModelData.Loading; } + } + + public Kilogram TotalMass + { + get { return ModelData.TotalVehicleWeight; } + } + + public CubicMeter CargoVolume + { + get { return ModelData.CargoVolume; } + } + + public class VehicleState + { + public Meter Distance = 0.SI<Meter>(); + public Second SimulationInterval = 0.SI<Second>(); + public Newton AirDragResistance = 0.SI<Newton>(); + public Newton DriverAcceleration = 0.SI<Newton>(); + public Newton RollingResistance = 0.SI<Newton>(); + public Newton SlopeResistance = 0.SI<Newton>(); + public Newton VehicleTractionForce = 0.SI<Newton>(); + public MeterPerSecond Velocity = 0.SI<MeterPerSecond>(); + public MeterPerSquareSecond Acceleration = 0.SI<MeterPerSquareSecond>(); + + public override string ToString() + { + return + string.Format( + "v: {0} a: {1}, dt: {2}, driver_acc: {3}, roll_res: {4}, slope_res: {5}, air_drag: {6}, traction force: {7}", + Velocity, Acceleration, SimulationInterval, DriverAcceleration, RollingResistance, SlopeResistance, + AirDragResistance, + VehicleTractionForce); + } + } + } } \ No newline at end of file