Skip to content

Commit 1eba10d

Browse files
committed
tests: add infra to test stdcm takeover setups
Signed-off-by: Eloi Charpentier <eloi.charpentier.42@gmail.com>
1 parent ecb261f commit 1eba10d

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

tests/infra-scripts/test_takeover.py

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#!/usr/bin/env python3
2+
from dataclasses import dataclass
3+
from typing import List
4+
5+
from railjson_generator import (
6+
ApplicableDirection,
7+
Direction,
8+
InfraBuilder,
9+
get_output_dir,
10+
)
11+
from railjson_generator.schema.infra.electrification import Electrification
12+
from railjson_generator.schema.infra.track_section import TrackSection
13+
14+
OUTPUT_DIR = get_output_dir()
15+
16+
# See https://github.com/OpenRailAssociation/osrd/issues/10570 for context
17+
# The goal of this infra is to test minimal takeover setups in STDCM
18+
#
19+
#
20+
# t.takeover
21+
# _>__>______>>__
22+
# t.1 / op.center \ t.3
23+
# op___>___>___>___>___s________>___op___s___>___>___>___>___>___op
24+
# op.start s.1 t.2 s.2 op.end
25+
#
26+
# op.* = operational point id
27+
# t.* = track id
28+
# s.* = switch id
29+
# > = signal
30+
#
31+
# Signals are placed roughly every 2km on t.1 and t.3.
32+
# Signal placements are described more accurately on t.takeover
33+
# in the signal array as comments.
34+
35+
36+
# GENERATE INFRA
37+
builder = InfraBuilder()
38+
39+
# Create operational points
40+
op_start = builder.add_operational_point("op.start", trigram="STA", uic=0, weight=1)
41+
op_center = builder.add_operational_point("op.center", trigram="CEN", uic=1, weight=0.5)
42+
op_takeover = builder.add_operational_point("op.takeover", trigram="TAK", uic=3, weight=0.5)
43+
op_end = builder.add_operational_point("op.end", trigram="END", uic=2, weight=1)
44+
45+
# Create track sections
46+
47+
t_1 = builder.add_track_section(length=20_000, label="t_1")
48+
t_2 = builder.add_track_section(length=2_000, label="t_2")
49+
t_takeover = builder.add_track_section(length=2_100, label="t_takeover")
50+
t_3 = builder.add_track_section(length=20_000, label="t_3")
51+
52+
# Add objects on tracks
53+
54+
op_start.add_part(t_1, 0)
55+
op_end.add_part(t_3, 20_000)
56+
op_center.add_part(t_2, 1_500)
57+
op_takeover.add_part(t_takeover, 1_500)
58+
t_1.add_buffer_stop(label="bf.1", position=0)
59+
t_3.add_buffer_stop(label="bf.3", position=20_000)
60+
61+
builder.infra.electrifications.append(Electrification("electrification_1500", "1500V", [t_1, t_2, t_3, t_takeover]))
62+
63+
speed_limit = builder.add_speed_section(30 / 3.6)
64+
speed_limit.add_track_range(t_takeover, 0, t_takeover.length, ApplicableDirection.BOTH)
65+
66+
# Signals
67+
68+
default_sight_distance = 400
69+
70+
71+
@dataclass
72+
class Signal:
73+
name: str
74+
track: TrackSection
75+
position: int
76+
is_route_delimiter: bool
77+
sight_distance: int = default_sight_distance
78+
79+
80+
raw_signals: List[Signal] = [
81+
Signal("s.2.1500", t_2, 1_500, False),
82+
Signal("s.takeover.start.1", t_takeover, 1, True),
83+
# start.1 -> start.2 : needs to be at least as long as the new train
84+
# (we still have constraints from the main path while the tail hasn't left)
85+
Signal("s.takeover.start.2", t_takeover, 500, True),
86+
# start.2 -> end.1 : where the engineering allowance happens.
87+
# Needs to be long enough to almost stop and speed up from/to the maximum
88+
# speed set on the takeover track (here 30km/h)
89+
Signal("s.takeover.end.1", t_takeover, 2_000 - default_sight_distance - 2, True, 0),
90+
# end.1 -> end.2 : stops the signal propagation to the main track
91+
Signal("s.takeover.end.2", t_takeover, 2_000 - default_sight_distance - 1, True, 0),
92+
# end.2 -> end of the takeover track : needs to be as long as the default
93+
# signal sight distance. We must not see the signals on the main track while
94+
# in the block used for the engineering allowance.
95+
]
96+
for offset in range(0, 20_000, 2_000):
97+
raw_signals.append(Signal(f"s.1.{offset}", t_1, offset, False))
98+
raw_signals.append(Signal(f"s.3.{offset}", t_3, offset, False))
99+
100+
signals = []
101+
for raw_signal in raw_signals:
102+
detector = raw_signal.track.add_detector(label=f"det.{raw_signal.name[2:]}", position=raw_signal.position)
103+
signal = raw_signal.track.add_signal(
104+
label=raw_signal.name,
105+
position=raw_signal.position,
106+
direction=Direction.START_TO_STOP,
107+
is_route_delimiter=raw_signal.is_route_delimiter,
108+
sight_distance=raw_signal.sight_distance,
109+
)
110+
signal.add_logical_signal("BAL", settings={"Nf": "true" if raw_signal.is_route_delimiter else "false"})
111+
signals.append(signal)
112+
113+
# Add links
114+
115+
s_1 = builder.add_point_switch(t_1.end(), t_2.begin(), t_takeover.begin(), label="s.1")
116+
s_2 = builder.add_point_switch(t_3.begin(), t_2.end(), t_takeover.end(), label="s.2")
117+
118+
# Set coordinates
119+
120+
lat_track_1 = 50
121+
lat_track_2 = 49.999
122+
123+
t_1.begin().set_coords(-0.12, lat_track_1)
124+
t_1.end().set_coords(-0.1, lat_track_1)
125+
t_2.begin().set_coords(-0.1, lat_track_1)
126+
t_2.end().set_coords(-0.09, lat_track_1)
127+
t_3.begin().set_coords(-0.09, lat_track_1)
128+
t_3.end().set_coords(-0.07, lat_track_1)
129+
130+
t_takeover.begin().set_coords(-0.1, lat_track_2)
131+
t_takeover.end().set_coords(-0.09, lat_track_2)
132+
133+
# Build infra
134+
infra = builder.build()
135+
136+
# Save railjson
137+
infra.save(OUTPUT_DIR / "infra.json")

0 commit comments

Comments
 (0)