Skip to content

Commit a2a3f4b

Browse files
committed
core: add compulsory EnvelopeProfile attribute to EnvelopePart
1 parent 0cda4bd commit a2a3f4b

File tree

13 files changed

+80
-44
lines changed

13 files changed

+80
-44
lines changed

core/envelope-sim/src/main/java/fr/sncf/osrd/envelope/EnvelopeSpeedCap.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
package fr.sncf.osrd.envelope;
22

33
import fr.sncf.osrd.envelope.part.EnvelopePartBuilder;
4+
import fr.sncf.osrd.envelope_sim.EnvelopeProfile;
45
import fr.sncf.osrd.envelope_utils.CmpOperator;
6+
import java.util.Collection;
7+
import java.util.HashSet;
58

69
public class EnvelopeSpeedCap {
710
/** Adds a global speed limit to an envelope */
811
public static Envelope from(
912
Envelope base,
10-
Iterable<EnvelopeAttr> attrs,
13+
Collection<EnvelopeAttr> attrs,
1114
double speedLimit
1215
) {
1316
var cursor = new EnvelopeCursor(base, false);
1417
var builder = OverlayEnvelopeBuilder.forward(base);
18+
var envelopeAttrs = new HashSet<>(attrs);
19+
envelopeAttrs.add(EnvelopeProfile.CONSTANT_SPEED);
1520
while (cursor.findSpeed(speedLimit, CmpOperator.STRICTLY_HIGHER)) {
1621
var startPos = cursor.getPosition();
1722

1823
var partBuilder = new EnvelopePartBuilder();
19-
partBuilder.setAttrs(attrs);
24+
partBuilder.setAttrs(envelopeAttrs);
2025
partBuilder.initEnvelopePart(startPos, speedLimit, 1);
2126

2227
var hasNotReachedEnd = cursor.findSpeed(speedLimit, CmpOperator.STRICTLY_LOWER);

core/envelope-sim/src/main/java/fr/sncf/osrd/envelope/part/EnvelopePart.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package fr.sncf.osrd.envelope.part;
22

33
import static fr.sncf.osrd.envelope.EnvelopePhysics.intersectStepWithSpeed;
4+
import static fr.sncf.osrd.envelope_sim.TrainPhysicsIntegrator.areSpeedsEqual;
45

56
import com.carrotsearch.hppc.DoubleArrayList;
67
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
78
import fr.sncf.osrd.envelope.EnvelopeAttr;
89
import fr.sncf.osrd.envelope.EnvelopePhysics;
910
import fr.sncf.osrd.envelope.SearchableEnvelope;
11+
import fr.sncf.osrd.envelope_sim.EnvelopeProfile;
1012
import fr.sncf.osrd.envelope_utils.ExcludeFromGeneratedCodeCoverage;
1113
import java.util.Arrays;
1214
import java.util.Collections;
@@ -111,11 +113,16 @@ public static EnvelopePart generateTimes(
111113
double[] positions,
112114
double[] speeds
113115
) {
114-
return new EnvelopePart(
115-
new HashMap<>(),
116+
var envelopeProfile = EnvelopeProfile.BRAKING;
117+
if (areSpeedsEqual(speeds[0], speeds[speeds.length - 1])) {
118+
envelopeProfile = EnvelopeProfile.CONSTANT_SPEED;
119+
} else if (speeds[0] < speeds[speeds.length - 1]) {
120+
envelopeProfile = EnvelopeProfile.ACCELERATING;
121+
}
122+
return generateTimes(
123+
Collections.singleton(envelopeProfile),
116124
positions,
117-
speeds,
118-
computeTimes(positions, speeds)
125+
speeds
119126
);
120127
}
121128

@@ -165,6 +172,7 @@ public Map<Class<? extends EnvelopeAttr>, EnvelopeAttr> getAttrs() {
165172
* (which should be avoided when possible) */
166173
private void runSanityChecks() {
167174
assert attrs != null : "missing attributes";
175+
assert hasAttr(EnvelopeProfile.class) : "missing EnvelopeProfile attribute";
168176
assert positions.length > 0 : "attempted to create an empty EnvelopePart";
169177
assert positions.length == speeds.length : "there must be the same number of point and speeds";
170178
assert timeDeltas.length == positions.length - 1 : "there must be as many timeDeltas as gaps between points";

core/envelope-sim/src/main/java/fr/sncf/osrd/envelope_sim/allowances/AbstractAllowanceWithRanges.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import fr.sncf.osrd.envelope.part.constraints.EnvelopeConstraint;
1515
import fr.sncf.osrd.envelope.part.constraints.EnvelopePartConstraint;
1616
import fr.sncf.osrd.envelope.part.constraints.PositionConstraint;
17+
import fr.sncf.osrd.envelope_sim.EnvelopeProfile;
1718
import fr.sncf.osrd.envelope_sim.EnvelopeSimContext;
1819
import fr.sncf.osrd.envelope_sim.PhysicsRollingStock;
1920
import fr.sncf.osrd.envelope_sim.allowances.utils.AllowanceRange;
@@ -157,7 +158,7 @@ private Envelope[] computeAllowanceRegion(Envelope envelopeRegion, EnvelopeSimCo
157158
var range = ranges.get(i);
158159
var percentage = range.value.getAllowanceRatio(
159160
envelopeRegion.getTimeBetween(range.beginPos, range.endPos),
160-
range.beginPos - range.endPos
161+
range.endPos - range.beginPos
161162
);
162163
rangePercentages[i] = new RangePercentage(range, percentage);
163164
}
@@ -401,6 +402,7 @@ private EnvelopePart computeLeftJunction(Envelope envelopeSection,
401402
EnvelopeDeceleration.decelerate(
402403
context, envelopeSection.getBeginPos(), imposedBeginSpeed, constrainedBuilder, 1
403404
);
405+
partBuilder.setAttr(EnvelopeProfile.BRAKING);
404406
lastIntersection = constrainedBuilder.lastIntersection;
405407
} else if (imposedBeginSpeed < envelopeSection.getBeginSpeed()) {
406408
constraints.add(new EnvelopeConstraint(envelopeTarget, CEILING));
@@ -412,6 +414,7 @@ private EnvelopePart computeLeftJunction(Envelope envelopeSection,
412414
EnvelopeAcceleration.accelerate(
413415
context, envelopeSection.getBeginPos(), imposedBeginSpeed, constrainedBuilder, 1
414416
);
417+
partBuilder.setAttr(EnvelopeProfile.ACCELERATING);
415418
lastIntersection = constrainedBuilder.lastIntersection;
416419
}
417420
if (lastIntersection == 0) {
@@ -449,6 +452,7 @@ private EnvelopePart computeRightJunction(Envelope envelopeSection,
449452
EnvelopeAcceleration.accelerate(
450453
context, envelopeSection.getEndPos(), imposedEndSpeed, constrainedBuilder, -1
451454
);
455+
partBuilder.setAttr(EnvelopeProfile.ACCELERATING);
452456
lastIntersection = constrainedBuilder.lastIntersection;
453457
} else if (imposedEndSpeed < envelopeSection.getEndSpeed()) {
454458
constraints.add(new EnvelopeConstraint(envelopeTarget, CEILING));
@@ -459,6 +463,7 @@ private EnvelopePart computeRightJunction(Envelope envelopeSection,
459463
EnvelopeDeceleration.decelerate(
460464
context, envelopeSection.getEndPos(), imposedEndSpeed, constrainedBuilder, -1
461465
);
466+
partBuilder.setAttr(EnvelopeProfile.BRAKING);
462467
lastIntersection = constrainedBuilder.lastIntersection;
463468
}
464469
if (lastIntersection == 0) {

core/envelope-sim/src/main/java/fr/sncf/osrd/envelope_sim/allowances/mareco_impl/CoastingGenerator.java

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public static EnvelopePart coastFromEnd(
5252

5353
// coast backwards from the end position until the base curve is met
5454
var backwardPartBuilder = new EnvelopePartBuilder();
55+
backwardPartBuilder.setAttr(EnvelopeProfile.COASTING);
5556
var constrainedBuilder = new ConstrainedEnvelopePartBuilder(
5657
backwardPartBuilder,
5758
new SpeedConstraint(0, FLOOR),

core/envelope-sim/src/test/java/fr/sncf/osrd/envelope/ConstraintBuilderTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import fr.sncf.osrd.envelope.part.constraints.EnvelopeConstraint;
1212
import fr.sncf.osrd.envelope.part.constraints.PositionConstraint;
1313
import fr.sncf.osrd.envelope.part.constraints.SpeedConstraint;
14+
import fr.sncf.osrd.envelope_sim.EnvelopeProfile;
1415
import org.junit.jupiter.api.Test;
1516
import java.util.List;
1617

@@ -28,12 +29,10 @@ public class ConstraintBuilderTest {
2829

2930
private ConstrainedEnvelopePartBuilder wrap(EnvelopePartConsumer sink) {
3031
var envelopeFloor = Envelope.make(EnvelopePart.generateTimes(
31-
List.of(),
3232
new double[] {0, 3, 4, 5, 6, 7, 10},
3333
new double[] {0, 0, 1, 2, 1, 0, 0}
3434
));
3535
var envelopeCeiling = Envelope.make(EnvelopePart.generateTimes(
36-
List.of(),
3736
new double[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
3837
new double[] {2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2}
3938
));
@@ -53,6 +52,7 @@ void testAttrs() {
5352
var builder = wrap(partBuilder);
5453
builder.setAttrs(List.of(TestAttr.A));
5554
builder.setAttr(TestAttr.B);
55+
builder.setAttr(EnvelopeProfile.ACCELERATING);
5656
assertTrue(builder.initEnvelopePart(2, 0, 1));
5757
assertFalse(builder.addStep(5, 1));
5858
var part = partBuilder.build();

core/envelope-sim/src/test/java/fr/sncf/osrd/envelope/EnvelopeOverlayTest.java

+14-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import fr.sncf.osrd.envelope.part.EnvelopePart;
99
import fr.sncf.osrd.envelope.part.EnvelopePartBuilder;
1010
import fr.sncf.osrd.envelope.part.constraints.EnvelopeConstraint;
11+
import fr.sncf.osrd.envelope_sim.EnvelopeProfile;
1112
import org.junit.jupiter.api.Test;
1213
import org.junit.jupiter.params.ParameterizedTest;
1314
import org.junit.jupiter.params.provider.ValueSource;
@@ -66,6 +67,7 @@ void testConstantSpeedOverlay() {
6667
var builder = OverlayEnvelopeBuilder.forward(constSpeedEnvelope);
6768
{
6869
var partBuilder = new EnvelopePartBuilder();
70+
partBuilder.setAttr(EnvelopeProfile.COASTING);
6971
var overlayBuilder = new ConstrainedEnvelopePartBuilder(
7072
partBuilder, new EnvelopeConstraint(constSpeedEnvelope, CEILING));
7173
overlayBuilder.initEnvelopePart(3, constSpeedEnvelope.interpolateSpeed(3), 1);
@@ -94,6 +96,7 @@ void testMultipleOverlays() {
9496

9597
{
9698
var partBuilder = new EnvelopePartBuilder();
99+
partBuilder.setAttr(EnvelopeProfile.COASTING);
97100
var overlayBuilder = new ConstrainedEnvelopePartBuilder(
98101
partBuilder, new EnvelopeConstraint(constSpeedEnvelope, CEILING));
99102
overlayBuilder.initEnvelopePart(0, constSpeedEnvelope.interpolateSpeed(0), 1);
@@ -104,6 +107,7 @@ void testMultipleOverlays() {
104107

105108
{
106109
var partBuilder = new EnvelopePartBuilder();
110+
partBuilder.setAttr(EnvelopeProfile.COASTING);
107111
var overlayBuilder = new ConstrainedEnvelopePartBuilder(
108112
partBuilder, new EnvelopeConstraint(constSpeedEnvelope, CEILING));
109113
overlayBuilder.initEnvelopePart(6, constSpeedEnvelope.interpolateSpeed(6), 1);
@@ -123,7 +127,7 @@ void testMultipleOverlays() {
123127
@ValueSource(booleans = {false, true})
124128
void testSymmetricOverlay(boolean backwardDir) {
125129
var constSpeedPart = EnvelopePart.generateTimes(
126-
List.of(TestAttr.B),
130+
List.of(TestAttr.B, EnvelopeProfile.CONSTANT_SPEED),
127131
new double[]{0, 3.5, 8},
128132
new double[]{2, 2, 2}
129133
);
@@ -134,6 +138,7 @@ void testSymmetricOverlay(boolean backwardDir) {
134138
{
135139
var partBuilder = new EnvelopePartBuilder();
136140
partBuilder.setAttr(TestAttr.A);
141+
partBuilder.setAttr(EnvelopeProfile.COASTING);
137142
var overlayBuilder = new ConstrainedEnvelopePartBuilder(
138143
partBuilder, new EnvelopeConstraint(constSpeedEnvelope, CEILING));
139144
overlayBuilder.initEnvelopePart(overlayPoints[0], 2, backwardDir ? -1 : 1);
@@ -149,7 +154,7 @@ void testSymmetricOverlay(boolean backwardDir) {
149154
var expectedFirst = constSpeedPart.sliceBeginning(constSpeedPart.findLeft(3), 3, Double.NaN);
150155
EnvelopeTestUtils.assertEquals(expectedFirst, envelope.get(0));
151156
var expectedMid = EnvelopePart.generateTimes(
152-
List.of(TestAttr.A),
157+
List.of(TestAttr.A, EnvelopeProfile.COASTING),
153158
new double[]{3, 4, 5},
154159
new double[]{2, 1, 2}
155160
);
@@ -190,7 +195,8 @@ void testBaseCurveSplit(boolean isBackward) {
190195
var cursor = new EnvelopeCursor(baseEnvelope, isBackward);
191196
var positions = new double[] { 3, 4, 6 };
192197
var speeds = new double[] { 4, 3, 4 };
193-
builder.addPart(EnvelopeTestUtils.buildContinuous(cursor, List.of(), positions, speeds, isBackward));
198+
builder.addPart(EnvelopeTestUtils.buildContinuous(cursor, List.of(EnvelopeProfile.COASTING), positions, speeds,
199+
isBackward));
194200
var envelope = builder.build();
195201
assertEquals(4, envelope.size());
196202
assertTrue(envelope.continuous);
@@ -233,6 +239,7 @@ void testDiscontinuityOverlayEnd() {
233239

234240
{
235241
var partBuilder = new EnvelopePartBuilder();
242+
partBuilder.setAttr(EnvelopeProfile.BRAKING);
236243
var overlayBuilder = new ConstrainedEnvelopePartBuilder(
237244
partBuilder,
238245
new EnvelopeConstraint(baseEnvelope, CEILING)
@@ -279,7 +286,8 @@ void testLongOverlay(boolean reverse) {
279286
var cursor = new EnvelopeCursor(baseEnvelope, reverse);
280287
var positions = new double[] { 3, 4, 5, 6 };
281288
var speeds = new double[] { 4, 3, 3, 4 };
282-
builder.addPart(EnvelopeTestUtils.buildContinuous(cursor, List.of(), positions, speeds, reverse));
289+
builder.addPart(EnvelopeTestUtils.buildContinuous(cursor, List.of(EnvelopeProfile.COASTING), positions, speeds,
290+
reverse));
283291
var envelope = builder.build();
284292
assertEquals(4, envelope.size());
285293
assertTrue(envelope.continuous);
@@ -296,6 +304,7 @@ void testUnlikelyIntersection() {
296304

297305
{
298306
var partBuilder = new EnvelopePartBuilder();
307+
partBuilder.setAttr(EnvelopeProfile.COASTING);
299308
var overlayBuilder = new ConstrainedEnvelopePartBuilder(
300309
partBuilder,
301310
new EnvelopeConstraint(inputEnvelope, CEILING)
@@ -322,6 +331,7 @@ void testIncreasingContinuousOverlay() {
322331

323332
{
324333
var partBuilder = new EnvelopePartBuilder();
334+
partBuilder.setAttr(EnvelopeProfile.ACCELERATING);
325335
var overlayBuilder = new ConstrainedEnvelopePartBuilder(
326336
partBuilder,
327337
new EnvelopeConstraint(inputEnvelope, CEILING)

core/envelope-sim/src/test/java/fr/sncf/osrd/envelope/EnvelopePartSliceTest.java

+11-10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import fr.sncf.osrd.envelope.EnvelopeTestUtils.TestAttr;
88
import fr.sncf.osrd.envelope.part.EnvelopePart;
9+
import fr.sncf.osrd.envelope_sim.EnvelopeProfile;
910
import org.junit.jupiter.api.Test;
1011
import java.util.List;
1112

@@ -14,12 +15,12 @@ public class EnvelopePartSliceTest {
1415
@Test
1516
void sliceIndex() {
1617
var ep1 = EnvelopePart.generateTimes(
17-
List.of(TestAttr.A),
18+
List.of(TestAttr.A, EnvelopeProfile.ACCELERATING),
1819
new double[] {1.5, 3, 5},
1920
new double[] {3, 4, 4}
2021
);
2122
var ep2 = EnvelopePart.generateTimes(
22-
List.of(TestAttr.A),
23+
List.of(TestAttr.A, EnvelopeProfile.ACCELERATING),
2324
new double[] {1.5, 3},
2425
new double[] {3, 4}
2526
);
@@ -31,7 +32,7 @@ void sliceIndex() {
3132
@Test
3233
void sliceIndexFull() {
3334
var ep1 = EnvelopePart.generateTimes(
34-
List.of(TestAttr.A),
35+
List.of(TestAttr.A, EnvelopeProfile.ACCELERATING),
3536
new double[] {1.5, 3, 5},
3637
new double[] {3, 3, 4}
3738
);
@@ -43,7 +44,7 @@ void sliceIndexFull() {
4344
@Test
4445
void sliceIndexEmpty() {
4546
var ep1 = EnvelopePart.generateTimes(
46-
List.of(TestAttr.A),
47+
List.of(TestAttr.A, EnvelopeProfile.ACCELERATING),
4748
new double[] {1.5, 3, 5},
4849
new double[] {3, 3, 4}
4950
);
@@ -54,7 +55,7 @@ void sliceIndexEmpty() {
5455
@Test
5556
void sliceOffsetEmpty() {
5657
var ep1 = EnvelopePart.generateTimes(
57-
List.of(TestAttr.A),
58+
List.of(TestAttr.A, EnvelopeProfile.ACCELERATING),
5859
new double[] {1.5, 3, 5},
5960
new double[] {3, 3, 4}
6061
);
@@ -65,7 +66,7 @@ void sliceOffsetEmpty() {
6566
@Test
6667
void sliceOffsetFull() {
6768
var ep1 = EnvelopePart.generateTimes(
68-
List.of(TestAttr.A),
69+
List.of(TestAttr.A, EnvelopeProfile.ACCELERATING),
6970
new double[] {1.5, 3, 5},
7071
new double[] {3, 3, 4}
7172
);
@@ -76,13 +77,13 @@ void sliceOffsetFull() {
7677
@Test
7778
void sliceOffsetInterpolate() {
7879
var ep1 = EnvelopePart.generateTimes(
79-
List.of(TestAttr.A),
80+
List.of(TestAttr.A, EnvelopeProfile.BRAKING),
8081
new double[] {0, 3},
8182
new double[] {3.46, 0}
8283
);
8384
var slice = ep1.slice(Double.NEGATIVE_INFINITY, 2);
8485
var expectedSlice = new EnvelopePart(
85-
List.of(TestAttr.A),
86+
List.of(TestAttr.A, EnvelopeProfile.BRAKING),
8687
new double[] {0, 2},
8788
new double[] {3.46, 2},
8889
new double[] {0.73}
@@ -93,13 +94,13 @@ void sliceOffsetInterpolate() {
9394
@Test
9495
void sliceWithImposedSpeeds() {
9596
var ep1 = EnvelopePart.generateTimes(
96-
List.of(TestAttr.A),
97+
List.of(TestAttr.A, EnvelopeProfile.ACCELERATING),
9798
new double[] {1, 3, 5},
9899
new double[] {3, 3, 4}
99100
);
100101
var slice = ep1.sliceWithSpeeds(2, 3, 4, 3.5);
101102
var expectedSlice = EnvelopePart.generateTimes(
102-
List.of(TestAttr.A),
103+
List.of(TestAttr.A, EnvelopeProfile.ACCELERATING),
103104
new double[] {2, 3, 4},
104105
new double[] {3, 3, 3.5}
105106
);

0 commit comments

Comments
 (0)