Skip to content

Commit 5df99d8

Browse files
KhoyoSh099078
andcommitted
core: add a SubPhysicsPath implementation
This will be necessary to call the simulation on various sections of the path to handle consist changes. Co-authored-by: Loup Federico <16464925+Sh099078@users.noreply.github.com> Signed-off-by: Younes Khoudli <younes.khoudli@epita.fr>
1 parent d76057a commit 5df99d8

File tree

2 files changed

+254
-0
lines changed

2 files changed

+254
-0
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package fr.sncf.osrd.path.implementations
2+
3+
import com.google.common.collect.ImmutableRangeMap
4+
import fr.sncf.osrd.path.interfaces.Electrification
5+
import fr.sncf.osrd.path.interfaces.PhysicsPath
6+
import fr.sncf.osrd.utils.DistanceRangeMap
7+
import fr.sncf.osrd.utils.distanceRangeMapOf
8+
import fr.sncf.osrd.utils.units.meters
9+
10+
class SubPhysicsPath(val begin: Double, val end: Double, val path: PhysicsPath) : PhysicsPath {
11+
init {
12+
require(begin in 0.0..<end && end <= path.length)
13+
}
14+
15+
override val length: Double
16+
get() = end - begin
17+
18+
override fun getAverageGrade(begin: Double, end: Double): Double {
19+
require(end <= this.length)
20+
require(begin >= 0)
21+
val newBegin = begin + this.begin
22+
val newEnd = end + this.begin
23+
return path.getAverageGrade(newBegin, newEnd)
24+
}
25+
26+
override fun getMinGrade(begin: Double, end: Double): Double {
27+
require(end <= this.length)
28+
require(begin >= 0)
29+
val newBegin = begin + this.begin
30+
val newEnd = end + this.begin
31+
return path.getMinGrade(newBegin, newEnd)
32+
}
33+
34+
override fun getElectrificationMap(
35+
basePowerClass: String?,
36+
powerRestrictionMap: DistanceRangeMap<String>?,
37+
powerRestrictionToPowerClass: Map<String, String>?,
38+
ignoreElectricalProfiles: Boolean,
39+
): DistanceRangeMap<Electrification> {
40+
val powerRestrictionMapBuilder = ImmutableRangeMap.Builder<Double, String>()
41+
val newPowerRestrictionMap =
42+
powerRestrictionMap
43+
?.map {
44+
DistanceRangeMap.RangeMapEntry(
45+
it.lower + begin.meters,
46+
it.upper + begin.meters,
47+
it.value,
48+
)
49+
}
50+
?.let { distanceRangeMapOf(it) }
51+
val electrificationMap =
52+
path.getElectrificationMap(
53+
basePowerClass,
54+
newPowerRestrictionMap,
55+
powerRestrictionToPowerClass,
56+
ignoreElectricalProfiles,
57+
)
58+
return electrificationMap
59+
.map {
60+
DistanceRangeMap.RangeMapEntry(
61+
it.lower - begin.meters,
62+
it.upper - begin.meters,
63+
it.value,
64+
)
65+
}
66+
.let { distanceRangeMapOf(it) }
67+
}
68+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package fr.sncf.osrd.path
2+
3+
import fr.sncf.osrd.path.implementations.SubPhysicsPath
4+
import fr.sncf.osrd.path.interfaces.Electrification
5+
import fr.sncf.osrd.path.interfaces.PhysicsPath
6+
import fr.sncf.osrd.utils.DistanceRangeMap
7+
import fr.sncf.osrd.utils.distanceRangeMapOf
8+
import fr.sncf.osrd.utils.units.meters
9+
import kotlin.test.assertEquals
10+
import kotlin.test.assertFailsWith
11+
import kotlin.test.assertNotNull
12+
import org.junit.Test
13+
14+
class SubPhysicsPathTest {
15+
private data class TestElectrification(val id: String) : Electrification {
16+
override fun withElectricalProfile(profile: String): Electrification = this
17+
18+
override fun withPowerRestriction(powerRestriction: String): Electrification = this
19+
}
20+
21+
private class FakePhysicsPath(
22+
override val length: Double,
23+
private val averageGradeResult: Double,
24+
private val minGradeResult: Double,
25+
private val electrificationResult: DistanceRangeMap<Electrification>,
26+
) : PhysicsPath {
27+
var lastAverageGradeCall: Pair<Double, Double>? = null
28+
var lastMinGradeCall: Pair<Double, Double>? = null
29+
var lastBasePowerClass: String? = null
30+
var lastPowerRestrictionMap: DistanceRangeMap<String>? = null
31+
var lastPowerRestrictionToPowerClass: Map<String, String>? = null
32+
var lastIgnoreElectricalProfiles: Boolean? = null
33+
34+
override fun getAverageGrade(begin: Double, end: Double): Double {
35+
lastAverageGradeCall = Pair(begin, end)
36+
return averageGradeResult
37+
}
38+
39+
override fun getMinGrade(begin: Double, end: Double): Double {
40+
lastMinGradeCall = Pair(begin, end)
41+
return minGradeResult
42+
}
43+
44+
override fun getElectrificationMap(
45+
basePowerClass: String?,
46+
powerRestrictionMap: DistanceRangeMap<String>?,
47+
powerRestrictionToPowerClass: Map<String, String>?,
48+
ignoreElectricalProfiles: Boolean,
49+
): DistanceRangeMap<Electrification> {
50+
lastBasePowerClass = basePowerClass
51+
lastPowerRestrictionMap = powerRestrictionMap
52+
lastPowerRestrictionToPowerClass = powerRestrictionToPowerClass
53+
lastIgnoreElectricalProfiles = ignoreElectricalProfiles
54+
return electrificationResult
55+
}
56+
}
57+
58+
@Test
59+
fun lengthIsSubRangeSize() {
60+
val path =
61+
FakePhysicsPath(
62+
1_000.0,
63+
averageGradeResult = 0.0,
64+
minGradeResult = 0.0,
65+
electrificationResult = distanceRangeMapOf(),
66+
)
67+
68+
val subPath = SubPhysicsPath(begin = 125.0, end = 425.0, path = path)
69+
70+
assertEquals(300.0, subPath.length)
71+
}
72+
73+
@Test
74+
fun gradeQueriesAreForwardedWithBeginOffset() {
75+
val path =
76+
FakePhysicsPath(
77+
1_000.0,
78+
averageGradeResult = 1.5,
79+
minGradeResult = -4.0,
80+
electrificationResult = distanceRangeMapOf(),
81+
)
82+
val subPath = SubPhysicsPath(begin = 100.0, end = 300.0, path = path)
83+
84+
assertEquals(1.5, subPath.getAverageGrade(begin = 10.0, end = 70.0))
85+
assertEquals(Pair(110.0, 170.0), path.lastAverageGradeCall)
86+
87+
assertEquals(-4.0, subPath.getMinGrade(begin = 0.0, end = 50.0))
88+
assertEquals(Pair(100.0, 150.0), path.lastMinGradeCall)
89+
}
90+
91+
@Test
92+
fun gradeQueriesRejectNegativeBeginAndTooLargeEnd() {
93+
val path =
94+
FakePhysicsPath(
95+
1_000.0,
96+
averageGradeResult = 0.0,
97+
minGradeResult = 0.0,
98+
electrificationResult = distanceRangeMapOf(),
99+
)
100+
val subPath = SubPhysicsPath(begin = 200.0, end = 400.0, path = path)
101+
102+
assertFailsWith<IllegalArgumentException> {
103+
subPath.getAverageGrade(begin = -1.0, end = 0.0)
104+
}
105+
assertFailsWith<IllegalArgumentException> { subPath.getMinGrade(begin = 0.0, end = 401.0) }
106+
}
107+
108+
@Test
109+
fun electrificationMapAndRestrictionsAreShiftedAndBoundsPreserved() {
110+
val returnedElectrificationMap =
111+
distanceRangeMapOf<Electrification>(
112+
DistanceRangeMap.RangeMapEntry(
113+
101.0.meters,
114+
102.0.meters,
115+
TestElectrification("e1"),
116+
),
117+
DistanceRangeMap.RangeMapEntry(
118+
103.0.meters,
119+
104.0.meters,
120+
TestElectrification("e2"),
121+
),
122+
DistanceRangeMap.RangeMapEntry(
123+
105.0.meters,
124+
106.0.meters,
125+
TestElectrification("e3"),
126+
),
127+
DistanceRangeMap.RangeMapEntry(
128+
107.0.meters,
129+
108.0.meters,
130+
TestElectrification("e4"),
131+
),
132+
)
133+
134+
val path =
135+
FakePhysicsPath(
136+
1_000.0,
137+
averageGradeResult = 0.0,
138+
minGradeResult = 0.0,
139+
electrificationResult = returnedElectrificationMap,
140+
)
141+
val subPath = SubPhysicsPath(begin = 100.0, end = 300.0, path = path)
142+
143+
val inputRestrictionMap =
144+
distanceRangeMapOf(
145+
DistanceRangeMap.RangeMapEntry(0.0.meters, 10.0.meters, "r1"),
146+
DistanceRangeMap.RangeMapEntry(11.0.meters, 20.0.meters, "r2"),
147+
DistanceRangeMap.RangeMapEntry(21.0.meters, 30.0.meters, "r3"),
148+
DistanceRangeMap.RangeMapEntry(31.0.meters, 40.0.meters, "r4"),
149+
)
150+
val powerClassMap = mapOf("r1" to "A", "r2" to "B")
151+
152+
val result =
153+
subPath.getElectrificationMap(
154+
basePowerClass = "base",
155+
powerRestrictionMap = inputRestrictionMap,
156+
powerRestrictionToPowerClass = powerClassMap,
157+
ignoreElectricalProfiles = true,
158+
)
159+
160+
assertEquals("base", path.lastBasePowerClass)
161+
assertEquals(powerClassMap, path.lastPowerRestrictionToPowerClass)
162+
assertEquals(true, path.lastIgnoreElectricalProfiles)
163+
164+
val forwardedRestrictions = path.lastPowerRestrictionMap
165+
assertNotNull(forwardedRestrictions)
166+
assertEquals(
167+
listOf(
168+
DistanceRangeMap.RangeMapEntry(100.0.meters, 110.0.meters, "r1"),
169+
DistanceRangeMap.RangeMapEntry(111.0.meters, 120.0.meters, "r2"),
170+
DistanceRangeMap.RangeMapEntry(121.0.meters, 130.0.meters, "r3"),
171+
DistanceRangeMap.RangeMapEntry(131.0.meters, 140.0.meters, "r4"),
172+
),
173+
forwardedRestrictions.toList(),
174+
)
175+
176+
assertEquals(
177+
listOf<DistanceRangeMap.RangeMapEntry<Electrification>>(
178+
DistanceRangeMap.RangeMapEntry(1.0.meters, 2.0.meters, TestElectrification("e1")),
179+
DistanceRangeMap.RangeMapEntry(3.0.meters, 4.0.meters, TestElectrification("e2")),
180+
DistanceRangeMap.RangeMapEntry(5.0.meters, 6.0.meters, TestElectrification("e3")),
181+
DistanceRangeMap.RangeMapEntry(7.0.meters, 8.0.meters, TestElectrification("e4")),
182+
),
183+
result.toList(),
184+
)
185+
}
186+
}

0 commit comments

Comments
 (0)