Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2010-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 MSSwarmTrafficLightLogic.h
15 : /// @author Gianfilippo Slager
16 : /// @author Federico Caselli
17 : /// @date Mar 2010
18 : ///
19 : // The class for Swarm-based logics
20 : /****************************************************************************/
21 : #pragma once
22 : #include <config.h>
23 :
24 : #include "MSSOTLHiLevelTrafficLightLogic.h"
25 : #include "MSSOTLPhasePolicy.h"
26 : #include "MSSOTLPlatoonPolicy.h"
27 : #include "MSSOTLMarchingPolicy.h"
28 : #include "MSSOTLCongestionPolicy.h"
29 : #include "MSSOTLPolicy3DStimulus.h"
30 : #include "MSSOTLPolicy5DFamilyStimulus.h"
31 :
32 : template<class T>
33 : class CircularBuffer {
34 : public:
35 128 : CircularBuffer(int size) :
36 128 : m_size(size), m_currentIndex(0), m_firstTime(true) {
37 128 : m_buffer = new T[m_size];
38 128 : }
39 :
40 128 : virtual ~CircularBuffer() {
41 128 : delete[] m_buffer;
42 256 : }
43 :
44 : bool addValue(const T newValue, T& replacedValue) {
45 : bool result = !m_firstTime;
46 : if (result) {
47 : replacedValue = m_buffer[m_currentIndex];
48 : }
49 : insert(newValue);
50 : return result;
51 : }
52 :
53 : void push_front(const T value) {
54 : insert(value);
55 : }
56 :
57 : T at(const int index) const {
58 313096 : int idx = (m_currentIndex - 1 - index + m_size) % m_size;
59 229372 : return m_buffer[idx];
60 : }
61 :
62 : T front() const {
63 : return at(0);
64 : }
65 :
66 : T back() const {
67 : return at(size() - 1);
68 : }
69 :
70 : int size() const {
71 468700 : if (m_firstTime) {
72 14152 : return m_currentIndex;
73 : }
74 454548 : return m_size;
75 : }
76 :
77 : void clear() {
78 16828 : m_currentIndex = 0;
79 8414 : m_firstTime = true;
80 : }
81 :
82 : private:
83 : T* m_buffer;
84 : int m_size;
85 : int m_currentIndex;
86 : bool m_firstTime;
87 :
88 : inline void insert(const T& value) {
89 54010 : m_buffer[m_currentIndex++] = value;
90 54010 : if (m_currentIndex == m_size) {
91 15183 : m_currentIndex = 0;
92 15183 : m_firstTime = false;
93 : }
94 : }
95 : };
96 :
97 : class MSSwarmTrafficLightLogic: public MSSOTLHiLevelTrafficLightLogic {
98 : public:
99 : //****************************************************
100 : /**
101 : * @brief Constructor without sensors passed
102 : * @param[in] tlcontrol The tls control responsible for this tls
103 : * @param[in] id This tls' id
104 : * @param[in] programID This tls' sub-id (program id)
105 : * @param[in] phases Definitions of the phases
106 : * @param[in] step The initial phase index
107 : * @param[in] delay The time to wait before the first switch
108 : * @param[in] parameters Parameters defined for the tll
109 : */
110 : MSSwarmTrafficLightLogic(MSTLLogicControl& tlcontrol, const std::string& id,
111 : const std::string& programID, const Phases& phases, int step,
112 : SUMOTime delay,
113 : const Parameterised::Map& parameters);
114 :
115 : ~MSSwarmTrafficLightLogic();
116 :
117 : /**
118 : * @brief Initialises the tls with sensors on incoming and outgoing lanes
119 : * Sensors are built in the simulation according to the type of sensor specified in the simulation parameter
120 : * @param[in] nb The detector builder
121 : * @exception ProcessError If something fails on initialisation
122 : */
123 : void init(NLDetectorBuilder& nb);
124 :
125 0 : SUMOTime getMaxCongestionDuration() {
126 0 : return StringUtils::toInt(getParameter("MAX_CONGESTION_DUR", "120"));
127 : }
128 :
129 127904 : double getPheroMaxVal() {
130 255808 : return StringUtils::toDouble(getParameter("PHERO_MAXVAL", "10"));
131 : }
132 :
133 15976 : double getBetaNo() {
134 31952 : return StringUtils::toDouble(getParameter("BETA_NO", "0.99"));
135 : }
136 :
137 15976 : double getGammaNo() {
138 31952 : return StringUtils::toDouble(getParameter("GAMMA_NO", "1.0"));
139 : }
140 :
141 15976 : double getBetaSp() {
142 31952 : return StringUtils::toDouble(getParameter("BETA_SP", "0.99"));
143 : }
144 :
145 15976 : double getGammaSp() {
146 31952 : return StringUtils::toDouble(getParameter("GAMMA_SP", "1.0"));
147 : }
148 :
149 153 : double getChangePlanProbability() {
150 306 : return StringUtils::toDouble(getParameter("CHANGE_PLAN_PROBABILITY", "0.003"));
151 : }
152 :
153 564 : double getThetaMax() {
154 1128 : return StringUtils::toDouble(getParameter("THETA_MAX", "0.8"));
155 : }
156 :
157 564 : double getThetaMin() {
158 1128 : return StringUtils::toDouble(getParameter("THETA_MIN", "0.2"));
159 : }
160 :
161 0 : double getThetaInit() {
162 0 : return StringUtils::toDouble(getParameter("THETA_INIT", "0.5"));
163 : }
164 :
165 141 : double getLearningCox() {
166 282 : return StringUtils::toDouble(getParameter("LEARNING_COX", "0.0005"));
167 : }
168 :
169 423 : double getForgettingCox() {
170 846 : return StringUtils::toDouble(getParameter("FORGETTING_COX", "0.0005"));
171 : }
172 :
173 : double getScaleFactorDispersionIn() {
174 0 : return scaleFactorDispersionIn;
175 : }
176 :
177 : double getScaleFactorDispersionOut() {
178 0 : return scaleFactorDispersionOut;
179 : }
180 :
181 : /** @brief Returns the type of the logic as a string
182 : * @return The type of the logic
183 : */
184 : const std::string getLogicType() const {
185 : return "swarmBasedTrafficLogic";
186 : }
187 : /// @}
188 :
189 : protected:
190 : /**
191 : * @brief This pheronome is an indicator of congestion on input lanes.\n
192 : * Its levels refer to the average speed of vehicles passing the input lane:
193 : * the lower the speed the higher the pheromone.\n
194 : * These levels are updated on every input lane, independently on lights state.
195 : */
196 : MSLaneId_PheromoneMap pheromoneInputLanes;
197 :
198 : /**
199 : * \brief This pheromone is an indicator of congestion on output lanes.\n
200 : * Its levels refer to the average speed of vehicles passing the output lane:
201 : * the lower the speed the higher the pheromone.\n
202 : * These levels are updated on every output lane, independently on lights state.
203 : */
204 : MSLaneId_PheromoneMap pheromoneOutputLanes;
205 :
206 : /**
207 : * This member keeps track of the last thresholds update, s.t.
208 : * updates can be correctly performed even on time-variable interations.
209 : * @see MSSwarmTrafficLightLogic::updateSensitivities()
210 : */
211 : SUMOTime lastThetaSensitivityUpdate;
212 :
213 : /*
214 : * This member has to contain the switching logic for SOTL policies
215 : */
216 :
217 : int decideNextPhase();
218 :
219 : bool canRelease();
220 :
221 : /*
222 : * Computes how much time will pass after decideNextPhase will be executed again
223 : */
224 15976 : virtual SUMOTime computeReturnTime() {
225 :
226 15976 : return DELTA_T;
227 :
228 : }
229 :
230 : /**
231 : * @brief Resets pheromone levels
232 : */
233 : void resetPheromone();
234 :
235 : /*
236 : * @return The average pheromone level regarding congestion on input lanes
237 : */
238 : double getPheromoneForInputLanes();
239 :
240 : /*
241 : * @return The average pheromone level regarding congestion on output lanes
242 : */
243 : double getPheromoneForOutputLanes();
244 :
245 : /*
246 : * @return The dispersion level regarding congestion on input lanes
247 : */
248 : double getDispersionForInputLanes(double average_phero_in);
249 :
250 : /*
251 : * @return The dispersion level regarding congestion on output lanes
252 : */
253 : double getDispersionForOutputLanes(double average_phero_out);
254 :
255 : /*
256 : * @return The difference between the current max phero value and the average phero of the other lanes
257 : */
258 : double getDistanceOfMaxPheroForInputLanes();
259 :
260 : /*
261 : * @return The difference between the current max phero value and the average phero of the other lanes
262 : */
263 : double getDistanceOfMaxPheroForOutputLanes();
264 : /**
265 : * @brief Update pheromone levels
266 : * Pheromone on input lanes is costantly updated
267 : * Pheromone follows a discrete-time dynamic law "pheromone(k+1) = beta*pheromone(k) + gamma * sensed_val(k)"
268 : */
269 : void updatePheromoneLevels();
270 :
271 : /**
272 : * @brief Utility method to avoid code duplication
273 : */
274 : void updatePheromoneLevels(MSLaneId_PheromoneMap&, std::string, const double, const double);
275 :
276 : /**
277 : * After a policy has been chosen, for every iteration thresholds has to be updated.
278 : * Thresholds reinforcement lowers the theta_sensitivity for the current policy and raises the ones for currently unused policies.
279 : * Thresholds belongs to the interval [THETA_MIN THETA_MAX]
280 : */
281 : void updateSensitivities();
282 :
283 : /**
284 : * @brief Decide the current policy according to pheromone levels
285 : * The decision reflects on currentPolicy value
286 : */
287 : void decidePolicy();
288 :
289 : /**
290 : * \brief Method that should calculate the valor of phi a coefficient to amplify/attenuate eta based on a factor.
291 : * The factor depends on the situation when the function is called; should be the number of cars in the target lanes
292 : * or the number of cars in the lanes with a red tl.
293 : * @param[in] factor - the value to consider to compute this coefficient.
294 : */
295 : double calculatePhi(int factor);
296 :
297 : /**
298 : * \brief Method that should calculate the valor of eta a coefficient to evaluate the current
299 : * policy's work. This eta is based on the difference between the number of vehicles that enters a tl
300 : * and the ones that exit it. It consider vehicles on a lane with a tl set to red as well to determinate
301 : * policy work.
302 : */
303 : double calculateEtaDiff();
304 :
305 : double calculateEtaRatio();
306 :
307 : /*
308 : * \brief Method to reset the map that stores if a lane is already been checked during the
309 : * evaluation of eta.
310 : */
311 : void resetLaneCheck();
312 : void choosePolicy(double phero_in, double phero_out, double dispersion_in, double dispersion_out);
313 : void choosePolicy(double phero_in, double phero_out);
314 :
315 16 : std::string getPoliciesParam() {
316 32 : return getParameter("POLICIES", "Platoon;Phase;Marching;Congestion");
317 : }
318 :
319 : /*
320 : * Reinforcement modes:
321 : * 0-> elapsed time
322 : * 1-> diff
323 : * 2-> ratio
324 : */
325 153 : int getReinforcementMode() {
326 306 : return StringUtils::toInt(getParameter("REIMODE", "0"));
327 : }
328 :
329 16 : void initScaleFactorDispersionIn(int lanes_in) {
330 : std::vector<double> phero_values;
331 :
332 48 : for (int i = 0; i < lanes_in / 2; i++) {
333 32 : phero_values.push_back(getPheroMaxVal());
334 : }
335 48 : for (int i = lanes_in / 2; i < lanes_in; i++) {
336 32 : phero_values.push_back(0.0);
337 : }
338 :
339 : double sum_avg_tmp = 0;
340 :
341 80 : for (int i = 0; i < (int)phero_values.size(); i++) {
342 64 : sum_avg_tmp += phero_values[i];
343 : }
344 :
345 16 : const double mean = sum_avg_tmp / (double)phero_values.size();
346 :
347 : double sum_dev_tmp = 0;
348 80 : for (int i = 0; i < (int)phero_values.size(); i++) {
349 64 : sum_dev_tmp += pow(phero_values[i] - mean, 2);
350 : }
351 :
352 16 : const double deviation = sqrt(sum_dev_tmp / (double)phero_values.size());
353 :
354 16 : scaleFactorDispersionIn = getPheroMaxVal() / deviation;
355 16 : }
356 :
357 16 : void initScaleFactorDispersionOut(int lanes_out) {
358 : std::vector<double> phero_values;
359 :
360 48 : for (int i = 0; i < lanes_out / 2; i++) {
361 32 : phero_values.push_back(getPheroMaxVal());
362 : }
363 48 : for (int i = lanes_out / 2; i < lanes_out; i++) {
364 32 : phero_values.push_back(0.0);
365 : }
366 :
367 : double sum_avg_tmp = 0;
368 80 : for (int i = 0; i < (int)phero_values.size(); i++) {
369 64 : sum_avg_tmp += phero_values[i];
370 : }
371 16 : const double mean = sum_avg_tmp / (double)phero_values.size();
372 :
373 : double sum_dev_tmp = 0;
374 :
375 80 : for (int i = 0; i < (int)phero_values.size(); i++) {
376 64 : sum_dev_tmp += pow(phero_values[i] - mean, 2);
377 : }
378 :
379 16 : const double deviation = sqrt(sum_dev_tmp / (double)phero_values.size());
380 :
381 16 : scaleFactorDispersionOut = getPheroMaxVal() / deviation;
382 16 : }
383 :
384 : /**
385 : * @brief Check if a lane is allowed to be added to the maps pheromoneInputLanes and pheromoneOutputLanes
386 : * Control in this function if the lane is a walking area, a crossing, or if only pedestrian are allowed.
387 : * Return true if the lane has to be added, false otherwise.
388 : */
389 : bool allowLine(MSLane*);
390 :
391 : bool logData;
392 : std::ofstream swarmLogFile;
393 : /**
394 : * \brief When true, indicates that the current policy MUST be changed.\n
395 : * It's used to force the exit from the congestion policy
396 : */
397 : bool mustChange;
398 : SUMOTime congestion_steps;
399 :
400 : /**
401 : * \brief Map to check if a lane was already controlled during the elaboration of eta.
402 : */
403 : LaneCheckMap laneCheck;
404 : /**
405 : * \brief A copy of the target lanes of this phase.
406 : */
407 : LaneIdVector targetLanes;
408 : /**
409 : * \brief When true indicates that we can skip the evaluation of eta since we've
410 : * a congestion policy that is lasting too much.
411 : */
412 : bool skipEta;
413 : /**
414 : * \brief When true indicates that we've already acquired the target lanes for this
415 : * particular phase.
416 : */
417 : bool gotTargetLane;
418 :
419 : int carsIn;
420 : int carsOut;
421 : int inTarget;
422 : int notTarget;
423 : /**
424 : * \factors to scale pheromoneDispersion in range [0, 10]
425 : */
426 : double scaleFactorDispersionIn;
427 : double scaleFactorDispersionOut;
428 :
429 : // For every lane its index. Esed to get the current lane state for the lane
430 : std::map<std::string, std::vector<int> > m_laneIndexMap;
431 : std::string getLaneLightState(const std::string& laneId);
432 : // store the last message logged. if equal do not log it again
433 : Parameterised::Map m_pheroLevelLog;
434 :
435 : //derivative
436 : std::map<std::string, CircularBuffer<double>* > m_meanSpeedHistory;
437 : std::map<std::string, CircularBuffer<double>* > m_derivativeHistory;
438 : double m_derivativeAlpha;
439 : int m_losCounter;//los: loss of signal
440 : int m_losMaxLimit;
441 : bool m_useVehicleTypesWeights;
442 :
443 : // double pheroBegin;
444 : };
|