Line data Source code
1 : /****************************************************************************/ 2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo 3 : // Copyright (C) 2001-2024 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 MSSimpleTrafficLightLogic.cpp 15 : /// @author Daniel Krajzewicz 16 : /// @author Julia Ringel 17 : /// @author Jakob Erdmann 18 : /// @author Michael Behrisch 19 : /// @author Friedemann Wesner 20 : /// @date Sept 2002 21 : /// 22 : // A fixed traffic light logic 23 : /****************************************************************************/ 24 : #include <config.h> 25 : 26 : #include <cassert> 27 : #include <utility> 28 : #include <vector> 29 : #include <bitset> 30 : #include <sstream> 31 : #include <utils/common/StringUtils.h> 32 : #include <microsim/MSEventControl.h> 33 : #include <microsim/MSNet.h> 34 : #include <microsim/MSEventControl.h> 35 : #include "MSTLLogicControl.h" 36 : #include "MSTrafficLightLogic.h" 37 : #include "MSSimpleTrafficLightLogic.h" 38 : 39 : //#define DEBUG_COORDINATION 40 : #define DEBUG_COND (getID()=="C") 41 : 42 : 43 : // =========================================================================== 44 : // member method definitions 45 : // =========================================================================== 46 106411 : MSSimpleTrafficLightLogic::MSSimpleTrafficLightLogic(MSTLLogicControl& tlcontrol, 47 : const std::string& id, const std::string& programID, const SUMOTime offset, const TrafficLightType logicType, const Phases& phases, 48 : int step, SUMOTime delay, 49 106411 : const Parameterised::Map& parameters) : 50 : MSTrafficLightLogic(tlcontrol, id, programID, offset, logicType, delay, parameters), 51 106411 : myPhases(phases), 52 106411 : myStep(step) { 53 106411 : myDefaultCycleTime = computeCycleTime(myPhases); 54 106411 : if (myStep < (int)myPhases.size()) { 55 106236 : myPhases[myStep]->myLastSwitch = SIMSTEP; 56 : } 57 : // the following initializations are only used by 'actuated' and 'delay_based' but do not affect 'static' 58 212822 : if (hasParameter(toString(SUMO_ATTR_CYCLETIME))) { 59 6 : myDefaultCycleTime = TIME2STEPS(StringUtils::toDouble(Parameterised::getParameter(toString(SUMO_ATTR_CYCLETIME), ""))); 60 : } 61 106411 : myCoordinated = StringUtils::toBool(Parameterised::getParameter("coordinated", "false")); 62 106411 : if (myPhases.size() > 0) { 63 106236 : SUMOTime earliest = SIMSTEP + getEarliest(-1); 64 106236 : if (earliest > getNextSwitchTime()) { 65 12 : mySwitchCommand->deschedule(this); 66 12 : mySwitchCommand = new SwitchCommand(tlcontrol, this, earliest); 67 12 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(mySwitchCommand, earliest); 68 : } 69 : } 70 106411 : } 71 : 72 : 73 211128 : MSSimpleTrafficLightLogic::~MSSimpleTrafficLightLogic() { 74 106129 : deletePhases(); 75 211128 : } 76 : 77 : 78 : // ------------ Switching and setting current rows 79 : SUMOTime 80 8538162 : MSSimpleTrafficLightLogic::trySwitch() { 81 : // check whether the current duration shall be increased 82 8538162 : if (myCurrentDurationIncrement > 0) { 83 : SUMOTime delay = myCurrentDurationIncrement; 84 0 : myCurrentDurationIncrement = 0; 85 0 : return delay; 86 : } 87 : 88 : // increment the index 89 8538162 : if (myPhases[myStep]->nextPhases.size() > 0 && myPhases[myStep]->nextPhases.front() >= 0) { 90 266 : myStep = myPhases[myStep]->nextPhases.front(); 91 : } else { 92 8537896 : myStep++; 93 : } 94 : // if the last phase was reached ... 95 8538162 : if (myStep >= (int)myPhases.size()) { 96 : // ... set the index to the first phase 97 3355570 : myStep = 0; 98 : } 99 : assert((int)myPhases.size() > myStep); 100 : //stores the time the phase started 101 8538162 : myPhases[myStep]->myLastSwitch = MSNet::getInstance()->getCurrentTimeStep(); 102 : // check whether the next duration was overridden 103 8538162 : if (myOverridingTimes.size() > 0) { 104 0 : SUMOTime nextDuration = myOverridingTimes[0]; 105 0 : myOverridingTimes.erase(myOverridingTimes.begin()); 106 0 : return nextDuration; 107 : } 108 : // return offset to the next switch 109 8538162 : return myPhases[myStep]->duration; 110 : } 111 : 112 : 113 : // ------------ Static Information Retrieval 114 : int 115 5695 : MSSimpleTrafficLightLogic::getPhaseNumber() const { 116 5695 : return (int) myPhases.size(); 117 : } 118 : 119 : 120 : const MSSimpleTrafficLightLogic::Phases& 121 247185 : MSSimpleTrafficLightLogic::getPhases() const { 122 247185 : return myPhases; 123 : } 124 : 125 : 126 : MSSimpleTrafficLightLogic::Phases& 127 3276 : MSSimpleTrafficLightLogic::getPhases() { 128 3276 : return myPhases; 129 : } 130 : 131 : 132 : const MSPhaseDefinition& 133 222071 : MSSimpleTrafficLightLogic::getPhase(int givenStep) const { 134 : assert((int)myPhases.size() > givenStep); 135 222071 : return *myPhases[givenStep]; 136 : } 137 : 138 : 139 : // ------------ Dynamic Information Retrieval 140 : int 141 20169822 : MSSimpleTrafficLightLogic::getCurrentPhaseIndex() const { 142 20169822 : return myStep; 143 : } 144 : 145 : 146 : const MSPhaseDefinition& 147 17945026 : MSSimpleTrafficLightLogic::getCurrentPhaseDef() const { 148 17945026 : return *myPhases[myStep]; 149 : } 150 : 151 : 152 : // ------------ Conversion between time and phase 153 : SUMOTime 154 0 : MSSimpleTrafficLightLogic::getPhaseIndexAtTime(SUMOTime simStep) const { 155 : SUMOTime position = 0; 156 0 : if (myStep > 0) { 157 0 : for (int i = 0; i < myStep; i++) { 158 0 : position = position + getPhase(i).duration; 159 : } 160 : } 161 0 : position = position + simStep - getPhase(myStep).myLastSwitch; 162 0 : position = position % myDefaultCycleTime; 163 : assert(position <= myDefaultCycleTime); 164 0 : return position; 165 : } 166 : 167 : 168 : SUMOTime 169 328 : MSSimpleTrafficLightLogic::getOffsetFromIndex(int index) const { 170 : assert(index < (int)myPhases.size()); 171 328 : if (index == 0) { 172 : return 0; 173 : } 174 : SUMOTime pos = 0; 175 770 : for (int i = 0; i < index; i++) { 176 556 : pos += getPhase(i).duration; 177 : } 178 : return pos; 179 : } 180 : 181 : 182 : int 183 8 : MSSimpleTrafficLightLogic::getIndexFromOffset(SUMOTime offset) const { 184 8 : offset = offset % myDefaultCycleTime; 185 8 : if (offset == myDefaultCycleTime) { 186 : return 0; 187 : } 188 : SUMOTime testPos = 0; 189 8 : for (int i = 0; i < (int)myPhases.size(); i++) { 190 8 : testPos = testPos + getPhase(i).duration; 191 8 : if (testPos > offset) { 192 8 : return i; 193 : } 194 0 : if (testPos == offset) { 195 : assert((int)myPhases.size() > (i + 1)); 196 0 : return (i + 1); 197 : } 198 : } 199 : return 0; 200 : } 201 : 202 : 203 : SUMOTime 204 145620 : MSSimpleTrafficLightLogic::mapTimeInCycle(SUMOTime t) const { 205 145620 : return (myCoordinated 206 145620 : ? (t - myOffset) % myDefaultCycleTime 207 59923 : : (t - myPhases[0]->myLastSwitch) % myDefaultCycleTime); 208 : } 209 : 210 : 211 : 212 : 213 : SUMOTime 214 316623 : MSSimpleTrafficLightLogic::getEarliest(SUMOTime prevStart) const { 215 316623 : SUMOTime earliest = getEarliestEnd(); 216 316623 : if (earliest == MSPhaseDefinition::UNSPECIFIED_DURATION) { 217 : return 0; 218 : } else { 219 3460 : if (prevStart >= SIMSTEP - getTimeInCycle() && prevStart < getCurrentPhaseDef().myLastEnd) { 220 : // phase was started and ended once already in the current cycle 221 : // it should not end a second time in the same cycle 222 167 : earliest += myDefaultCycleTime; 223 : #ifdef DEBUG_COORDINATION 224 : if (DEBUG_COND) { 225 : std::cout << SIMTIME << " tl=" << getID() << " getEarliest phase=" << myStep 226 : << " prevStart= " << STEPS2TIME(prevStart) 227 : << " prevEnd= " << STEPS2TIME(getCurrentPhaseDef().myLastEnd) 228 : << " cycleStart=" << STEPS2TIME(SIMSTEP - getTimeInCycle()) << " started Twice - move into next cycle\n"; 229 : } 230 : #endif 231 : } else { 232 3293 : SUMOTime latest = getLatestEnd(); 233 3293 : if (latest != MSPhaseDefinition::UNSPECIFIED_DURATION) { 234 2246 : const SUMOTime minRemaining = getMinDur() - (SIMSTEP - getCurrentPhaseDef().myLastSwitch); 235 2246 : const SUMOTime minEnd = getTimeInCycle() + minRemaining; 236 2246 : if (latest > earliest && latest < minEnd) { 237 : // cannot terminate phase between earliest and latest -> move end into next cycle 238 82 : earliest += myDefaultCycleTime; 239 2164 : } else if (latest < earliest && latest >= minEnd) { 240 : // can ignore earliest since it counts from the previous cycle 241 144 : earliest -= myDefaultCycleTime; 242 : } 243 : #ifdef DEBUG_COORDINATION 244 : if (DEBUG_COND) { 245 : std::cout << SIMTIME << " tl=" << getID() << " getEarliest phase=" << myStep << " latest=" << STEPS2TIME(latest) << " minEnd=" 246 : << STEPS2TIME(minEnd) << " earliest=" << STEPS2TIME(earliest) << "\n"; 247 : } 248 : #endif 249 : } 250 : } 251 3460 : const SUMOTime maxRemaining = getMaxDur() - (SIMSTEP - getCurrentPhaseDef().myLastSwitch); 252 3460 : return MIN2(earliest - getTimeInCycle(), maxRemaining); 253 : } 254 : } 255 : 256 : 257 : SUMOTime 258 1250406 : MSSimpleTrafficLightLogic::getLatest() const { 259 1250406 : const SUMOTime latest = getLatestEnd(); 260 1250406 : if (latest == MSPhaseDefinition::UNSPECIFIED_DURATION) { 261 : return SUMOTime_MAX; // no restriction 262 : } else { 263 125203 : if (latest < getEarliestEnd()) { 264 10828 : const SUMOTime running = SIMSTEP - getCurrentPhaseDef().myLastSwitch; 265 10828 : if (running < getTimeInCycle()) { 266 : // phase was started in the current cycle so the restriction does not apply yet 267 : return SUMOTime_MAX; 268 : } 269 : } 270 : #ifdef DEBUG_COORDINATION 271 : if (DEBUG_COND) { 272 : std::cout << SIMTIME << " tl=" << getID() << " getLatest phase=" << myStep << " latest=" << STEPS2TIME(latest) 273 : << " cycTime=" << STEPS2TIME(getTimeInCycle()) << " res=" << STEPS2TIME(latest - getTimeInCycle()) << "\n"; 274 : } 275 : #endif 276 117264 : if (latest == myDefaultCycleTime && getTimeInCycle() == 0) { 277 : // special case: end on cylce time wrap-around 278 : return 0; 279 : } 280 117252 : return MAX2(SUMOTime(0), latest - getTimeInCycle()); 281 : } 282 : } 283 : 284 : 285 : 286 : // ------------ Changing phases and phase durations 287 : void 288 5480 : MSSimpleTrafficLightLogic::changeStepAndDuration(MSTLLogicControl& tlcontrol, 289 : SUMOTime simStep, int step, SUMOTime stepDuration) { 290 5480 : mySwitchCommand->deschedule(this); 291 5480 : mySwitchCommand = new SwitchCommand(tlcontrol, this, stepDuration + simStep); 292 5480 : if (step >= 0 && step != myStep) { 293 1455 : myStep = step; 294 1455 : myPhases[myStep]->myLastSwitch = MSNet::getInstance()->getCurrentTimeStep(); 295 1455 : setTrafficLightSignals(simStep); 296 1455 : tlcontrol.get(getID()).executeOnSwitchActions(); 297 : } 298 5480 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent( 299 5480 : mySwitchCommand, stepDuration + simStep); 300 5480 : } 301 : 302 : 303 : void 304 22 : MSSimpleTrafficLightLogic::setPhases(const Phases& phases, int step) { 305 : assert(step < (int)phases.size()); 306 22 : deletePhases(); 307 22 : myPhases = phases; 308 22 : myStep = step; 309 22 : myDefaultCycleTime = computeCycleTime(myPhases); 310 22 : } 311 : 312 : 313 : void 314 106151 : MSSimpleTrafficLightLogic::deletePhases() { 315 659445 : for (int i = 0; i < (int)myPhases.size(); i++) { 316 553294 : delete myPhases[i]; 317 : } 318 106151 : } 319 : 320 : void 321 1951 : MSSimpleTrafficLightLogic::saveState(OutputDevice& out) const { 322 1951 : out.openTag(SUMO_TAG_TLLOGIC); 323 : out.writeAttr(SUMO_ATTR_ID, getID()); 324 : out.writeAttr(SUMO_ATTR_PROGRAMID, getProgramID()); 325 1951 : out.writeAttr(SUMO_ATTR_PHASE, getCurrentPhaseIndex()); 326 1951 : out.writeAttr(SUMO_ATTR_DURATION, getSpentDuration()); 327 1951 : out.closeTag(); 328 1951 : } 329 : 330 : const std::string 331 2233231 : MSSimpleTrafficLightLogic::getParameter(const std::string& key, const std::string defaultValue) const { 332 2233231 : if (key == "cycleTime") { 333 12 : return toString(STEPS2TIME(myDefaultCycleTime)); 334 2233219 : } else if (key == "offset") { 335 12 : return toString(STEPS2TIME(myOffset)); 336 2233207 : } else if (key == "coordinated") { 337 12 : return toString(myCoordinated); 338 2233195 : } else if (key == "cycleSecond") { 339 12 : return toString(STEPS2TIME(getTimeInCycle())); 340 2233183 : } else if (key == "typeName") { 341 6 : return toString(this->getLogicType()); 342 : } 343 4466354 : return Parameterised::getParameter(key, defaultValue); 344 : } 345 : 346 : void 347 89 : MSSimpleTrafficLightLogic::setParameter(const std::string& key, const std::string& value) { 348 89 : if (key == "cycleTime") { 349 6 : myDefaultCycleTime = string2time(value); 350 6 : Parameterised::setParameter(key, value); 351 166 : } else if (key == "cycleSecond" || key == "typeName") { 352 0 : throw InvalidArgument(key + " cannot be changed dynamically for traffic light '" + getID() + "'"); 353 83 : } else if (key == "offset") { 354 6 : myOffset = string2time(value); 355 77 : } else if (key == "coordinated") { 356 6 : myCoordinated = StringUtils::toBool(value); 357 6 : Parameterised::setParameter(key, value); 358 : } else { 359 71 : Parameterised::setParameter(key, value); 360 : } 361 89 : } 362 : 363 : /****************************************************************************/