Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netload/NLJunctionControlBuilder.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file NLJunctionControlBuilder.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Sascha Krieg
18
/// @author Michael Behrisch
19
/// @date Mon, 9 Jul 2001
20
///
21
// Builder of microsim-junctions and tls
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <map>
26
#include <string>
27
#include <vector>
28
#include <list>
29
#include <algorithm>
30
#include <utils/xml/SUMOXMLDefinitions.h>
31
#include <utils/common/UtilExceptions.h>
32
#include <utils/common/ToString.h>
33
#include <microsim/MSGlobals.h>
34
#include <microsim/MSNet.h>
35
#include <microsim/MSJunctionLogic.h>
36
#include <microsim/MSNoLogicJunction.h>
37
#include <microsim/MSRightOfWayJunction.h>
38
#include <microsim/MSInternalJunction.h>
39
#include <microsim/MSJunctionControl.h>
40
#include <microsim/MSEventControl.h>
41
#include <microsim/traffic_lights/MSTrafficLightLogic.h>
42
#include <microsim/traffic_lights/MSSimpleTrafficLightLogic.h>
43
#include <microsim/traffic_lights/MSRailSignal.h>
44
#include <microsim/traffic_lights/MSRailCrossing.h>
45
#include <microsim/traffic_lights/MSSOTLPolicyBasedTrafficLightLogic.h>
46
#include <microsim/traffic_lights/MSSOTLPlatoonPolicy.h>
47
#include <microsim/traffic_lights/MSSOTLRequestPolicy.h>
48
#include <microsim/traffic_lights/MSSOTLPhasePolicy.h>
49
#include <microsim/traffic_lights/MSSOTLMarchingPolicy.h>
50
#include <microsim/traffic_lights/MSSwarmTrafficLightLogic.h>
51
#include <microsim/traffic_lights/MSDeterministicHiLevelTrafficLightLogic.h>
52
#include <microsim/traffic_lights/MSSOTLWaveTrafficLightLogic.h>
53
#include <microsim/traffic_lights/MSDelayBasedTrafficLightLogic.h>
54
#include <microsim/traffic_lights/MSOffTrafficLightLogic.h>
55
#include <microsim/traffic_lights/MSTLLogicControl.h>
56
#include "NLBuilder.h"
57
#include "NLJunctionControlBuilder.h"
58
#include "microsim/traffic_lights/NEMAController.h"
59
60
61
// ===========================================================================
62
// static members
63
// ===========================================================================
64
const int NLJunctionControlBuilder::NO_REQUEST_SIZE = -1;
65
66
// ===========================================================================
67
// method definitions
68
// ===========================================================================
69
NLJunctionControlBuilder::NLJunctionControlBuilder(MSNet& net, NLDetectorBuilder& db) :
70
myNet(net),
71
myDetectorBuilder(db),
72
myOffset(0),
73
myJunctions(new MSJunctionControl()),
74
myNetIsLoaded(false) {
75
myLogicControl = new MSTLLogicControl();
76
}
77
78
79
NLJunctionControlBuilder::~NLJunctionControlBuilder() {
80
delete myLogicControl;
81
delete myJunctions;
82
}
83
84
85
void
86
NLJunctionControlBuilder::openJunction(const std::string& id,
87
const std::string& key,
88
const SumoXMLNodeType type,
89
const Position pos,
90
const PositionVector& shape,
91
const std::vector<MSLane*>& incomingLanes,
92
const std::vector<MSLane*>& internalLanes,
93
const std::string& name) {
94
myActiveInternalLanes = internalLanes;
95
myActiveIncomingLanes = incomingLanes;
96
myActiveID = id;
97
myActiveKey = key;
98
myType = type;
99
myPosition.set(pos);
100
myShape = shape;
101
myActiveName = name;
102
myAdditionalParameter.clear();
103
}
104
105
106
void
107
NLJunctionControlBuilder::closeJunction(const std::string& basePath) {
108
if (myCurrentHasError) {
109
// had an error before...
110
return;
111
}
112
if (myRequestSize != NO_REQUEST_SIZE && myRequestItemNumber != myRequestSize) {
113
throw InvalidArgument("The description for the junction logic '" + myActiveKey + "' is malicious.");
114
}
115
if (myJunctions == nullptr) {
116
throw ProcessError(TL("Information about the number of nodes was missing."));
117
}
118
MSJunction* junction = nullptr;
119
switch (myType) {
120
case SumoXMLNodeType::NOJUNCTION:
121
case SumoXMLNodeType::DEAD_END:
122
case SumoXMLNodeType::DEAD_END_DEPRECATED:
123
case SumoXMLNodeType::DISTRICT:
124
case SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION:
125
if (!myActiveLogic.empty()) {
126
WRITE_WARNINGF(TL("Ignoring junction logic for junction '%'."), myActiveID)
127
}
128
junction = buildNoLogicJunction();
129
break;
130
case SumoXMLNodeType::TRAFFIC_LIGHT:
131
case SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED:
132
case SumoXMLNodeType::RIGHT_BEFORE_LEFT:
133
case SumoXMLNodeType::LEFT_BEFORE_RIGHT:
134
case SumoXMLNodeType::PRIORITY:
135
case SumoXMLNodeType::PRIORITY_STOP:
136
case SumoXMLNodeType::ALLWAY_STOP:
137
case SumoXMLNodeType::ZIPPER:
138
junction = buildLogicJunction(new MSBitsetLogic(myRequestSize, myActiveLogic, myActiveFoes, myActiveConts));
139
break;
140
case SumoXMLNodeType::INTERNAL:
141
if (MSGlobals::gUsingInternalLanes) {
142
if (!myActiveLogic.empty()) {
143
WRITE_WARNINGF(TL("Ignoring junction logic for junction '%'."), myActiveID)
144
}
145
junction = buildInternalJunction();
146
}
147
break;
148
case SumoXMLNodeType::RAIL_SIGNAL:
149
case SumoXMLNodeType::RAIL_CROSSING:
150
myOffset = 0;
151
myActiveKey = myActiveID;
152
myActiveProgram = "0";
153
myLogicType = myType == SumoXMLNodeType::RAIL_SIGNAL ? TrafficLightType::RAIL_SIGNAL : TrafficLightType::RAIL_CROSSING;
154
closeTrafficLightLogic(basePath);
155
junction = buildLogicJunction(new MSBitsetLogic(myRequestSize, myActiveLogic, myActiveFoes, myActiveConts));
156
break;
157
default:
158
throw InvalidArgument("False junction logic type.");
159
}
160
if (junction != nullptr) {
161
if (!myJunctions->add(myActiveID, junction)) {
162
throw InvalidArgument("Another junction with the id '" + myActiveID + "' exists.");
163
}
164
junction->updateParameters(myAdditionalParameter);
165
}
166
}
167
168
169
MSJunctionControl*
170
NLJunctionControlBuilder::build() const {
171
MSJunctionControl* js = myJunctions;
172
myJunctions = nullptr;
173
return js;
174
}
175
176
177
MSJunction*
178
NLJunctionControlBuilder::buildNoLogicJunction() {
179
return new MSNoLogicJunction(myActiveID, myType, myPosition, myShape, myActiveName,
180
myActiveIncomingLanes, myActiveInternalLanes);
181
}
182
183
184
MSJunction*
185
NLJunctionControlBuilder::buildLogicJunction(MSJunctionLogic* const logic) {
186
return new MSRightOfWayJunction(myActiveID, myType, myPosition, myShape, myActiveName,
187
myActiveIncomingLanes, myActiveInternalLanes, logic);
188
}
189
190
191
MSJunction*
192
NLJunctionControlBuilder::buildInternalJunction() {
193
// build the junction
194
return new MSInternalJunction(myActiveID, myType, myPosition, myShape, myActiveIncomingLanes,
195
myActiveInternalLanes);
196
}
197
198
199
MSTLLogicControl::TLSLogicVariants&
200
NLJunctionControlBuilder::getTLLogic(const std::string& id) const {
201
return getTLLogicControlToUse().get(id);
202
}
203
204
205
void
206
NLJunctionControlBuilder::closeTrafficLightLogic(const std::string& basePath) {
207
if (myActiveProgram == "off") {
208
if (myAbsDuration > 0) {
209
throw InvalidArgument("The off program for TLS '" + myActiveKey + "' has phases.");
210
}
211
MSOffTrafficLightLogic* off = new MSOffTrafficLightLogic(getTLLogicControlToUse(), myActiveKey);
212
if (!getTLLogicControlToUse().add(myActiveKey, myActiveProgram, off)) {
213
throw InvalidArgument("Another logic with id '" + myActiveKey + "' and programID '" + myActiveProgram + "' exists.");
214
}
215
return;
216
}
217
SUMOTime firstEventOffset = 0;
218
int step = 0;
219
MSSimpleTrafficLightLogic::Phases::const_iterator i = myActivePhases.begin();
220
MSTrafficLightLogic* existing = getTLLogicControlToUse().get(myActiveKey, myActiveProgram);
221
if (existing != nullptr && (existing->getLogicType() == TrafficLightType::RAIL_SIGNAL || existing->getLogicType() == TrafficLightType::RAIL_CROSSING)) {
222
existing->updateParameters(myAdditionalParameter);
223
return;
224
} else {
225
if (myLogicType != TrafficLightType::RAIL_SIGNAL && myLogicType != TrafficLightType::RAIL_CROSSING) {
226
if (myAbsDuration == 0) {
227
if (existing == nullptr) {
228
throw InvalidArgument("TLS program '" + myActiveProgram + "' for TLS '" + myActiveKey + "' has a duration of 0.");
229
} else {
230
// only modify the offset of an existing logic
231
myAbsDuration = existing->getDefaultCycleTime();
232
i = existing->getPhases().begin();
233
}
234
} else if (existing != nullptr) {
235
throw InvalidArgument("Another logic with id '" + myActiveKey + "' and programID '" + myActiveProgram + "' exists.");
236
}
237
// compute the initial step and first switch time of the tls-logic
238
// a positive offset delays all phases by x (advance by absDuration - x) while a negative offset advances all phases by x seconds
239
// @note The implementation of % for negative values is implementation defined in ISO1998
240
SUMOTime offset; // the time to run the traffic light in advance
241
if (myOffset >= 0) {
242
offset = (myNet.getCurrentTimeStep() + myAbsDuration - (myOffset % myAbsDuration)) % myAbsDuration;
243
} else {
244
offset = (myNet.getCurrentTimeStep() + ((-myOffset) % myAbsDuration)) % myAbsDuration;
245
}
246
while (offset >= (*i)->duration) {
247
step++;
248
offset -= (*i)->duration;
249
++i;
250
}
251
firstEventOffset = (*i)->duration - offset + myNet.getCurrentTimeStep();
252
if (existing != nullptr) {
253
existing->changeStepAndDuration(getTLLogicControlToUse(),
254
myNet.getCurrentTimeStep(), step, (*i)->duration - offset);
255
// parameters that are used when initializing a logic will not take
256
// effect but parameters that are checked at runtime can be used
257
// here (i.e. device.glosa.range)
258
myLogicParams[existing] = myAdditionalParameter;
259
if (myAdditionalParameter.count(MESegment::OVERRIDE_TLS_PENALTIES) != 0) {
260
// value must be available when calling setMesoTypes and before setting the rest in postLoadInitialization
261
existing->setParameter(MESegment::OVERRIDE_TLS_PENALTIES, myAdditionalParameter[MESegment::OVERRIDE_TLS_PENALTIES]);
262
}
263
return;
264
}
265
}
266
}
267
268
if (myActiveProgram == "") {
269
myActiveProgram = "default";
270
}
271
MSTrafficLightLogic* tlLogic = nullptr;
272
// build the tls-logic in dependence to its type
273
switch (myLogicType) {
274
case TrafficLightType::SWARM_BASED:
275
firstEventOffset = DELTA_T; //this is needed because swarm needs to update the pheromone on the lanes at every step
276
tlLogic = new MSSwarmTrafficLightLogic(getTLLogicControlToUse(), myActiveKey, myActiveProgram, myActivePhases, step, firstEventOffset, myAdditionalParameter);
277
break;
278
case TrafficLightType::HILVL_DETERMINISTIC:
279
tlLogic = new MSDeterministicHiLevelTrafficLightLogic(getTLLogicControlToUse(), myActiveKey, myActiveProgram, myActivePhases, step, firstEventOffset, myAdditionalParameter);
280
break;
281
case TrafficLightType::SOTL_REQUEST:
282
tlLogic = new MSSOTLPolicyBasedTrafficLightLogic(getTLLogicControlToUse(), myActiveKey, myActiveProgram, myLogicType, myActivePhases, step, firstEventOffset, myAdditionalParameter, new MSSOTLRequestPolicy(myAdditionalParameter));
283
break;
284
case TrafficLightType::SOTL_PLATOON:
285
tlLogic = new MSSOTLPolicyBasedTrafficLightLogic(getTLLogicControlToUse(), myActiveKey, myActiveProgram, myLogicType, myActivePhases, step, firstEventOffset, myAdditionalParameter, new MSSOTLPlatoonPolicy(myAdditionalParameter));
286
break;
287
case TrafficLightType::SOTL_WAVE:
288
tlLogic = new MSSOTLWaveTrafficLightLogic(getTLLogicControlToUse(), myActiveKey, myActiveProgram, myActivePhases, step, firstEventOffset, myAdditionalParameter);
289
break;
290
case TrafficLightType::SOTL_PHASE:
291
tlLogic = new MSSOTLPolicyBasedTrafficLightLogic(getTLLogicControlToUse(), myActiveKey, myActiveProgram, myLogicType, myActivePhases, step, firstEventOffset, myAdditionalParameter, new MSSOTLPhasePolicy(myAdditionalParameter));
292
break;
293
case TrafficLightType::SOTL_MARCHING:
294
tlLogic = new MSSOTLPolicyBasedTrafficLightLogic(getTLLogicControlToUse(), myActiveKey, myActiveProgram, myLogicType, myActivePhases, step, firstEventOffset, myAdditionalParameter, new MSSOTLMarchingPolicy(myAdditionalParameter));
295
break;
296
case TrafficLightType::ACTUATED:
297
// @note it is unclear how to apply the given offset in the context
298
// of variable-length phases
299
tlLogic = new MSActuatedTrafficLightLogic(getTLLogicControlToUse(),
300
myActiveKey, myActiveProgram, myOffset,
301
myActivePhases, step, (*i)->minDuration + myNet.getCurrentTimeStep(),
302
myAdditionalParameter, basePath, myActiveConditions, myActiveAssignments, myActiveFunctions);
303
break;
304
case TrafficLightType::NEMA:
305
tlLogic = new NEMALogic(getTLLogicControlToUse(),
306
myActiveKey, myActiveProgram, myOffset,
307
myActivePhases, step, (*i)->minDuration + myNet.getCurrentTimeStep(),
308
myAdditionalParameter, basePath);
309
break;
310
case TrafficLightType::DELAYBASED:
311
tlLogic = new MSDelayBasedTrafficLightLogic(getTLLogicControlToUse(),
312
myActiveKey, myActiveProgram, myOffset,
313
myActivePhases, step, (*i)->minDuration + myNet.getCurrentTimeStep(),
314
myAdditionalParameter, basePath);
315
break;
316
case TrafficLightType::STATIC:
317
tlLogic = new MSSimpleTrafficLightLogic(getTLLogicControlToUse(),
318
myActiveKey, myActiveProgram, myOffset,
319
TrafficLightType::STATIC,
320
myActivePhases, step, firstEventOffset,
321
myAdditionalParameter);
322
break;
323
case TrafficLightType::RAIL_SIGNAL:
324
tlLogic = new MSRailSignal(getTLLogicControlToUse(),
325
myActiveKey, myActiveProgram, myNet.getCurrentTimeStep(),
326
myAdditionalParameter);
327
break;
328
case TrafficLightType::RAIL_CROSSING:
329
tlLogic = new MSRailCrossing(getTLLogicControlToUse(),
330
myActiveKey, myActiveProgram, myNet.getCurrentTimeStep(),
331
myAdditionalParameter);
332
break;
333
case TrafficLightType::OFF:
334
tlLogic = new MSOffTrafficLightLogic(getTLLogicControlToUse(), myActiveKey);
335
break;
336
case TrafficLightType::INVALID:
337
throw ProcessError(TLF("Invalid traffic light type '%'", toString(myLogicType)));
338
}
339
myActivePhases.clear();
340
if (tlLogic != nullptr) {
341
if (getTLLogicControlToUse().add(myActiveKey, myActiveProgram, tlLogic)) {
342
if (myNetIsLoaded) {
343
myAdditionalLogics.push_back(tlLogic);
344
} else if (myLogicType == TrafficLightType::RAIL_SIGNAL) {
345
// special case: intialize earlier because signals are already used when
346
// loading train routes in additional files
347
myRailSignals.push_back(tlLogic);
348
} else {
349
myNetworkLogics.push_back(tlLogic);
350
}
351
} else {
352
WRITE_ERRORF(TL("Another logic with id '%' and programID '%' exists."), myActiveKey, myActiveProgram);
353
}
354
}
355
}
356
357
358
void
359
NLJunctionControlBuilder::initJunctionLogic(const std::string& id) {
360
myActiveKey = id;
361
myActiveProgram = "";
362
myActiveLogic.clear();
363
myActiveFoes.clear();
364
myActiveConts.reset();
365
myRequestSize = NO_REQUEST_SIZE; // seems not to be used
366
myRequestItemNumber = 0;
367
myCurrentHasError = false;
368
}
369
370
371
void
372
NLJunctionControlBuilder::addLogicItem(int request,
373
const std::string& response,
374
const std::string& foes,
375
bool cont) {
376
if (myCurrentHasError) {
377
// had an error
378
return;
379
}
380
if (request >= SUMO_MAX_CONNECTIONS) {
381
// bad request
382
myCurrentHasError = true;
383
throw InvalidArgument("Junction logic '" + myActiveKey + "' is larger than allowed; recheck the network.");
384
}
385
if (myRequestSize == NO_REQUEST_SIZE) {
386
// initialize
387
myRequestSize = (int)response.size();
388
}
389
if (static_cast<int>(response.size()) != myRequestSize) {
390
myCurrentHasError = true;
391
throw InvalidArgument("Invalid response size " + toString(response.size()) +
392
" in Junction logic '" + myActiveKey + "' (expected " + toString(myRequestSize) + ")");
393
}
394
if (static_cast<int>(foes.size()) != myRequestSize) {
395
myCurrentHasError = true;
396
throw InvalidArgument("Invalid foes size " + toString(foes.size()) +
397
" in Junction logic '" + myActiveKey + "' (expected " + toString(myRequestSize) + ")");
398
}
399
// assert that the logicitems come ordered by their request index
400
assert((int)myActiveLogic.size() == request);
401
assert((int)myActiveFoes.size() == request);
402
// add the read response for the given request index
403
myActiveLogic.push_back(std::bitset<SUMO_MAX_CONNECTIONS>(response));
404
// add the read junction-internal foes for the given request index
405
myActiveFoes.push_back(std::bitset<SUMO_MAX_CONNECTIONS>(foes));
406
// add whether the vehicle may drive a little bit further
407
myActiveConts.set(request, cont);
408
// increse number of set information
409
myRequestItemNumber++;
410
}
411
412
413
void
414
NLJunctionControlBuilder::initTrafficLightLogic(const std::string& id, const std::string& programID,
415
TrafficLightType type, SUMOTime offset) {
416
myActiveKey = id;
417
myActiveProgram = programID;
418
myActivePhases.clear();
419
myActiveConditions.clear();
420
myActiveAssignments.clear();
421
myActiveFunctions.clear();
422
myAbsDuration = 0;
423
myRequestSize = NO_REQUEST_SIZE;
424
myLogicType = type;
425
myOffset = offset;
426
myAdditionalParameter.clear();
427
}
428
429
430
void
431
NLJunctionControlBuilder::addPhase(MSPhaseDefinition* phase) {
432
// build and add the phase definition to the list
433
myActivePhases.push_back(phase);
434
// add phase duration to the absolute duration
435
myAbsDuration += phase->duration;
436
}
437
438
439
bool
440
NLJunctionControlBuilder::addCondition(const std::string& id, const std::string& value) {
441
if (myActiveConditions.count(id) == 0) {
442
myActiveConditions[id] = value;
443
return true;
444
} else {
445
return false;
446
}
447
}
448
449
450
void
451
NLJunctionControlBuilder::addAssignment(const std::string& id, const std::string& check, const std::string& value) {
452
if (myActiveFunction.id == "") {
453
myActiveAssignments.push_back(std::make_tuple(id, check, value));
454
} else {
455
myActiveFunction.assignments.push_back(std::make_tuple(id, check, value));
456
}
457
}
458
459
460
void
461
NLJunctionControlBuilder::addFunction(const std::string& id, int nArgs) {
462
myActiveFunction.id = id;
463
myActiveFunction.nArgs = nArgs;
464
}
465
466
467
void
468
NLJunctionControlBuilder::closeFunction() {
469
myActiveFunctions[myActiveFunction.id] = myActiveFunction;
470
myActiveFunction.id = "";
471
myActiveFunction.assignments.clear();
472
}
473
474
475
MSTLLogicControl*
476
NLJunctionControlBuilder::buildTLLogics() {
477
if (!myLogicControl->closeNetworkReading()) {
478
throw ProcessError(TL("Traffic lights could not be built."));
479
}
480
for (MSTrafficLightLogic* const logic : myRailSignals) {
481
logic->init(myDetectorBuilder);
482
}
483
MSTLLogicControl* ret = myLogicControl;
484
myNetIsLoaded = true;
485
myLogicControl = nullptr;
486
return ret;
487
}
488
489
490
void
491
NLJunctionControlBuilder::addParam(const std::string& key,
492
const std::string& value) {
493
myAdditionalParameter[key] = value;
494
}
495
496
497
MSTLLogicControl&
498
NLJunctionControlBuilder::getTLLogicControlToUse() const {
499
if (myLogicControl != nullptr) {
500
return *myLogicControl;
501
}
502
return myNet.getTLSControl();
503
}
504
505
506
const std::string&
507
NLJunctionControlBuilder::getActiveKey() const {
508
return myActiveKey;
509
}
510
511
512
const std::string&
513
NLJunctionControlBuilder::getActiveSubKey() const {
514
return myActiveProgram;
515
}
516
517
518
void
519
NLJunctionControlBuilder::postLoadInitialization() {
520
for (MSTrafficLightLogic* const logic : myNetworkLogics) {
521
logic->init(myDetectorBuilder);
522
}
523
for (MSTrafficLightLogic* const logic : myAdditionalLogics) {
524
logic->init(myDetectorBuilder);
525
}
526
// delay parameter loading until initialization
527
for (auto item : myLogicParams) {
528
item.first->updateParameters(item.second);
529
}
530
}
531
532
533
MSJunction*
534
NLJunctionControlBuilder::retrieve(const std::string id) {
535
if (myJunctions != nullptr) {
536
return myJunctions->get(id);
537
} else {
538
return nullptr;
539
}
540
}
541
542
543
/****************************************************************************/
544
545