Skip to content

Commit a8228b7

Browse files
committed
core, editoast: return conflict requirements
Closes: #8680 Signed-off-by: Simon Ser <[email protected]>
1 parent 72cd833 commit a8228b7

File tree

7 files changed

+105
-11
lines changed

7 files changed

+105
-11
lines changed

core/src/main/java/fr/sncf/osrd/api/ConflictDetectionEndpoint.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,26 @@ public enum ConflictType {
9090
@Json(name = "conflict_type")
9191
public final ConflictType conflictType;
9292

93-
public Conflict(Collection<Long> trainIds, double startTime, double endTime, ConflictType conflictType) {
93+
public final transient Collection<ConflictRequirement> requirements;
94+
95+
public Conflict(Collection<Long> trainIds, double startTime, double endTime, ConflictType conflictType, Collection<ConflictRequirement> requirements) {
9496
this.trainIds = trainIds;
9597
this.startTime = startTime;
9698
this.endTime = endTime;
9799
this.conflictType = conflictType;
100+
this.requirements = requirements;
101+
}
102+
}
103+
104+
public static class ConflictRequirement {
105+
public final String zone;
106+
public final double startTime;
107+
public final double endTime;
108+
109+
public ConflictRequirement(String zone, double startTime, double endTime) {
110+
this.zone = zone;
111+
this.startTime = startTime;
112+
this.endTime = endTime;
98113
}
99114
}
100115

core/src/main/java/fr/sncf/osrd/conflicts/Conflicts.kt

+21-9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.carrotsearch.hppc.IntArrayList
44
import com.squareup.moshi.Json
55
import fr.sncf.osrd.api.ConflictDetectionEndpoint.ConflictDetectionResult.Conflict
66
import fr.sncf.osrd.api.ConflictDetectionEndpoint.ConflictDetectionResult.Conflict.ConflictType
7+
import fr.sncf.osrd.api.ConflictDetectionEndpoint.ConflictDetectionResult.ConflictRequirement
78
import fr.sncf.osrd.standalone_sim.result.ResultTrain.RoutingRequirement
89
import fr.sncf.osrd.standalone_sim.result.ResultTrain.SpacingRequirement
910
import kotlin.math.max
@@ -171,12 +172,13 @@ class IncrementalConflictDetectorImpl(trainRequirements: List<TrainRequirements>
171172
// look for requirement times overlaps.
172173
// as spacing requirements are exclusive, any overlap is a conflict
173174
val res = mutableListOf<Conflict>()
174-
for (requirements in spacingZoneRequirements.values) {
175-
for (conflictGroup in detectRequirementConflicts(requirements) { _, _ -> true }) {
175+
for (entry in spacingZoneRequirements) {
176+
for (conflictGroup in detectRequirementConflicts(entry.value) { _, _ -> true }) {
176177
val trains = conflictGroup.map { it.trainId }
177178
val beginTime = conflictGroup.minBy { it.beginTime }.beginTime
178179
val endTime = conflictGroup.maxBy { it.endTime }.endTime
179-
res.add(Conflict(trains, beginTime, endTime, ConflictType.SPACING))
180+
val conflictReq = ConflictRequirement(entry.key, beginTime, endTime)
181+
res.add(Conflict(trains, beginTime, endTime, ConflictType.SPACING, listOf(conflictReq)))
180182
}
181183
}
182184
return res
@@ -185,13 +187,14 @@ class IncrementalConflictDetectorImpl(trainRequirements: List<TrainRequirements>
185187
private fun detectRoutingConflicts(): List<Conflict> {
186188
// for each zone, check compatibility of overlapping requirements
187189
val res = mutableListOf<Conflict>()
188-
for (requirements in routingZoneRequirements.values) {
190+
for (entry in routingZoneRequirements) {
189191
for (conflictGroup in
190-
detectRequirementConflicts(requirements) { a, b -> a.config != b.config }) {
192+
detectRequirementConflicts(entry.value) { a, b -> a.config != b.config }) {
191193
val trains = conflictGroup.map { it.trainId }
192194
val beginTime = conflictGroup.minBy { it.beginTime }.beginTime
193195
val endTime = conflictGroup.maxBy { it.endTime }.endTime
194-
res.add(Conflict(trains, beginTime, endTime, ConflictType.ROUTING))
196+
val conflictReq = ConflictRequirement(entry.key, beginTime, endTime)
197+
res.add(Conflict(trains, beginTime, endTime, ConflictType.ROUTING, listOf(conflictReq)))
195198
}
196199
}
197200
return res
@@ -218,9 +221,10 @@ class IncrementalConflictDetectorImpl(trainRequirements: List<TrainRequirements>
218221
for (otherReq in requirements) {
219222
val beginTime = max(req.beginTime, otherReq.beginTime)
220223
val endTime = min(req.endTime, otherReq.endTime)
224+
val conflictReq = ConflictRequirement(req.zone, beginTime, endTime)
221225
if (beginTime < endTime)
222226
res.add(
223-
Conflict(listOf(otherReq.trainId), beginTime, endTime, ConflictType.SPACING)
227+
Conflict(listOf(otherReq.trainId), beginTime, endTime, ConflictType.SPACING, listOf(conflictReq))
224228
)
225229
}
226230

@@ -238,9 +242,10 @@ class IncrementalConflictDetectorImpl(trainRequirements: List<TrainRequirements>
238242
if (otherReq.config == zoneReqConfig) continue
239243
val beginTime = max(req.beginTime, otherReq.beginTime)
240244
val endTime = min(zoneReq.endTime, otherReq.endTime)
245+
val conflictReq = ConflictRequirement(zoneReq.zone, beginTime, endTime)
241246
if (beginTime < endTime)
242247
res.add(
243-
Conflict(listOf(otherReq.trainId), beginTime, endTime, ConflictType.ROUTING)
248+
Conflict(listOf(otherReq.trainId), beginTime, endTime, ConflictType.ROUTING, listOf(conflictReq))
244249
)
245250
}
246251
}
@@ -447,6 +452,12 @@ fun mergeMap(
447452
events.add(Event(EventType.END, conflict.endTime))
448453
}
449454

455+
// TODO: accumulate in the for loop below somehow?
456+
val conflictReqs = mutableListOf<ConflictRequirement>()
457+
for (conflict in conflicts) {
458+
conflictReqs.addAll(conflict.requirements);
459+
}
460+
450461
events.sort()
451462
var eventCount = 0
452463
var eventBeginning = 0.0
@@ -462,7 +473,8 @@ fun mergeMap(
462473
trainIds.toMutableList(),
463474
eventBeginning,
464475
event.time,
465-
conflictType
476+
conflictType,
477+
conflictReqs
466478
)
467479
)
468480
}

core/src/main/kotlin/fr/sncf/osrd/api/api_v2/conflicts/ConflictDetectionEndpointV2.kt

+8-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,14 @@ private fun makeConflictDetectionResponse(
5252
it.trainIds,
5353
startTime.plus(Duration.ofMillis((it.startTime * 1000).toLong())),
5454
startTime.plus(Duration.ofMillis((it.endTime * 1000).toLong())),
55-
it.conflictType
55+
it.conflictType,
56+
it.requirements.map {
57+
ConflictRequirement(
58+
it.zone,
59+
startTime.plus(Duration.ofMillis((it.startTime * 1000).toLong())),
60+
startTime.plus(Duration.ofMillis((it.endTime * 1000).toLong())),
61+
)
62+
}
5663
)
5764
}
5865
)

core/src/main/kotlin/fr/sncf/osrd/api/api_v2/conflicts/ConflictDetectionResponse.kt

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ class Conflict(
1818
@Json(name = "end_time") val endTime: ZonedDateTime,
1919
@Json(name = "conflict_type")
2020
val conflictType: ConflictDetectionEndpoint.ConflictDetectionResult.Conflict.ConflictType,
21+
@Json(name = "requirements") val requirements: Collection<ConflictRequirement>,
22+
)
23+
24+
class ConflictRequirement(
25+
@Json(name = "zone") val zone: String,
26+
@Json(name = "start_time") val startTime: ZonedDateTime,
27+
@Json(name = "end_time") val endTime: ZonedDateTime,
2128
)
2229

2330
val conflictResponseAdapter: JsonAdapter<ConflictDetectionResponse> =

editoast/openapi.yaml

+32
Original file line numberDiff line numberDiff line change
@@ -2953,6 +2953,7 @@ components:
29532953
- start_time
29542954
- end_time
29552955
- conflict_type
2956+
- requirements
29562957
properties:
29572958
conflict_type:
29582959
type: string
@@ -2963,6 +2964,11 @@ components:
29632964
type: string
29642965
format: date-time
29652966
description: Datetime of the end of the conflict
2967+
requirements:
2968+
type: array
2969+
items:
2970+
$ref: '#/components/schemas/ConflictRequirement'
2971+
description: List of requirements causing the conflict
29662972
start_time:
29672973
type: string
29682974
format: date-time
@@ -2987,6 +2993,7 @@ components:
29872993
- start_time
29882994
- end_time
29892995
- conflict_type
2996+
- requirements
29902997
properties:
29912998
conflict_type:
29922999
type: string
@@ -2997,6 +3004,11 @@ components:
29973004
type: string
29983005
format: date-time
29993006
description: Datetime of the end of the conflict
3007+
requirements:
3008+
type: array
3009+
items:
3010+
$ref: '#/components/schemas/ConflictRequirement'
3011+
description: List of requirements causing the conflict
30003012
start_time:
30013013
type: string
30023014
format: date-time
@@ -3008,6 +3020,26 @@ components:
30083020
format: int64
30093021
description: List of train ids involved in the conflict
30103022
description: List of conflicts detected
3023+
ConflictRequirement:
3024+
type: object
3025+
description: |-
3026+
Unmet requirement causing a conflict.
3027+
3028+
The start and end time describe the conflicting time span (not the full
3029+
requirement's time span).
3030+
required:
3031+
- zone
3032+
- start_time
3033+
- end_time
3034+
properties:
3035+
end_time:
3036+
type: string
3037+
format: date-time
3038+
start_time:
3039+
type: string
3040+
format: date-time
3041+
zone:
3042+
type: string
30113043
CopyOperation:
30123044
type: object
30133045
description: JSON Patch 'copy' operation representation

editoast/src/core/conflict_detection.rs

+14
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use super::simulation::SpacingRequirement;
1313
editoast_common::schemas! {
1414
ConflictDetectionResponse,
1515
Conflict,
16+
ConflictRequirement,
1617
}
1718

1819
#[derive(Debug, Serialize)]
@@ -47,6 +48,19 @@ pub struct Conflict {
4748
/// Type of the conflict
4849
#[schema(inline)]
4950
pub conflict_type: ConflictType,
51+
/// List of requirements causing the conflict
52+
pub requirements: Vec<ConflictRequirement>,
53+
}
54+
55+
/// Unmet requirement causing a conflict.
56+
///
57+
/// The start and end time describe the conflicting time span (not the full
58+
/// requirement's time span).
59+
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
60+
pub struct ConflictRequirement {
61+
pub zone: String,
62+
pub start_time: DateTime<Utc>,
63+
pub end_time: DateTime<Utc>,
5064
}
5165

5266
#[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema)]

front/src/common/api/generatedEditoastApi.ts

+7
Original file line numberDiff line numberDiff line change
@@ -2744,10 +2744,17 @@ export type TimetableDetailedResult = {
27442744
timetable_id: number;
27452745
train_ids: number[];
27462746
};
2747+
export type ConflictRequirement = {
2748+
end_time: string;
2749+
start_time: string;
2750+
zone: string;
2751+
};
27472752
export type Conflict = {
27482753
conflict_type: 'Spacing' | 'Routing';
27492754
/** Datetime of the end of the conflict */
27502755
end_time: string;
2756+
/** List of requirements causing the conflict */
2757+
requirements: ConflictRequirement[];
27512758
/** Datetime of the start of the conflict */
27522759
start_time: string;
27532760
/** List of train ids involved in the conflict */

0 commit comments

Comments
 (0)