1
1
package fr .sncf .osrd .train ;
2
2
3
3
import com .google .common .collect .ImmutableRangeMap ;
4
+ import com .google .common .collect .Range ;
4
5
import com .google .common .collect .RangeMap ;
5
6
import com .google .common .collect .TreeRangeMap ;
6
7
import edu .umd .cs .findbugs .annotations .SuppressFBWarnings ;
8
+ import fr .sncf .osrd .envelope .Envelope ;
7
9
import fr .sncf .osrd .envelope_sim .PhysicsRollingStock ;
8
10
import fr .sncf .osrd .envelope_sim .electrification .Electrification ;
9
11
import fr .sncf .osrd .envelope_sim .electrification .Electrified ;
@@ -96,6 +98,8 @@ public class RollingStock implements PhysicsRollingStock {
96
98
private final String defaultMode ;
97
99
public final String basePowerClass ;
98
100
public final Map <String , String > powerRestrictions ;
101
+ public final Double electricalPowerStartUpTime ;
102
+ public final Double raisePantographTime ;
99
103
100
104
@ Override
101
105
public double getMass () {
@@ -188,17 +192,18 @@ public double getDeceleration() {
188
192
}
189
193
190
194
/**
191
- * Returns the tractive effort curve that matches best, along with the infra conditions that matched
195
+ * Returns the tractive effort curve that matches best, along with the electrification conditions that matched
192
196
*/
193
197
protected CurveAndCondition findTractiveEffortCurve (Comfort comfort , Electrification electrification ) {
194
198
if (electrification instanceof Neutral n ) {
195
- var wouldUseRes = findTractiveEffortCurve (comfort , n .overlappedElectrification );
196
- if (!modes .get (wouldUseRes .cond .mode ).isElectric ) {
197
- return wouldUseRes ;
198
- } else {
199
- return new CurveAndCondition (COASTING_CURVE , new InfraConditions (null , null , null ));
199
+ var overlappedCurve = findTractiveEffortCurve (comfort , n .overlappedElectrification );
200
+ var isOverlappedCurveThermal = !modes .get (overlappedCurve .cond .mode ).isElectric ;
201
+ if (isOverlappedCurveThermal ) {
202
+ return overlappedCurve ;
200
203
}
201
- } else if (electrification instanceof NonElectrified ) {
204
+ return new CurveAndCondition (COASTING_CURVE , new InfraConditions (null , null , null ));
205
+ }
206
+ if (electrification instanceof NonElectrified ) {
202
207
return new CurveAndCondition (modes .get (defaultMode ).defaultCurve ,
203
208
new InfraConditions (defaultMode , null , null ));
204
209
}
@@ -221,6 +226,7 @@ protected CurveAndCondition findTractiveEffortCurve(Comfort comfort, Electrifica
221
226
222
227
/**
223
228
* Returns the tractive effort curves corresponding to the electrical conditions map
229
+ * The neutral sections are not extended in this function.
224
230
*
225
231
* @param electrificationMap The map of electrification conditions to use
226
232
* @param comfort The comfort level to get the curves for
@@ -238,19 +244,88 @@ public CurvesAndConditions mapTractiveEffortCurves(RangeMap<Double, Electrificat
238
244
return new CurvesAndConditions (ImmutableRangeMap .copyOf (res ), ImmutableRangeMap .copyOf (conditionsUsed ));
239
245
}
240
246
247
+
248
+ protected Range <Double > computeDeadSectionRange (Range <Double > neutralRange , Neutral n , Envelope maxEffortEnvelope ) {
249
+ var endRange = neutralRange .upperEndpoint ();
250
+ var finalSpeed = maxEffortEnvelope .interpolateSpeedLeftDir (endRange , 1 );
251
+ double additionalRange = finalSpeed * electricalPowerStartUpTime ;
252
+ if (n .lowerPantograph ) {
253
+ additionalRange += finalSpeed * raisePantographTime ;
254
+ }
255
+ return Range .closed (neutralRange .lowerEndpoint (), neutralRange .upperEndpoint () + additionalRange );
256
+ }
257
+
258
+ /**
259
+ * Returns the tractive effort curves corresponding to the electrical conditions map with neutral sections
260
+ *
261
+ * @param electrificationMap The map of electrification conditions to use
262
+ * @param comfort The comfort level to get the curves for
263
+ * @param maxSpeedEnvelope The maxSpeedEnvelope used to extend the neutral sections
264
+ */
265
+ public RangeMap <Double , TractiveEffortPoint []> addNeutralSystemTimes (
266
+ RangeMap <Double , Electrification > electrificationMap , Comfort comfort , Envelope maxSpeedEnvelope ,
267
+ RangeMap <Double , TractiveEffortPoint []> curvesUsed ) {
268
+
269
+ TreeRangeMap <Double , TractiveEffortPoint []> newCurves = TreeRangeMap .create ();
270
+ newCurves .putAll (curvesUsed );
271
+
272
+ for (var elecCondEntry : electrificationMap .asMapOfRanges ().entrySet ()) {
273
+ if (elecCondEntry .getValue () instanceof Neutral n ) {
274
+ // estimate the distance during which the train will be coasting, due to having respected the
275
+ // neutral section
276
+ var deadSectionRange = computeDeadSectionRange (elecCondEntry .getKey (), n , maxSpeedEnvelope );
277
+ var curveAndCondition = findTractiveEffortCurve (comfort , n );
278
+ if (curveAndCondition .cond .mode == null ) { // The train is effectively coasting
279
+ newCurves .put (deadSectionRange , curveAndCondition .curve );
280
+ }
281
+ }
282
+ }
283
+ return ImmutableRangeMap .copyOf (newCurves );
284
+ }
285
+
241
286
public Set <String > getModeNames () {
242
287
return modes .keySet ();
243
288
}
244
289
245
290
/**
246
- * Return whether this rolling stock support only electric modes
291
+ * Return whether this rolling stock's default mode is thermal
247
292
*/
248
- public boolean isElectricOnly () {
249
- for (var mode : modes .values ()) {
250
- if (!mode .isElectric )
251
- return false ;
252
- }
253
- return true ;
293
+ public boolean isThermal () {
294
+ return !modes .get (defaultMode ).isElectric ();
295
+ }
296
+
297
+ /**
298
+ * Return whether this rolling stock's has an electric mode
299
+ */
300
+ public final boolean isElectric () {
301
+ return modes .values ().stream ().anyMatch (ModeEffortCurves ::isElectric );
302
+ }
303
+
304
+ /**
305
+ * Creates a new rolling stock (a physical train inventory item).
306
+ */
307
+ public RollingStock (
308
+ String id ,
309
+ double length ,
310
+ double mass ,
311
+ double inertiaCoefficient ,
312
+ double a ,
313
+ double b ,
314
+ double c ,
315
+ double maxSpeed ,
316
+ double startUpTime ,
317
+ double startUpAcceleration ,
318
+ double comfortAcceleration ,
319
+ double gamma ,
320
+ GammaType gammaType ,
321
+ RJSLoadingGaugeType loadingGaugeType ,
322
+ Map <String , ModeEffortCurves > modes ,
323
+ String defaultMode ,
324
+ String basePowerclass
325
+ ) {
326
+ this (id , length , mass , inertiaCoefficient , a , b , c , maxSpeed , startUpTime , startUpAcceleration ,
327
+ comfortAcceleration , gamma , gammaType , loadingGaugeType , modes , defaultMode , basePowerclass , Map .of (),
328
+ 0. , 0. );
254
329
}
255
330
256
331
/**
@@ -274,7 +349,9 @@ public RollingStock(
274
349
Map <String , ModeEffortCurves > modes ,
275
350
String defaultMode ,
276
351
String basePowerclass ,
277
- Map <String , String > powerRestrictions
352
+ Map <String , String > powerRestrictions ,
353
+ Double electricalPowerStartUpTime ,
354
+ Double raisePantographTime
278
355
) {
279
356
this .id = id ;
280
357
this .A = a ;
@@ -295,5 +372,10 @@ public RollingStock(
295
372
this .loadingGaugeType = loadingGaugeType ;
296
373
this .basePowerClass = basePowerclass ;
297
374
this .powerRestrictions = powerRestrictions ;
375
+ this .electricalPowerStartUpTime = electricalPowerStartUpTime ;
376
+ this .raisePantographTime = raisePantographTime ;
377
+
378
+ assert !isElectric () || (this .electricalPowerStartUpTime != null && this .raisePantographTime != null ) :
379
+ "Electrical power start up time and Raise pantograph time must be defined for an electric train" ;
298
380
}
299
381
}
0 commit comments