Skip to content

Commit

Permalink
editoast: add simulation summary and simulation endpoints for paced t…
Browse files Browse the repository at this point in the history
…rain

Signed-off-by: Youness CHRIFI ALAOUI <[email protected]>
  • Loading branch information
younesschrifi committed Mar 7, 2025
1 parent 28261be commit 03d6c19
Show file tree
Hide file tree
Showing 9 changed files with 454 additions and 160 deletions.
39 changes: 32 additions & 7 deletions editoast/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5140,9 +5140,10 @@ components:
- $ref: '#/components/schemas/EditoastOperationErrorInvalidPatch'
- $ref: '#/components/schemas/EditoastOperationErrorModifyId'
- $ref: '#/components/schemas/EditoastOperationErrorObjectNotFound'
- $ref: '#/components/schemas/EditoastPacedTrainErrorBatchPacedTrainNotFound'
- $ref: '#/components/schemas/EditoastPacedTrainErrorBatchNotFound'
- $ref: '#/components/schemas/EditoastPacedTrainErrorDatabase'
- $ref: '#/components/schemas/EditoastPacedTrainErrorPacedTrainNotFound'
- $ref: '#/components/schemas/EditoastPacedTrainErrorInfraNotFound'
- $ref: '#/components/schemas/EditoastPacedTrainErrorNotFound'
- $ref: '#/components/schemas/EditoastPaginationErrorInvalidPage'
- $ref: '#/components/schemas/EditoastPaginationErrorInvalidPageSize'
- $ref: '#/components/schemas/EditoastPathfindingErrorInfraNotFound'
Expand Down Expand Up @@ -5637,7 +5638,7 @@ components:
type: string
enum:
- editoast:operation:ObjectNotFound
EditoastPacedTrainErrorBatchPacedTrainNotFound:
EditoastPacedTrainErrorBatchNotFound:
type: object
required:
- type
Expand All @@ -5660,7 +5661,7 @@ components:
type:
type: string
enum:
- editoast:paced_train:BatchPacedTrainNotFound
- editoast:paced_train:BatchNotFound
EditoastPacedTrainErrorDatabase:
type: object
required:
Expand All @@ -5680,7 +5681,31 @@ components:
type: string
enum:
- editoast:paced_train:Database
EditoastPacedTrainErrorPacedTrainNotFound:
EditoastPacedTrainErrorInfraNotFound:
type: object
required:
- type
- status
- message
properties:
context:
type: object
required:
- infra_id
properties:
infra_id:
type: integer
message:
type: string
status:
type: integer
enum:
- 404
type:
type: string
enum:
- editoast:paced_train:InfraNotFound
EditoastPacedTrainErrorNotFound:
type: object
required:
- type
Expand All @@ -5703,7 +5728,7 @@ components:
type:
type: string
enum:
- editoast:paced_train:PacedTrainNotFound
- editoast:paced_train:NotFound
EditoastPaginationErrorInvalidPage:
type: object
required:
Expand Down Expand Up @@ -8570,7 +8595,7 @@ components:
timetable_id:
type: integer
format: int64
description: Timetable attached to the train schedule
description: Timetable attached to the paced train
nullable: true
PacedTrainResult:
allOf:
Expand Down
23 changes: 23 additions & 0 deletions editoast/src/models/paced_train.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::models::train_schedule::TrainSchedule;
use chrono::DateTime;
use chrono::Duration as ChronoDuration;
use chrono::Utc;
Expand Down Expand Up @@ -50,6 +51,28 @@ pub struct PacedTrain {
pub step: ChronoDuration,
}

impl PacedTrain {
pub fn into_first_occurrence(self) -> TrainSchedule {
TrainSchedule {
id: self.id,
train_name: self.train_name,
labels: self.labels.into(),
rolling_stock_name: self.rolling_stock_name,
timetable_id: self.timetable_id,
path: self.path,
start_time: self.start_time,
schedule: self.schedule,
margins: self.margins,
initial_speed: self.initial_speed,
comfort: self.comfort,
constraint_distribution: self.constraint_distribution,
speed_limit_tag: self.speed_limit_tag,
power_restrictions: self.power_restrictions,
options: self.options,
}
}
}

impl From<PacedTrainBase> for PacedTrainChangeset {
fn from(
PacedTrainBase {
Expand Down
109 changes: 109 additions & 0 deletions editoast/src/views/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ use crate::client::get_app_version;
use crate::core::mq_client;
use crate::core::pathfinding::PathfindingInputError;
use crate::core::pathfinding::PathfindingNotFound;
use crate::core::simulation::SimulationResponse;
use crate::core::version::CoreVersionRequest;
use crate::core::AsCoreRequest;
use crate::core::CoreClient;
Expand All @@ -93,6 +94,7 @@ use crate::map::MapLayers;
use crate::models;
use crate::models::auth::PgAuthDriver;
use crate::valkey_utils::ValkeyConfig;
use crate::views::path::pathfinding::PathfindingFailure;
use crate::ValkeyClient;

crate::routes! {
Expand Down Expand Up @@ -171,6 +173,7 @@ pub struct InfraIdQueryParam {
}

#[derive(Debug, Serialize, ToSchema)]
#[cfg_attr(test, derive(PartialEq, Deserialize))]
#[serde(tag = "status", rename_all = "snake_case")]
enum SimulationSummaryResult {
/// Minimal information on a simulation's result
Expand Down Expand Up @@ -201,6 +204,47 @@ enum SimulationSummaryResult {
PathfindingInputError(PathfindingInputError),
}

impl From<core::simulation::SimulationResponse> for SimulationSummaryResult {
fn from(sim:SimulationResponse) -> Self {
match sim {
SimulationResponse::Success {
final_output,
provisional,
base,
..
} => {
let report = final_output.report_train;
Self::Success {
length: *report.positions.last().unwrap(),
time: *report.times.last().unwrap(),
energy_consumption: report.energy_consumption,
path_item_times_final: report.path_item_times.clone(),
path_item_times_provisional: provisional.path_item_times.clone(),
path_item_times_base: base.path_item_times.clone(),
}
}
SimulationResponse::PathfindingFailed { pathfinding_failed } => match pathfinding_failed {
PathfindingFailure::InternalError { core_error } => {
Self::PathfindingFailure { core_error }
}

PathfindingFailure::PathfindingInputError(input_error) => {
Self::PathfindingInputError(input_error)
}

PathfindingFailure::PathfindingNotFound(not_found) => {
Self::PathfindingNotFound(not_found)
}
},
SimulationResponse::SimulationFailed { core_error } => {
Self::SimulationFailed {
error_type: core_error.get_type().into(),
}
}
}
}
}

/// Represents the bundle of information about the issuer of a request
/// that can be extracted form recognized headers.
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -662,6 +706,71 @@ mod tests {
use super::test_app::TestAppBuilder;
use crate::core::mocking::MockingClient;

#[cfg(test)]
pub fn mocked_core_pathfinding_sim_and_proj(train_id: i64) -> MockingClient {
let mut core = MockingClient::new();
core.stub("/v2/pathfinding/blocks")
.method(reqwest::Method::POST)
.response(StatusCode::OK)
.json(json!({
"blocks":[],
"routes": [],
"track_section_ranges": [],
"path_item_positions": [0,1,2,3],
"length": 1,
"status": "success"
}))
.finish();
core.stub("/v2/standalone_simulation")
.method(reqwest::Method::POST)
.response(StatusCode::OK)
.json(json!({
"status": "success",
"base": {
"positions": [],
"times": [],
"speeds": [],
"energy_consumption": 0.0,
"path_item_times": [0, 1000, 2000, 3000]
},
"provisional": {
"positions": [],
"times": [],
"speeds": [],
"energy_consumption": 0.0,
"path_item_times": [0, 1000, 2000, 3000]
},
"final_output": {
"positions": [0],
"times": [0],
"speeds": [],
"energy_consumption": 0.0,
"path_item_times": [0, 1000, 2000, 3000],
"signal_critical_positions": [],
"zone_updates": [],
"spacing_requirements": [],
"routing_requirements": []
},
"mrsp": {
"boundaries": [],
"values": []
},
"electrical_profiles": {
"boundaries": [],
"values": []
}
}))
.finish();
core.stub("/v2/signal_projection")
.method(reqwest::Method::POST)
.response(StatusCode::OK)
.json(json!({
"signal_updates": {train_id.to_string(): [] },
}))
.finish();
core
}

#[rstest]
async fn health() {
let app = TestAppBuilder::default_app();
Expand Down
Loading

0 comments on commit 03d6c19

Please sign in to comment.