Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 MSTrafficLightLogic.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Sept 2002
19 : ///
20 : // The parent class for traffic light logics
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <cassert>
25 : #include <string>
26 : #include <iostream>
27 : #include <map>
28 : #include <microsim/MSLink.h>
29 : #include <microsim/MSLane.h>
30 : #include <microsim/MSEventControl.h>
31 : #include <microsim/MSJunctionLogic.h>
32 : #include <microsim/MSNet.h>
33 : #include <microsim/MSEdge.h>
34 : #include <microsim/MSGlobals.h>
35 : #include <mesosim/MELoop.h>
36 : #include <mesosim/MESegment.h>
37 : #include "MSTLLogicControl.h"
38 : #include "MSTrafficLightLogic.h"
39 :
40 :
41 : // ===========================================================================
42 : // static value definitions
43 : // ===========================================================================
44 : const MSTrafficLightLogic::LaneVector MSTrafficLightLogic::myEmptyLaneVector;
45 :
46 : #define SHORT_EDGE ((SUMOVTypeParameter::getDefault().length + SUMOVTypeParameter::getDefault().minGap) * 2)
47 :
48 : // ===========================================================================
49 : // member method definitions
50 : // ===========================================================================
51 : /* -------------------------------------------------------------------------
52 : * member method definitions
53 : * ----------------------------------------------------------------------- */
54 125176 : MSTrafficLightLogic::SwitchCommand::SwitchCommand(MSTLLogicControl& tlcontrol,
55 125176 : MSTrafficLightLogic* tlLogic, SUMOTime nextSwitch) :
56 125176 : myTLControl(tlcontrol), myTLLogic(tlLogic),
57 125176 : myAssumedNextSwitch(nextSwitch), myAmValid(true) {
58 : // higher than default command priority of 0
59 125176 : priority = std::numeric_limits<int>::max();
60 125176 : }
61 :
62 :
63 248842 : MSTrafficLightLogic::SwitchCommand::~SwitchCommand() {}
64 :
65 :
66 :
67 : SUMOTime
68 5813784 : MSTrafficLightLogic::SwitchCommand::execute(SUMOTime t) {
69 : // check whether this command has been descheduled
70 5813784 : if (!myAmValid) {
71 : return 0;
72 : }
73 5805984 : int step1 = myTLLogic->getCurrentPhaseIndex();
74 5805984 : SUMOTime next = myTLLogic->trySwitch();
75 5806449 : while (next == 0) {
76 : // skip phase and switch again
77 465 : next = myTLLogic->trySwitch();
78 : }
79 5805984 : int step2 = myTLLogic->getCurrentPhaseIndex();
80 5805984 : if (step1 != step2) {
81 3666257 : if (myTLLogic->isActive()) {
82 : // execute any action connected to this tls
83 2867517 : const MSTLLogicControl::TLSLogicVariants& vars = myTLControl.get(myTLLogic->getID());
84 : // set link priorities
85 2867517 : myTLLogic->setTrafficLightSignals(t);
86 : // execute switch actions
87 2867517 : vars.executeOnSwitchActions();
88 : }
89 : }
90 5805984 : myAssumedNextSwitch += next;
91 5805984 : return next;
92 : }
93 :
94 :
95 : void
96 8246 : MSTrafficLightLogic::SwitchCommand::deschedule(MSTrafficLightLogic* tlLogic) {
97 8246 : if (tlLogic == myTLLogic) {
98 8246 : myAmValid = false;
99 8246 : myAssumedNextSwitch = -1;
100 : }
101 8246 : }
102 :
103 :
104 : SUMOTime
105 1012 : MSTrafficLightLogic::SwitchCommand::shiftTime(SUMOTime currentTime, SUMOTime execTime, SUMOTime newTime) {
106 : if (myTLLogic->getDefaultCycleTime() == DELTA_T) {
107 : // MSRailSignal
108 : return newTime;
109 : } else {
110 : UNUSED_PARAMETER(currentTime);
111 : UNUSED_PARAMETER(execTime);
112 : // XXX changeStepAndDuration (computed as in NLJunctionControlBuilder::closeTrafficLightLogic
113 : return newTime;
114 : }
115 : }
116 :
117 : /* -------------------------------------------------------------------------
118 : * member method definitions
119 : * ----------------------------------------------------------------------- */
120 121627 : MSTrafficLightLogic::MSTrafficLightLogic(MSTLLogicControl& tlcontrol, const std::string& id,
121 : const std::string& programID, const SUMOTime offset, const TrafficLightType logicType, const SUMOTime delay,
122 121627 : const Parameterised::Map& parameters) :
123 : Named(id), Parameterised(parameters),
124 121627 : myProgramID(programID),
125 121627 : myOffset(offset),
126 121627 : myLogicType(logicType),
127 121627 : myCurrentDurationIncrement(-1),
128 121627 : myDefaultCycleTime(0),
129 121627 : myAmActive(true) {
130 121627 : mySwitchCommand = new SwitchCommand(tlcontrol, this, delay);
131 121627 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(mySwitchCommand, delay);
132 121627 : }
133 :
134 :
135 : void
136 108506 : MSTrafficLightLogic::init(NLDetectorBuilder&) {
137 108506 : const Phases& phases = getPhases();
138 108506 : if (phases.size() > 0 && (MSGlobals::gUseMesoSim || MSGlobals::gTLSPenalty > 0)) {
139 16715 : initMesoTLSPenalties();
140 : }
141 108506 : if (phases.size() > 1) {
142 : bool haveWarnedAboutUnusedStates = false;
143 608778 : for (int i = 0; i < (int)phases.size(); ++i) {
144 : // warn about unused states
145 : std::vector<int> nextPhases;
146 522451 : nextPhases.push_back((i + 1) % phases.size());
147 : bool iNextDefault = true;
148 522451 : if (phases[i]->nextPhases.size() > 0) {
149 413 : nextPhases = phases[i]->nextPhases;
150 : iNextDefault = false;
151 : }
152 1045128 : for (int iNext : nextPhases) {
153 522683 : if (iNext < 0 || iNext >= (int)phases.size()) {
154 2 : throw ProcessError("Invalid nextPhase " + toString(iNext) + " in tlLogic '" + getID()
155 8 : + "', program '" + getProgramID() + "' with " + toString(phases.size()) + " phases");
156 : }
157 522681 : if (iNext == i && (int)nextPhases.size() == 1 && (int)phases.size() > 1) {
158 6 : WRITE_WARNINGF("Phase % only loops backs to itself in tlLogic '%', program '%'.", i, getID(), getProgramID());
159 : }
160 523324 : const std::string optionalFrom = iNextDefault ? "" : " from phase " + toString(i);
161 522681 : const std::string& state1 = phases[i]->getState();
162 522681 : const std::string& state2 = phases[iNext]->getState();
163 522681 : if (state1.size() != state2.size()) {
164 2 : throw ProcessError("Mismatching phase state length in tlLogic '" + getID()
165 8 : + "', program '" + getProgramID() + "' in phases " + toString(i) + " and " + toString(iNext));
166 : }
167 522679 : if (!haveWarnedAboutUnusedStates && state1.size() > myLanes.size() + myIgnoredIndices.size()) {
168 228 : WRITE_WARNINGF(TL("Unused states in tlLogic '%', program '%' in phase % after tl-index %"),
169 : getID(), getProgramID(), i, (int)myLanes.size() - 1);
170 : haveWarnedAboutUnusedStates = true;
171 : }
172 : // detect illegal states
173 : const std::string::size_type illegal = state1.find_first_not_of(SUMOXMLDefinitions::ALLOWED_TLS_LINKSTATES);
174 522679 : if (std::string::npos != illegal) {
175 2 : throw ProcessError("Illegal character '" + toString(state1[illegal]) + "' in tlLogic '" + getID()
176 6 : + "', program '" + getProgramID() + "' in phase " + toString(i));
177 : }
178 : // warn about transitions from green to red without intermediate yellow
179 : bool haveWarned = false;
180 6566638 : for (int j = 0; j < (int)MIN3(state1.size(), state2.size(), myLanes.size()) && !haveWarned; ++j) {
181 6043961 : if ((LinkState)state2[j] == LINKSTATE_TL_RED
182 6043961 : && ((LinkState)state1[j] == LINKSTATE_TL_GREEN_MAJOR
183 3508927 : || (LinkState)state1[j] == LINKSTATE_TL_GREEN_MINOR)) {
184 31601 : for (LaneVector::const_iterator it = myLanes[j].begin(); it != myLanes[j].end(); ++it) {
185 16535 : if ((*it)->getPermissions() != SVC_PEDESTRIAN) {
186 1519 : if (getLogicType() != TrafficLightType::NEMA) {
187 1045 : WRITE_WARNINGF(TL("Missing yellow phase in tlLogic '%', program '%' for tl-index % when switching% to phase %."),
188 : getID(), getProgramID(), j, optionalFrom, iNext);
189 : // one warning per program is enough
190 : haveWarned = true;
191 : }
192 : break;
193 : }
194 : }
195 : }
196 : }
197 : }
198 522451 : }
199 : }
200 : // warn about links that never get the green light
201 108500 : std::vector<bool> foundGreen(phases.front()->getState().size(), false);
202 653102 : for (int i = 0; i < (int)phases.size(); ++i) {
203 544602 : const std::string& state = phases[i]->getState();
204 6666148 : for (int j = 0; j < (int)state.size(); ++j) {
205 6121546 : LinkState ls = (LinkState)state[j];
206 6121546 : if (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR || ls == LINKSTATE_TL_OFF_BLINKING || ls == LINKSTATE_TL_OFF_NOSIGNAL || ls == LINKSTATE_STOP) {
207 : foundGreen[j] = true;
208 : }
209 : }
210 : }
211 108500 : std::vector<bool> usedIndices(phases.front()->getState().size(), false);
212 1048161 : for (auto lv : myLinks) {
213 1878655 : for (const MSLink* link : lv) {
214 938994 : if (link->getTLIndex() >= 0) {
215 : usedIndices[link->getTLIndex()] = true;
216 : }
217 : }
218 939661 : }
219 2083400 : for (int j = 0; j < (int)foundGreen.size(); ++j) {
220 933729 : if (!foundGreen[j] && usedIndices[j]) {
221 1587 : WRITE_WARNINGF(TL("Missing green phase in tlLogic '%', program '%' for tl-index %."), getID(), getProgramID(), j);
222 529 : break;
223 : }
224 : }
225 : // check direct conflict (two green links targeting the same lane)
226 108500 : const int numLinks = (int)myLinks.size();
227 : std::set<const MSLane*> unsafeGreen;
228 : int firstUnsafePhase = -1;
229 : const MSLane* firstUnsafeLane = nullptr;
230 : int firstUnsafeOrigins = 0;
231 : int unsafeGreenPhases = 0;
232 653102 : for (int i = 0; i < (int)phases.size(); ++i) {
233 : std::map<const MSLane*, int, ComparatorNumericalIdLess> greenLanes;
234 544602 : const std::string& state = phases[i]->getState();
235 6654611 : for (int j = 0; j < numLinks; ++j) {
236 6110009 : if (state[j] == LINKSTATE_TL_GREEN_MAJOR) {
237 1833913 : for (const MSLink* link : myLinks[j]) {
238 916888 : if (link->isInternalJunctionLink()) {
239 : // links from an internal junction have implicit priority in case of conflict
240 158 : continue;
241 : }
242 916730 : greenLanes[link->getLane()] += 1;
243 : }
244 : }
245 : }
246 : bool unsafe = false;
247 1453051 : for (auto item : greenLanes) {
248 908449 : if (item.second > 1) {
249 3386 : if (unsafeGreenPhases == 0 && !unsafe) {
250 : firstUnsafePhase = i;
251 581 : firstUnsafeLane = item.first;
252 : firstUnsafeOrigins = item.second;
253 : }
254 : unsafe = true;
255 : unsafeGreen.insert(item.first);
256 : }
257 : }
258 544602 : if (unsafe) {
259 1017 : unsafeGreenPhases++;
260 : }
261 : }
262 108500 : if (unsafeGreenPhases > 0) {
263 581 : const std::string furtherAffected = unsafeGreen.size() > 1 || unsafeGreenPhases > 1 ? TLF(" Overall % lanes in % phases are unsafe.", unsafeGreen.size(), unsafeGreenPhases) : "";
264 1743 : WRITE_WARNINGF(TL("Unsafe green phase % in tlLogic '%', program '%'. Lane '%' is targeted by % 'G'-links. (use 'g' instead)%"),
265 : firstUnsafePhase, getID(), getProgramID(), firstUnsafeLane->getID(), firstUnsafeOrigins, furtherAffected);
266 : }
267 :
268 : // check incompatible junction logic
269 : // this can happen if the network was built with a very different signal
270 : // plan from the one currently being used.
271 : // Connections that never had a common green phase during network building may
272 : // have a symmetric response relation to avoid certain kinds of jam but this
273 : // can lead to deadlock if a different program gives minor green to both
274 : // connections at the same time
275 : // Note: mutual conflict between 'g' and 'G' is expected for traffic_light_right_on_red
276 :
277 108500 : const bool mustCheck = MSNet::getInstance()->hasInternalLinks();
278 : // The checks only runs for definitions from additional file and this is sufficient.
279 : // The distinction is implicit because original logics are loaded earlier and at that time hasInternalLinks is always false
280 : // Also, when the network has no internal links, mutual conflicts are not built by netconvert
281 : //std::cout << "init tlLogic=" << getID() << " prog=" << getProgramID() << " links=" << myLinks.size() << " internal=" << MSNet::getInstance()->hasInternalLinks() << "\n";
282 108500 : if (mustCheck && phases.size() > 0) {
283 : // see NBNode::tlsConflict
284 : std::set<const MSJunction*> controlledJunctions;
285 321325 : for (int j = 0; j < numLinks; ++j) {
286 555961 : for (int k = 0; k < (int)myLinks[j].size(); ++k) {
287 277646 : MSLink* link = myLinks[j][k];
288 : assert(link->getJunction() != nullptr);
289 277646 : controlledJunctions.insert(link->getJunction());
290 : }
291 : }
292 43010 : const std::string minor = "gos";
293 86726 : for (const MSJunction* junction : controlledJunctions) {
294 43716 : const MSJunctionLogic* logic = junction->getLogic();
295 43716 : if (logic != nullptr) {
296 : // find symmetrical response
297 : const int logicSize = logic->getLogicSize();
298 : bool foundProblem = false;
299 : std::vector<int> tlIndex;
300 321949 : for (int u = 0; u < logicSize && !foundProblem; u++) {
301 278292 : const MSLogicJunction::LinkBits& response = logic->getResponseFor(u);
302 3975706 : for (int v = 0; v < logicSize && !foundProblem; v++) {
303 3697414 : if (response.test(v)) {
304 718567 : if (logic->getResponseFor(v).test(u)) {
305 : // get tls link index for links u and v
306 165326 : if (tlIndex.size() == 0) {
307 : // init tlindex for all links once
308 6005 : tlIndex.resize(logicSize, -1);
309 122813 : for (int j = 0; j < numLinks; ++j) {
310 234059 : for (int k = 0; k < (int)myLinks[j].size(); ++k) {
311 117251 : MSLink* link = myLinks[j][k];
312 117251 : if (link->getJunction() == junction) {
313 116459 : if (link->fromInternalLane()) {
314 : // internal links may have their own control (i.e. for indirect left turn) but they also have their own conflict matrix
315 174 : continue;
316 : }
317 116285 : if (link->isCont() && link->getViaLane() != nullptr && link->getViaLane()->getLinkCont()[0]->getTLIndex() >= 0) {
318 : // if the internal junction link is controlled, the first-part indices are not deadlock-relevant
319 98 : continue;
320 : }
321 116187 : tlIndex[link->getIndex()] = link->getTLIndex();
322 : }
323 : }
324 : }
325 : }
326 165326 : const int tlu = tlIndex[u];
327 165326 : const int tlv = tlIndex[v];
328 165326 : if (tlu >= 0 && tlv >= 0) {
329 : int phaseIndex = 0;
330 1443532 : for (MSPhaseDefinition* p : phases) {
331 1279296 : if (minor.find(p->getState()[tlu]) != std::string::npos
332 1279296 : && minor.find(p->getState()[tlv]) != std::string::npos) {
333 30 : WRITE_WARNING(TLF("Program '%' at tlLogic '%' is incompatible with logic at junction '%' (mutual conflict between link indices %,% tl indices %,% phase %).\n"
334 : " To avoid deadlock/collisions, either: rebuild the signal plan with a newer version of netconvert/netedit\n"
335 : " or rebuild the network with option '--tls.ignore-internal-junction-jam' or include the program when building.",
336 : getProgramID(), getID(), junction->getID(), u, v, tlu, tlv, phaseIndex));
337 : // only one warning per program
338 : foundProblem = true;
339 10 : break;
340 : }
341 1279286 : phaseIndex++;
342 : }
343 : }
344 : }
345 : }
346 : }
347 : }
348 43657 : }
349 : }
350 : }
351 108500 : myNumLinks = (int)myLinks.size();
352 108500 : }
353 :
354 :
355 242832 : MSTrafficLightLogic::~MSTrafficLightLogic() {
356 : // no need to do something about mySwitchCommand here,
357 : // it is handled by the event control
358 242832 : }
359 :
360 :
361 : // ----------- Handling of controlled links
362 : void
363 867512 : MSTrafficLightLogic::addLink(MSLink* link, MSLane* lane, int pos) {
364 : // !!! should be done within the loader (checking necessary)
365 867512 : myLinks.reserve(pos + 1);
366 1736016 : while ((int)myLinks.size() <= pos) {
367 868504 : myLinks.push_back(LinkVector());
368 : }
369 867512 : myLinks[pos].push_back(link);
370 : //
371 867512 : myLanes.reserve(pos + 1);
372 1736016 : while ((int)myLanes.size() <= pos) {
373 868504 : myLanes.push_back(LaneVector());
374 : }
375 867512 : myLanes[pos].push_back(lane);
376 867512 : link->setTLState((LinkState) getCurrentPhaseDef().getState()[pos], MSNet::getInstance()->getCurrentTimeStep());
377 867512 : }
378 :
379 :
380 : void
381 9781 : MSTrafficLightLogic::adaptLinkInformationFrom(const MSTrafficLightLogic& logic) {
382 9781 : myLinks = logic.myLinks;
383 9781 : myLanes = logic.myLanes;
384 : myIgnoredIndices = logic.myIgnoredIndices;
385 9781 : }
386 :
387 :
388 : std::map<MSLink*, LinkState>
389 110976 : MSTrafficLightLogic::collectLinkStates() const {
390 : std::map<MSLink*, LinkState> ret;
391 971200 : for (LinkVectorVector::const_iterator i1 = myLinks.begin(); i1 != myLinks.end(); ++i1) {
392 : const LinkVector& l = (*i1);
393 1719452 : for (LinkVector::const_iterator i2 = l.begin(); i2 != l.end(); ++i2) {
394 859228 : ret[*i2] = (*i2)->getState();
395 : }
396 : }
397 110976 : return ret;
398 : }
399 :
400 :
401 : bool
402 21117046 : MSTrafficLightLogic::setTrafficLightSignals(SUMOTime t) const {
403 : // get the current traffic light signal combination
404 21117046 : const std::string& state = getCurrentPhaseDef().getState();
405 : // go through the links
406 86478501 : for (int i = 0; i < (int)myLinks.size(); i++) {
407 65361455 : const LinkVector& currGroup = myLinks[i];
408 65361455 : LinkState ls = (LinkState) state[i];
409 130847157 : for (LinkVector::const_iterator j = currGroup.begin(); j != currGroup.end(); j++) {
410 65485702 : (*j)->setTLState(ls, t);
411 : }
412 : }
413 21117046 : return true;
414 : }
415 :
416 :
417 : void
418 0 : MSTrafficLightLogic::resetLinkStates(const std::map<MSLink*, LinkState>& vals) const {
419 0 : for (LinkVectorVector::const_iterator i1 = myLinks.begin(); i1 != myLinks.end(); ++i1) {
420 : const LinkVector& l = (*i1);
421 0 : for (LinkVector::const_iterator i2 = l.begin(); i2 != l.end(); ++i2) {
422 : assert(vals.find(*i2) != vals.end());
423 0 : (*i2)->setTLState(vals.find(*i2)->second, MSNet::getInstance()->getCurrentTimeStep());
424 : }
425 : }
426 0 : }
427 :
428 :
429 : // ----------- Static Information Retrieval
430 : int
431 0 : MSTrafficLightLogic::getLinkIndex(const MSLink* const link) const {
432 : int index = 0;
433 0 : for (LinkVectorVector::const_iterator i1 = myLinks.begin(); i1 != myLinks.end(); ++i1, ++index) {
434 : const LinkVector& l = (*i1);
435 0 : for (LinkVector::const_iterator i2 = l.begin(); i2 != l.end(); ++i2) {
436 0 : if ((*i2) == link) {
437 : return index;
438 : }
439 : }
440 : }
441 : return -1;
442 : }
443 :
444 :
445 :
446 : // ----------- Dynamic Information Retrieval
447 : SUMOTime
448 118177 : MSTrafficLightLogic::getNextSwitchTime() const {
449 118177 : return mySwitchCommand != nullptr ? mySwitchCommand->getNextSwitchTime() : -1;
450 : }
451 :
452 :
453 : SUMOTime
454 4985 : MSTrafficLightLogic::getSpentDuration(SUMOTime simStep) const {
455 4985 : if (simStep == -1) {
456 4337 : simStep = SIMSTEP;
457 : }
458 4985 : return simStep - getCurrentPhaseDef().myLastSwitch;
459 : }
460 :
461 :
462 : // ----------- Changing phases and phase durations
463 : void
464 0 : MSTrafficLightLogic::addOverridingDuration(SUMOTime duration) {
465 0 : myOverridingTimes.push_back(duration);
466 0 : }
467 :
468 :
469 : void
470 0 : MSTrafficLightLogic::setCurrentDurationIncrement(SUMOTime delay) {
471 0 : myCurrentDurationIncrement = delay;
472 0 : }
473 :
474 :
475 16751 : void MSTrafficLightLogic::initMesoTLSPenalties() {
476 16751 : if (myLogicType == TrafficLightType::RAIL_SIGNAL) {
477 4 : return;
478 : }
479 : // set mesoscopic time penalties
480 16747 : const Phases& phases = getPhases();
481 16747 : const int numLinks = (int)myLinks.size();
482 : // warning already given if not all states are used
483 : assert(numLinks <= (int)phases.front()->getState().size());
484 : SUMOTime duration = 0;
485 16747 : std::vector<double> firstRedDuration(numLinks, 0);
486 16747 : std::vector<double> redDuration(numLinks, 0);
487 16747 : std::vector<double> totalRedDuration(numLinks, 0);
488 16747 : std::vector<double> penalty(numLinks, 0);
489 121130 : for (int i = 0; i < (int)phases.size(); ++i) {
490 104383 : const std::string& state = phases[i]->getState();
491 104383 : duration += phases[i]->duration;
492 : // warn about transitions from green to red without intermediate yellow
493 1340002 : for (int j = 0; j < numLinks; ++j) {
494 1235619 : double& red = redDuration[j];
495 1235619 : if ((LinkState)state[j] == LINKSTATE_TL_RED
496 1235619 : || (LinkState)state[j] == LINKSTATE_TL_REDYELLOW) {
497 713680 : red += STEPS2TIME(phases[i]->duration);
498 713680 : totalRedDuration[j] += STEPS2TIME(phases[i]->duration);
499 521939 : } else if (red > 0) {
500 82141 : if (firstRedDuration[j] == 0) {
501 : // store for handling wrap-around
502 82075 : firstRedDuration[j] = red;
503 : } else {
504 : // vehicle may arive in any second or the red duration
505 : // compute the sum over [0,red]
506 66 : penalty[j] += 0.5 * (red * red + red);
507 : }
508 82141 : red = 0;
509 : }
510 : }
511 : }
512 : // final phase and wrap-around to first phase
513 195409 : for (int j = 0; j < numLinks; ++j) {
514 178662 : double red = redDuration[j] + firstRedDuration[j];
515 178662 : if (red) {
516 170028 : penalty[j] += 0.5 * (red * red + red);
517 : }
518 : }
519 16747 : double tlsPenalty = MSGlobals::gTLSPenalty;
520 16747 : const double durationSeconds = STEPS2TIME(duration);
521 : std::set<const MSJunction*> controlledJunctions;
522 : std::set<const MSEdge*> shortEdges;;
523 16747 : const bool overridePenalty = StringUtils::toBool(getParameter(MESegment::OVERRIDE_TLS_PENALTIES, "0"));
524 195409 : for (int j = 0; j < numLinks; ++j) {
525 357272 : for (int k = 0; k < (int)myLinks[j].size(); ++k) {
526 178610 : MSLink* link = myLinks[j][k];
527 : MSEdge& edge = link->getLaneBefore()->getEdge();
528 178610 : if (MSGlobals::gUseMesoSim) {
529 178450 : const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(edge.getEdgeType());
530 178450 : tlsPenalty = edgeType.tlsPenalty;
531 178450 : double greenFraction = (durationSeconds - totalRedDuration[j]) / durationSeconds;
532 178450 : if (edgeType.tlsFlowPenalty == 0) {
533 : greenFraction = 1;
534 : } else {
535 648 : greenFraction = MAX2(MIN2(greenFraction / edgeType.tlsFlowPenalty, 1.0), 0.01);
536 : }
537 : if (greenFraction == 0.01) {
538 48 : WRITE_WARNINGF(TL("Green fraction is only 1% for link % in tlLogic '%', program '%'."), "%", j, getID(), getProgramID());
539 : }
540 : link->setGreenFraction(greenFraction);
541 178450 : if (tlsPenalty > 0 && edge.getLength() < SHORT_EDGE && shortEdges.count(&edge) == 0) {
542 4 : shortEdges.insert(&edge);
543 12 : WRITE_WARNINGF(TL("Edge '%' is shorter than %m (%m) and will cause incorrect flow reduction with option --meso-tls-penalty"), edge.getID(), SHORT_EDGE, edge.getLength());
544 : }
545 178450 : if (overridePenalty) {
546 132 : MESegment* last = MSGlobals::gMesoNet->getSegmentForEdge(edge, std::numeric_limits<double>::max());
547 : last->overrideTLSPenalty();
548 : }
549 : }
550 178610 : link->setMesoTLSPenalty(TIME2STEPS(tlsPenalty * penalty[j] / durationSeconds));
551 178610 : controlledJunctions.insert(link->getLane()->getEdge().getFromJunction()); // MSLink::myJunction is not yet initialized
552 : //std::cout << " tls=" << getID() << " i=" << j << " link=" << link->getDescription() << " p=" << penalty[j] << " fr=" << firstRedDuration[j] << " r=" << redDuration[j] << " tr=" << totalRedDuration[j] << " durSecs=" << durationSeconds << " tlsPen=" << STEPS2TIME(link->getMesoTLSPenalty()) << " gF=" << myLinks[j][k]->getGreenFraction() << "\n";
553 : }
554 : }
555 : // initialize empty-net travel times
556 : // XXX refactor after merging sharps (links know their incoming edge)
557 33526 : for (std::set<const MSJunction*>::iterator it = controlledJunctions.begin(); it != controlledJunctions.end(); ++it) {
558 16779 : const ConstMSEdgeVector incoming = (*it)->getIncoming();
559 101339 : for (ConstMSEdgeVector::const_iterator it_e = incoming.begin(); it_e != incoming.end(); ++it_e) {
560 84560 : const_cast<MSEdge*>(*it_e)->recalcCache();
561 : }
562 16779 : }
563 :
564 16747 : }
565 :
566 :
567 : void
568 952 : MSTrafficLightLogic::ignoreLinkIndex(int pos) {
569 : myIgnoredIndices.insert(pos);
570 952 : }
571 :
572 : SUMOTime
573 291224 : MSTrafficLightLogic::getTimeInCycle() const {
574 291224 : return mapTimeInCycle(SIMSTEP);
575 : }
576 :
577 :
578 : SUMOTime
579 0 : MSTrafficLightLogic::mapTimeInCycle(SUMOTime t) const {
580 0 : return (t - myOffset) % myDefaultCycleTime;
581 : }
582 :
583 :
584 : bool
585 0 : MSTrafficLightLogic::isSelected() const {
586 0 : return MSNet::getInstance()->isSelected(this);
587 : }
588 :
589 :
590 : void
591 122124 : MSTrafficLightLogic::activateProgram() {
592 122124 : myAmActive = true;
593 : // updated the traffic light logic stored in the link
594 284063 : for (const LinkVector& currGroup : myLinks) {
595 324086 : for (MSLink* link : currGroup) {
596 162147 : link->setTLLogic(this);
597 : }
598 : }
599 122124 : }
600 :
601 :
602 : void
603 10390 : MSTrafficLightLogic::deactivateProgram() {
604 10390 : myAmActive = false;
605 10390 : }
606 :
607 : bool
608 18822 : MSTrafficLightLogic::getsMajorGreen(int linkIndex) const {
609 18822 : if (linkIndex >= 0 && linkIndex < getNumLinks()) {
610 43835 : for (const MSPhaseDefinition* p : getPhases()) {
611 : const std::string& s = p->getState();
612 : assert(linkIndex < (int)s.size());
613 39097 : if (s[linkIndex] == LINKSTATE_TL_GREEN_MAJOR) {
614 : return true;
615 : }
616 : }
617 : }
618 : return false;
619 :
620 : }
621 :
622 :
623 : SUMOTime
624 1698 : MSTrafficLightLogic::getMinDur(int step) const {
625 1698 : const MSPhaseDefinition& p = step < 0 ? getCurrentPhaseDef() : getPhase(step);
626 1698 : return p.minDuration;
627 : }
628 :
629 : SUMOTime
630 2970 : MSTrafficLightLogic::getMaxDur(int step) const {
631 2970 : const MSPhaseDefinition& p = step < 0 ? getCurrentPhaseDef() : getPhase(step);
632 2970 : return p.maxDuration;
633 : }
634 :
635 : SUMOTime
636 316836 : MSTrafficLightLogic::getEarliestEnd(int step) const {
637 316836 : const MSPhaseDefinition& p = step < 0 ? getCurrentPhaseDef() : getPhase(step);
638 316836 : return p.earliestEnd;
639 : }
640 :
641 : SUMOTime
642 914658 : MSTrafficLightLogic::getLatestEnd(int step) const {
643 914658 : const MSPhaseDefinition& p = step < 0 ? getCurrentPhaseDef() : getPhase(step);
644 914658 : return p.latestEnd;
645 : }
646 :
647 :
648 : void
649 1695 : MSTrafficLightLogic::loadState(MSTLLogicControl& tlcontrol, SUMOTime t, int step, SUMOTime spentDuration, bool active) {
650 1695 : myAmActive = active;
651 1695 : const SUMOTime remaining = getPhase(step).duration - spentDuration;
652 1695 : changeStepAndDuration(tlcontrol, t, step, remaining);
653 1695 : if (myAmActive) {
654 1680 : setTrafficLightSignals(t - spentDuration);
655 : }
656 1695 : }
657 :
658 :
659 : SUMOTime
660 116775 : MSTrafficLightLogic::computeCycleTime(const Phases& phases) {
661 : SUMOTime result = 0;
662 708395 : for (const MSPhaseDefinition* p : phases) {
663 591620 : result += p->duration;
664 : }
665 116775 : return result;
666 : }
667 :
668 :
669 :
670 : /****************************************************************************/
|