diff --git a/editoast/Cargo.lock b/editoast/Cargo.lock index 376cc9a00c4..525430a9dc2 100644 --- a/editoast/Cargo.lock +++ b/editoast/Cargo.lock @@ -1371,6 +1371,7 @@ dependencies = [ "tracing", "tracing-opentelemetry", "tracing-subscriber", + "uom", "url", "utoipa", "uuid", @@ -1400,6 +1401,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.3", + "uom", "utoipa", ] @@ -1466,6 +1468,7 @@ dependencies = [ "serde_json", "strum", "thiserror 2.0.3", + "uom", "utoipa", "uuid", ] @@ -2846,6 +2849,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", + "serde", ] [[package]] @@ -2855,6 +2859,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", + "serde", ] [[package]] @@ -2892,6 +2897,7 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", + "serde", ] [[package]] @@ -5017,6 +5023,20 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "uom" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd36e5350a65d112584053ee91843955826bf9e56ec0d1351214e01f6d7cd9c" +dependencies = [ + "num-bigint", + "num-complex", + "num-rational", + "num-traits", + "serde", + "typenum", +] + [[package]] name = "url" version = "2.5.4" diff --git a/editoast/Cargo.toml b/editoast/Cargo.toml index 4fc8b4750da..40d6b5aa0b5 100644 --- a/editoast/Cargo.toml +++ b/editoast/Cargo.toml @@ -78,6 +78,7 @@ tracing = { version = "0.1.41", default-features = false, features = [ "attributes", "log", ] } +uom = { version = "0.36.0", features = ["serde"] } url = { version = "2.5.4", features = ["serde"] } urlencoding = "2.1.3" utoipa = { version = "4.2.3", features = ["chrono", "uuid"] } @@ -184,6 +185,7 @@ tracing-opentelemetry = { version = "0.28.0", default-features = false, features "tracing-log", ] } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +uom.workspace = true url.workspace = true utoipa.workspace = true uuid.workspace = true diff --git a/editoast/editoast_common/Cargo.toml b/editoast/editoast_common/Cargo.toml index 0b71df445b6..c6f66a1a448 100644 --- a/editoast/editoast_common/Cargo.toml +++ b/editoast/editoast_common/Cargo.toml @@ -11,6 +11,7 @@ rangemap.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true thiserror.workspace = true +uom.workspace = true utoipa.workspace = true [lints] diff --git a/editoast/editoast_common/src/hash_rounded_float.rs b/editoast/editoast_common/src/hash_rounded_float.rs index a341bfd6834..c011a62b28a 100644 --- a/editoast/editoast_common/src/hash_rounded_float.rs +++ b/editoast/editoast_common/src/hash_rounded_float.rs @@ -1,4 +1,10 @@ use std::hash::{Hash, Hasher}; +use uom::si::{ + acceleration::meter_per_second_squared, + f64::{Acceleration, Length, Velocity}, + length::meter, + velocity::meter_per_second, +}; /// Hash a float through a rounded integer value /// `hash_float<3,_>` means that the value is rounded to the nearest thousandth @@ -6,6 +12,24 @@ pub fn hash_float(value: &f64, state: &mut H) { ((value * 10i64.pow(T as u32) as f64).round() as i64).hash(state); } +/// Hash a length through a rounded integer value +/// `hash_length<3,_>` means that the value is rounded to the nearest thousandth +pub fn hash_length(value: &Length, state: &mut H) { + hash_float::(&value.get::(), state); +} + +/// Hash a acceleration through a rounded integer value +/// `hash_acceleration<3,_>` means that the value is rounded to the nearest thousandth +pub fn hash_acceleration(value: &Acceleration, state: &mut H) { + hash_float::(&value.get::(), state); +} + +/// Hash a velocity through a rounded integer value +/// `hash_velocity<3,_>` means that the value is rounded to the nearest thousandth +pub fn hash_velocity(value: &Velocity, state: &mut H) { + hash_float::(&value.get::(), state); +} + /// Hash a list of floats through a list of rounded integer value /// `hash_float_slice<3,_>` means that the values are rounded to the nearest thousandth pub fn hash_float_slice(value: &[f64], state: &mut H) { diff --git a/editoast/editoast_common/src/lib.rs b/editoast/editoast_common/src/lib.rs index c7e38d3b550..e92b2f006c0 100644 --- a/editoast/editoast_common/src/lib.rs +++ b/editoast/editoast_common/src/lib.rs @@ -3,8 +3,11 @@ mod hash_rounded_float; pub mod rangemap_utils; pub mod schemas; +pub use hash_rounded_float::hash_acceleration; pub use hash_rounded_float::hash_float; pub use hash_rounded_float::hash_float_slice; +pub use hash_rounded_float::hash_length; +pub use hash_rounded_float::hash_velocity; schemas! { geometry::schemas(), diff --git a/editoast/editoast_schemas/Cargo.toml b/editoast/editoast_schemas/Cargo.toml index 142b4c00e14..e033bfdf4fe 100644 --- a/editoast/editoast_schemas/Cargo.toml +++ b/editoast/editoast_schemas/Cargo.toml @@ -16,6 +16,7 @@ serde.workspace = true serde_json.workspace = true strum.workspace = true thiserror.workspace = true +uom.workspace = true utoipa.workspace = true uuid.workspace = true diff --git a/editoast/editoast_schemas/src/rolling_stock.rs b/editoast/editoast_schemas/src/rolling_stock.rs index 721788d29d8..51e63628b05 100644 --- a/editoast/editoast_schemas/src/rolling_stock.rs +++ b/editoast/editoast_schemas/src/rolling_stock.rs @@ -34,6 +34,7 @@ pub use towed_rolling_stock::TowedRollingStock; use serde::Deserialize; use serde::Serialize; use std::collections::HashMap; +use uom::si::f64::{Acceleration, Length, Velocity}; editoast_common::schemas! { effort_curves::schemas(), @@ -54,14 +55,14 @@ pub struct RollingStock { pub effort_curves: EffortCurves, pub base_power_class: Option, /// In m - pub length: f64, + pub length: Length, /// In m/s - pub max_speed: f64, - pub startup_time: f64, + pub max_speed: Velocity, + pub startup_time: f64, // What unit ? /// In m/s² - pub startup_acceleration: f64, + pub startup_acceleration: Acceleration, /// In m/s² - pub comfort_acceleration: f64, + pub comfort_acceleration: Acceleration, // The constant gamma braking coefficient used when NOT circulating // under ETCS/ERTMS signaling system in m/s^2 pub const_gamma: f64, diff --git a/editoast/editoast_schemas/src/rolling_stock/towed_rolling_stock.rs b/editoast/editoast_schemas/src/rolling_stock/towed_rolling_stock.rs index 4f549d59a15..3a6c174df20 100644 --- a/editoast/editoast_schemas/src/rolling_stock/towed_rolling_stock.rs +++ b/editoast/editoast_schemas/src/rolling_stock/towed_rolling_stock.rs @@ -1,3 +1,5 @@ +use uom::si::f64::{Acceleration, Length}; + use super::RollingResistancePerWeight; #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] @@ -8,11 +10,11 @@ pub struct TowedRollingStock { /// In kg pub mass: f64, /// In m - pub length: f64, + pub length: Length, /// In m/s² - pub comfort_acceleration: f64, + pub comfort_acceleration: Acceleration, /// In m/s² - pub startup_acceleration: f64, + pub startup_acceleration: Acceleration, pub inertia_coefficient: f64, pub rolling_resistance: RollingResistancePerWeight, /// The constant gamma braking coefficient used when NOT circulating diff --git a/editoast/src/core/simulation.rs b/editoast/src/core/simulation.rs index 2adc8789121..5b2e507d669 100644 --- a/editoast/src/core/simulation.rs +++ b/editoast/src/core/simulation.rs @@ -12,6 +12,7 @@ use editoast_schemas::train_schedule::ReceptionSignal; use editoast_schemas::train_schedule::TrainScheduleOptions; use serde::Deserialize; use serde::Serialize; +use uom::si::f64::{Acceleration, Length, Velocity}; use utoipa::ToSchema; use super::pathfinding::TrackRange; @@ -38,22 +39,21 @@ editoast_common::schemas! { pub struct PhysicsConsist { pub effort_curves: EffortCurves, pub base_power_class: Option, - /// Length of the rolling stock in mm - pub length: u64, - /// Maximum speed of the rolling stock in m/s - #[derivative(Hash(hash_with = "editoast_common::hash_float::<3,_>"))] - pub max_speed: f64, + /// Length of the rolling stock + #[derivative(Hash(hash_with = "editoast_common::hash_length::<3,_>"))] + pub length: Length, + /// Maximum speed of the rolling stock + #[derivative(Hash(hash_with = "editoast_common::hash_velocity::<3,_>"))] + pub max_speed: Velocity, // Time in ms pub startup_time: u64, - #[derivative(Hash(hash_with = "editoast_common::hash_float::<5,_>"))] - /// In m/s² - pub startup_acceleration: f64, - #[derivative(Hash(hash_with = "editoast_common::hash_float::<5,_>"))] - /// In m/s² - pub comfort_acceleration: f64, - #[derivative(Hash(hash_with = "editoast_common::hash_float::<5,_>"))] + #[derivative(Hash(hash_with = "editoast_common::hash_acceleration::<5,_>"))] + pub startup_acceleration: Acceleration, + #[derivative(Hash(hash_with = "editoast_common::hash_acceleration::<5,_>"))] + pub comfort_acceleration: Acceleration, /// The constant gamma braking coefficient used when NOT circulating /// under ETCS/ERTMS signaling system in m/s^2 + #[derivative(Hash(hash_with = "editoast_common::hash_float::<5,_>"))] pub const_gamma: f64, #[derivative(Hash(hash_with = "editoast_common::hash_float::<5,_>"))] pub inertia_coefficient: f64, @@ -76,9 +76,9 @@ pub struct PhysicsConsistParameters { /// In kg pub total_mass: Option, /// In m - pub total_length: Option, + pub total_length: Option, /// In m/s - pub max_speed: Option, + pub max_speed: Option, pub towed_rolling_stock: Option, pub traction_engine: RollingStock, } @@ -96,51 +96,41 @@ impl PhysicsConsistParameters { } impl PhysicsConsistParameters { - pub fn compute_length(&self) -> u64 { + pub fn compute_length(&self) -> Length { let towed_rolling_stock_length = self .towed_rolling_stock .as_ref() .map(|trs| trs.length) - .unwrap_or(0.0); - - let length = self - .total_length - .unwrap_or(self.traction_engine.length + towed_rolling_stock_length); - - // Convert m to mm - let length = length * 1000.0; + .unwrap_or_default(); - length.round() as u64 + self.total_length + .unwrap_or(self.traction_engine.length + towed_rolling_stock_length) } - pub fn compute_max_speed(&self) -> f64 { + pub fn compute_max_speed(&self) -> Velocity { self.max_speed - .map(|max_speed_parameter| { - f64::min(self.traction_engine.max_speed, max_speed_parameter) - }) + .map(|max_speed_parameter| self.traction_engine.max_speed.min(max_speed_parameter)) .unwrap_or(self.traction_engine.max_speed) } - pub fn compute_startup_acceleration(&self) -> f64 { + pub fn compute_startup_acceleration(&self) -> Acceleration { self.towed_rolling_stock .as_ref() .map(|towed_rolling_stock| { - f64::max( - self.traction_engine.startup_acceleration, - towed_rolling_stock.startup_acceleration, - ) + self.traction_engine + .startup_acceleration + .max(towed_rolling_stock.startup_acceleration) }) .unwrap_or(self.traction_engine.startup_acceleration) } - pub fn compute_comfort_acceleration(&self) -> f64 { + pub fn compute_comfort_acceleration(&self) -> Acceleration { self.towed_rolling_stock .as_ref() .map(|towed_rolling_stock| { - f64::min( - self.traction_engine.comfort_acceleration, - towed_rolling_stock.comfort_acceleration, - ) + self.traction_engine + .comfort_acceleration + .min(towed_rolling_stock.comfort_acceleration) }) .unwrap_or(self.traction_engine.comfort_acceleration) } @@ -499,6 +489,10 @@ impl SimulationResponse { mod tests { use editoast_schemas::rolling_stock::RollingResistance; use pretty_assertions::assert_eq; + use uom::si::acceleration::meter_per_second_squared; + use uom::si::f64::{Acceleration, Length, Velocity}; + use uom::si::length::{meter, millimeter}; + use uom::si::velocity::meter_per_second; use crate::models::fixtures::create_simple_rolling_stock; use crate::models::fixtures::create_towed_rolling_stock; @@ -507,9 +501,9 @@ mod tests { fn create_physics_consist() -> PhysicsConsistParameters { PhysicsConsistParameters { - total_length: Some(100.0), + total_length: Some(Length::new::(100.0)), total_mass: Some(50000.0), - max_speed: Some(22.0), + max_speed: Some(Velocity::new::(22.0)), towed_rolling_stock: Some(create_towed_rolling_stock()), traction_engine: create_simple_rolling_stock(), } @@ -518,20 +512,29 @@ mod tests { #[test] fn physics_consist_compute_length() { let mut physics_consist = create_physics_consist(); - physics_consist.total_length = Some(100.0); // m - physics_consist.traction_engine.length = 40.0; // m + physics_consist.total_length = Some(Length::new::(100.0)); + physics_consist.traction_engine.length = Length::new::(40.0); // We always take total_length - assert_eq!(physics_consist.compute_length(), 100000); + assert_eq!( + physics_consist.compute_length(), + Length::new::(100000.) + ); physics_consist.total_length = None; // When no total_length we take towed length + traction_engine length - assert_eq!(physics_consist.compute_length(), 70000); + assert_eq!( + physics_consist.compute_length(), + Length::new::(70000.) + ); physics_consist.total_length = None; physics_consist.towed_rolling_stock = None; // When no user specified length and towed rolling stock, we take traction_engine length - assert_eq!(physics_consist.compute_length(), 40000); + assert_eq!( + physics_consist.compute_length(), + Length::new::(40000.) + ); } #[test] @@ -556,19 +559,28 @@ mod tests { #[test] fn physics_consist_max_speed() { let mut physics_consist = create_physics_consist(); - physics_consist.max_speed = Some(20.0); // m/s - physics_consist.traction_engine.max_speed = 22.0; // m/s + physics_consist.max_speed = Some(Velocity::new::(20.0)); + physics_consist.traction_engine.max_speed = Velocity::new::(22.0); // We take the smallest max speed - assert_eq!(physics_consist.compute_max_speed(), 20.0); + assert_eq!( + physics_consist.compute_max_speed(), + Velocity::new::(20.0) + ); - physics_consist.max_speed = Some(25.0); // m/s - physics_consist.traction_engine.max_speed = 24.0; // m/s + physics_consist.max_speed = Some(Velocity::new::(25.0)); // m/s + physics_consist.traction_engine.max_speed = Velocity::new::(24.0); // m/s - assert_eq!(physics_consist.compute_max_speed(), 24.0); + assert_eq!( + physics_consist.compute_max_speed(), + Velocity::new::(24.0) + ); physics_consist.max_speed = None; - assert_eq!(physics_consist.compute_max_speed(), 24.0); + assert_eq!( + physics_consist.compute_max_speed(), + Velocity::new::(24.0) + ); } #[test] @@ -576,10 +588,16 @@ mod tests { let mut physics_consist = create_physics_consist(); // 0.06 // We take the biggest - assert_eq!(physics_consist.compute_startup_acceleration(), 0.06); + assert_eq!( + physics_consist.compute_startup_acceleration(), + Acceleration::new::(0.06) + ); physics_consist.towed_rolling_stock = None; - assert_eq!(physics_consist.compute_startup_acceleration(), 0.04); + assert_eq!( + physics_consist.compute_startup_acceleration(), + Acceleration::new::(0.04) + ); } #[test] @@ -587,10 +605,16 @@ mod tests { let mut physics_consist = create_physics_consist(); // 0.2 // We take the smallest - assert_eq!(physics_consist.compute_comfort_acceleration(), 0.1); + assert_eq!( + physics_consist.compute_comfort_acceleration(), + Acceleration::new::(0.1) + ); physics_consist.towed_rolling_stock = None; - assert_eq!(physics_consist.compute_comfort_acceleration(), 0.1); + assert_eq!( + physics_consist.compute_comfort_acceleration(), + Acceleration::new::(0.1) + ); } #[test] diff --git a/editoast/src/models/fixtures.rs b/editoast/src/models/fixtures.rs index 5a93f662aa3..fe4f485382d 100644 --- a/editoast/src/models/fixtures.rs +++ b/editoast/src/models/fixtures.rs @@ -21,6 +21,12 @@ use editoast_schemas::rolling_stock::TowedRollingStock; use editoast_schemas::train_schedule::TrainScheduleBase; use postgis_diesel::types::LineString; use serde_json::Value; +use uom::si::acceleration::meter_per_second_squared; +use uom::si::f64::Acceleration; +use uom::si::f64::Length; +use uom::si::f64::Velocity; +use uom::si::length::meter; +use uom::si::velocity::meter_per_second; use crate::infra_cache::operation::create::apply_create_operation; use crate::models::electrical_profiles::ElectricalProfileSet; @@ -227,10 +233,10 @@ pub fn create_towed_rolling_stock() -> TowedRollingStock { TowedRollingStock { name: "TOWED_ROLLING_STOCK".to_string(), label: "towed".to_string(), - mass: 50000.0, // kg - length: 30.0, // m - comfort_acceleration: 0.2, // In m/s² - startup_acceleration: 0.06, + mass: 50000.0, // kg + length: Length::new::(30.0), + comfort_acceleration: Acceleration::new::(0.2), + startup_acceleration: Acceleration::new::(0.06), inertia_coefficient: 1.05, rolling_resistance: RollingResistancePerWeight { rolling_resistance_type: "davis".to_string(), @@ -249,9 +255,9 @@ pub fn create_simple_rolling_stock() -> RollingStock { loading_gauge: LoadingGaugeType::G1, supported_signaling_systems: RollingStockSupportedSignalingSystems(vec![]), base_power_class: None, - comfort_acceleration: 0.1, // In m/s² + comfort_acceleration: Acceleration::new::(0.1), inertia_coefficient: 1.10, - startup_acceleration: 0.04, // In m/s² + startup_acceleration: Acceleration::new::(0.04), startup_time: 1.0, effort_curves: EffortCurves::default(), electrical_power_startup_time: None, @@ -268,9 +274,9 @@ pub fn create_simple_rolling_stock() -> RollingStock { B: 0.01, // In N/(m/s) C: 0.0005, // In N/(m/s)² }, - length: 140.0, // m - mass: 15000.0, // kg - max_speed: 20.0, // m/s + length: Length::new::(140.0), + mass: 15000.0, // kg + max_speed: Velocity::new::(20.0), } } diff --git a/editoast/src/models/rolling_stock_model.rs b/editoast/src/models/rolling_stock_model.rs index 43fcda323d6..a8a0db9c85b 100644 --- a/editoast/src/models/rolling_stock_model.rs +++ b/editoast/src/models/rolling_stock_model.rs @@ -13,6 +13,11 @@ use editoast_schemas::rolling_stock::RollingStockSupportedSignalingSystems; use power_restrictions::PowerRestriction; use serde::Deserialize; use serde::Serialize; +use uom::si::acceleration::meter_per_second_squared; +use uom::si::length::meter; +use uom::si::velocity::meter_per_second; + +use uom::si::f64::{Acceleration, Length, Velocity}; use utoipa::ToSchema; use validator::Validate; use validator::ValidationError; @@ -148,11 +153,15 @@ impl From for RollingStock { name: rolling_stock_model.name, effort_curves: rolling_stock_model.effort_curves, base_power_class: rolling_stock_model.base_power_class, - length: rolling_stock_model.length, - max_speed: rolling_stock_model.max_speed, + length: Length::new::(rolling_stock_model.length), + max_speed: Velocity::new::(rolling_stock_model.max_speed), startup_time: rolling_stock_model.startup_time, - startup_acceleration: rolling_stock_model.startup_acceleration, - comfort_acceleration: rolling_stock_model.comfort_acceleration, + startup_acceleration: Acceleration::new::( + rolling_stock_model.startup_acceleration, + ), + comfort_acceleration: Acceleration::new::( + rolling_stock_model.comfort_acceleration, + ), const_gamma: rolling_stock_model.const_gamma, inertia_coefficient: rolling_stock_model.inertia_coefficient, mass: rolling_stock_model.mass, @@ -176,11 +185,19 @@ impl From for RollingStockModelChangeset { .name(rolling_stock.name) .effort_curves(rolling_stock.effort_curves) .base_power_class(rolling_stock.base_power_class) - .length(rolling_stock.length) - .max_speed(rolling_stock.max_speed) + .length(rolling_stock.length.get::()) + .max_speed(rolling_stock.max_speed.get::()) .startup_time(rolling_stock.startup_time) - .startup_acceleration(rolling_stock.startup_acceleration) - .comfort_acceleration(rolling_stock.comfort_acceleration) + .startup_acceleration( + rolling_stock + .startup_acceleration + .get::(), + ) + .comfort_acceleration( + rolling_stock + .comfort_acceleration + .get::(), + ) .const_gamma(rolling_stock.const_gamma) .inertia_coefficient(rolling_stock.inertia_coefficient) .mass(rolling_stock.mass) diff --git a/editoast/src/models/towed_rolling_stock.rs b/editoast/src/models/towed_rolling_stock.rs index 12c458efb2d..47a634d9357 100644 --- a/editoast/src/models/towed_rolling_stock.rs +++ b/editoast/src/models/towed_rolling_stock.rs @@ -3,6 +3,9 @@ use editoast_schemas::rolling_stock::RollingResistancePerWeight; use editoast_schemas::rolling_stock::TowedRollingStock; use serde::Deserialize; use serde::Serialize; +use uom::si::acceleration::meter_per_second_squared; +use uom::si::f64::{Acceleration, Length}; +use uom::si::length::meter; use utoipa::ToSchema; use validator::Validate; @@ -23,10 +26,9 @@ pub struct TowedRollingStockModel { /// In kg pub mass: f64, - /// In m pub length: f64, - pub comfort_acceleration: f64, pub startup_acceleration: f64, + pub comfort_acceleration: f64, pub inertia_coefficient: f64, #[model(json)] pub rolling_resistance: RollingResistancePerWeight, @@ -42,9 +44,13 @@ impl From for TowedRollingStock { label: model.label, railjson_version: model.railjson_version, mass: model.mass, - length: model.length, - comfort_acceleration: model.comfort_acceleration, - startup_acceleration: model.startup_acceleration, + length: Length::new::(model.length), + comfort_acceleration: Acceleration::new::( + model.comfort_acceleration, + ), + startup_acceleration: Acceleration::new::( + model.startup_acceleration, + ), inertia_coefficient: model.inertia_coefficient, rolling_resistance: model.rolling_resistance, const_gamma: model.const_gamma, @@ -59,9 +65,17 @@ impl From for Changeset { .label(towed_rolling_stock.label) .railjson_version(towed_rolling_stock.railjson_version) .mass(towed_rolling_stock.mass) - .length(towed_rolling_stock.length) - .comfort_acceleration(towed_rolling_stock.comfort_acceleration) - .startup_acceleration(towed_rolling_stock.startup_acceleration) + .length(towed_rolling_stock.length.get::()) + .comfort_acceleration( + towed_rolling_stock + .comfort_acceleration + .get::(), + ) + .startup_acceleration( + towed_rolling_stock + .startup_acceleration + .get::(), + ) .inertia_coefficient(towed_rolling_stock.inertia_coefficient) .rolling_resistance(towed_rolling_stock.rolling_resistance) .const_gamma(towed_rolling_stock.const_gamma) diff --git a/editoast/src/views/rolling_stock/form.rs b/editoast/src/views/rolling_stock/form.rs index 32cacfef05e..8e369c17a8f 100644 --- a/editoast/src/views/rolling_stock/form.rs +++ b/editoast/src/views/rolling_stock/form.rs @@ -9,6 +9,10 @@ use editoast_schemas::rolling_stock::RollingStockSupportedSignalingSystems; use editoast_schemas::rolling_stock::ROLLING_STOCK_RAILJSON_VERSION; use serde::Deserialize; use serde::Serialize; +use uom::si::acceleration::meter_per_second_squared; +use uom::si::f64::{Acceleration, Length, Velocity}; +use uom::si::length::meter; +use uom::si::velocity::meter_per_second; use utoipa::ToSchema; use validator::Validate; use validator::ValidationError; @@ -25,11 +29,11 @@ pub struct RollingStockForm { pub effort_curves: EffortCurves, #[schema(example = "5", required)] pub base_power_class: Option, - pub length: f64, - pub max_speed: f64, + pub length: Length, + pub max_speed: Velocity, pub startup_time: f64, - pub startup_acceleration: f64, - pub comfort_acceleration: f64, + pub startup_acceleration: Acceleration, + pub comfort_acceleration: Acceleration, pub const_gamma: f64, pub inertia_coefficient: f64, pub mass: f64, @@ -61,11 +65,19 @@ impl From for Changeset { .name(rolling_stock.name) .effort_curves(rolling_stock.effort_curves) .base_power_class(rolling_stock.base_power_class) - .length(rolling_stock.length) - .max_speed(rolling_stock.max_speed) + .length(rolling_stock.length.get::()) + .max_speed(rolling_stock.max_speed.get::()) .startup_time(rolling_stock.startup_time) - .startup_acceleration(rolling_stock.startup_acceleration) - .comfort_acceleration(rolling_stock.comfort_acceleration) + .startup_acceleration( + rolling_stock + .startup_acceleration + .get::(), + ) + .comfort_acceleration( + rolling_stock + .comfort_acceleration + .get::(), + ) .const_gamma(rolling_stock.const_gamma) .inertia_coefficient(rolling_stock.inertia_coefficient) .mass(rolling_stock.mass) @@ -97,11 +109,15 @@ impl From for RollingStockForm { name: value.name, effort_curves: value.effort_curves, base_power_class: value.base_power_class, - length: value.length, - max_speed: value.max_speed, + length: Length::new::(value.length), + max_speed: Velocity::new::(value.max_speed), startup_time: value.startup_time, - startup_acceleration: value.startup_acceleration, - comfort_acceleration: value.comfort_acceleration, + startup_acceleration: Acceleration::new::( + value.startup_acceleration, + ), + comfort_acceleration: Acceleration::new::( + value.comfort_acceleration, + ), const_gamma: value.const_gamma, inertia_coefficient: value.inertia_coefficient, mass: value.mass, diff --git a/editoast/src/views/rolling_stock/light.rs b/editoast/src/views/rolling_stock/light.rs index 3fb925e3e66..3935d3eb126 100644 --- a/editoast/src/views/rolling_stock/light.rs +++ b/editoast/src/views/rolling_stock/light.rs @@ -17,6 +17,10 @@ use editoast_schemas::rolling_stock::RollingStockSupportedSignalingSystems; use itertools::Itertools; use serde::Serialize; use std::collections::HashMap; +use uom::si::acceleration::meter_per_second_squared; +use uom::si::f64::{Acceleration, Length, Velocity}; +use uom::si::length::meter; +use uom::si::velocity::meter_per_second; use utoipa::ToSchema; use super::RollingStockError; @@ -214,11 +218,11 @@ struct LightRollingStock { locked: bool, effort_curves: LightEffortCurves, base_power_class: Option, - length: f64, - max_speed: f64, + length: Length, + max_speed: Velocity, startup_time: f64, - startup_acceleration: f64, - comfort_acceleration: f64, + startup_acceleration: Acceleration, + comfort_acceleration: Acceleration, const_gamma: f64, inertia_coefficient: f64, mass: f64, @@ -263,11 +267,15 @@ impl From for LightRollingStock { locked, effort_curves: effort_curves.into(), base_power_class, - length, - max_speed, + length: Length::new::(length), + max_speed: Velocity::new::(max_speed), startup_time, - startup_acceleration, - comfort_acceleration, + startup_acceleration: Acceleration::new::( + startup_acceleration, + ), + comfort_acceleration: Acceleration::new::( + comfort_acceleration, + ), const_gamma, inertia_coefficient, mass, diff --git a/editoast/src/views/timetable/stdcm.rs b/editoast/src/views/timetable/stdcm.rs index 1abf7ef1ae3..672c8a0eb4f 100644 --- a/editoast/src/views/timetable/stdcm.rs +++ b/editoast/src/views/timetable/stdcm.rs @@ -458,6 +458,10 @@ mod tests { use rstest::rstest; use serde_json::json; use std::str::FromStr; + use uom::si::acceleration::meter_per_second_squared; + use uom::si::length::meter; + use uom::si::length::millimeter; + use uom::si::velocity::meter_per_second; use uuid::Uuid; use crate::core::conflict_detection::Conflict; @@ -484,10 +488,10 @@ mod tests { fn simulation_with_towed_rolling_stock_parameters() { let mut rolling_stock = create_simple_rolling_stock(); rolling_stock.mass = 100000.0; - rolling_stock.length = 20.0; + rolling_stock.length = Length::new::(20.0); rolling_stock.inertia_coefficient = 1.10; // m/s² - rolling_stock.comfort_acceleration = 0.1; - rolling_stock.startup_acceleration = 0.04; // m/s² + rolling_stock.comfort_acceleration = Acceleration::new::(0.1); + rolling_stock.startup_acceleration = Acceleration::new::(0.04); rolling_stock.rolling_resistance = RollingResistance { rolling_resistance_type: "davis".to_string(), A: 1.0, @@ -528,8 +532,8 @@ mod tests { fn simulation_with_parameters() { let simulation_parameters = PhysicsConsistParameters { total_mass: Some(123.0), - total_length: Some(455.0), - max_speed: Some(10.0), // m/s + total_length: Some(Length::new::(455.0)), + max_speed: Some(Velocity::new::(10.0)), towed_rolling_stock: None, traction_engine: create_simple_rolling_stock(), }; @@ -537,8 +541,11 @@ mod tests { let physics_consist: PhysicsConsist = simulation_parameters.into(); assert_eq!(physics_consist.mass, 123_u64); - assert_eq!(physics_consist.length, 455000_u64); // It should be converted in mm - assert_eq!(physics_consist.max_speed, 10_f64); // It should be in m/s + assert_eq!(physics_consist.length, Length::new::(455000.0)); // It should be converted in mm + assert_eq!( + physics_consist.max_speed, + Velocity::new::(10_f64) + ); // It should be in m/s } #[test] @@ -549,16 +556,20 @@ mod tests { let physics_consist: PhysicsConsist = simulation_parameters.into(); assert_eq!(physics_consist.mass, 15000_u64); - assert_eq!(physics_consist.length, 140000_u64); // It should be converted in mm - assert_eq!(physics_consist.max_speed, 20_f64); + assert_eq!(physics_consist.length, Length::new::(140000.)); // It should be converted in mm + assert_eq!( + physics_consist.max_speed, + Velocity::new::(20_f64) + ); } #[test] fn new_physics_rolling_stock_keeps_the_smallest_available_comfort_acceleration() { let mut rolling_stock = create_simple_rolling_stock(); let mut towed_rolling_stock = create_towed_rolling_stock(); - rolling_stock.comfort_acceleration = 0.2; - towed_rolling_stock.comfort_acceleration = 0.1; + rolling_stock.comfort_acceleration = Acceleration::new::(0.2); + towed_rolling_stock.comfort_acceleration = + Acceleration::new::(0.1); let mut simulation_parameters = PhysicsConsistParameters { max_speed: None, @@ -570,15 +581,23 @@ mod tests { let physics_consist: PhysicsConsist = simulation_parameters.clone().into(); - assert_eq!(physics_consist.comfort_acceleration, 0.1); + assert_eq!( + physics_consist.comfort_acceleration, + Acceleration::new::(0.1) + ); - simulation_parameters.traction_engine.comfort_acceleration = 0.2; - towed_rolling_stock.comfort_acceleration = 0.67; + simulation_parameters.traction_engine.comfort_acceleration = + Acceleration::new::(0.2); + towed_rolling_stock.comfort_acceleration = + Acceleration::new::(0.67); simulation_parameters.towed_rolling_stock = Some(towed_rolling_stock); let physics_consist: PhysicsConsist = simulation_parameters.into(); - assert_eq!(physics_consist.comfort_acceleration, 0.2); + assert_eq!( + physics_consist.comfort_acceleration, + Acceleration::new::(0.2) + ); } #[test] @@ -591,23 +610,31 @@ mod tests { traction_engine: create_simple_rolling_stock(), }; - simulation_parameters.traction_engine.startup_acceleration = 0.3; + simulation_parameters.traction_engine.startup_acceleration = + Acceleration::new::(0.3); if let Some(trs) = simulation_parameters.towed_rolling_stock.as_mut() { - trs.startup_acceleration = 0.45; + trs.startup_acceleration = Acceleration::new::(0.45); } let physics_consist: PhysicsConsist = simulation_parameters.clone().into(); - assert_eq!(physics_consist.startup_acceleration, 0.45); + assert_eq!( + physics_consist.startup_acceleration, + Acceleration::new::(0.45) + ); if let Some(trs) = simulation_parameters.towed_rolling_stock.as_mut() { - trs.startup_acceleration = 0.4; + trs.startup_acceleration = Acceleration::new::(0.4); } - simulation_parameters.traction_engine.startup_acceleration = 0.88; + simulation_parameters.traction_engine.startup_acceleration = + Acceleration::new::(0.88); let physics_consist: PhysicsConsist = simulation_parameters.into(); - assert_eq!(physics_consist.startup_acceleration, 0.88); + assert_eq!( + physics_consist.startup_acceleration, + Acceleration::new::(0.88) + ); } #[test] @@ -615,14 +642,17 @@ mod tests { let simulation_parameters = PhysicsConsistParameters { total_mass: None, total_length: None, - max_speed: Some(30.0), // m/s + max_speed: Some(Velocity::new::(30.0)), towed_rolling_stock: None, traction_engine: create_simple_rolling_stock(), }; let physics_consist: PhysicsConsist = simulation_parameters.into(); - assert_eq!(physics_consist.max_speed, 20_f64); + assert_eq!( + physics_consist.max_speed, + Velocity::new::(20_f64) + ); } fn pathfinding_result_success() -> PathfindingResult { diff --git a/editoast/src/views/timetable/stdcm/request.rs b/editoast/src/views/timetable/stdcm/request.rs index 5c3ef3bfbe2..f0bc4fa52b0 100644 --- a/editoast/src/views/timetable/stdcm/request.rs +++ b/editoast/src/views/timetable/stdcm/request.rs @@ -10,6 +10,8 @@ use editoast_schemas::train_schedule::PathItemLocation; use itertools::Itertools; use serde::Deserialize; use serde::Serialize; +use uom::si::f64::Length; +use uom::si::f64::Velocity; use utoipa::ToSchema; use crate::core::pathfinding::PathfindingInputError; @@ -104,9 +106,9 @@ pub(super) struct Request { /// Total mass of the consist in kg pub(super) total_mass: Option, /// Total length of the consist in meters - pub(super) total_length: Option, + pub(super) total_length: Option, /// Maximum speed of the consist in km/h - pub(super) max_speed: Option, + pub(super) max_speed: Option, pub(super) loading_gauge_type: Option, } diff --git a/editoast/src/views/train_schedule/projection.rs b/editoast/src/views/train_schedule/projection.rs index 8bfa58abdae..2a833c28941 100644 --- a/editoast/src/views/train_schedule/projection.rs +++ b/editoast/src/views/train_schedule/projection.rs @@ -320,7 +320,7 @@ async fn project_path( id, ProjectPathTrainResult { departure_time: train.start_time, - rolling_stock_length: (length * 1000.).round() as u64, + rolling_stock_length: (length * 1000.) as u64, cached, }, );