Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-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 MSActuatedTrafficLightLogic.h
15 : /// @author Daniel Krajzewicz
16 : /// @author Michael Behrisch
17 : /// @author Jakob Erdmann
18 : /// @date Sept 2002
19 : ///
20 : // An actuated (adaptive) traffic light logic
21 : /****************************************************************************/
22 : #pragma once
23 : #include <config.h>
24 :
25 : #include <utility>
26 : #include <vector>
27 : #include <bitset>
28 : #include <map>
29 : #include <microsim/MSEventControl.h>
30 : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
31 : #include <microsim/output/MSDetectorControl.h>
32 : #include <microsim/output/MSInductLoop.h>
33 : #include "MSSimpleTrafficLightLogic.h"
34 :
35 :
36 : // ===========================================================================
37 : // class declarations
38 : // ===========================================================================
39 : class NLDetectorBuilder;
40 :
41 : // ===========================================================================
42 : // class definitions
43 : // ===========================================================================
44 : /**
45 : * @class MSActuatedTrafficLightLogic
46 : * @brief An actuated (adaptive) traffic light logic
47 : */
48 : class MSActuatedTrafficLightLogic : public MSSimpleTrafficLightLogic {
49 : public:
50 :
51 : typedef Parameterised::Map ConditionMap;
52 : typedef std::vector<std::tuple<std::string, std::string, std::string> > AssignmentMap;
53 :
54 41785 : struct Function {
55 41785 : Function(const std::string& _id = "", int _nArgs = -1):
56 41785 : id(_id), nArgs(_nArgs) {}
57 : std::string id;
58 : int nArgs;
59 : AssignmentMap assignments;
60 : };
61 :
62 : typedef std::map<std::string, Function> FunctionMap;
63 :
64 :
65 : /** @brief Constructor
66 : * @param[in] tlcontrol The tls control responsible for this tls
67 : * @param[in] id This tls' id
68 : * @param[in] programID This tls' sub-id (program id)
69 : * @param[in] phases Definitions of the phases
70 : * @param[in] step The initial phase index
71 : * @param[in] delay The time to wait before the first switch
72 : * @param[in] parameter The parameter to use for tls set-up
73 : */
74 : MSActuatedTrafficLightLogic(MSTLLogicControl& tlcontrol,
75 : const std::string& id, const std::string& programID,
76 : const SUMOTime offset,
77 : const MSSimpleTrafficLightLogic::Phases& phases,
78 : int step, SUMOTime delay,
79 : const Parameterised::Map& parameter,
80 : const std::string& basePath,
81 : const ConditionMap& conditions = ConditionMap(),
82 : const AssignmentMap& assignments = AssignmentMap(),
83 : const FunctionMap& functions = FunctionMap());
84 :
85 :
86 : /** @brief Initialises the tls with information about incoming lanes
87 : * @param[in] nb The detector builder
88 : * @exception ProcessError If something fails on initialisation
89 : */
90 : void init(NLDetectorBuilder& nb) override;
91 :
92 :
93 : /// @brief Destructor
94 : ~MSActuatedTrafficLightLogic();
95 :
96 :
97 :
98 : /// @name Switching and setting current rows
99 : /// @{
100 :
101 : /** @brief Switches to the next phase
102 : * @return The time of the next switch
103 : * @see MSTrafficLightLogic::trySwitch
104 : */
105 : SUMOTime trySwitch() override;
106 : /// @}
107 :
108 : SUMOTime getMinDur(int step = -1) const override;
109 : SUMOTime getMaxDur(int step = -1) const override;
110 : SUMOTime getEarliestEnd(int step = -1) const override;
111 : SUMOTime getLatestEnd(int step = -1) const override;
112 :
113 : /// @name Changing phases and phase durations
114 : /// @{
115 :
116 : /** @brief Changes the current phase and her duration
117 : * @param[in] tlcontrol The responsible traffic lights control
118 : * @param[in] simStep The current simulation step
119 : * @param[in] step Index of the phase to use
120 : * @param[in] stepDuration The left duration of the phase
121 : * @see MSTrafficLightLogic::changeStepAndDuration
122 : */
123 : void changeStepAndDuration(MSTLLogicControl& tlcontrol, SUMOTime simStep,
124 : int step, SUMOTime stepDuration) override;
125 :
126 : /// @brief called when switching programs
127 : void activateProgram() override;
128 : void deactivateProgram() override;
129 :
130 : bool showDetectors() const {
131 0 : return myShowDetectors;
132 : }
133 :
134 : void setShowDetectors(bool show);
135 :
136 : void saveState(OutputDevice& out) const override;
137 :
138 : void loadExtraState(const std::string& state) override;
139 :
140 : /// @brief try to get the value of the given parameter (including prefixed parameters)
141 : const std::string getParameter(const std::string& key, const std::string defaultValue = "") const override;
142 :
143 : /**@brief Sets a parameter and updates internal constants */
144 : void setParameter(const std::string& key, const std::string& value) override;
145 :
146 : /// @brief retrieve all detectors used by this program
147 : std::map<std::string, double> getDetectorStates() const override;
148 :
149 : /// @brief retrieve a specific detector used by this program
150 : double getDetectorState(const std::string laneID) const override;
151 :
152 : /// @brief return all named conditions defined for this traffic light
153 : std::map<std::string, double> getConditions() const override;
154 :
155 : void loadState(MSTLLogicControl& tlcontrol, SUMOTime t, int step, SUMOTime spentDuration, bool active) override;
156 :
157 : protected:
158 : /// @brief initialize custom switching rules
159 : void initAttributeOverride();
160 : void initSwitchingRules();
161 :
162 125639 : struct InductLoopInfo {
163 4246 : InductLoopInfo(MSInductLoop* _loop, const MSLane* _lane, int numPhases, double _maxGap, double _jamThreshold):
164 4246 : loop(_loop),
165 4246 : lane(_lane),
166 8492 : servedPhase(numPhases, false),
167 4246 : maxGap(_maxGap),
168 4246 : jamThreshold(_jamThreshold)
169 : {}
170 :
171 :
172 : bool isJammed() const {
173 941291 : return jamThreshold > 0 && loop->getOccupancyTime() >= jamThreshold;
174 : }
175 :
176 : MSInductLoop* loop;
177 : const MSLane* lane;
178 : SUMOTime lastGreenTime = 0;
179 : std::vector<bool> servedPhase;
180 : double maxGap;
181 : double jamThreshold;
182 :
183 : };
184 :
185 : /// @brief Definition of a map from phases to induct loops controlling them
186 : typedef std::vector<std::vector<InductLoopInfo*> > InductLoopMap;
187 :
188 : /// @name "actuated" algorithm methods
189 : /// @{
190 :
191 : /** @brief Returns the minimum duration of the current phase
192 : * @param[in] detectionGap The minimum detection gap for the current phase
193 : * @return The minimum duration of the current phase
194 : */
195 : SUMOTime duration(const double detectionGap) const;
196 :
197 : /// @brief get the minimum min duration for all stretchable phases that affect the given lane
198 : SUMOTime getMinimumMinDuration(MSLane* lane, const std::set<int>& multiNextTargets) const;
199 :
200 : /** @brief Return the minimum detection gap of all detectors if the current phase should be extended and double::max otherwise
201 : */
202 : double gapControl();
203 :
204 :
205 : /// @brief return whether there is a major link from the given lane in the given phase
206 : bool hasMajor(const std::string& state, const LaneVector& lanes) const;
207 : /// @}
208 :
209 : /// @brief select among candidate phases based on detector states
210 : int decideNextPhase();
211 :
212 : /// @brief select among candidate phases based on detector states and custom switching rules
213 : int decideNextPhaseCustom(bool mustSwitch);
214 :
215 : /// @brief evaluate custom switching condition
216 : double evalExpression(const std::string& condition) const;
217 :
218 : /// @brief evaluate atomic expression
219 : double evalTernaryExpression(double a, const std::string& o, double b, const std::string& condition) const;
220 :
221 : /// @brief evaluate atomic expression
222 : double evalAtomicExpression(const std::string& expr) const;
223 :
224 : /// @brief evaluate function expression
225 : double evalCustomFunction(const std::string& fun, const std::string& arg) const;
226 :
227 : /// @brief execute assignemnts of the logic or a custom function
228 : void executeAssignments(const AssignmentMap& assignments, ConditionMap& conditions, const ConditionMap& forbidden = ConditionMap()) const;
229 :
230 : int getDetectorPriority(const InductLoopInfo& loopInfo) const;
231 :
232 : /// @brief count the number of active detectors for the given step
233 : int getPhasePriority(int step) const;
234 :
235 : /// @brief get the green phase following step and the transition time
236 : std::pair<int, SUMOTime> getTarget(int step) const;
237 :
238 : /// @brief whether the current phase cannot be continued due to linkMaxDur constraints
239 : bool maxLinkDurationReached();
240 :
241 : /// @brief whether the target phase is acceptable in light of linkMaxDur constraints
242 : bool canExtendLinkGreen(int target);
243 :
244 : /// @brief the minimum duratin for keeping the current phase due to linkMinDur constraints
245 : SUMOTime getLinkMinDuration(int target) const;
246 :
247 : /// @brief whether a given link has only weak mode foes that are green in the given state
248 : bool weakConflict(int linkIndex, const std::string& state) const;
249 :
250 : template<typename T, SumoXMLTag Tag>
251 106636 : const T* retrieveDetExpression(const std::string& arg, const std::string& expr, bool tryPrefix) const {
252 62012 : const T* det = dynamic_cast<const T*>(
253 106636 : MSNet::getInstance()->getDetectorControl().getTypedDetectors(Tag).get(
254 106636 : (tryPrefix ? myDetectorPrefix : "") + arg));
255 106636 : if (det == nullptr) {
256 44624 : if (tryPrefix) {
257 : // try again without prefix
258 33902 : return retrieveDetExpression<T, Tag>(arg, expr, false);
259 : } else {
260 32166 : throw ProcessError("Unknown detector '" + arg + "' in expression '" + expr + "'");
261 : }
262 : } else {
263 : return det;
264 : }
265 : }
266 :
267 : /// find green phases target by a next attribute
268 : std::set<int> getMultiNextTargets() const;
269 :
270 : void initTargets(int step);
271 : void findTargets(int origStep, int n, SUMOTime priorTransition, std::map<int, SUMOTime>& found);
272 :
273 : protected:
274 : /// @brief A map from phase to induction loops to be used for gap control
275 : InductLoopMap myInductLoopsForPhase;
276 : std::vector<std::vector<const MSLink*> > myCrossingsForPhase;
277 :
278 : std::vector<InductLoopInfo> myInductLoops;
279 :
280 : /// @brief extra loops for output/tracking
281 : std::vector<const MSInductLoop*> myExtraLoops;
282 : std::vector<const MSE2Collector*> myExtraE2;
283 :
284 : /// The maximum gap to check in seconds
285 : double myMaxGap;
286 :
287 : /// The minimum continuous occupancy time to mark a detector as jammed
288 : double myJamThreshold;
289 :
290 : /// The passing time used in seconds
291 : double myPassingTime;
292 :
293 : /// The detector distance in seconds
294 : double myDetectorGap;
295 :
296 : /// The time threshold to avoid starved phases
297 : SUMOTime myInactiveThreshold;
298 :
299 : /// Whether the detectors shall be shown in the GUI
300 : bool myShowDetectors;
301 :
302 : /// Whether all detectors shall be built
303 : bool myBuildAllDetectors;
304 :
305 : /// Whether any of the phases has multiple targets
306 : bool myHasMultiTarget;
307 :
308 : /// The output file for generated detectors
309 : std::string myFile;
310 :
311 : /// The frequency for aggregating detector output
312 : SUMOTime myFreq;
313 :
314 : /// Whether detector output separates by vType
315 : std::string myVehicleTypes;
316 :
317 : /// @brief last time trySwitch was called
318 : SUMOTime myLastTrySwitchTime;
319 :
320 : /// @brief consecutive time that the given link index has been green
321 : std::vector<SUMOTime> myLinkGreenTimes;
322 : std::vector<SUMOTime> myLinkRedTimes;
323 : /// @brief maximum consecutive time that the given link may remain green
324 : std::vector<SUMOTime> myLinkMaxGreenTimes;
325 : /// @brief minimum consecutive time that the given link must remain green
326 : std::vector<SUMOTime> myLinkMinGreenTimes;
327 :
328 : /// @brief The custom switching conditions
329 : ConditionMap myConditions;
330 :
331 : /// @brief The condition assignments
332 : AssignmentMap myAssignments;
333 :
334 : /// @brief The loaded functions
335 : FunctionMap myFunctions;
336 :
337 : /// @brief The function call stack;
338 : mutable std::vector<std::map<std::string, double> > myStack;
339 :
340 : /// @brief the conditions which shall be listed in GUITLLogicPhasesTrackerWindow
341 : std::set<std::string> myListedConditions;
342 :
343 : /// @brief whether the next switch time was requested via TraCI
344 : bool myTraCISwitch;
345 :
346 : struct SwitchingRules {
347 : bool enabled = false;
348 : };
349 :
350 : std::vector<SwitchingRules> mySwitchingRules;
351 :
352 : const std::string myDetectorPrefix;
353 :
354 : /* @brief for every actuated phase,
355 : * then for every target phase,
356 : * provide the list of green phases that are reached quickest from the target phase
357 : */
358 : std::map<int, std::map<int, std::vector<int> > > myTargets;
359 :
360 : static const std::vector<std::string> OPERATOR_PRECEDENCE;
361 : };
|