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 MSTLLogicControl.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Friedemann Wesner
18 : /// @author Laura Bieker
19 : /// @author Julia Ringel
20 : /// @author Michael Behrisch
21 : /// @author Sascha Krieg
22 : /// @date Sept 2002
23 : ///
24 : // A class that stores and controls tls and switching of their programs
25 : /****************************************************************************/
26 : #include <config.h>
27 :
28 : #include <vector>
29 : #include <algorithm>
30 : #include <cassert>
31 : #include <iterator>
32 : #include "MSTrafficLightLogic.h"
33 : #include "MSSimpleTrafficLightLogic.h"
34 : #include "MSTLLogicControl.h"
35 : #include "MSOffTrafficLightLogic.h"
36 : #include "MSRailSignalConstraint.h"
37 : #include "MSDriveWay.h"
38 : #include <microsim/MSEventControl.h>
39 : #include <microsim/MSNet.h>
40 : #include <utils/common/StringUtils.h>
41 : #include <utils/common/ToString.h>
42 : #include <utils/common/MsgHandler.h>
43 :
44 : #define TRACI_PROGRAM "online"
45 :
46 : // ===========================================================================
47 : // method definitions
48 : // ===========================================================================
49 : /* -------------------------------------------------------------------------
50 : * MSTLLogicControl::TLSLogicVariants - methods
51 : * ----------------------------------------------------------------------- */
52 112030 : MSTLLogicControl::TLSLogicVariants::TLSLogicVariants() :
53 112030 : myCurrentProgram(nullptr),
54 112030 : myDefaultProgram(nullptr) {
55 112030 : }
56 :
57 :
58 111788 : MSTLLogicControl::TLSLogicVariants::~TLSLogicVariants() {
59 : std::map<std::string, MSTrafficLightLogic*>::const_iterator j;
60 233457 : for (const auto& var : myVariants) {
61 121669 : delete var.second;
62 : }
63 115975 : for (OnSwitchAction* osa : mySwitchActions) {
64 4187 : delete osa;
65 : }
66 111788 : }
67 :
68 :
69 : bool
70 111271 : MSTLLogicControl::TLSLogicVariants::checkOriginalTLS() const {
71 : bool hadErrors = false;
72 222665 : for (std::map<std::string, MSTrafficLightLogic*>::const_iterator j = myVariants.begin(); j != myVariants.end(); ++j) {
73 111394 : const MSTrafficLightLogic::Phases& phases = (*j).second->getPhases();
74 111394 : int linkNo = (int)(*j).second->getLinks().size();
75 : bool hadProgramErrors = false;
76 631133 : for (MSTrafficLightLogic::Phases::const_iterator i = phases.begin(); i != phases.end(); ++i) {
77 519739 : if ((int)(*i)->getState().length() < linkNo) {
78 : hadProgramErrors = true;
79 : }
80 : }
81 111394 : if (hadProgramErrors) {
82 0 : WRITE_ERRORF(TL("Mismatching phase size in tls '%', program '%'."), (*j).second->getID(), (*j).first);
83 : hadErrors = true;
84 : }
85 : }
86 111271 : return !hadErrors;
87 : }
88 :
89 :
90 : void
91 111271 : MSTLLogicControl::TLSLogicVariants::saveInitialStates() {
92 111271 : myOriginalLinkStates = myCurrentProgram->collectLinkStates();
93 111271 : }
94 :
95 :
96 : void
97 1602 : MSTLLogicControl::TLSLogicVariants::saveState(OutputDevice& out) {
98 3221 : for (const auto& item : myVariants) {
99 1619 : item.second->saveState(out);
100 : }
101 1602 : }
102 :
103 :
104 : bool
105 121930 : MSTLLogicControl::TLSLogicVariants::addLogic(const std::string& programID,
106 : MSTrafficLightLogic* logic, bool netWasLoaded, bool isNewDefault) {
107 121930 : if (myVariants.find(programID) != myVariants.end()) {
108 0 : delete logic;
109 0 : return false;
110 : }
111 : // assert the links are set
112 121930 : if (netWasLoaded) {
113 : // this one has not yet its links set
114 9777 : if (myCurrentProgram == nullptr) {
115 : const std::string id = logic->getID();
116 0 : delete logic;
117 0 : throw ProcessError(TLF("No initial signal plan loaded for tls '%'.", id));
118 : }
119 9777 : logic->adaptLinkInformationFrom(*myCurrentProgram);
120 9777 : if (logic->getLinks().size() > logic->getPhase(0).getState().size()) {
121 : const std::string id = logic->getID();
122 6 : delete logic;
123 18 : throw ProcessError(TLF("Mismatching phase size in tls '%', program '%'.", id, programID));
124 : }
125 : }
126 : // add to the list of active
127 121924 : if (myVariants.size() == 0 || isNewDefault) {
128 121924 : if (myCurrentProgram != nullptr) {
129 9894 : myCurrentProgram->deactivateProgram();
130 : }
131 121924 : myCurrentProgram = logic;
132 121924 : myCurrentProgram->activateProgram();
133 121924 : if (myVariants.size() == 0) {
134 112030 : myDefaultProgram = logic;
135 : }
136 : }
137 : // add to the list of logic
138 121924 : myVariants[programID] = logic;
139 121924 : if (myVariants.size() == 1 || isNewDefault) {
140 121924 : logic->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
141 121924 : executeOnSwitchActions();
142 : }
143 : return true;
144 : }
145 :
146 :
147 : MSTrafficLightLogic*
148 22187 : MSTLLogicControl::TLSLogicVariants::getLogic(const std::string& programID) const {
149 22187 : if (myVariants.find(programID) == myVariants.end()) {
150 : return nullptr;
151 : }
152 2765 : return myVariants.find(programID)->second;
153 : }
154 :
155 :
156 : MSTrafficLightLogic*
157 792 : MSTLLogicControl::TLSLogicVariants::getLogicInstantiatingOff(MSTLLogicControl& tlc, const std::string& programID) {
158 792 : if (myVariants.find(programID) == myVariants.end()) {
159 44 : if (programID == "off") {
160 : // build an off-tll if this switch indicates it
161 41 : MSTrafficLightLogic* tlLogic = new MSOffTrafficLightLogic(tlc, myCurrentProgram->getID());
162 82 : if (!addLogic("off", tlLogic, true, true)) {
163 : // inform the user if this fails
164 0 : throw ProcessError(TLF("Could not build an off-state for tls '%'.", myCurrentProgram->getID()));
165 : }
166 : } else {
167 : // inform the user about a missing logic
168 12 : throw ProcessError(TLF("Can not switch tls '%' to program '%';\n The program is not known.", myCurrentProgram->getID(), programID));
169 : }
170 : }
171 789 : return getLogic(programID);
172 : }
173 :
174 :
175 : void
176 42 : MSTLLogicControl::TLSLogicVariants::setStateInstantiatingOnline(MSTLLogicControl& tlc,
177 : const std::string& state) {
178 : // build only once...
179 42 : MSTrafficLightLogic* logic = getLogic(TRACI_PROGRAM);
180 42 : if (logic == nullptr) {
181 32 : MSPhaseDefinition* phase = new MSPhaseDefinition(SUMOTime_DAY, state);
182 32 : phase->earliestEnd = SUMOTime_DAY; // prevent immediate switch
183 : std::vector<MSPhaseDefinition*> phases;
184 32 : phases.push_back(phase);
185 32 : logic = new MSSimpleTrafficLightLogic(tlc, myCurrentProgram->getID(), TRACI_PROGRAM, 0, TrafficLightType::STATIC, phases, 0,
186 32 : MSNet::getInstance()->getCurrentTimeStep() + DELTA_T,
187 96 : Parameterised::Map());
188 64 : if (addLogic(TRACI_PROGRAM, logic, true, true)) {
189 32 : MSNet::getInstance()->createTLWrapper(logic);
190 : }
191 32 : } else {
192 10 : MSPhaseDefinition nphase(SUMOTime_DAY, state);
193 10 : *(dynamic_cast<MSSimpleTrafficLightLogic*>(logic)->getPhases()[0]) = nphase;
194 10 : switchTo(tlc, TRACI_PROGRAM);
195 10 : }
196 42 : }
197 :
198 :
199 : void
200 4187 : MSTLLogicControl::TLSLogicVariants::addSwitchCommand(OnSwitchAction* c) {
201 4187 : mySwitchActions.push_back(c);
202 4187 : }
203 :
204 :
205 : std::vector<MSTrafficLightLogic*>
206 41028 : MSTLLogicControl::TLSLogicVariants::getAllLogics() const {
207 : std::vector<MSTrafficLightLogic*> ret;
208 : std::map<std::string, MSTrafficLightLogic*>::const_iterator i;
209 87934 : for (i = myVariants.begin(); i != myVariants.end(); ++i) {
210 46906 : ret.push_back((*i).second);
211 : }
212 41028 : return ret;
213 0 : }
214 :
215 :
216 : bool
217 0 : MSTLLogicControl::TLSLogicVariants::isActive(const MSTrafficLightLogic* tl) const {
218 0 : return tl == myCurrentProgram;
219 : }
220 :
221 :
222 : MSTrafficLightLogic*
223 15297776 : MSTLLogicControl::TLSLogicVariants::getActive() const {
224 15297776 : return myCurrentProgram;
225 : }
226 :
227 : MSTrafficLightLogic*
228 21372 : MSTLLogicControl::TLSLogicVariants::getDefault() const {
229 21372 : return myDefaultProgram;
230 : }
231 :
232 :
233 : void
234 504 : MSTLLogicControl::TLSLogicVariants::switchTo(MSTLLogicControl& tlc, const std::string& programID) {
235 : // set the found wished sub-program as this tls' current one
236 504 : const std::string state = myCurrentProgram->getCurrentPhaseDef().getState();
237 504 : myCurrentProgram->deactivateProgram();
238 504 : myCurrentProgram = getLogicInstantiatingOff(tlc, programID);
239 503 : myCurrentProgram->activateProgram();
240 503 : myCurrentProgram->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
241 503 : if (state != myCurrentProgram->getCurrentPhaseDef().getState()) {
242 302 : myCurrentProgram->resetLastSwitch(SIMSTEP);
243 : };
244 503 : executeOnSwitchActions();
245 503 : }
246 :
247 :
248 : void
249 1598 : MSTLLogicControl::TLSLogicVariants::switchToLoaded(MSTrafficLightLogic* tl) {
250 : // setting tl as active and updating signal states happens on the calling side (MSTrafficLightLogic::loadState)
251 1598 : if (myCurrentProgram != tl) {
252 1 : myCurrentProgram->deactivateProgram();
253 1 : myCurrentProgram = tl;
254 : }
255 1598 : }
256 :
257 :
258 : void
259 2994581 : MSTLLogicControl::TLSLogicVariants::executeOnSwitchActions() const {
260 3133405 : for (std::vector<OnSwitchAction*>::const_iterator i = mySwitchActions.begin(); i != mySwitchActions.end(); ++i) {
261 138824 : (*i)->execute();
262 : }
263 2994581 : }
264 :
265 :
266 : void
267 869067 : MSTLLogicControl::TLSLogicVariants::addLink(MSLink* link, MSLane* lane, int pos) {
268 1740586 : for (std::map<std::string, MSTrafficLightLogic*>::iterator i = myVariants.begin(); i != myVariants.end(); ++i) {
269 871519 : (*i).second->addLink(link, lane, pos);
270 : }
271 869067 : }
272 :
273 : void
274 980 : MSTLLogicControl::TLSLogicVariants::ignoreLinkIndex(int pos) {
275 1968 : for (std::map<std::string, MSTrafficLightLogic*>::iterator i = myVariants.begin(); i != myVariants.end(); ++i) {
276 988 : (*i).second->ignoreLinkIndex(pos);
277 : }
278 980 : }
279 :
280 :
281 : /* -------------------------------------------------------------------------
282 : * method definitions for the Switching Procedures
283 : * ----------------------------------------------------------------------- */
284 : /* -------------------------------------------------------------------------
285 : * method definitions for WAUTSwitchProcedure
286 : * ----------------------------------------------------------------------- */
287 : bool
288 648 : MSTLLogicControl::WAUTSwitchProcedure::trySwitch(SUMOTime step) {
289 : // switch to the next programm if the GSP is reached
290 648 : if (isPosAtGSP(step, *myFrom)) {
291 : // adapt program's state
292 8 : if (mySwitchSynchron) {
293 0 : adaptLogic(step);
294 : } else {
295 8 : switchToPos(step, *myTo, getGSPTime(*myTo));
296 : }
297 : // switch to destination program
298 8 : return true;
299 : }
300 : // do not switch, yet
301 : return false;
302 : }
303 :
304 :
305 : SUMOTime
306 656 : MSTLLogicControl::WAUTSwitchProcedure::getGSPTime(const MSTrafficLightLogic& logic) const {
307 1312 : return string2time(logic.getParameter("GSP", "0"));
308 : }
309 :
310 :
311 : bool
312 648 : MSTLLogicControl::WAUTSwitchProcedure::isPosAtGSP(SUMOTime currentTime, const MSTrafficLightLogic& logic) {
313 648 : const SUMOTime gspTime = getGSPTime(logic) % logic.getDefaultCycleTime();
314 648 : const SUMOTime programTime = logic.getOffsetFromIndex(logic.getCurrentPhaseIndex()) + logic.getSpentDuration(currentTime);
315 648 : return gspTime == programTime;
316 : }
317 :
318 :
319 : SUMOTime
320 8 : MSTLLogicControl::WAUTSwitchProcedure::getDiffToStartOfPhase(MSTrafficLightLogic& logic, SUMOTime toTime) {
321 8 : int stepOfMyPos = logic.getIndexFromOffset(toTime);
322 8 : SUMOTime startOfPhase = logic.getOffsetFromIndex(stepOfMyPos);
323 : assert(toTime >= startOfPhase);
324 8 : return toTime - startOfPhase;
325 : }
326 :
327 :
328 : void
329 8 : MSTLLogicControl::WAUTSwitchProcedure::switchToPos(SUMOTime simStep, MSTrafficLightLogic& logic, SUMOTime toTime) {
330 8 : int stepTo = logic.getIndexFromOffset(toTime);
331 8 : SUMOTime diff = getDiffToStartOfPhase(logic, toTime);
332 8 : const MSPhaseDefinition& phase = logic.getPhase(stepTo);
333 8 : SUMOTime leftDuration = phase.duration - diff;
334 8 : logic.changeStepAndDuration(myControl, simStep, stepTo, leftDuration);
335 8 : }
336 :
337 :
338 :
339 : /* -------------------------------------------------------------------------
340 : * method definitions for WAUTSwitchProcedure_JustSwitch
341 : * ----------------------------------------------------------------------- */
342 278 : MSTLLogicControl::WAUTSwitchProcedure_JustSwitch::WAUTSwitchProcedure_JustSwitch(
343 : MSTLLogicControl& control, WAUT& waut,
344 : MSTrafficLightLogic* from, MSTrafficLightLogic* to, bool synchron)
345 278 : : MSTLLogicControl::WAUTSwitchProcedure(control, waut, from, to, synchron) {}
346 :
347 :
348 556 : MSTLLogicControl::WAUTSwitchProcedure_JustSwitch::~WAUTSwitchProcedure_JustSwitch() {}
349 :
350 :
351 : bool
352 278 : MSTLLogicControl::WAUTSwitchProcedure_JustSwitch::trySwitch(SUMOTime) {
353 278 : return true;
354 : }
355 :
356 :
357 :
358 : /* -------------------------------------------------------------------------
359 : * method definitions for WAUTSwitchProcedure_GSP
360 : * ----------------------------------------------------------------------- */
361 8 : MSTLLogicControl::WAUTSwitchProcedure_GSP::WAUTSwitchProcedure_GSP(
362 : MSTLLogicControl& control, WAUT& waut,
363 : MSTrafficLightLogic* from, MSTrafficLightLogic* to, bool synchron)
364 8 : : MSTLLogicControl::WAUTSwitchProcedure(control, waut, from, to, synchron) {}
365 :
366 :
367 16 : MSTLLogicControl::WAUTSwitchProcedure_GSP::~WAUTSwitchProcedure_GSP() {}
368 :
369 :
370 : void
371 0 : MSTLLogicControl::WAUTSwitchProcedure_GSP::adaptLogic(SUMOTime step) {
372 0 : const SUMOTime gspTo = getGSPTime(*myTo) % myTo->getDefaultCycleTime();
373 0 : const SUMOTime currentPosTo = myTo->getOffsetFromIndex(myTo->getCurrentPhaseIndex()) + myTo->getSpentDuration(step);
374 0 : SUMOTime deltaToStretch = gspTo - currentPosTo;
375 0 : if (deltaToStretch < 0) {
376 0 : deltaToStretch += myTo->getDefaultCycleTime();
377 : }
378 0 : const int stepTo = myTo->getIndexFromOffset(gspTo);
379 0 : const SUMOTime newdur = myTo->getPhase(stepTo).duration - getDiffToStartOfPhase(*myTo, gspTo) + deltaToStretch;
380 0 : myTo->changeStepAndDuration(myControl, step, stepTo, newdur);
381 0 : }
382 :
383 :
384 :
385 : /* -------------------------------------------------------------------------
386 : * method definitions for WAUTSwitchProcedure_Stretch
387 : * ----------------------------------------------------------------------- */
388 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::WAUTSwitchProcedure_Stretch(
389 : MSTLLogicControl& control, WAUT& waut,
390 0 : MSTrafficLightLogic* from, MSTrafficLightLogic* to, bool synchron)
391 0 : : MSTLLogicControl::WAUTSwitchProcedure(control, waut, from, to, synchron) {
392 0 : int idx = 1;
393 0 : while (myTo->hasParameter("B" + toString(idx) + ".begin")) {
394 : StretchRange def;
395 0 : def.begin = string2time(myTo->getParameter("B" + toString(idx) + ".begin"));
396 0 : def.end = string2time(myTo->getParameter("B" + toString(idx) + ".end"));
397 0 : def.fac = StringUtils::toDouble(myTo->getParameter("B" + toString(idx) + ".factor"));
398 0 : myStretchRanges.emplace_back(def);
399 : }
400 :
401 0 : }
402 :
403 :
404 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::~WAUTSwitchProcedure_Stretch() {}
405 :
406 :
407 : void
408 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::adaptLogic(SUMOTime step) {
409 0 : SUMOTime gspTo = getGSPTime(*myTo);
410 0 : SUMOTime cycleTime = myTo->getDefaultCycleTime();
411 : // the position, where the logic has to be after synchronisation
412 0 : SUMOTime posAfterSyn = myTo->getPhaseIndexAtTime(step);
413 : // calculate the difference, that has to be equalized
414 : SUMOTime deltaToCut = 0;
415 0 : if (posAfterSyn < gspTo) {
416 0 : deltaToCut = posAfterSyn + cycleTime - gspTo;
417 : } else {
418 0 : deltaToCut = posAfterSyn - gspTo;
419 : }
420 : // test, wheter cutting of the Signalplan is possible
421 : SUMOTime deltaPossible = 0;
422 0 : for (const StretchRange& def : myStretchRanges) {
423 : assert(def.end >= def.begin);
424 0 : deltaPossible += def.end - def.begin;
425 : }
426 0 : int stretchUmlaufAnz = (int) StringUtils::toDouble(myTo->getParameter("StretchUmlaufAnz", ""));
427 0 : deltaPossible = stretchUmlaufAnz * deltaPossible;
428 0 : if ((deltaPossible > deltaToCut) && (deltaToCut < (cycleTime / 2))) {
429 0 : cutLogic(step, gspTo, deltaToCut);
430 : } else {
431 0 : SUMOTime deltaToStretch = (cycleTime - deltaToCut) % cycleTime;
432 0 : stretchLogic(step, gspTo, deltaToStretch);
433 : }
434 0 : }
435 :
436 :
437 : void
438 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::cutLogic(SUMOTime step, SUMOTime startPos, SUMOTime allCutTime) {
439 0 : int actStep = myTo->getIndexFromOffset(startPos);
440 : // switches to startPos and cuts this phase, if there is a "Bereich"
441 : SUMOTime toCut = 0;
442 0 : for (const StretchRange& def : myStretchRanges) {
443 0 : int stepOfBegin = myTo->getIndexFromOffset(def.begin);
444 0 : if (stepOfBegin == actStep) {
445 0 : if (def.begin < startPos) {
446 0 : toCut = def.end - startPos;
447 : } else {
448 0 : toCut = def.end - def.begin;
449 : }
450 : toCut = MIN2(allCutTime, toCut);
451 0 : allCutTime = allCutTime - toCut;
452 : }
453 : }
454 0 : SUMOTime remainingDur = myTo->getPhase(actStep).duration - getDiffToStartOfPhase(*myTo, startPos);
455 0 : SUMOTime newDur = remainingDur - toCut;
456 0 : myTo->changeStepAndDuration(myControl, step, actStep, newDur);
457 :
458 : // changes the duration of all other phases
459 0 : int currStep = (actStep + 1) % (int)myTo->getPhases().size();
460 0 : while (allCutTime > 0) {
461 0 : for (int i = currStep; i < (int) myTo->getPhases().size(); i++) {
462 0 : SUMOTime beginOfPhase = myTo->getOffsetFromIndex(i);
463 0 : SUMOTime durOfPhase = myTo->getPhase(i).duration;
464 0 : SUMOTime endOfPhase = beginOfPhase + durOfPhase;
465 0 : for (const StretchRange& def : myStretchRanges) {
466 0 : if ((beginOfPhase <= def.begin) && (endOfPhase >= def.end)) {
467 0 : SUMOTime maxCutOfPhase = MIN2(def.end - def.begin, allCutTime);
468 0 : allCutTime = allCutTime - maxCutOfPhase;
469 0 : durOfPhase = durOfPhase - maxCutOfPhase;
470 : }
471 : }
472 0 : myTo->addOverridingDuration(durOfPhase);
473 : }
474 : currStep = 0;
475 : }
476 0 : }
477 :
478 : void
479 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::stretchLogic(SUMOTime step, SUMOTime startPos, SUMOTime allStretchTime) {
480 0 : int currStep = myTo->getIndexFromOffset(startPos);
481 0 : SUMOTime durOfPhase = myTo->getPhase(currStep).duration;
482 : SUMOTime remainingStretchTime = allStretchTime;
483 : SUMOTime StretchTimeOfPhase = 0;
484 0 : int stretchUmlaufAnz = (int) StringUtils::toDouble(myTo->getParameter("StretchUmlaufAnz", ""));
485 : double facSum = 0;
486 0 : for (const StretchRange& def : myStretchRanges) {
487 0 : facSum += def.fac;
488 : }
489 0 : facSum *= stretchUmlaufAnz;
490 :
491 : //switch to startPos and stretch this phase, if there is a end of "bereich" between startpos and end of phase
492 0 : SUMOTime diffToStart = getDiffToStartOfPhase(*myTo, startPos);
493 0 : for (const StretchRange& def : myStretchRanges) {
494 0 : SUMOTime endOfPhase = (startPos + durOfPhase - diffToStart);
495 0 : if (def.end <= endOfPhase && def.end >= startPos) {
496 0 : double actualfac = def.fac / facSum;
497 0 : facSum = facSum - def.fac;
498 0 : StretchTimeOfPhase = TIME2STEPS(int(STEPS2TIME(remainingStretchTime) * actualfac + 0.5));
499 0 : remainingStretchTime = allStretchTime - StretchTimeOfPhase;
500 : }
501 : }
502 0 : if (facSum == 0) {
503 0 : WRITE_WARNINGF(TL("The computed factor sum in WAUT '%' at time '%' equals zero;\n assuming an error in WAUT definition."), myWAUT.id, toString(STEPS2TIME(step)));
504 0 : return;
505 : }
506 0 : durOfPhase = durOfPhase - diffToStart + StretchTimeOfPhase;
507 0 : myTo->changeStepAndDuration(myControl, step, currStep, durOfPhase);
508 :
509 0 : currStep = (currStep + 1) % (int)myTo->getPhases().size();
510 : // stretch all other phases, if there is a "bereich"
511 0 : while (remainingStretchTime > 0) {
512 0 : for (int i = currStep; i < (int)myTo->getPhases().size() && remainingStretchTime > 0; i++) {
513 0 : durOfPhase = myTo->getPhase(i).duration;
514 0 : SUMOTime beginOfPhase = myTo->getOffsetFromIndex(i);
515 0 : SUMOTime endOfPhase = beginOfPhase + durOfPhase;
516 0 : for (const StretchRange& def : myStretchRanges) {
517 0 : if ((beginOfPhase <= def.end) && (endOfPhase >= def.end)) {
518 0 : double actualfac = def.fac / facSum;
519 0 : StretchTimeOfPhase = TIME2STEPS(int(STEPS2TIME(remainingStretchTime) * actualfac + 0.5));
520 0 : facSum -= def.fac;
521 0 : durOfPhase += StretchTimeOfPhase;
522 0 : remainingStretchTime -= StretchTimeOfPhase;
523 : }
524 : }
525 0 : myTo->addOverridingDuration(durOfPhase);
526 : }
527 : currStep = 0;
528 : }
529 : }
530 :
531 :
532 : /* -------------------------------------------------------------------------
533 : * method definitions for MSTLLogicControl
534 : * ----------------------------------------------------------------------- */
535 41511 : MSTLLogicControl::MSTLLogicControl()
536 41511 : : myNetWasLoaded(false) {}
537 :
538 :
539 41061 : MSTLLogicControl::~MSTLLogicControl() {
540 : // delete tls
541 152849 : for (std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.begin(); i != myLogics.end(); ++i) {
542 111788 : delete (*i).second;
543 : }
544 : // delete WAUTs
545 41233 : for (std::map<std::string, WAUT*>::const_iterator i = myWAUTs.begin(); i != myWAUTs.end(); ++i) {
546 172 : delete (*i).second;
547 : }
548 41061 : }
549 :
550 :
551 : void
552 0 : MSTLLogicControl::setTrafficLightSignals(SUMOTime t) const {
553 0 : for (std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.begin(); i != myLogics.end(); ++i) {
554 0 : (*i).second->getActive()->setTrafficLightSignals(t);
555 : }
556 0 : }
557 :
558 :
559 : std::vector<MSTrafficLightLogic*>
560 17910 : MSTLLogicControl::getAllLogics() const {
561 : std::vector<MSTrafficLightLogic*> ret;
562 : std::map<std::string, TLSLogicVariants*>::const_iterator i;
563 58835 : for (i = myLogics.begin(); i != myLogics.end(); ++i) {
564 40925 : std::vector<MSTrafficLightLogic*> s = (*i).second->getAllLogics();
565 : copy(s.begin(), s.end(), back_inserter(ret));
566 40925 : }
567 17910 : return ret;
568 0 : }
569 :
570 : MSTLLogicControl::TLSLogicVariants&
571 4767715 : MSTLLogicControl::get(const std::string& id) const {
572 : std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.find(id);
573 4767715 : if (i == myLogics.end()) {
574 12 : throw InvalidArgument("The tls '" + id + "' is not known.");
575 : }
576 4767711 : return *(*i).second;
577 : }
578 :
579 :
580 : MSTrafficLightLogic*
581 240470 : MSTLLogicControl::get(const std::string& id, const std::string& programID) const {
582 : std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.find(id);
583 240470 : if (i == myLogics.end()) {
584 : return nullptr;
585 : }
586 21270 : return (*i).second->getLogic(programID);
587 : }
588 :
589 :
590 : std::vector<std::string>
591 2532 : MSTLLogicControl::getAllTLIds() const {
592 : std::vector<std::string> ret;
593 9387 : for (std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.begin(); i != myLogics.end(); ++i) {
594 6855 : ret.push_back((*i).first);
595 : }
596 2532 : return ret;
597 0 : }
598 :
599 :
600 : bool
601 121718 : MSTLLogicControl::add(const std::string& id, const std::string& programID,
602 : MSTrafficLightLogic* logic, bool newDefault) {
603 : std::map<std::string, TLSLogicVariants*>::iterator it = myLogics.find(id);
604 : TLSLogicVariants* tlmap;
605 121718 : if (it == myLogics.end()) {
606 112030 : tlmap = myLogics[id] = new TLSLogicVariants();
607 : } else {
608 9688 : tlmap = it->second;
609 : }
610 121718 : return tlmap->addLogic(programID, logic, myNetWasLoaded, newDefault);
611 : }
612 :
613 :
614 : bool
615 149480 : MSTLLogicControl::knows(const std::string& id) const {
616 149480 : return myLogics.count(id) != 0;
617 : }
618 :
619 :
620 : bool
621 41045 : MSTLLogicControl::closeNetworkReading() {
622 : bool hadErrors = false;
623 152316 : for (const auto& it : myLogics) {
624 111271 : hadErrors |= !it.second->checkOriginalTLS();
625 111271 : it.second->saveInitialStates();
626 : }
627 41045 : myNetWasLoaded = true;
628 41045 : return !hadErrors;
629 : }
630 :
631 :
632 : bool
633 0 : MSTLLogicControl::isActive(const MSTrafficLightLogic* tl) const {
634 : std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.find(tl->getID());
635 0 : if (i == myLogics.end()) {
636 : return false;
637 : }
638 0 : return (*i).second->isActive(tl);
639 : }
640 :
641 :
642 : MSTrafficLightLogic*
643 80877 : MSTLLogicControl::getActive(const std::string& id) const {
644 : std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.find(id);
645 80877 : if (i == myLogics.end()) {
646 : return nullptr;
647 : }
648 80877 : return (*i).second->getActive();
649 : }
650 :
651 :
652 : void
653 450 : MSTLLogicControl::switchTo(const std::string& id, const std::string& programID) {
654 : // try to get the tls program definitions
655 : std::map<std::string, TLSLogicVariants*>::iterator i = myLogics.find(id);
656 : // handle problems
657 450 : if (i == myLogics.end()) {
658 0 : throw ProcessError(TLF("Could not switch tls '%' to program '%': No such tls exists.", id, programID));
659 : }
660 450 : (*i).second->switchTo(*this, programID);
661 450 : }
662 :
663 :
664 : void
665 172 : MSTLLogicControl::addWAUT(SUMOTime refTime, const std::string& id,
666 : const std::string& startProg, SUMOTime period) {
667 : // check whether the waut was already defined
668 172 : if (myWAUTs.find(id) != myWAUTs.end()) {
669 : // report an error if so
670 0 : throw InvalidArgument(TLF("Waut '%' was already defined.", id));
671 : }
672 172 : WAUT* w = new WAUT;
673 172 : w->id = id;
674 172 : w->refTime = refTime;
675 172 : w->startProg = startProg;
676 172 : w->period = period;
677 172 : myWAUTs[id] = w;
678 172 : }
679 :
680 :
681 : void
682 346 : MSTLLogicControl::addWAUTSwitch(const std::string& wautid,
683 : SUMOTime when, const std::string& to) {
684 : // try to get the waut
685 346 : if (myWAUTs.find(wautid) == myWAUTs.end()) {
686 : // report an error if the waut is not known
687 0 : throw InvalidArgument(TLF("Waut '%' was not yet defined.", wautid));
688 : }
689 : // build and save the waut switch definition
690 346 : WAUT* waut = myWAUTs[wautid];
691 : WAUTSwitch s;
692 : s.to = to;
693 346 : s.when = (waut->refTime + when);
694 346 : if (waut->period > 0) {
695 82 : s.when = s.when % waut->period;
696 : }
697 346 : myWAUTs[wautid]->switches.push_back(s);
698 346 : }
699 :
700 :
701 : void
702 170 : MSTLLogicControl::addWAUTJunction(const std::string& wautid,
703 : const std::string& tls,
704 : const std::string& proc,
705 : bool synchron) {
706 : // try to get the waut
707 170 : if (myWAUTs.find(wautid) == myWAUTs.end()) {
708 : // report an error if the waut is not known
709 12 : throw InvalidArgument(TLF("Waut '%' was not yet defined.", wautid));
710 : }
711 : // try to get the tls to switch
712 166 : if (myLogics.find(tls) == myLogics.end()) {
713 : // report an error if the tls is not known
714 6 : throw InvalidArgument(TLF("TLS '%' to switch in WAUT '%' was not yet defined.", tls, wautid));
715 : }
716 : WAUTJunction j;
717 : j.junction = tls;
718 : j.procedure = proc;
719 164 : j.synchron = synchron;
720 164 : myWAUTs[wautid]->junctions.push_back(j);
721 :
722 164 : std::string initProg = myWAUTs[wautid]->startProg;
723 164 : std::vector<WAUTSwitch>::const_iterator first = myWAUTs[wautid]->switches.end();
724 : SUMOTime minExecTime = -1;
725 506 : for (std::vector<WAUTSwitch>::const_iterator i = myWAUTs[wautid]->switches.begin(); i != myWAUTs[wautid]->switches.end(); ++i) {
726 342 : if ((*i).when > MSNet::getInstance()->getCurrentTimeStep() && (minExecTime == -1 || (*i).when < minExecTime)) {
727 128 : minExecTime = (*i).when;
728 : first = i;
729 : }
730 342 : if (first != myWAUTs[wautid]->switches.begin()) {
731 220 : initProg = (*(first - 1)).to;
732 : }
733 : }
734 : // activate the first one
735 164 : switchTo(tls, initProg);
736 164 : }
737 :
738 :
739 : void
740 168 : MSTLLogicControl::closeWAUT(const std::string& wautid) {
741 : // try to get the waut
742 168 : if (myWAUTs.find(wautid) == myWAUTs.end()) {
743 : // report an error if the waut is not known
744 0 : throw InvalidArgument(TLF("Waut '%' was not yet defined.", wautid));
745 : }
746 168 : WAUT* w = myWAUTs.find(wautid)->second;
747 168 : std::string initProg = myWAUTs[wautid]->startProg;
748 : // get the switch to be performed as first
749 : SUMOTime minExecTime = SUMOTime_MAX;
750 : int firstIndex = -1;
751 : int i = 0;
752 514 : for (const WAUTSwitch& s : w->switches) {
753 346 : if (s.when >= SIMSTEP && s.when < minExecTime) {
754 : minExecTime = s.when;
755 : firstIndex = i;
756 : }
757 346 : i++;
758 : }
759 : // activate the first one
760 168 : if (firstIndex >= 0) {
761 312 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
762 156 : new SwitchInitCommand(*this, wautid, firstIndex), MAX2(SIMSTEP, minExecTime));
763 : }
764 : /*
765 : // set the current program to all junctions
766 : for(std::vector<WAUTJunction>::const_iterator i=w->junctions.begin(); i!=w->junctions.end(); ++i) {
767 : switchTo((*i).junction, initProg);
768 : }
769 : */
770 168 : }
771 :
772 :
773 : SUMOTime
774 288 : MSTLLogicControl::initWautSwitch(MSTLLogicControl::SwitchInitCommand& cmd) {
775 : const std::string& wautid = cmd.getWAUTID();
776 : int& index = cmd.getIndex();
777 288 : WAUT* waut = myWAUTs[wautid];
778 288 : WAUTSwitch s = waut->switches[index];
779 574 : for (std::vector<WAUTJunction>::iterator i = myWAUTs[wautid]->junctions.begin(); i != myWAUTs[wautid]->junctions.end(); ++i) {
780 : // get the current program and the one to instantiate
781 288 : TLSLogicVariants* vars = myLogics.find((*i).junction)->second;
782 288 : MSTrafficLightLogic* from = vars->getActive();
783 288 : MSTrafficLightLogic* to = vars->getLogicInstantiatingOff(*this, s.to);
784 : WAUTSwitchProcedure* proc = nullptr;
785 286 : if ((*i).procedure == "GSP") {
786 8 : proc = new WAUTSwitchProcedure_GSP(*this, *myWAUTs[wautid], from, to, (*i).synchron);
787 278 : } else if ((*i).procedure == "Stretch") {
788 0 : proc = new WAUTSwitchProcedure_Stretch(*this, *myWAUTs[wautid], from, to, (*i).synchron);
789 : } else {
790 278 : proc = new WAUTSwitchProcedure_JustSwitch(*this, *myWAUTs[wautid], from, to, (*i).synchron);
791 : }
792 :
793 : WAUTSwitchProcess p;
794 : p.junction = (*i).junction;
795 286 : p.proc = proc;
796 286 : p.from = from;
797 286 : p.to = to;
798 :
799 286 : myCurrentlySwitched.push_back(p);
800 : }
801 286 : index++;
802 286 : if (index == (int)waut->switches.size()) {
803 154 : if (waut->period <= 0) {
804 : return 0;
805 : } else {
806 52 : index = 0; // start over
807 148 : for (WAUTSwitch& ws : waut->switches) {
808 96 : ws.when += waut->period;
809 : }
810 : }
811 : }
812 184 : return myWAUTs[wautid]->switches[index].when - MSNet::getInstance()->getCurrentTimeStep();
813 : }
814 :
815 :
816 : void
817 55343877 : MSTLLogicControl::check2Switch(SUMOTime step) {
818 55344803 : for (std::vector<WAUTSwitchProcess>::iterator i = myCurrentlySwitched.begin(); i != myCurrentlySwitched.end();) {
819 : const WAUTSwitchProcess& proc = *i;
820 926 : if (proc.proc->trySwitch(step)) {
821 286 : delete proc.proc;
822 : // do not switch away from TraCI control
823 286 : if (getActive(proc.to->getID())->getProgramID() != TRACI_PROGRAM) {
824 286 : switchTo(proc.to->getID(), proc.to->getProgramID());
825 : }
826 286 : i = myCurrentlySwitched.erase(i);
827 : } else {
828 : ++i;
829 : }
830 : }
831 55343877 : }
832 :
833 :
834 : std::pair<SUMOTime, MSPhaseDefinition>
835 0 : MSTLLogicControl::getPhaseDef(const std::string& tlid) const {
836 0 : MSTrafficLightLogic* tl = getActive(tlid);
837 0 : return std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), tl->getCurrentPhaseDef());
838 : }
839 :
840 :
841 : void
842 114 : MSTLLogicControl::switchOffAll() {
843 223 : for (const auto& logic : myLogics) {
844 109 : if (logic.second->getActive()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
845 : // there is no sensible fall-back behavior when switching of rail
846 : // signals so they should ignore tls.all-off
847 10 : continue;
848 : }
849 198 : logic.second->addLogic("off", new MSOffTrafficLightLogic(*this, logic.first), true, true);
850 : }
851 114 : }
852 :
853 :
854 : void
855 476 : MSTLLogicControl::saveState(OutputDevice& out) {
856 476 : MSRailSignalConstraint::saveState(out); // always saves vehicle tracker states
857 2078 : for (const auto& logic : myLogics) {
858 1602 : logic.second->saveState(out);
859 : }
860 476 : MSDriveWay::saveState(out);
861 476 : }
862 :
863 :
864 : void
865 168 : MSTLLogicControl::clearState(SUMOTime time, bool quickReload) {
866 168 : MSRailSignalConstraint::clearState();
867 168 : if (quickReload) {
868 0 : for (const auto& variants : myLogics) {
869 0 : for (auto& logic : variants.second->getAllLogics()) {
870 0 : if (logic->getLogicType() == TrafficLightType::OFF
871 0 : || logic->getLogicType() == TrafficLightType::RAIL_SIGNAL
872 0 : || logic->getLogicType() == TrafficLightType::RAIL_CROSSING) {
873 0 : continue;
874 : }
875 : int step = 0;
876 : const SUMOTime cycleTime = logic->getDefaultCycleTime();
877 0 : auto& phases = logic->getPhases();
878 0 : SUMOTime offset = logic->getOffset();
879 0 : if (offset >= 0) {
880 0 : offset = (time + cycleTime - (offset % cycleTime)) % cycleTime;
881 : } else {
882 0 : offset = (time + ((-offset) % cycleTime)) % cycleTime;
883 : }
884 :
885 0 : while (offset >= phases[step]->duration) {
886 0 : offset -= phases[step]->duration;
887 0 : step++;
888 : }
889 0 : logic->loadState(*this, time, step, offset, logic->isActive());
890 0 : }
891 : }
892 : }
893 168 : }
894 :
895 :
896 : /****************************************************************************/
|