Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSLCM_LC2013.cpp
Go to the documentation of this file.
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/****************************************************************************/
24// A lane change model developed by J. Erdmann
25// based on the model of D. Krajzewicz developed between 2004 and 2011 (MSLCM_DK2004)
26/****************************************************************************/
27#include <config.h>
28
29#include <iostream>
35#include <microsim/MSEdge.h>
36#include <microsim/MSLane.h>
37#include <microsim/MSLink.h>
39#include <microsim/MSNet.h>
40#include <microsim/MSStop.h>
41#include "MSLCHelper.h"
42#include "MSLCM_LC2013.h"
43
44
45// ===========================================================================
46// variable definitions
47// ===========================================================================
48#define LOOK_FORWARD 10.
49
50#define JAM_FACTOR 1.
51
52#define LCA_RIGHT_IMPATIENCE -1.
53#define CUT_IN_LEFT_SPEED_THRESHOLD 27.
54
55#define LOOK_AHEAD_MIN_SPEED 0.0
56#define LOOK_AHEAD_SPEED_MEMORY 0.9
57
58#define HELP_DECEL_FACTOR 1.0
59
60#define HELP_OVERTAKE (10.0 / 3.6)
61#define MIN_FALLBEHIND (7.0 / 3.6)
62
63#define RELGAIN_NORMALIZATION_MIN_SPEED 10.0
64#define URGENCY 2.0
65#define OPPOSITE_URGENCY 5.0
66
67#define KEEP_RIGHT_TIME 5.0 // the number of seconds after which a vehicle should move to the right lane
68
69#define KEEP_RIGHT_HEADWAY 2.0
70#define MAX_ONRAMP_LENGTH 200.
71#define TURN_LANE_DIST 200.0 // the distance at which a lane leading elsewhere is considered to be a turn-lane that must be avoided
72
73#define LC_RESOLUTION_SPEED_LAT 0.5 // the lateral speed (in m/s) for a standing vehicle which was unable to finish a continuous LC in time (in case mySpeedLatStanding==0), see #3771
74
75#define REACT_TO_STOPPED_DISTANCE 100
76#define BLOCKER_IS_BLOCKED_TIME_THRESHOLD 5 // the time after which a blocking neighbor is treated similar to a stopped vehicle
77
78#define HYST_PRECISION 10000000
79
80// ===========================================================================
81// debug defines
82// ===========================================================================
83//#define DEBUG_CONSTRUCTOR
84//#define DEBUG_PATCH_SPEED
85//#define DEBUG_INFORMED
86//#define DEBUG_INFORMER
87//#define DEBUG_WANTS_CHANGE
88//#define DEBUG_SLOW_DOWN
89//#define DEBUG_COOPERATE
90//#define DEBUG_SAVE_BLOCKER_LENGTH
91
92//#define DEBUG_COND (myVehicle.getID() == "ego")
93#define DEBUG_COND (myVehicle.isSelected())
94//#define DEBUG_COND (true)
95
96// ===========================================================================
97// member method definitions
98// ===========================================================================
105 myLeftSpace(0),
107 myDontBrake(false),
108 myStrategicParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_STRATEGIC_PARAM, 1)),
109 myCooperativeParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_PARAM, 1)),
110 mySpeedGainParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAIN_PARAM, 1)),
111 myKeepRightParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_KEEPRIGHT_PARAM, 1)),
112 myOppositeParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_OPPOSITE_PARAM, 1)),
113 myLookaheadLeft(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_LOOKAHEADLEFT, 2.0)),
114 mySpeedGainRight(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAINRIGHT, 0.1)),
115 mySpeedGainLookahead(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD, 0)),
116 mySpeedGainRemainTime(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME, 20)),
117 mySpeedGainUrgency(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAIN_URGENCY, 50)),
122 myExperimentalParam1(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_EXPERIMENTAL1, 0)) {
124#ifdef DEBUG_CONSTRUCTOR
125 if (DEBUG_COND) {
126 std::cout << SIMTIME
127 << " create lcModel veh=" << myVehicle.getID()
128 << " lcStrategic=" << myStrategicParam
129 << " lcCooperative=" << myCooperativeParam
130 << " lcSpeedGain=" << mySpeedGainParam
131 << " lcKeepRight=" << myKeepRightParam
132 << "\n";
133 }
134#endif
135}
136
140
141
142void
144 if (mySpeedGainParam <= 0) {
145 myChangeProbThresholdRight = std::numeric_limits<long long int>::max();
146 myChangeProbThresholdLeft = std::numeric_limits<long long int>::max();
147 } else {
150 }
151}
152
153
154bool
156 return DEBUG_COND;
157}
158
159
160int
162 int laneOffset,
164 int blocked,
165 const std::pair<MSVehicle*, double>& leader,
166 const std::pair<MSVehicle*, double>& follower,
167 const std::pair<MSVehicle*, double>& neighLead,
168 const std::pair<MSVehicle*, double>& neighFollow,
169 const MSLane& neighLane,
170 const std::vector<MSVehicle::LaneQ>& preb,
171 MSVehicle** lastBlocked,
172 MSVehicle** firstBlocked) {
173
174#ifdef DEBUG_WANTS_CHANGE
175 if (DEBUG_COND) {
176 std::cout << "\nWANTS_CHANGE\n" << SIMTIME
177 << std::setprecision(gPrecision)
178 << " veh=" << myVehicle.getID()
179 << " lane=" << myVehicle.getLane()->getID()
180 << " pos=" << myVehicle.getPositionOnLane()
181 << " posLat=" << myVehicle.getLateralPositionOnLane()
182 << " speed=" << myVehicle.getSpeed()
183 << " considerChangeTo=" << (laneOffset == -1 ? "right" : "left")
184 << "\n";
185 }
186#endif
187
188 const int result = _wantsChange(laneOffset, msgPass, blocked, leader, follower, neighLead, neighFollow, neighLane, preb, *lastBlocked, *firstBlocked);
189
190#ifdef DEBUG_WANTS_CHANGE
191 if (DEBUG_COND) {
192 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " result=" << toString((LaneChangeAction)result) << " blocked=" << toString((LaneChangeAction)blocked) << "\n\n\n";
193 }
194#endif
195
196 return result;
197}
198
199
200double
201MSLCM_LC2013::patchSpeed(const double min, const double wanted, const double max, const MSCFModel& cfModel) {
202
203#ifdef DEBUG_PATCH_SPEED
204 if (DEBUG_COND) {
205 std::cout << "\nPATCH_SPEED\n"
206 << SIMTIME
207 << " veh=" << myVehicle.getID()
208 << " lane=" << myVehicle.getLane()->getID()
209 << " pos=" << myVehicle.getPositionOnLane()
210 << " v=" << myVehicle.getSpeed()
211 << " min=" << min
212 << " wanted=" << wanted
213 << " max=" << max
214 << "\n";
215 }
216#endif
217
218 // negative min speed may be passed when using ballistic updated
219 const double newSpeed = _patchSpeed(MAX2(min, 0.0), wanted, max, cfModel);
220
221#ifdef DEBUG_PATCH_SPEED
222 if (DEBUG_COND) {
223 const std::string patched = (wanted != newSpeed ? " patched=" + toString(newSpeed) : "");
224 std::cout << patched
225 << "\n";
226 }
227#endif
228
229 return newSpeed;
230}
231
232
233double
234MSLCM_LC2013::_patchSpeed(double min, const double wanted, double max, const MSCFModel& cfModel) {
235 int state = myOwnState;
236#ifdef DEBUG_PATCH_SPEED
237 if (DEBUG_COND) {
238 std::cout
239 << "\n" << SIMTIME << std::setprecision(gPrecision)
240 << " patchSpeed state=" << toString((LaneChangeAction)state) << " myLCAccelerationAdvices=" << toString(myLCAccelerationAdvices)
241 << "\n speed=" << myVehicle.getSpeed() << " min=" << min << " wanted=" << wanted
242 << "\n myLeadingBlockerLength=" << myLeadingBlockerLength
243 << "\n";
244 }
245#endif
246
247 // letting vehicles merge in at the end of the lane in case of counter-lane change, step#2
248 double nVSafe = wanted;
249 bool gotOne = false;
250 // if we want to change and have a blocking leader and there is enough room for him in front of us
251 if (myLeadingBlockerLength != 0) {
252 double space = myLeftSpace - myLeadingBlockerLength - POSITION_EPS;
253#ifdef DEBUG_PATCH_SPEED
254 if (DEBUG_COND) {
255 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " myLeftSpace=" << myLeftSpace << " myLeadingBlockerLength=" << myLeadingBlockerLength << " space=" << space << "\n";
256 }
257#endif
258 if (space > 0 && (myVehicle.getLane()->isNormal() || myVehicle.getCurrentEdge()->isRoundabout())) {
259 // compute speed for decelerating towards a place which allows the blocking leader to merge in in front
260 const double vMinEmergency = myVehicle.getCarFollowModel().minNextSpeedEmergency(myVehicle.getSpeed(), &myVehicle);
261 double safe = cfModel.stopSpeed(&myVehicle, myVehicle.getSpeed(), space, MSCFModel::CalcReason::LANE_CHANGE);
262 max = MIN2(max, MAX2(safe, vMinEmergency));
263 // if we are approaching this place
264 if (safe < wanted) {
265 // return this speed as the speed to use
266 if (safe < min) {
267 if (safe >= vMinEmergency) {
268 // permit harder braking if needed and helpful
269 min = MAX2(vMinEmergency, safe);
270 }
271 }
272#ifdef DEBUG_PATCH_SPEED
273 if (DEBUG_COND) {
274 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " slowing down for leading blocker, safe=" << safe << (safe + NUMERICAL_EPS < min ? " (not enough)" : "") << "\n";
275 }
276#endif
277 nVSafe = MAX2(min, safe);
278 gotOne = true;
279 }
280 }
281 }
282
283 const double coopWeight = MAX2(0.0, MIN2(1.0, myCooperativeSpeed));
284 for (auto i : myLCAccelerationAdvices) {
285 double a = i.first;
286 double v = myVehicle.getSpeed() + ACCEL2SPEED(a);
287
288 if (v >= min && v <= max && (MSGlobals::gSemiImplicitEulerUpdate
289 // ballistic update: (negative speeds may appear, e.g. min<0, v<0), BUT:
290 // XXX: LaneChanging returns -1 to indicate no restrictions, which leads to probs here (Leo), refs. #2577
291 // As a quick fix, we just dismiss cases where v=-1
292 // VERY rarely (whenever a requested help-acceleration is really indicated by v=-1)
293 // this can lead to failing lane-change attempts, though)
294 || v != -1)) {
295 if (i.second) {
296 // own advice, no scaling needed
297 nVSafe = MIN2(v, nVSafe);
298 } else {
299 nVSafe = MIN2(v * coopWeight + (1 - coopWeight) * wanted, nVSafe);
300 }
301 gotOne = true;
302#ifdef DEBUG_PATCH_SPEED
303 if (DEBUG_COND) {
304 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " got nVSafe=" << nVSafe << " isOwn: " << i.second << " rawV=" << v << "\n";
305 }
306#endif
307 } else {
308 if (v < min) {
309#ifdef DEBUG_PATCH_SPEED
310 if (DEBUG_COND) {
311 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " ignoring low nVSafe=" << v << " min=" << min << "\n";
312 }
313#endif
314 } else {
315#ifdef DEBUG_PATCH_SPEED
316 if (DEBUG_COND) {
317 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " ignoring high nVSafe=" << v << " max=" << max << "\n";
318 }
319#endif
320 }
321 }
322 }
323 // myDontBrake is used in counter-lane-change situations with relief connection
324 if (gotOne && !myDontBrake) {
325#ifdef DEBUG_PATCH_SPEED
326 if (DEBUG_COND) {
327 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " got vSafe\n";
328 }
329#endif
330 return nVSafe;
331 }
332
333 // check whether the vehicle is blocked
334 if ((state & LCA_WANTS_LANECHANGE) != 0 && (state & LCA_BLOCKED) != 0) {
335 if ((state & LCA_STRATEGIC) != 0) {
336 // necessary decelerations are controlled via vSafe. If there are
337 // none it means we should speed up
338#ifdef DEBUG_PATCH_SPEED
339 if (DEBUG_COND) {
340 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_WANTS_LANECHANGE (strat, no vSafe)\n";
341 }
342#endif
343 return (max + wanted) / 2.0;
344 } else if ((state & LCA_COOPERATIVE) != 0) {
345 // only minor adjustments in speed should be done
346 if ((state & LCA_BLOCKED_BY_LEADER) != 0) {
347#ifdef DEBUG_PATCH_SPEED
348 if (DEBUG_COND) {
349 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_BLOCKED_BY_LEADER (coop)\n";
350 }
351#endif
352 if (wanted >= 0.) {
353 return (MAX2(0., min) + wanted) / 2.0;
354 } else {
355 return wanted;
356 }
357 }
358 if ((state & LCA_BLOCKED_BY_FOLLOWER) != 0) {
359#ifdef DEBUG_PATCH_SPEED
360 if (DEBUG_COND) {
361 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_BLOCKED_BY_FOLLOWER (coop)\n";
362 }
363#endif
364 return (max + wanted) / 2.0;
365 }
366 //} else { // VARIANT_16
367 // // only accelerations should be performed
368 // if ((state & LCA_BLOCKED_BY_FOLLOWER) != 0) {
369 // if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_BLOCKED_BY_FOLLOWER\n";
370 // return (max + wanted) / 2.0;
371 // }
372 }
373 }
374
375 /*
376 // decelerate if being a blocking follower
377 // (and does not have to change lanes)
378 if ((state & LCA_AMBLOCKINGFOLLOWER) != 0) {
379 if (fabs(max - myVehicle.getCarFollowModel().maxNextSpeed(myVehicle.getSpeed(), &myVehicle)) < 0.001 && min == 0) { // !!! was standing
380 if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGFOLLOWER (standing)\n";
381 return 0;
382 }
383 if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGFOLLOWER\n";
384
385 //return min; // VARIANT_3 (brakeStrong)
386 return (min + wanted) / 2.0;
387 }
388 if ((state & LCA_AMBACKBLOCKER) != 0) {
389 if (max <= myVehicle.getCarFollowModel().maxNextSpeed(myVehicle.getSpeed(), &myVehicle) && min == 0) { // !!! was standing
390 if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBACKBLOCKER (standing)\n";
391 //return min; VARIANT_9 (backBlockVSafe)
392 return nVSafe;
393 }
394 }
395 if ((state & LCA_AMBACKBLOCKER_STANDING) != 0) {
396 if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBACKBLOCKER_STANDING\n";
397 //return min;
398 return nVSafe;
399 }
400 */
401
402 // accelerate if being a blocking leader or blocking follower not able to brake
403 // (and does not have to change lanes)
404 if ((state & LCA_AMBLOCKINGLEADER) != 0 && myCooperativeSpeed >= 0) {
405#ifdef DEBUG_PATCH_SPEED
406 if (DEBUG_COND) {
407 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGLEADER\n";
408 }
409#endif
410 return (max + wanted) / 2.0;
411 }
412
413 if ((state & LCA_AMBLOCKINGFOLLOWER_DONTBRAKE) != 0) {
414#ifdef DEBUG_PATCH_SPEED
415 if (DEBUG_COND) {
416 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGFOLLOWER_DONTBRAKE\n";
417 }
418#endif
419 /*
420 // VARIANT_4 (dontbrake)
421 if (max <= myVehicle.getCarFollowModel().maxNextSpeed(myVehicle.getSpeed(), &myVehicle) && min == 0) { // !!! was standing
422 return wanted;
423 }
424 return (min + wanted) / 2.0;
425 */
426 }
427 if (!myVehicle.getLane()->getEdge().hasLaneChanger()) {
428 // remove chaning information if on a road with a single lane
429 changed();
430 }
431 return wanted;
432}
433
434
435void*
436MSLCM_LC2013::inform(void* info, MSVehicle* sender) {
437 UNUSED_PARAMETER(sender);
438 Info* pinfo = (Info*)info;
439 assert(pinfo->first >= 0 || !MSGlobals::gSemiImplicitEulerUpdate);
440 addLCSpeedAdvice(pinfo->first, false);
441 myOwnState |= pinfo->second;
442#ifdef DEBUG_INFORMED
443 if (DEBUG_COND) {
444 std::cout << SIMTIME
445 << " veh=" << myVehicle.getID()
446 << " informedBy=" << sender->getID()
447 << " info=" << pinfo->second
448 << " vSafe=" << pinfo->first
449 << "\n";
450 }
451#endif
452 delete pinfo;
453 return (void*) true;
454}
455
456double
457MSLCM_LC2013::overtakeDistance(const MSVehicle* follower, const MSVehicle* leader, const double gap, double followerSpeed, double leaderSpeed) {
458 followerSpeed = followerSpeed == INVALID_SPEED ? follower->getSpeed() : followerSpeed;
459 leaderSpeed = leaderSpeed == INVALID_SPEED ? leader->getSpeed() : leaderSpeed;
460 double overtakeDist = (gap // drive to back of leader
461 + leader->getVehicleType().getLengthWithGap() // drive to front of leader
462 + follower->getVehicleType().getLength() // follower back reaches leader front
463 + leader->getCarFollowModel().getSecureGap( // save gap to leader
464 leader, follower, leaderSpeed, followerSpeed, follower->getCarFollowModel().getMaxDecel()));
465 return MAX2(overtakeDist, 0.);
466}
467
468
469double
471 int blocked,
472 int dir,
473 const std::pair<MSVehicle*, double>& neighLead,
474 double remainingSeconds) {
475 double plannedSpeed = myVehicle.getSpeed();
476 if (!isOpposite()) {
477 plannedSpeed = MIN2(plannedSpeed,
478 myVehicle.getCarFollowModel().stopSpeed(&myVehicle, myVehicle.getSpeed(), myLeftSpace - myLeadingBlockerLength));
479 }
480 for (auto i : myLCAccelerationAdvices) {
481 const double a = i.first;
482 if (a >= -myVehicle.getCarFollowModel().getMaxDecel()) {
483 plannedSpeed = MIN2(plannedSpeed, myVehicle.getSpeed() + ACCEL2SPEED(a));
484 }
485 }
486#ifdef DEBUG_INFORMER
487 if (DEBUG_COND) {
488 std::cout << "\nINFORM_LEADER"
489 << "\nspeed=" << myVehicle.getSpeed() << " planned=" << plannedSpeed << "\n";
490 }
491#endif
492
493 const MSVehicle* const nv = neighLead.first;
494 if (nv == nullptr) {
495 // not overtaking
496 return plannedSpeed;
497 }
498 const double neighNextSpeed = nv->getSpeed() - ACCEL2SPEED(MAX2(1.0, -nv->getAcceleration()));
499 double neighNextGap;
501 neighNextGap = neighLead.second + SPEED2DIST(neighNextSpeed - plannedSpeed);
502 } else {
503 neighNextGap = neighLead.second + SPEED2DIST((nv->getSpeed() + neighNextSpeed) / 2) - SPEED2DIST((myVehicle.getSpeed() + plannedSpeed) / 2);
504 }
505 if ((blocked & LCA_BLOCKED_BY_LEADER) != 0) {
507 //std::cout << SIMTIME << " ego=" << myVehicle.getID() << " ignoresDivergentBlockingLeader=" << nv->getID() << "\n";
508 return plannedSpeed;
509 }
510#ifdef DEBUG_INFORMER
511 if (DEBUG_COND) {
512 std::cout << " blocked by leader nv=" << nv->getID() << " nvSpeed=" << nv->getSpeed() << " needGap="
513 << myVehicle.getCarFollowModel().getSecureGap(&myVehicle, nv, myVehicle.getSpeed(), nv->getSpeed(), nv->getCarFollowModel().getMaxDecel()) << "\n";
514 }
515#endif
516 // decide whether we want to overtake the leader or follow it
517 double overtakeTime;
518 const double overtakeDist = overtakeDistance(&myVehicle, nv, neighLead.second);
519 const double dv = plannedSpeed - nv->getSpeed();
520
521 if (dv > myOvertakeDeltaSpeedFactor * myVehicle.getLane()->getSpeedLimit()) {
522 overtakeTime = overtakeDist / dv;
524 && !isOpposite()
525 && (myVehicle.getVehicleType().getLengthWithGap() + nv->getVehicleType().getLengthWithGap()) <= myLeftSpace) {
526 // -> set overtakeTime to indicate possibility of overtaking (only if there is enough space)
527 overtakeTime = remainingSeconds - 1;
528 } else {
529 // -> set overtakeTime to something indicating impossibility of overtaking
530 overtakeTime = remainingSeconds + 1;
531 }
532
533#ifdef DEBUG_INFORMER
534 if (DEBUG_COND) {
535 std::cout << SIMTIME << " informLeader() of " << myVehicle.getID()
536 << "\nnv = " << nv->getID()
537 << "\nplannedSpeed = " << plannedSpeed
538 << "\nleaderSpeed = " << nv->getSpeed()
539 << "\nmyLeftSpace = " << myLeftSpace
540 << "\nremainingSeconds = " << remainingSeconds
541 << "\novertakeDist = " << overtakeDist
542 << "\novertakeTime = " << overtakeTime
543 << std::endl;
544 }
545#endif
546
547 if ((dv < myOvertakeDeltaSpeedFactor * myVehicle.getLane()->getSpeedLimit()
548 // overtaking on the right on an uncongested highway is forbidden (noOvertakeLCLeft)
549 || (dir == LCA_MLEFT && avoidOvertakeRight(neighLead.first))
550 // not enough space to overtake?
551 || (MSGlobals::gSemiImplicitEulerUpdate && myLeftSpace - myLeadingBlockerLength - myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed()) < overtakeDist)
552 // using brakeGap() without headway seems adequate in a situation where the obstacle (the lane end) is not moving [XXX implemented in branch ticket860, can be used in general if desired, refs. #2575] (Leo).
553 || (!MSGlobals::gSemiImplicitEulerUpdate && myLeftSpace - myLeadingBlockerLength - myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed(), getCarFollowModel().getMaxDecel(), 0.) < overtakeDist)
554 // not enough time to overtake? (skipped for a stopped leader [currently only for ballistic update XXX: check if appropriate for euler, too, refs. #2575] to ensure that it can be overtaken if only enough space is exists) (Leo)
555 || (remainingSeconds < overtakeTime && (MSGlobals::gSemiImplicitEulerUpdate || !nv->isStopped())))
556 // opposite driving and must overtake
557 && (!neighLead.first->isStopped() || (isOpposite() && neighLead.second >= 0))) {
558 // cannot overtake
559 msgPass.informNeighLeader(new Info(std::numeric_limits<double>::max(), dir | LCA_AMBLOCKINGLEADER), &myVehicle);
560 // slow down smoothly to follow leader
561 // account for minor decelerations by the leader (dawdling)
562 double targetSpeed = MAX3(myVehicle.getCarFollowModel().minNextSpeed(myVehicle.getSpeed(), &myVehicle),
563 getCarFollowModel().followSpeed(&myVehicle, myVehicle.getSpeed(), neighNextGap, neighNextSpeed, nv->getCarFollowModel().getMaxDecel()),
564 // avoid changing on intersection
565 (myVehicle.getLane()->isNormal() || myVehicle.getCurrentEdge()->isRoundabout()) ? 0 : ACCEL2SPEED(myVehicle.getCarFollowModel().getMaxAccel()));
566 if (targetSpeed < myVehicle.getSpeed()) {
567 // slow down smoothly to follow leader
568 const double decel = remainingSeconds == 0. ? myVehicle.getCarFollowModel().getMaxDecel() :
569 MIN2(myVehicle.getCarFollowModel().getMaxDecel(),
570 MAX2(MIN_FALLBEHIND, (myVehicle.getSpeed() - targetSpeed) / remainingSeconds));
571 const double nextSpeed = MIN2(plannedSpeed, MAX2(0.0, myVehicle.getSpeed() - ACCEL2SPEED(decel)));
572#ifdef DEBUG_INFORMER
573 if (DEBUG_COND) {
574 std::cout << SIMTIME
575 << " cannot overtake leader nv=" << nv->getID()
576 << " dv=" << dv
577 << " myLookAheadSpeed=" << myLookAheadSpeed
578 << " myLeftSpace=" << myLeftSpace
579 << " overtakeDist=" << overtakeDist
580 << " overtakeTime=" << overtakeTime
581 << " remainingSeconds=" << remainingSeconds
582 << " currentGap=" << neighLead.second
583 << " brakeGap=" << myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed(), getCarFollowModel().getMaxDecel(), 0.)
584 << " neighNextSpeed=" << neighNextSpeed
585 << " neighNextGap=" << neighNextGap
586 << " targetSpeed=" << targetSpeed
587 << " nextSpeed=" << nextSpeed
588 << "\n";
589 }
590#endif
591 addLCSpeedAdvice(nextSpeed);
592 return nextSpeed;
593 } else {
594 // leader is fast enough anyway
595#ifdef DEBUG_INFORMER
596 if (DEBUG_COND) {
597 std::cout << SIMTIME
598 << " cannot overtake fast leader nv=" << nv->getID()
599 << " dv=" << dv
600 << " myLookAheadSpeed=" << myLookAheadSpeed
601 << " myLeftSpace=" << myLeftSpace
602 << " overtakeDist=" << overtakeDist
603 << " myLeadingBlockerLength=" << myLeadingBlockerLength
604 << " overtakeTime=" << overtakeTime
605 << " remainingSeconds=" << remainingSeconds
606 << " currentGap=" << neighLead.second
607 << " neighNextSpeed=" << neighNextSpeed
608 << " neighNextGap=" << neighNextGap
609 << " targetSpeed=" << targetSpeed
610 << "\n";
611 }
612#endif
613 addLCSpeedAdvice(targetSpeed);
614 return plannedSpeed;
615 }
616 } else {
617 // overtaking, leader should not accelerate
618#ifdef DEBUG_INFORMER
619 if (DEBUG_COND) {
620 std::cout << SIMTIME
621 << " wants to overtake leader nv=" << nv->getID()
622 << " dv=" << dv
623 << " overtakeDist=" << overtakeDist
624 << " remainingSeconds=" << remainingSeconds
625 << " overtakeTime=" << overtakeTime
626 << " currentGap=" << neighLead.second
627 << " secureGap=" << nv->getCarFollowModel().getSecureGap(nv, &myVehicle, nv->getSpeed(), myVehicle.getSpeed(), myVehicle.getCarFollowModel().getMaxDecel())
628 << "\n";
629 }
630#endif
631 // no need to pass a message if the neighbor is waiting/stuck anyway (but sending it would risk deadlock)
633 msgPass.informNeighLeader(new Info(nv->getSpeed(), dir | LCA_AMBLOCKINGLEADER), &myVehicle);
634 }
635 return -1; // XXX: using -1 is ambiguous for the ballistic update! Currently this is being catched in patchSpeed() (Leo), consider returning INVALID_SPEED, refs. #2577
636 }
637 } else { // (remainUnblocked)
638 // we are not blocked now. make sure we stay far enough from the leader
639 const double targetSpeed = MAX2(
640 myVehicle.getCarFollowModel().minNextSpeed(myVehicle.getSpeed(), &myVehicle),
641 getCarFollowModel().followSpeed(&myVehicle, myVehicle.getSpeed(), neighNextGap, neighNextSpeed, nv->getCarFollowModel().getMaxDecel()));
642 addLCSpeedAdvice(targetSpeed);
643#ifdef DEBUG_INFORMER
644 if (DEBUG_COND) {
645 std::cout << " not blocked by leader nv=" << nv->getID()
646 << " nvSpeed=" << nv->getSpeed()
647 << " gap=" << neighLead.second
648 << " neighNextSpeed=" << neighNextSpeed
649 << " neighNextGap=" << neighNextGap
650 << " needGap=" << myVehicle.getCarFollowModel().getSecureGap(&myVehicle, nv, myVehicle.getSpeed(), nv->getSpeed(), nv->getCarFollowModel().getMaxDecel())
651 << " targetSpeed=" << targetSpeed
652 << "\n";
653 }
654#endif
655 return MIN2(targetSpeed, plannedSpeed);
656 }
657}
658
659void
661 int blocked,
662 int dir,
663 const std::pair<MSVehicle*, double>& neighFollow,
664 double remainingSeconds,
665 double plannedSpeed) {
666
667 MSVehicle* nv = neighFollow.first;
668 const double plannedAccel = SPEED2ACCEL(MAX2(MIN2(getCarFollowModel().getMaxAccel(), plannedSpeed - myVehicle.getSpeed()), -getCarFollowModel().getMaxDecel()));
669
670#ifdef DEBUG_INFORMER
671 if (DEBUG_COND) {
672 std::cout << "\nINFORM_FOLLOWER"
673 << "\nspeed=" << myVehicle.getSpeed() << " planned=" << plannedSpeed << "\n";
674 }
675
676#endif
677 if ((blocked & LCA_BLOCKED_BY_FOLLOWER) != 0 && nv != nullptr) {
679 //std::cout << SIMTIME << " ego=" << myVehicle.getID() << " ignoresDivergentBlockingFollower=" << nv->getID() << "\n";
680 return;
681 }
682#ifdef DEBUG_INFORMER
683 if (DEBUG_COND) {
684 std::cout << " blocked by follower nv=" << nv->getID() << " nvSpeed=" << nv->getSpeed() << " needGap="
685 << nv->getCarFollowModel().getSecureGap(nv, &myVehicle, nv->getSpeed(), myVehicle.getSpeed(), myVehicle.getCarFollowModel().getMaxDecel()) << " planned=" << plannedSpeed << "\n";
686 }
687#endif
688
689 // are we fast enough to cut in without any help?
690 if (MAX2(plannedSpeed, 0.) - nv->getSpeed() >= HELP_OVERTAKE) {
691 const double neededGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, nv->getSpeed(), plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel());
692 if ((neededGap - neighFollow.second) / remainingSeconds < (MAX2(plannedSpeed, 0.) - nv->getSpeed())) {
693#ifdef DEBUG_INFORMER
694 if (DEBUG_COND) {
695 std::cout << " wants to cut in before nv=" << nv->getID() << " without any help." << "\nneededGap = " << neededGap << "\n";
696 }
697#endif
698 // follower might even accelerate but not to much
699 // XXX: I don't understand this. The needed gap was determined for nv->getSpeed(), not for (plannedSpeed - HELP_OVERTAKE)?! (Leo), refs. #2578
700 msgPass.informNeighFollower(new Info(MAX2(plannedSpeed, 0.) - HELP_OVERTAKE, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
701 return;
702 }
703 }
704
705 // decide whether we will request help to cut in before the follower or allow to be overtaken
706
707 // PARAMETERS
708 // assume other vehicle will assume the equivalent of 1 second of
709 // maximum deceleration to help us (will probably be spread over
710 // multiple seconds)
711 // -----------
712 const double helpDecel = nv->getCarFollowModel().getMaxDecel() * HELP_DECEL_FACTOR;
713
714 // follower's new speed in next step
715 double neighNewSpeed;
716 // follower's new speed after 1s.
717 double neighNewSpeed1s;
718 // velocity difference, gap after follower-deceleration
719 double dv, decelGap;
720
722 // euler
723 neighNewSpeed = MAX2(0., nv->getSpeed() - ACCEL2SPEED(helpDecel));
724 neighNewSpeed1s = MAX2(0., nv->getSpeed() - helpDecel); // TODO: consider introduction of a configurable anticipationTime here (see far below in the !blocked part). Refs. #2578
725 // change in the gap between ego and blocker over 1 second (not STEP!)
726 // XXX: though here it is calculated as if it were one step!? (Leo) Refs. #2578
727 dv = plannedSpeed - neighNewSpeed1s; // XXX: what is this quantity (if TS!=1)?
728 // new gap between follower and self in case the follower does brake for 1s
729 // XXX: if the step-length is not 1s., this is not the gap after 1s. deceleration!
730 // And this formula overestimates the real gap. Isn't that problematic? (Leo)
731 // Below, it seems that decelGap > secureGap is taken to indicate the possibility
732 // to cut in within the next time-step. However, this is not the case, if TS<1s.,
733 // since decelGap is (not exactly, though!) the gap after 1s. Refs. #2578
734 decelGap = neighFollow.second + dv;
735 } else {
736 // ballistic
737 // negative newSpeed-extrapolation possible, if stop lies within the next time-step
738 // XXX: this code should work for the euler case as well, since gapExtrapolation() takes
739 // care of this, but for TS!=1 we will have different behavior (see previous remark) Refs. #2578
740 neighNewSpeed = nv->getSpeed() - ACCEL2SPEED(helpDecel);
741 neighNewSpeed1s = nv->getSpeed() - helpDecel;
742
743 dv = myVehicle.getSpeed() - nv->getSpeed(); // current velocity difference
744 decelGap = getCarFollowModel().gapExtrapolation(1., neighFollow.second, myVehicle.getSpeed(),
745 nv->getSpeed(), plannedAccel, -helpDecel, myVehicle.getMaxSpeedOnLane(), nv->getMaxSpeedOnLane());
746 }
747
748 const double secureGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, MAX2(neighNewSpeed1s, 0.),
749 MAX2(plannedSpeed, 0.), myVehicle.getCarFollowModel().getMaxDecel());
750
751 const double onRampThreshold = myVehicle.getLane()->getSpeedLimit() * 0.8 * myExperimentalParam1 * (1 - myVehicle.getImpatience());
752
753#ifdef DEBUG_INFORMER
754 if (DEBUG_COND) {
755 std::cout << SIMTIME
756 << " speed=" << myVehicle.getSpeed()
757 << " plannedSpeed=" << plannedSpeed
758 << " threshold=" << onRampThreshold
759 << " neighNewSpeed=" << neighNewSpeed
760 << " neighNewSpeed1s=" << neighNewSpeed1s
761 << " dv=" << dv
762 << " gap=" << neighFollow.second
763 << " decelGap=" << decelGap
764 << " secureGap=" << secureGap
765 << "\n";
766 }
767#endif
768 // prevent vehicles on an on ramp stopping the main flow
769 if (dir == LCA_MLEFT
770 && myVehicle.getLane()->isAccelLane()
771 && neighNewSpeed1s < onRampThreshold) {
772 return;
773 }
774
775 if (decelGap > 0 && decelGap >= secureGap) {
776 // XXX: This does not assure that the leader can cut in in the next step if TS < 1 (see above)
777 // this seems to be supposed in the following (euler code)...?! (Leo) Refs. #2578
778
779 // if the blocking follower brakes it could help
780 // how hard does it actually need to be?
781 // to be safe in the next step the following equation has to hold for the follower's vsafe:
782 // vsafe <= followSpeed(gap=currentGap - SPEED2DIST(vsafe), ...)
783 double vsafe, vsafe1;
784
786 // euler
787 // we compute an upper bound on vsafe by doing the computation twice
788 vsafe1 = MAX2(neighNewSpeed, nv->getCarFollowModel().followSpeed(
789 nv, nv->getSpeed(), neighFollow.second + SPEED2DIST(plannedSpeed), plannedSpeed, getCarFollowModel().getMaxDecel()));
790 vsafe = MAX2(neighNewSpeed, nv->getCarFollowModel().followSpeed(
791 nv, nv->getSpeed(), neighFollow.second + SPEED2DIST(plannedSpeed - vsafe1), plannedSpeed, getCarFollowModel().getMaxDecel()));
792 //assert(vsafe <= vsafe1); assertion does not hold for models with randomness in followSpeed (W99)
793 } else {
794 // ballistic
795
796 // XXX: This block should actually do as well for euler update (TODO: test!), refs #2575
797 // we compute an upper bound on vsafe
798 // next step's gap without help deceleration (nv's speed assumed constant)
799 double nextGap = getCarFollowModel().gapExtrapolation(TS,
800 neighFollow.second, myVehicle.getSpeed(),
801 nv->getSpeed(), plannedAccel, 0,
802 myVehicle.getMaxSpeedOnLane(), nv->getMaxSpeedOnLane());
803#ifdef DEBUG_INFORMER
804 if (DEBUG_COND) {
805 std::cout << "nextGap=" << nextGap << " (without help decel) \n";
806 }
807#endif
808
809 // NOTE: the second argument of MIN2() can get larger than nv->getSpeed()
810 vsafe1 = MIN2(nv->getSpeed(), MAX2(neighNewSpeed,
812 nv->getSpeed(), nextGap,
813 MAX2(0., plannedSpeed),
814 getCarFollowModel().getMaxDecel())));
815
816
817 // next step's gap with possibly less than maximal help deceleration (in case vsafe1 > neighNewSpeed)
818 double decel2 = SPEED2ACCEL(nv->getSpeed() - vsafe1);
820 neighFollow.second, myVehicle.getSpeed(),
821 nv->getSpeed(), plannedAccel, -decel2,
822 myVehicle.getMaxSpeedOnLane(), nv->getMaxSpeedOnLane());
823
824 // vsafe = MAX(neighNewSpeed, safe speed assuming next_gap)
825 // Thus, the gap resulting from vsafe is larger or equal to next_gap
826 // in contrast to the euler case, where nv's follow speed doesn't depend on the actual speed,
827 // we need to assure, that nv doesn't accelerate
828 vsafe = MIN2(nv->getSpeed(), MAX2(neighNewSpeed,
830 nv->getSpeed(), nextGap,
831 MAX2(0., plannedSpeed),
832 getCarFollowModel().getMaxDecel())));
833
834 assert(vsafe >= vsafe1 - NUMERICAL_EPS);
835
836#ifdef DEBUG_INFORMER
837 if (DEBUG_COND) {
838 std::cout << "nextGap=" << nextGap
839 << " (with vsafe1 and help decel) \nvsafe1=" << vsafe1
840 << " vsafe=" << vsafe
841 << "\n";
842 }
843#endif
844
845 // For subsecond simulation, this might not lead to secure gaps for a long time,
846 // we seek to establish a secure gap as soon as possible
847 double nextSecureGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, vsafe, plannedSpeed, getCarFollowModel().getMaxDecel());
848
849 if (nextGap < nextSecureGap) {
850 // establish a secureGap as soon as possible
851 vsafe = neighNewSpeed;
852 }
853
854#ifdef DEBUG_INFORMER
855 if (DEBUG_COND) {
856 std::cout << "nextGap=" << nextGap
857 << " minNextSecureGap=" << nextSecureGap
858 << " vsafe=" << vsafe << "\n";
859 }
860#endif
861
862 }
863 msgPass.informNeighFollower(
864 new Info(vsafe, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
865
866#ifdef DEBUG_INFORMER
867 if (DEBUG_COND) {
868 std::cout << " wants to cut in before nv=" << nv->getID()
869 << " vsafe1=" << vsafe1 << " vsafe=" << vsafe
870 << " newSecGap="
871 << nv->getCarFollowModel().getSecureGap(nv, &myVehicle, vsafe,
872 plannedSpeed,
873 myVehicle.getCarFollowModel().getMaxDecel())
874 << "\n";
875 }
876#endif
877 } else if ((MSGlobals::gSemiImplicitEulerUpdate && dv > 0 && dv * remainingSeconds > (secureGap - decelGap + POSITION_EPS))
878 || (!MSGlobals::gSemiImplicitEulerUpdate && dv > 0 && dv * (remainingSeconds - 1) > secureGap - decelGap + POSITION_EPS)
879 ) {
880
881 // XXX: Alternative formulation (encapsulating differences of euler and ballistic) TODO: test, refs. #2575
882 // double eventualGap = getCarFollowModel().gapExtrapolation(remainingSeconds - 1., decelGap, plannedSpeed, neighNewSpeed1s);
883 // } else if (eventualGap > secureGap + POSITION_EPS) {
884
885
886 // NOTE: This case corresponds to the situation, where some time is left to perform the lc
887 // For the ballistic case this is interpreted as follows:
888 // If the follower breaks with helpDecel for one second, this vehicle maintains the plannedSpeed,
889 // and both continue with their speeds for remainingSeconds seconds the gap will suffice for a laneChange
890 // For the euler case we had the following comment:
891 // 'decelerating once is sufficient to open up a large enough gap in time', but:
892 // XXX: 1) Decelerating *once* does not necessarily lead to the gap decelGap! (if TS<1s.) (Leo)
893 // 2) Probably, the if() for euler should test for dv * (remainingSeconds-1) > ..., too ?!, refs. #2578
894 msgPass.informNeighFollower(new Info(neighNewSpeed, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
895#ifdef DEBUG_INFORMER
896 if (DEBUG_COND) {
897 std::cout << " wants to cut in before nv=" << nv->getID() << " (eventually)\n";
898 }
899#endif
900 } else if (dir == LCA_MRIGHT && nv->getLaneChangeModel().avoidOvertakeRight(&myVehicle)) {
901 // XXX: check if this requires a special treatment for the ballistic update, refs. #2575
902 const double vhelp = MAX2(neighNewSpeed, HELP_OVERTAKE);
903 msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
904#ifdef DEBUG_INFORMER
905 if (DEBUG_COND) {
906 std::cout << " wants to cut in before nv=" << nv->getID() << " (nv cannot overtake right)\n";
907 }
908#endif
909 } else {
910 double vhelp = MAX2(nv->getSpeed(), myVehicle.getSpeed() + HELP_OVERTAKE);
911 //if (dir == LCA_MRIGHT && myVehicle.getWaitingSeconds() > LCA_RIGHT_IMPATIENCE &&
912 // nv->getSpeed() > myVehicle.getSpeed()) {
913 if (nv->getSpeed() > myVehicle.getSpeed() &&
914 ((dir == LCA_MRIGHT && myVehicle.getWaitingSeconds() > LCA_RIGHT_IMPATIENCE) // NOTE: it might be considered to use myVehicle.getAccumulatedWaitingSeconds() > LCA_RIGHT_IMPATIENCE instead (Leo). Refs. #2578
915 || (dir == LCA_MLEFT && plannedSpeed > CUT_IN_LEFT_SPEED_THRESHOLD) // VARIANT_22 (slowDownLeft)
916 // XXX this is a hack to determine whether the vehicles is on an on-ramp. This information should be retrieved from the network itself
917 || (dir == LCA_MLEFT && myVehicle.getLane()->getLength() > MAX_ONRAMP_LENGTH)
918 )) {
919 // let the follower slow down to increase the likelihood that later vehicles will be slow enough to help
920 // follower should still be fast enough to open a gap
921 // XXX: The probability for that success would be larger if the slow down of the appropriate following vehicle
922 // would take place without the immediate follower slowing down. We might consider to model reactions of
923 // vehicles that are not immediate followers. (Leo) -> see ticket #2532
924 vhelp = MAX2(neighNewSpeed, myVehicle.getSpeed() + HELP_OVERTAKE);
925#ifdef DEBUG_INFORMER
926 if (DEBUG_COND) {
927 // NOTE: the condition labeled "VARIANT_22" seems to imply that this could as well concern the *left* follower?! (Leo)
928 // Further, vhelp might be larger than nv->getSpeed(), so the request issued below is not to slow down!? (see below) Refs. #2578
929 std::cout << " wants right follower to slow down a bit\n";
930 }
931#endif
933 // euler
934 if ((nv->getSpeed() - myVehicle.getSpeed()) / helpDecel < remainingSeconds) {
935
936#ifdef DEBUG_INFORMER
937 if (DEBUG_COND) {
938 // NOTE: the condition labeled "VARIANT_22" seems to imply that this could as well concern the *left* follower?! Refs. #2578
939 std::cout << " wants to cut in before right follower nv=" << nv->getID() << " (eventually)\n";
940 }
941#endif
942 // XXX: I don't understand. This vhelp might be larger than nv->getSpeed() but the above condition seems to rely
943 // on the reasoning that if nv breaks with helpDecel for remaining Seconds, nv will be so slow, that this
944 // vehicle will be able to cut in. But nv might have overtaken this vehicle already (or am I missing sth?). (Leo)
945 // Ad: To my impression, the intention behind allowing larger speeds for the blocking follower is to prevent a
946 // situation, where an overlapping follower keeps blocking the ego vehicle. Refs. #2578
947 msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
948 return;
949 }
950 } else {
951
952 // ballistic (this block is a bit different to the logic in the euler part, but in general suited to work on euler as well.. must be tested <- TODO, refs. #2575)
953 // estimate gap after remainingSeconds.
954 // Assumptions:
955 // (A1) leader continues with currentSpeed. (XXX: That might be wrong: Think of accelerating on an on-ramp or of a congested region ahead!)
956 // (A2) follower breaks with helpDecel.
957 const double gapAfterRemainingSecs = getCarFollowModel().gapExtrapolation(
958 remainingSeconds, neighFollow.second, myVehicle.getSpeed(), nv->getSpeed(), 0, -helpDecel, myVehicle.getMaxSpeedOnLane(), nv->getMaxSpeedOnLane());
959 const double secureGapAfterRemainingSecs = nv->getCarFollowModel().getSecureGap(nv, &myVehicle,
960 MAX2(nv->getSpeed() - remainingSeconds * helpDecel, 0.), myVehicle.getSpeed(), myVehicle.getCarFollowModel().getMaxDecel());
961 if (gapAfterRemainingSecs >= secureGapAfterRemainingSecs) { // XXX: here it would be wise to check whether there is enough space for eventual braking if the maneuver doesn't succeed
962#ifdef DEBUG_INFORMER
963 if (DEBUG_COND) {
964 std::cout << " wants to cut in before follower nv=" << nv->getID() << " (eventually)\n";
965 }
966#endif
967 // NOTE: ballistic uses neighNewSpeed instead of vhelp, see my note above. (Leo)
968 // TODO: recheck if this might cause suboptimal behaviour in some LC-situations. Refs. #2578
969 msgPass.informNeighFollower(new Info(neighNewSpeed, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
970 return;
971 }
972 }
973
974
975 }
976
977#ifdef DEBUG_INFORMER
978 if (DEBUG_COND) {
979 std::cout << SIMTIME
980 << " veh=" << myVehicle.getID()
981 << " informs follower " << nv->getID()
982 << " vhelp=" << vhelp
983 << "\n";
984 }
985#endif
986
987 msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
988 // This follower is supposed to overtake us. Slow down smoothly to allow this.
989 const double overtakeDist = overtakeDistance(nv, &myVehicle, neighFollow.second, vhelp, plannedSpeed);
990 // speed difference to create a sufficiently large gap
991 const double needDV = overtakeDist / remainingSeconds;
992 // make sure the deceleration is not to strong (XXX: should be assured in finalizeSpeed -> TODO: remove the MAX2 if agreed) -> prob with possibly non-existing maximal deceleration for som CF Models(?) Refs. #2578
993 addLCSpeedAdvice(MAX2(vhelp - needDV, myVehicle.getSpeed() - ACCEL2SPEED(myVehicle.getCarFollowModel().getMaxDecel())));
994
995#ifdef DEBUG_INFORMER
996 if (DEBUG_COND) {
997 std::cout << SIMTIME
998 << " veh=" << myVehicle.getID()
999 << " wants to be overtaken by=" << nv->getID()
1000 << " overtakeDist=" << overtakeDist
1001 << " vneigh=" << nv->getSpeed()
1002 << " vhelp=" << vhelp
1003 << " needDV=" << needDV
1004 << " vsafe=" << myLCAccelerationAdvices.back().first
1005 << "\n";
1006 }
1007#endif
1008 }
1009 } else if (neighFollow.first != nullptr && (blocked & LCA_BLOCKED_BY_LEADER)) {
1010 // we are not blocked by the follower now, make sure it remains that way
1011 const double vsafe = MSLCHelper::getSpeedPreservingSecureGap(myVehicle, *neighFollow.first, neighFollow.second, plannedSpeed);
1012 msgPass.informNeighFollower(new Info(vsafe, dir), &myVehicle);
1013
1014#ifdef DEBUG_INFORMER
1015 if (DEBUG_COND) {
1016 std::cout << " wants to cut in before non-blocking follower nv=" << nv->getID() << "\n";
1017 }
1018#endif
1019 }
1020}
1021
1022
1023void
1026 // keep information about strategic change direction
1027 if (!isChangingLanes()) {
1029 }
1031 myLeftSpace = 0;
1033 myDontBrake = false;
1034 // truncate to work around numerical instability between different builds
1035 if (mySigma > 0 && !isChangingLanes()) {
1036 // disturb lateral position directly
1037 const double maxDist = SPEED2DIST(myVehicle.getVehicleType().getMaxSpeedLat());
1038 const double oldPosLat = myVehicle.getLateralPositionOnLane();
1039 const double overlap = myVehicle.getLateralOverlap();
1040 double scaledDelta;
1041 if (overlap > 0) {
1042 // return to within lane boundary
1043 scaledDelta = MIN2(overlap, maxDist);
1044 if (myVehicle.getLateralPositionOnLane() > 0) {
1045 scaledDelta *= -1;
1046 }
1047 } else {
1048 // random drift
1049 double deltaPosLat = OUProcess::step(oldPosLat,
1050 myVehicle.getActionStepLengthSecs(),
1051 MAX2(NUMERICAL_EPS, (1 - mySigma) * 100), mySigma) - oldPosLat;
1052 deltaPosLat = MAX2(MIN2(deltaPosLat, maxDist), -maxDist);
1053 scaledDelta = deltaPosLat * myVehicle.getSpeed() / myVehicle.getLane()->getSpeedLimit();
1054 }
1055 myVehicle.setLateralPositionOnLane(oldPosLat + scaledDelta);
1056 setSpeedLat(DIST2SPEED(scaledDelta));
1057 } else {
1058 resetSpeedLat();
1059 }
1060}
1061
1062
1063void
1065 myOwnState = 0;
1069 if (myVehicle.getBestLaneOffset() == 0) {
1070 // if we are not yet on our best lane there might still be unseen blockers
1071 // (during patchSpeed)
1073 myLeftSpace = 0;
1074 }
1077 myDontBrake = false;
1079}
1080
1081
1082void
1094
1095
1096int
1098 int laneOffset,
1100 int blocked,
1101 const std::pair<MSVehicle*, double>& leader,
1102 const std::pair<MSVehicle*, double>& follower,
1103 const std::pair<MSVehicle*, double>& neighLead,
1104 const std::pair<MSVehicle*, double>& neighFollow,
1105 const MSLane& neighLane,
1106 const std::vector<MSVehicle::LaneQ>& preb,
1107 MSVehicle* lastBlocked,
1108 MSVehicle* firstBlocked) {
1109 assert(laneOffset == 1 || laneOffset == -1);
1110 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
1111 // compute bestLaneOffset
1112 MSVehicle::LaneQ curr, neigh, best;
1113 int bestLaneOffset = 0;
1114 // What do these "dists" mean? Please comment. (Leo) Ad: I now think the following:
1115 // currentDist is the distance that the vehicle can go on its route without having to
1116 // change lanes from the current lane. neighDist as currentDist for the considered target lane (i.e., neigh)
1117 // If this is true I suggest to put this into the docu of wantsChange()
1118 double currentDist = 0;
1119 double neighDist = 0;
1120 int currIdx = 0;
1121 const bool checkOpposite = &neighLane.getEdge() != &myVehicle.getLane()->getEdge();
1122 const MSLane* prebLane = myVehicle.getLane();
1123 if (prebLane->getEdge().isInternal()) {
1124 // internal edges are not kept inside the bestLanes structure
1125 if (isOpposite()) {
1126 prebLane = prebLane->getNormalPredecessorLane();
1127 } else {
1128 prebLane = prebLane->getLinkCont()[0]->getLane();
1129 }
1130 }
1131 // special case: vehicle considers changing to the opposite direction edge
1132 const int prebOffset = laneOffset;
1133 for (int p = 0; p < (int) preb.size(); ++p) {
1134 //if (DEBUG_COND) {
1135 // std::cout << " p=" << p << " prebLane=" << prebLane->getID() << " preb.p=" << preb[p].lane->getID() << "\n";
1136 //}
1137 if (preb[p].lane == prebLane && p + laneOffset >= 0) {
1138 assert(p + prebOffset < (int)preb.size());
1139 curr = preb[p];
1140 neigh = preb[p + prebOffset];
1141 currentDist = curr.length;
1142 neighDist = neigh.length;
1143 bestLaneOffset = curr.bestLaneOffset;
1144 if (bestLaneOffset == 0 && preb[p + prebOffset].bestLaneOffset == 0 && !checkOpposite) {
1145#ifdef DEBUG_WANTS_CHANGE
1146 if (DEBUG_COND) {
1147 std::cout << STEPS2TIME(currentTime)
1148 << " veh=" << myVehicle.getID()
1149 << " bestLaneOffsetOld=" << bestLaneOffset
1150 << " bestLaneOffsetNew=" << laneOffset
1151 << "\n";
1152 }
1153#endif
1154 bestLaneOffset = prebOffset;
1155 }
1156 best = preb[p + bestLaneOffset];
1157 currIdx = p;
1158 break;
1159 }
1160 }
1161 assert(curr.lane != nullptr);
1162 assert(neigh.lane != nullptr);
1163 assert(best.lane != nullptr);
1164 // direction specific constants
1165 const bool right = (laneOffset == -1);
1166 const double posOnLane = getForwardPos();
1167 double driveToNextStop = -std::numeric_limits<double>::max();
1168 if (myVehicle.nextStopDist() < std::numeric_limits<double>::max()
1169 && &myVehicle.getNextStop().lane->getEdge() == &myVehicle.getLane()->getEdge()) {
1170 // vehicle can always drive up to stop distance
1171 // @note this information is dynamic and thus not available in updateBestLanes()
1172 // @note: nextStopDist was compute before the vehicle moved
1173 driveToNextStop = myVehicle.nextStopDist();
1174 const double stopPos = posOnLane + myVehicle.nextStopDist() - myVehicle.getLastStepDist();
1175#ifdef DEBUG_WANTS_CHANGE
1176 if (DEBUG_COND) {
1177 std::cout << SIMTIME << std::setprecision(gPrecision) << " veh=" << myVehicle.getID()
1178 << " stopDist=" << myVehicle.nextStopDist()
1179 << " lastDist=" << myVehicle.getLastStepDist()
1180 << " stopPos=" << stopPos
1181 << " currentDist=" << currentDist
1182 << " neighDist=" << neighDist
1183 << "\n";
1184 }
1185#endif
1186 currentDist = MAX2(currentDist, stopPos);
1187 neighDist = MAX2(neighDist, stopPos);
1188 }
1189 const int lca = (right ? LCA_RIGHT : LCA_LEFT);
1190 const int myLca = (right ? LCA_MRIGHT : LCA_MLEFT);
1191 const int lcaCounter = (right ? LCA_LEFT : LCA_RIGHT);
1192 bool changeToBest = (right && bestLaneOffset < 0) || (!right && bestLaneOffset > 0);
1193 // keep information about being a leader/follower
1194 int ret = (myOwnState & 0xffff0000);
1195 int req = 0; // the request to change or stay
1196
1197 ret = slowDownForBlocked(lastBlocked, ret);
1198 if (lastBlocked != firstBlocked) {
1199 ret = slowDownForBlocked(firstBlocked, ret);
1200 }
1201
1202#ifdef DEBUG_WANTS_CHANGE
1203 if (DEBUG_COND) {
1204 std::cout << SIMTIME
1205 << " veh=" << myVehicle.getID()
1206 << " _wantsChange state=" << myOwnState
1207 << " myLCAccelerationAdvices=" << toString(myLCAccelerationAdvices)
1208 << " firstBlocked=" << Named::getIDSecure(firstBlocked)
1209 << " lastBlocked=" << Named::getIDSecure(lastBlocked)
1210 << " leader=" << Named::getIDSecure(leader.first)
1211 << " leaderGap=" << leader.second
1212 << " follower=" << Named::getIDSecure(follower.first)
1213 << " followerGap=" << follower.second
1214 << " neighLead=" << Named::getIDSecure(neighLead.first)
1215 << " neighLeadGap=" << neighLead.second
1216 << " neighFollow=" << Named::getIDSecure(neighFollow.first)
1217 << " neighFollowGap=" << neighFollow.second
1218 << "\n";
1219 }
1220#endif
1221
1222 // we try to estimate the distance which is necessary to get on a lane
1223 // we have to get on in order to keep our route
1224 // we assume we need something that depends on our velocity
1225 // and compare this with the free space on our wished lane
1226 //
1227 // if the free space is somehow(<-?) less than the space we need, we should
1228 // definitely try to get to the desired lane
1229 //
1230 // this rule forces our vehicle to change the lane if a lane changing is necessary soon
1231
1232
1233 // we do not want the lookahead distance to change all the time so we let it decay slowly
1234 // (in contrast, growth is applied instantaneously)
1235 if (myVehicle.getSpeed() > myLookAheadSpeed) {
1236 myLookAheadSpeed = myVehicle.getSpeed();
1237 } else {
1238 // memory decay factor for this action step
1239 const double memoryFactor = 1. - (1. - LOOK_AHEAD_SPEED_MEMORY) * myVehicle.getActionStepLengthSecs();
1240 assert(memoryFactor > 0.);
1242 (memoryFactor * myLookAheadSpeed + (1 - memoryFactor) * myVehicle.getSpeed()));
1243 }
1244 double laDist = myLookAheadSpeed * LOOK_FORWARD * myStrategicParam * (right ? 1 : myLookaheadLeft);
1245 laDist += myVehicle.getVehicleType().getLengthWithGap() * 2.;
1246 const bool hasStoppedLeader = leader.first != 0 && leader.first->isStopped() && leader.second < (currentDist - posOnLane);
1247 const bool hasBidiLeader = myVehicle.getLane()->getBidiLane() != nullptr && MSLCHelper::isBidiLeader(leader.first, curr.bestContinuations);
1248 const bool hasBidiNeighLeader = neighLane.getBidiLane() != nullptr && MSLCHelper::isBidiLeader(neighLead.first, neigh.bestContinuations);
1249
1250 if (bestLaneOffset == 0 && hasBidiLeader) {
1251 // getting out of the way is enough to clear the blockage
1252 laDist = 0;
1253 } else if (bestLaneOffset == 0 && hasStoppedLeader) {
1254 // react to a stopped leader on the current lane
1255 // The value of laDist is doubled below for the check whether the lc-maneuver can be taken out
1256 // on the remaining distance (because the vehicle has to change back and forth). Therefore multiply with 0.5.
1257 laDist = 0.5 * (myVehicle.getVehicleType().getLengthWithGap()
1258 + leader.first->getVehicleType().getLengthWithGap()
1259 + leader.second);
1260 } else if (bestLaneOffset == laneOffset && neighLead.first != 0 && (neighLead.first->isStopped() || hasBidiNeighLeader) && neighLead.second < (currentDist - posOnLane)) {
1261 // react to a stopped leader on the target lane (if it is the bestLane)
1262 if (isOpposite()) {
1263 // always allow changing back
1264 laDist = (myVehicle.getVehicleType().getLengthWithGap()
1265 + neighLead.first->getVehicleType().getLengthWithGap()
1266 + neighLead.second);
1267 } else if (!hasStoppedLeader &&
1268 ((neighLead.second + myVehicle.getVehicleType().getLengthWithGap() + neighLead.first->getVehicleType().getLengthWithGap()) < (currentDist - posOnLane)
1269 || hasBidiNeighLeader)) {
1270 // do not change to the target lane until passing the stopped vehicle
1271 // (unless the vehicle blocks our intended stopping position, then we have to wait anyway)
1272 changeToBest = false;
1273 }
1274 }
1275 if (myStrategicParam < 0) {
1276 laDist = -1e3; // never perform strategic change
1277 }
1278
1279 // free space that is available for changing
1280 //const double neighSpeed = (neighLead.first != 0 ? neighLead.first->getSpeed() :
1281 // neighFollow.first != 0 ? neighFollow.first->getSpeed() :
1282 // best.lane->getSpeedLimit());
1283 // @note: while this lets vehicles change earlier into the correct direction
1284 // it also makes the vehicles more "selfish" and prevents changes which are necessary to help others
1285
1286
1287
1288 // Next we assign to roundabout edges a larger distance than to normal edges
1289 // in order to decrease sense of lc urgency and induce higher usage of inner roundabout lanes.
1290 const double roundaboutBonus = MSLCHelper::getRoundaboutDistBonus(myVehicle, myRoundaboutBonus, curr, neigh, best);
1291 currentDist += roundaboutBonus;
1292 neighDist += roundaboutBonus;
1293
1294 const double usableDist = MAX2(currentDist - posOnLane - best.occupation * JAM_FACTOR, driveToNextStop);
1295 //- (best.lane->getVehicleNumber() * neighSpeed)); // VARIANT 9 jfSpeed
1296 const double maxJam = MAX2(preb[currIdx + prebOffset].occupation, preb[currIdx].occupation);
1297 const double vMax = myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle);
1298 const double neighVMax = neighLane.getVehicleMaxSpeed(&myVehicle);
1299 // upper bound which will be restricted successively
1300 double thisLaneVSafe = vMax;
1301 const bool checkOverTakeRight = avoidOvertakeRight(neighLead.first, true);
1302
1303 double neighLeftPlace = MAX2(0.0, neighDist - posOnLane - maxJam);
1304 if (neighLead.first != 0 && neighLead.first->isStopped()) {
1305 neighLeftPlace = MIN2(neighLeftPlace, neighLead.second);
1306 }
1307
1308#ifdef DEBUG_WANTS_CHANGE
1309 if (DEBUG_COND) {
1310 std::cout << STEPS2TIME(currentTime)
1311 << " veh=" << myVehicle.getID()
1312 << " laSpeed=" << myLookAheadSpeed
1313 << " laDist=" << laDist
1314 << " currentDist=" << currentDist
1315 << " usableDist=" << usableDist
1316 << " bestLaneOffset=" << bestLaneOffset
1317 << " best.occupation=" << best.occupation
1318 << " best.length=" << best.length
1319 << "\n roundaboutBonus=" << roundaboutBonus
1320 << " maxJam=" << maxJam
1321 << " neighDist=" << neighDist
1322 << " neighLeftPlace=" << neighLeftPlace
1323 << (hasBidiLeader ? " bidiLeader" : "")
1324 << (hasBidiNeighLeader ? " bidiNeighLeader" : "")
1325 << "\n";
1326 }
1327#endif
1328
1329 bool changeLeftToAvoidOvertakeRight = false;
1330 if (changeToBest && bestLaneOffset == curr.bestLaneOffset
1331 && currentDistDisallows(usableDist, bestLaneOffset, laDist)) {
1333 ret = ret | lca | LCA_STRATEGIC | LCA_URGENT;
1334 } else {
1335 // VARIANT_20 (noOvertakeRight)
1336 if (neighLead.first != 0 && checkOverTakeRight && !right) {
1337 // check for slower leader on the left. we should not overtake but
1338 // rather move left ourselves (unless congested)
1339 const MSVehicle* nv = neighLead.first;
1340 double deltaV = 0.;
1341 double vSafe = 0.;
1342 if (canOvertakeRight(nv, neighLead.second, vMax - neighLane.getVehicleMaxSpeed(nv), HELP_OVERTAKE, vSafe, deltaV)) {
1344 vSafe = MAX2(vSafe, nv->getSpeed());
1345 }
1346 thisLaneVSafe = MIN2(thisLaneVSafe, vSafe);
1347 addLCSpeedAdvice(vSafe);
1348 // only generate impulse for overtaking left shortly before braking would be necessary
1349 const double deltaGapFuture = deltaV * 8;
1350 const double vSafeFuture = getCarFollowModel().followSpeed(
1351 &myVehicle, myVehicle.getSpeed(), neighLead.second - deltaGapFuture, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
1352 if (vSafeFuture < vSafe) {
1353 const double relativeGain = deltaV / MAX2(vMax,
1355 mySpeedGainProbabilityLeft += (long long int)(myVehicle.getActionStepLengthSecs() * relativeGain * HYST_PRECISION);
1356 changeLeftToAvoidOvertakeRight = true;
1357 }
1358#ifdef DEBUG_WANTS_CHANGE
1359 if (DEBUG_COND) {
1360 std::cout << STEPS2TIME(currentTime)
1361 << " avoid overtaking on the right nv=" << nv->getID()
1362 << " deltaV=" << deltaV
1363 << " nvSpeed=" << nv->getSpeed()
1364 << " speedGainL=" << mySpeedGainProbabilityLeft / HYST_PRECISION
1365 << " speedGainR=" << mySpeedGainProbabilityRight / HYST_PRECISION
1366 << " planned acceleration =" << myLCAccelerationAdvices.back().first
1367 << "\n";
1368 }
1369#endif
1370 }
1371 }
1372 const bool currFreeUntilNeighEnd = leader.first == nullptr || neighDist - posOnLane <= leader.second;
1373 const double overtakeDist = (leader.first == 0 || hasBidiLeader ? -1 :
1374 leader.second + myVehicle.getVehicleType().getLength() + leader.first->getVehicleType().getLengthWithGap());
1375 const double overtakeDist2 = (neighLead.first == 0 || !neighLead.first->isStopped() ? -1 :
1376 neighLead.second + myVehicle.getVehicleType().getLength() + neighLead.first->getVehicleType().getLengthWithGap());
1377 if (leader.first != 0 && (leader.first->isStopped() || hasBidiLeader) && leader.second < REACT_TO_STOPPED_DISTANCE
1378 // current destination leaves enough space to overtake the leader
1379 && MIN2(neighDist, currentDist) - posOnLane > overtakeDist
1380 // maybe do not overtake on the right at high speed
1381 && (!checkOverTakeRight || !right)
1382 && myStrategicParam >= 0
1383 && (neighLead.first == 0 || !neighLead.first->isStopped()
1384 // neighboring stopped vehicle leaves enough space to overtake leader
1385 || neighLead.second > overtakeDist
1386 // if we cannot pass neighLead before reaching leader we must find another free lane
1387 || (overtakeDist2 > leader.second && hasFreeLane(laneOffset, neighLead)))) {
1388 // avoid becoming stuck behind a stopped leader
1389 currentDist = myVehicle.getPositionOnLane() + leader.second;
1390#ifdef DEBUG_WANTS_CHANGE
1391 if (DEBUG_COND) {
1392 std::cout << " veh=" << myVehicle.getID() << " overtake stopped leader=" << leader.first->getID()
1393 << " overtakeDist=" << overtakeDist
1394 << " overtakeDist2=" << overtakeDist
1395 << " hasFreeLane=" << hasFreeLane(laneOffset, neighLead)
1396 << " remaining=" << MIN2(neighDist, currentDist) - posOnLane
1397 << "\n";
1398 }
1399#endif
1400 ret = ret | lca | LCA_STRATEGIC | LCA_URGENT;
1401 } else if (!changeToBest && currentDistDisallows(neighLeftPlace, abs(bestLaneOffset) + 2, laDist) && !hasBidiLeader) {
1402 // the opposite lane-changing direction should be done than the one examined herein
1403 // we'll check whether we assume we could change anyhow and get back in time...
1404 //
1405 // this rule prevents the vehicle from moving in opposite direction of the best lane
1406 // unless the way till the end where the vehicle has to be on the best lane
1407 // is long enough
1408#ifdef DEBUG_WANTS_CHANGE
1409 if (DEBUG_COND) {
1410 std::cout << " veh=" << myVehicle.getID() << " could not change back and forth in time (1) neighLeftPlace=" << neighLeftPlace << "\n";
1411 }
1412#endif
1413 ret = ret | LCA_STAY | LCA_STRATEGIC;
1414 } else if (bestLaneOffset == 0 && (neighLeftPlace * 2. < laDist)) {
1415 // the current lane is the best and a lane-changing would cause a situation
1416 // of which we assume we will not be able to return to the lane we have to be on.
1417 // this rule prevents the vehicle from leaving the current, best lane when it is
1418 // close to this lane's end
1419#ifdef DEBUG_WANTS_CHANGE
1420 if (DEBUG_COND) {
1421 std::cout << " veh=" << myVehicle.getID() << " could not change back and forth in time (2) neighLeftPlace=" << neighLeftPlace << "\n";
1422 }
1423#endif
1424 ret = ret | LCA_STAY | LCA_STRATEGIC;
1425 } else if (bestLaneOffset == 0
1426 && (leader.first == 0 || !leader.first->isStopped())
1427 && !hasBidiLeader
1428 && neigh.bestContinuations.back()->getLinkCont().size() != 0
1429 && roundaboutBonus == 0
1430 && !checkOpposite
1431 && ((myStrategicParam >= 0 && neighDist < TURN_LANE_DIST)
1432 // lane changing cannot possibly help
1433 || (myStrategicParam < 0 && currFreeUntilNeighEnd))
1434 ) {
1435 // VARIANT_21 (stayOnBest)
1436 // we do not want to leave the best lane for a lane which leads elsewhere
1437 // unless our leader is stopped or we are approaching a roundabout
1438#ifdef DEBUG_WANTS_CHANGE
1439 if (DEBUG_COND) {
1440 std::cout << " veh=" << myVehicle.getID() << " does not want to leave the bestLane (neighDist=" << neighDist << ")\n";
1441 }
1442#endif
1443 ret = ret | LCA_STAY | LCA_STRATEGIC;
1444 }
1445 }
1446 // check for overriding TraCI requests
1447#ifdef DEBUG_WANTS_CHANGE
1448 if (DEBUG_COND) {
1449 std::cout << STEPS2TIME(currentTime) << " veh=" << myVehicle.getID() << " ret=" << toString((LaneChangeAction)ret);
1450 }
1451#endif
1452 // store state before canceling
1453 getCanceledState(laneOffset) |= ret | blocked;
1454 ret = myVehicle.influenceChangeDecision(ret);
1455 if ((ret & lcaCounter) != 0) {
1456 // we are not interested in traci requests for the opposite direction here
1457 ret &= ~(LCA_TRACI | lcaCounter | LCA_URGENT);
1458 }
1459#ifdef DEBUG_WANTS_CHANGE
1460 if (DEBUG_COND) {
1461 std::cout << " retAfterInfluence=" << toString((LaneChangeAction)ret) << "\n";
1462 }
1463#endif
1464
1465 if ((ret & LCA_STAY) != 0) {
1466 // remove TraCI flags because it should not be included in "state-without-traci"
1467 ret = getCanceledState(laneOffset);
1468 return ret;
1469 }
1470 if ((ret & LCA_URGENT) != 0) {
1471 // prepare urgent lane change maneuver
1472 // save the left space
1473 myLeftSpace = currentDist - posOnLane;
1474 if (changeToBest && abs(bestLaneOffset) > 1 && myVehicle.getNumRemainingEdges() > 1) {
1475 // there might be a vehicle which needs to counter-lane-change one lane further and we cannot see it yet
1476 myLeadingBlockerLength = MAX2(getExtraReservation(bestLaneOffset, neighDist - currentDist), myLeadingBlockerLength);
1477#ifdef DEBUG_SAVE_BLOCKER_LENGTH
1478 if (DEBUG_COND) {
1479 std::cout << " reserving space for unseen blockers myLeadingBlockerLength=" << myLeadingBlockerLength << "\n";
1480 }
1481#endif
1482 }
1483
1484 // letting vehicles merge in at the end of the lane in case of counter-lane change, step#1
1485 // if there is a leader and he wants to change to the opposite direction
1486 const bool canContinue = curr.bestContinuations.size() > 1;
1487 bool canReserve = MSLCHelper::updateBlockerLength(myVehicle, neighLead.first, lcaCounter, myLeftSpace - POSITION_EPS, canContinue, myLeadingBlockerLength);
1488 if (firstBlocked != neighLead.first) {
1489 canReserve &= MSLCHelper::updateBlockerLength(myVehicle, firstBlocked, lcaCounter, myLeftSpace - POSITION_EPS, canContinue, myLeadingBlockerLength);
1490 }
1491#ifdef DEBUG_SAVE_BLOCKER_LENGTH
1492 if (DEBUG_COND) {
1493 std::cout << SIMTIME << " canReserve=" << canReserve << " canContinue=" << canContinue << "\n";
1494 }
1495#endif
1496 if (!canReserve && !isOpposite()) {
1497 // we have a low-priority relief connection
1498 // std::cout << SIMTIME << " veh=" << myVehicle.getID() << " cannotReserve for blockers\n";
1499 myDontBrake = canContinue;
1500 }
1501
1502 const int remainingLanes = MAX2(1, abs(bestLaneOffset));
1503 const double urgency = isOpposite() ? OPPOSITE_URGENCY : URGENCY;
1504 const double remainingSeconds = ((ret & LCA_TRACI) == 0 ?
1505 //MAX2(STEPS2TIME(TS), (myLeftSpace-myLeadingBlockerLength) / MAX2(myLookAheadSpeed, NUMERICAL_EPS) / remainingLanes / urgency) :
1506 MAX2(STEPS2TIME(TS), myLeftSpace / MAX2(myLookAheadSpeed, NUMERICAL_EPS) / remainingLanes / urgency) :
1507 myVehicle.getInfluencer().changeRequestRemainingSeconds(currentTime));
1508 if (!hasBidiNeighLeader) {
1509 const double plannedSpeed = informLeader(msgPass, blocked, myLca, neighLead, remainingSeconds);
1510 // NOTE: for the ballistic update case negative speeds may indicate a stop request,
1511 // while informLeader returns -1 in that case. Refs. #2577
1512 if (plannedSpeed >= 0 || (!MSGlobals::gSemiImplicitEulerUpdate && plannedSpeed != -1)) {
1513 // maybe we need to deal with a blocking follower
1514 const bool hasBidiNeighFollower = neighLane.getBidiLane() != nullptr && MSLCHelper::isBidiFollower(&myVehicle, neighFollow.first);
1515 if (!hasBidiNeighFollower) {
1516 informFollower(msgPass, blocked, myLca, neighFollow, remainingSeconds, plannedSpeed);
1517 }
1518 }
1519#ifdef DEBUG_WANTS_CHANGE
1520 if (DEBUG_COND) {
1521 std::cout << STEPS2TIME(currentTime)
1522 << " veh=" << myVehicle.getID()
1523 << " myLeftSpace=" << myLeftSpace
1524 << " remainingSeconds=" << remainingSeconds
1525 << " plannedSpeed=" << plannedSpeed
1526 << "\n";
1527 }
1528#endif
1529 } else {
1530#ifdef DEBUG_WANTS_CHANGE
1531 if (DEBUG_COND) {
1532 std::cout << STEPS2TIME(currentTime)
1533 << " veh=" << myVehicle.getID()
1534 << " myLeftSpace=" << myLeftSpace
1535 << " remainingSeconds=" << remainingSeconds
1536 << " hasBidiNeighLeader\n";
1537 }
1538#endif
1539 }
1540
1541
1542 // remove TraCI flags because it should not be included in "state-without-traci"
1543 ret = getCanceledState(laneOffset);
1544 return ret;
1545 }
1546
1547 // we wish to anticipate future speeds. This is difficult when the leading
1548 // vehicles are still accelerating so we resort to comparing speeds for the near future (1s) in this case
1549 const bool acceleratingLeader = (neighLead.first != 0 && neighLead.first->getAcceleration() > 0)
1550 || (leader.first != 0 && leader.first->getAcceleration() > 0);
1551 double neighLaneVSafe = MIN2(neighVMax, anticipateFollowSpeed(neighLead, neighDist, neighVMax, acceleratingLeader));
1552 thisLaneVSafe = MIN2(thisLaneVSafe, anticipateFollowSpeed(leader, currentDist, vMax, acceleratingLeader));
1553 //std::cout << SIMTIME << " veh=" << myVehicle.getID() << " thisLaneVSafe=" << thisLaneVSafe << " neighLaneVSafe=" << neighLaneVSafe << "\n";
1554
1555
1556 // a high inconvenience prevents cooperative changes and the following things are inconvenient:
1557 // - a desire to change in the opposite direction for speedGain
1558 // - low anticipated speed on the neighboring lane
1559 // - high occupancy on the neighboring lane while in a roundabout
1560
1561 double inconvenience = laneOffset < 0
1564
1565 const double relSpeedDiff = thisLaneVSafe == 0 ? 0 : (thisLaneVSafe - neighLaneVSafe) / MAX2(thisLaneVSafe, neighLaneVSafe);
1566 inconvenience = MAX2(relSpeedDiff, inconvenience);
1567 inconvenience = MIN2(1.0, inconvenience);
1568
1569 const bool speedGainInconvenient = inconvenience > myCooperativeParam;
1570 const bool neighOccupancyInconvenient = neigh.lane->getBruttoOccupancy() > curr.lane->getBruttoOccupancy();
1571#ifdef DEBUG_WANTS_CHANGE
1572 if (DEBUG_COND) {
1573 std::cout << STEPS2TIME(currentTime)
1574 << " veh=" << myVehicle.getID()
1575 << " speedGainL=" << mySpeedGainProbabilityLeft / HYST_PRECISION
1576 << " speedGainR=" << mySpeedGainProbabilityRight / HYST_PRECISION
1577 << " neighSpeedFactor=" << (thisLaneVSafe / neighLaneVSafe - 1)
1578 << " inconvenience=" << inconvenience
1579 << " speedInconv=" << speedGainInconvenient
1580 << " occInconv=" << neighOccupancyInconvenient
1581 << "\n";
1582 }
1583#endif
1584
1585 // VARIANT_15
1586 if (roundaboutBonus > 0) {
1587
1588#ifdef DEBUG_WANTS_CHANGE
1589 if (DEBUG_COND) {
1590 std::cout << STEPS2TIME(currentTime)
1591 << " veh=" << myVehicle.getID()
1592 << " roundaboutBonus=" << roundaboutBonus
1593 << " myLeftSpace=" << myLeftSpace
1594 << "\n";
1595 }
1596#endif
1597 // try to use the inner lanes of a roundabout to increase throughput
1598 // unless we are approaching the exit
1599 if (lca == LCA_LEFT) {
1600 // if inconvenience is not too high, request collaborative change (currently only for ballistic update)
1601 // TODO: test this for euler update! Refs. #2575
1602 if (MSGlobals::gSemiImplicitEulerUpdate || !neighOccupancyInconvenient) {
1603// if(MSGlobals::gSemiImplicitEulerUpdate || !speedGainInconvenient){
1604 req = ret | lca | LCA_COOPERATIVE;
1605 }
1606 } else {
1607 // if inconvenience is not too high, request collaborative change (currently only for ballistic update)
1608 if (MSGlobals::gSemiImplicitEulerUpdate || neighOccupancyInconvenient) {
1609// if(MSGlobals::gSemiImplicitEulerUpdate || speedGainInconvenient){
1610 req = ret | LCA_STAY | LCA_COOPERATIVE;
1611 }
1612 }
1613 if (!cancelRequest(req, laneOffset)) {
1614 return ret | req;
1615 }
1616 }
1617
1618 // let's also regard the case where the vehicle is driving on a highway...
1619 // in this case, we do not want to get to the dead-end of an on-ramp
1620 if (right) {
1621 if (bestLaneOffset == 0 && myVehicle.getLane()->getSpeedLimit() > 80. / 3.6 && myLookAheadSpeed > SUMO_const_haltingSpeed) {
1622#ifdef DEBUG_WANTS_CHANGE
1623 if (DEBUG_COND) {
1624 std::cout << " veh=" << myVehicle.getID() << " does not want to get stranded on the on-ramp of a highway\n";
1625 }
1626#endif
1627 req = ret | LCA_STAY | LCA_STRATEGIC;
1628 if (!cancelRequest(req, laneOffset)) {
1629 return ret | req;
1630 }
1631 }
1632 }
1633 // --------
1634
1635 // -------- make place on current lane if blocking follower
1636 //if (amBlockingFollowerPlusNB()) {
1637 // std::cout << myVehicle.getID() << ", " << currentDistAllows(neighDist, bestLaneOffset, laDist)
1638 // << " neighDist=" << neighDist
1639 // << " currentDist=" << currentDist
1640 // << "\n";
1641 //}
1642
1644 && (!speedGainInconvenient)
1645 && ((myOwnState & myLca) != 0) // VARIANT_6 : counterNoHelp
1646 && (changeToBest || currentDistAllows(neighDist, abs(bestLaneOffset) + 1, laDist))) {
1647
1648 // VARIANT_2 (nbWhenChangingToHelp)
1649#ifdef DEBUG_COOPERATE
1650 if (DEBUG_COND) {
1651 std::cout << STEPS2TIME(currentTime)
1652 << " veh=" << myVehicle.getID()
1653 << " wantsChangeToHelp=" << (right ? "right" : "left")
1654 << " state=" << myOwnState
1655 << (((myOwnState & myLca) == 0) ? " (counter)" : "")
1656 << "\n";
1657 }
1658#endif
1659 req = ret | lca | LCA_COOPERATIVE | LCA_URGENT ;//| LCA_CHANGE_TO_HELP;
1660 if (!cancelRequest(req, laneOffset)) {
1661 if ((blocked & LCA_BLOCKED_BY_LEFT_FOLLOWER) && !right && mySpeedGainProbabilityLeft > (long long int)(mySpeedGainUrgency * HYST_PRECISION)) {
1662 MSVehicle* nv = neighFollow.first;
1663 const bool hasBidiNeighFollower = neighLane.getBidiLane() != nullptr && MSLCHelper::isBidiFollower(&myVehicle, nv);
1664 if (nv != nullptr && !hasBidiNeighFollower) {
1665 const double helpSpeed = MAX2(nv->getCarFollowModel().minNextSpeed(nv->getSpeed(), nv), myVehicle.getSpeed() - 1);
1666 msgPass.informNeighFollower(new Info(helpSpeed, myLca | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
1667 }
1668 }
1669 return ret | req;
1670 }
1671 }
1672
1673 // --------
1674
1675
1678 //if ((blocked & LCA_BLOCKED) != 0) {
1679 // return ret;
1680 //}
1682
1683 // -------- higher speed
1684 //if ((congested(neighLead.first) && neighLead.second < 20) || predInteraction(leader.first)) { //!!!
1685 // return ret;
1686 //}
1687
1688 if (neighLane.getEdge().getPersons().size() > 0) {
1689 // react to pedestrians
1690 adaptSpeedToPedestrians(myVehicle.getLane(), thisLaneVSafe);
1691 adaptSpeedToPedestrians(&neighLane, neighLaneVSafe);
1692 }
1693
1694 const double relativeGain = (neighLaneVSafe - thisLaneVSafe) / MAX2(neighLaneVSafe,
1696
1697#ifdef DEBUG_WANTS_CHANGE
1698 if (DEBUG_COND) {
1699 std::cout << STEPS2TIME(currentTime)
1700 << " veh=" << myVehicle.getID()
1701 << " currentDist=" << currentDist
1702 << " neighDist=" << neighDist
1703 << " thisVSafe=" << thisLaneVSafe
1704 << " neighVSafe=" << neighLaneVSafe
1705 << " relGain=" << toString(relativeGain, 8)
1706 << "\n";
1707 }
1708#endif
1709
1710 if (right) {
1711 // ONLY FOR CHANGING TO THE RIGHT
1712 if (thisLaneVSafe - 5 / 3.6 > neighLaneVSafe) {
1713 // ok, the current lane is faster than the right one...
1714 mySpeedGainProbabilityRight = (long long int)((double)mySpeedGainProbabilityRight * pow(0.5, myVehicle.getActionStepLengthSecs()));
1715 //myKeepRightProbability /= 2.0;
1716 } else {
1717 // ok, the current lane is not (much) faster than the right one
1718 mySpeedGainProbabilityRight += (long long int)(myVehicle.getActionStepLengthSecs() * relativeGain * HYST_PRECISION);
1719
1720 // honor the obligation to keep right (Rechtsfahrgebot)
1721 const double roadSpeedFactor = vMax / myVehicle.getLane()->getSpeedLimit(); // differse from speedFactor if vMax < speedLimit
1722 double acceptanceTime;
1723 if (myKeepRightAcceptanceTime == -1) {
1724 // legacy behavior: scale acceptance time with current speed and
1725 // use old hard-coded constant
1726 acceptanceTime = 7 * roadSpeedFactor * MAX2(1.0, myVehicle.getSpeed());
1727 } else {
1728 acceptanceTime = myKeepRightAcceptanceTime * roadSpeedFactor;
1729 if (follower.first != nullptr && follower.second < 2 * follower.first->getCarFollowModel().brakeGap(follower.first->getSpeed())) {
1730 // reduce acceptanceTime if the follower vehicle is faster or wants to drive faster
1731 if (follower.first->getSpeed() >= myVehicle.getSpeed()) {
1732 acceptanceTime *= MAX2(1.0, myVehicle.getSpeed()) / MAX2(1.0, follower.first->getSpeed());
1733 const double fRSF = follower.first->getLane()->getVehicleMaxSpeed(follower.first) / follower.first->getLane()->getSpeedLimit();
1734 if (fRSF > roadSpeedFactor) {
1735 acceptanceTime /= fRSF;
1736 }
1737 }
1738 }
1739 }
1740 double fullSpeedGap = MAX2(0., neighDist - myVehicle.getCarFollowModel().brakeGap(vMax));
1741 double fullSpeedDrivingSeconds = MIN2(acceptanceTime, fullSpeedGap / vMax);
1742 if (neighLead.first != 0 && neighLead.first->getSpeed() < vMax) {
1743 fullSpeedGap = MAX2(0., MIN2(fullSpeedGap,
1744 neighLead.second - myVehicle.getCarFollowModel().getSecureGap(&myVehicle, neighLead.first,
1745 vMax, neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel())));
1746 fullSpeedDrivingSeconds = MIN2(fullSpeedDrivingSeconds, fullSpeedGap / (vMax - neighLead.first->getSpeed()));
1747 }
1748 // stay on the current lane if we cannot overtake a slow leader on the right
1749 if (checkOverTakeRight && leader.first != 0
1750 && leader.first->getLane()->getVehicleMaxSpeed(leader.first) < vMax) {
1751 fullSpeedGap = MIN2(fullSpeedGap, leader.second);
1752 fullSpeedDrivingSeconds = MIN2(fullSpeedDrivingSeconds, fullSpeedGap / (vMax - leader.first->getSpeed()));
1753 }
1754
1755 const double deltaProb = (myChangeProbThresholdRight == std::numeric_limits<long long int>::max()) ? 0 :
1756 ((double)myChangeProbThresholdRight * (fullSpeedDrivingSeconds / acceptanceTime) / KEEP_RIGHT_TIME);
1757 myKeepRightProbability -= (long long int)(myVehicle.getActionStepLengthSecs() * deltaProb);
1758
1759 //std::cout << STEPS2TIME(currentTime)
1760 // << " veh=" << myVehicle.getID()
1761 // << " acceptanceTime=" << acceptanceTime
1762 // << " fullSpeedDrivingSeconds=" << fullSpeedDrivingSeconds
1763 // << " dProb=" << deltaProb
1764 // << " myKeepRightProbability=" << myKeepRightProbability
1765 // << "\n";
1766
1767#ifdef DEBUG_WANTS_CHANGE
1768 if (DEBUG_COND) {
1769 std::cout << STEPS2TIME(currentTime)
1770 << " veh=" << myVehicle.getID()
1771 << " vMax=" << vMax
1772 << " neighDist=" << neighDist
1773 << " brakeGap=" << myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed())
1774 << " leaderSpeed=" << (neighLead.first == 0 ? -1 : neighLead.first->getSpeed())
1775 << " secGap=" << (neighLead.first == 0 ? -1 : myVehicle.getCarFollowModel().getSecureGap(&myVehicle, neighLead.first,
1776 myVehicle.getSpeed(), neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel()))
1777 << " acceptanceTime=" << acceptanceTime
1778 << " fullSpeedGap=" << fullSpeedGap
1779 << " fullSpeedDrivingSeconds=" << fullSpeedDrivingSeconds
1780 << " dProb=" << deltaProb / HYST_PRECISION
1781 << " myKeepRightProbability=" << myKeepRightProbability / HYST_PRECISION
1782 << "\n";
1783 }
1784#endif
1785 if ((long long int)((double)myKeepRightProbability * myKeepRightParam) < -myChangeProbThresholdRight) {
1786 req = ret | lca | LCA_KEEPRIGHT;
1787 if (!cancelRequest(req, laneOffset)) {
1788 return ret | req;
1789 }
1790 }
1791 }
1792
1793#ifdef DEBUG_WANTS_CHANGE
1794 if (DEBUG_COND) {
1795 std::cout << STEPS2TIME(currentTime)
1796 << " veh=" << myVehicle.getID()
1797 << " speed=" << myVehicle.getSpeed()
1798 << " speedGainL=" << mySpeedGainProbabilityLeft / HYST_PRECISION
1799 << " speedGainR=" << mySpeedGainProbabilityRight / HYST_PRECISION
1800 << " thisLaneVSafe=" << thisLaneVSafe
1801 << " neighLaneVSafe=" << neighLaneVSafe
1802 << " relativeGain=" << relativeGain
1803 << " blocked=" << blocked
1804 << "\n";
1805 }
1806#endif
1807
1809 && neighDist / MAX2(.1, myVehicle.getSpeed()) > mySpeedGainRemainTime) { //./MAX2( .1, myVehicle.getSpeed())) { // -.1
1810 req = ret | lca | LCA_SPEEDGAIN;
1812 req |= LCA_URGENT;
1813 }
1814 if (!cancelRequest(req, laneOffset)) {
1815 return ret | req;
1816 }
1817 }
1818 } else {
1819 // ONLY FOR CHANGING TO THE LEFT
1820 if (thisLaneVSafe > neighLaneVSafe) {
1821 // this lane is better
1822 mySpeedGainProbabilityLeft = (long long int)((double)mySpeedGainProbabilityLeft * pow(0.5, myVehicle.getActionStepLengthSecs()));
1823 } else if (thisLaneVSafe == neighLaneVSafe) {
1824 mySpeedGainProbabilityLeft = (long long int)((double)mySpeedGainProbabilityLeft * pow(0.8, myVehicle.getActionStepLengthSecs()));
1825 } else {
1826 mySpeedGainProbabilityLeft += (long long int)(myVehicle.getActionStepLengthSecs() * relativeGain * HYST_PRECISION);
1827 }
1828 // VARIANT_19 (stayRight)
1829 //if (neighFollow.first != 0) {
1830 // MSVehicle* nv = neighFollow.first;
1831 // const double secGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, nv->getSpeed(), myVehicle.getSpeed(), myVehicle.getCarFollowModel().getMaxDecel());
1832 // if (neighFollow.second < secGap * KEEP_RIGHT_HEADWAY) {
1833 // // do not change left if it would inconvenience faster followers
1834 // return ret | LCA_STAY | LCA_SPEEDGAIN;
1835 // }
1836 //}
1837
1838#ifdef DEBUG_WANTS_CHANGE
1839 if (DEBUG_COND) {
1840 std::cout << STEPS2TIME(currentTime)
1841 << " veh=" << myVehicle.getID()
1842 << " speed=" << myVehicle.getSpeed()
1843 << " speedGainL=" << mySpeedGainProbabilityLeft / HYST_PRECISION
1844 << " speedGainR=" << mySpeedGainProbabilityRight / HYST_PRECISION
1845 << " thisLaneVSafe=" << thisLaneVSafe
1846 << " neighLaneVSafe=" << neighLaneVSafe
1847 << " relativeGain=" << relativeGain
1848 << " blocked=" << blocked
1849 << "\n";
1850 }
1851#endif
1852
1854 && (relativeGain > NUMERICAL_EPS || changeLeftToAvoidOvertakeRight)
1855 && neighDist / MAX2(.1, myVehicle.getSpeed()) > mySpeedGainRemainTime) { // .1
1856 req = ret | lca | LCA_SPEEDGAIN;
1858 req |= LCA_URGENT;
1859 }
1860 if (!cancelRequest(req, laneOffset)) {
1861 if ((req & LCA_URGENT) && (blocked & LCA_BLOCKED_BY_LEFT_FOLLOWER)) {
1862 MSVehicle* nv = neighFollow.first;
1863 const bool hasBidiNeighFollower = neighLane.getBidiLane() != nullptr && MSLCHelper::isBidiFollower(&myVehicle, nv);
1864 if (nv != nullptr && !hasBidiNeighFollower) {
1865 const double helpSpeed = MAX2(nv->getCarFollowModel().minNextSpeed(nv->getSpeed(), nv), myVehicle.getSpeed() - 1);
1866 msgPass.informNeighFollower(new Info(helpSpeed, myLca | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
1867 }
1868 }
1869 return ret | req;
1870 }
1871 }
1872 }
1873 // --------
1874 if (changeToBest && bestLaneOffset == curr.bestLaneOffset
1875 && myStrategicParam >= 0
1876 && relativeGain >= 0
1878 // change towards the correct lane, speedwise it does not hurt
1879 req = ret | lca | LCA_STRATEGIC;
1880 if (!cancelRequest(req, laneOffset)) {
1881 return ret | req;
1882 }
1883 }
1884#ifdef DEBUG_WANTS_CHANGE
1885 if (DEBUG_COND) {
1886 std::cout << STEPS2TIME(currentTime)
1887 << " veh=" << myVehicle.getID()
1888 << " speedGainL=" << mySpeedGainProbabilityLeft / HYST_PRECISION
1889 << " speedGainR=" << mySpeedGainProbabilityRight / HYST_PRECISION
1890 << " myKeepRightProbability=" << myKeepRightProbability / HYST_PRECISION
1891 << " thisLaneVSafe=" << thisLaneVSafe
1892 << " neighLaneVSafe=" << neighLaneVSafe
1893 << "\n";
1894 }
1895#endif
1896
1897 return ret;
1898}
1899
1900
1901double
1902MSLCM_LC2013::anticipateFollowSpeed(const std::pair<MSVehicle*, double>& leaderDist, double dist, double vMax, bool acceleratingLeader) {
1903 const MSVehicle* leader = leaderDist.first;
1904 const double gap = leaderDist.second;
1905 double futureSpeed;
1906 if (acceleratingLeader) {
1907 // XXX see #6562
1908 const double maxSpeed1s = (myVehicle.getSpeed() + myVehicle.getCarFollowModel().getMaxAccel()
1909 - ACCEL2SPEED(myVehicle.getCarFollowModel().getMaxAccel()));
1910 if (leader == nullptr) {
1911 if (hasBlueLight()) {
1912 // can continue from any lane if necessary
1913 futureSpeed = vMax;
1914 } else {
1915 futureSpeed = getCarFollowModel().followSpeed(&myVehicle, maxSpeed1s, dist, 0, 0);
1916 }
1917 } else {
1918 futureSpeed = getCarFollowModel().followSpeed(&myVehicle, maxSpeed1s, gap, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
1919 }
1920 } else {
1921 // onInsertion = true because the vehicle has already moved
1922 if (leader == nullptr) {
1923 if (hasBlueLight()) {
1924 // can continue from any lane if necessary
1925 futureSpeed = vMax;
1926 } else {
1927 futureSpeed = getCarFollowModel().maximumSafeStopSpeed(dist, getCarFollowModel().getMaxDecel(), myVehicle.getSpeed(), true);
1928 }
1929 } else {
1930 futureSpeed = getCarFollowModel().maximumSafeFollowSpeed(gap, myVehicle.getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel(), true);
1931 }
1932 }
1933 futureSpeed = MIN2(vMax, futureSpeed);
1934 if (leader != nullptr && gap > 0 && mySpeedGainLookahead > 0) {
1935 const double futureLeaderSpeed = acceleratingLeader ? leader->getLane()->getVehicleMaxSpeed(leader) : leader->getSpeed();
1936 const double deltaV = vMax - futureLeaderSpeed;
1937 if (deltaV > 0 && gap > 0) {
1938 const double secGap = getCarFollowModel().getSecureGap(&myVehicle, leader, futureSpeed, leader->getSpeed(), getCarFollowModel().getMaxDecel());
1939 const double fullSpeedGap = gap - secGap;
1940 if (fullSpeedGap / deltaV < mySpeedGainLookahead) {
1941 // anticipate future braking by computing the average
1942 // speed over the next few seconds
1943 const double gapClosingTime = MAX2(0.0, fullSpeedGap / deltaV);
1944 const double foreCastTime = mySpeedGainLookahead * 2;
1945 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " leader=" << leader->getID() << " gap=" << gap << " deltaV=" << deltaV << " futureSpeed=" << futureSpeed << " futureLeaderSpeed=" << futureLeaderSpeed;
1946 futureSpeed = MIN2(futureSpeed, (gapClosingTime * futureSpeed + (foreCastTime - gapClosingTime) * futureLeaderSpeed) / foreCastTime);
1947 //if (DEBUG_COND) std::cout << " newFutureSpeed=" << futureSpeed << "\n";
1948 }
1949 }
1950 }
1951 return futureSpeed;
1952}
1953
1954
1955int
1957 // if this vehicle is blocking someone in front, we maybe decelerate to let him in
1958 if (blocked != nullptr) {
1959 double gap = blocked->getPositionOnLane() - blocked->getVehicleType().getLength() - myVehicle.getPositionOnLane() - myVehicle.getVehicleType().getMinGap();
1960#ifdef DEBUG_SLOW_DOWN
1961 if (DEBUG_COND) {
1962 std::cout << SIMTIME
1963 << " veh=" << myVehicle.getID()
1964 << " blocked=" << Named::getIDSecure(blocked)
1965 << " gap=" << gap
1966 << "\n";
1967 }
1968#endif
1969 if (gap > POSITION_EPS) {
1970 //const bool blockedWantsUrgentRight = (((*blocked)->getLaneChangeModel().getOwnState() & LCA_RIGHT != 0)
1971 // && ((*blocked)->getLaneChangeModel().getOwnState() & LCA_URGENT != 0));
1972
1973 if (myVehicle.getSpeed() < myVehicle.getCarFollowModel().getMaxDecel()
1974 //|| blockedWantsUrgentRight // VARIANT_10 (helpblockedRight)
1975 ) {
1976 if (blocked->getSpeed() < SUMO_const_haltingSpeed) {
1978 } else {
1979 state |= LCA_AMBACKBLOCKER;
1980 }
1981 addLCSpeedAdvice(getCarFollowModel().followSpeed(
1982 &myVehicle, myVehicle.getSpeed(),
1983 gap - POSITION_EPS, blocked->getSpeed(),
1984 blocked->getCarFollowModel().getMaxDecel()), false);
1985
1986 //(*blocked) = 0; // VARIANT_14 (furtherBlock)
1987#ifdef DEBUG_SLOW_DOWN
1988 if (DEBUG_COND) {
1989 std::cout << SIMTIME
1990 << " veh=" << myVehicle.getID()
1991 << " slowing down for"
1992 << " blocked=" << Named::getIDSecure(blocked)
1993 << " helpSpeed=" << myLCAccelerationAdvices.back().first
1994 << "\n";
1995 }
1996#endif
1997 } /*else if ((*blocked)->getWaitingSeconds() > 30 && gap > myVehicle.getBrakeGap()) {
1998 // experimental else-branch...
1999
2000 state |= LCA_AMBACKBLOCKER;
2001 addLCSpeedAdvice(getCarFollowModel().followSpeed(
2002 &myVehicle, myVehicle.getSpeed(),
2003 (gap - POSITION_EPS), (*blocked)->getSpeed(),
2004 (*blocked)->getCarFollowModel().getMaxDecel()));
2005 } */
2006 }
2007 }
2008 return state;
2009}
2010
2011
2012void
2014 if (lane->hasPedestrians()) {
2015#ifdef DEBUG_WANTS_CHANGE
2016 if (DEBUG_COND) {
2017 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << "\n";
2018 }
2019#endif
2020 PersonDist leader = lane->nextBlocking(myVehicle.getPositionOnLane(),
2021 myVehicle.getRightSideOnLane(), myVehicle.getRightSideOnLane() + myVehicle.getVehicleType().getWidth(),
2022 ceil(myVehicle.getSpeed() / myVehicle.getCarFollowModel().getMaxDecel()));
2023 if (leader.first != 0) {
2024 const double stopSpeed = myVehicle.getCarFollowModel().stopSpeed(&myVehicle, myVehicle.getSpeed(), leader.second - myVehicle.getVehicleType().getMinGap());
2025 v = MIN2(v, stopSpeed);
2026#ifdef DEBUG_WANTS_CHANGE
2027 if (DEBUG_COND) {
2028 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2029 }
2030#endif
2031 }
2032 }
2033}
2034
2035
2036double
2037MSLCM_LC2013::computeSpeedLat(double latDist, double& maneuverDist, bool urgent) const {
2038 double result = MSAbstractLaneChangeModel::computeSpeedLat(latDist, maneuverDist, urgent);
2039#ifdef DEBUG_WANTS_CHANGE
2040 if (DEBUG_COND) {
2041 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " myLeftSpace=" << myLeftSpace << " latDist=" << latDist << " maneuverDist=" << maneuverDist << " result=" << result << "\n";
2042 }
2043#endif
2044 if (myLeftSpace > POSITION_EPS || !urgent) {
2045 double speedBound = myMaxSpeedLatStanding + myMaxSpeedLatFactor * myVehicle.getSpeed();
2046 if (isChangingLanes()) {
2047 speedBound = MAX2(LC_RESOLUTION_SPEED_LAT, speedBound);
2048 }
2049 result = MAX2(-speedBound, MIN2(speedBound, result));
2050 }
2051 return result;
2052}
2053
2054
2055double
2057 return 1 / myAssertive;
2058}
2059
2060double
2062 return myOppositeParam <= 0 ? std::numeric_limits<double>::max() : 1 / myOppositeParam;
2063}
2064
2065bool
2066MSLCM_LC2013::saveBlockerLength(double length, double foeLeftSpace) {
2067 const bool canReserve = MSLCHelper::canSaveBlockerLength(myVehicle, length, myLeftSpace);
2068 if (!isOpposite() && (canReserve || myLeftSpace > foeLeftSpace)) {
2070#ifdef DEBUG_SAVE_BLOCKER_LENGTH
2071 if (DEBUG_COND) {
2072 std::cout << SIMTIME << " saveBlockerLength veh=" << myVehicle.getID() << " canReserve=" << canReserve << " myLeftSpace=" << myLeftSpace << " foeLeftSpace=" << foeLeftSpace << "\n";
2073 }
2074#endif
2075 if (myLeftSpace == 0 && foeLeftSpace < 0) {
2076 // called from opposite overtaking, myLeftSpace must be initialized
2077 myLeftSpace = myVehicle.getBestLanes()[myVehicle.getLane()->getIndex()].length - myVehicle.getPositionOnLane();
2078 }
2079 return true;
2080 } else {
2081 return false;
2082 }
2083}
2084
2085
2086bool
2087MSLCM_LC2013::hasFreeLane(int laneOffset, const std::pair<MSVehicle*, double>& neighLeadStopped) const {
2088 if (neighLeadStopped.first == nullptr) {
2089 return true;
2090 }
2091 int dir = (laneOffset > 0 ? 1 : -1);
2092 const MSLane* neigh = myVehicle.getLane()->getParallelLane(laneOffset);
2093 if (dir > 0 && !neigh->allowsChangingLeft(myVehicle.getVClass())) {
2094 return false;
2095 } else if (dir < 0 && !neigh->allowsChangingRight(myVehicle.getVClass())) {
2096 return false;
2097 }
2098 int nextOffset = laneOffset + dir;
2099 const MSLane* next = myVehicle.getLane()->getParallelLane(nextOffset);
2100 if (next == nullptr || !next->allowsVehicleClass(myVehicle.getVClass())) {
2101 return false;
2102 }
2103 const double overtakeDist = neighLeadStopped.second + neighLeadStopped.first->getVehicleType().getLengthWithGap() + myVehicle.getLength() + POSITION_EPS;
2104 std::pair<MSVehicle* const, double> nextLead = next->getLeader(&myVehicle, myVehicle.getPositionOnLane(), myVehicle.getBestLanesContinuation(next), overtakeDist);
2105 return nextLead.first == nullptr || nextLead.second >= overtakeDist || hasFreeLane(nextOffset, nextLead);
2106}
2107
2108
2109std::string
2110MSLCM_LC2013::getParameter(const std::string& key) const {
2112 return toString(myStrategicParam);
2113 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
2115 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
2116 return toString(mySpeedGainParam);
2117 } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
2118 return toString(myKeepRightParam);
2119 } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
2120 return toString(myOppositeParam);
2121 } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
2122 return toString(myLookaheadLeft);
2123 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
2124 return toString(mySpeedGainRight);
2125 } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
2126 return toString(myAssertive);
2127 } else if (key == toString(SUMO_ATTR_LCA_OVERTAKE_RIGHT)) {
2129 } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
2130 return toString(mySigma);
2135 } else if (key == toString(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD)) {
2137 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
2139 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME)) {
2143 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
2145 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
2147 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
2149 } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
2151 // access to internal state for debugging in sumo-gui (not documented since it may change at any time)
2152 } else if (key == "speedGainProbabilityRight") {
2154 } else if (key == "speedGainProbabilityLeft") {
2156 } else if (key == "keepRightProbability") {
2158 } else if (key == "lookAheadSpeed") {
2159 return toString(myLookAheadSpeed);
2160 // motivation relative to threshold
2161 } else if (key == "speedGainRP") {
2163 } else if (key == "speedGainLP") {
2165 } else if (key == "keepRightP") {
2167 }
2168 throw InvalidArgument("Parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
2169}
2170
2171
2172void
2173MSLCM_LC2013::setParameter(const std::string& key, const std::string& value) {
2174 double doubleValue;
2175 try {
2176 doubleValue = StringUtils::toDouble(value);
2177 } catch (NumberFormatException&) {
2178 throw InvalidArgument("Setting parameter '" + key + "' requires a number for laneChangeModel of type '" + toString(myModel) + "'");
2179 }
2181 myStrategicParam = doubleValue;
2182 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
2183 myCooperativeParam = doubleValue;
2184 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
2185 mySpeedGainParam = doubleValue;
2186 } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
2187 myKeepRightParam = doubleValue;
2188 } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
2189 myOppositeParam = doubleValue;
2190 } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
2191 myLookaheadLeft = doubleValue;
2192 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
2193 mySpeedGainRight = doubleValue;
2194 } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
2195 myAssertive = doubleValue;
2196 } else if (key == toString(SUMO_ATTR_LCA_OVERTAKE_RIGHT)) {
2197 myOvertakeRightParam = doubleValue;
2198 } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
2199 mySigma = doubleValue;
2201 myKeepRightAcceptanceTime = doubleValue;
2203 myOvertakeDeltaSpeedFactor = doubleValue;
2204 } else if (key == toString(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD)) {
2205 myStrategicLookahead = doubleValue;
2206 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
2207 mySpeedGainLookahead = doubleValue;
2208 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME)) {
2209 mySpeedGainRemainTime = doubleValue;
2211 myRoundaboutBonus = doubleValue;
2212 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
2213 myCooperativeSpeed = doubleValue;
2214 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
2215 myMaxSpeedLatStanding = doubleValue;
2216 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
2217 myMaxSpeedLatFactor = doubleValue;
2218 } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
2219 myMaxDistLatStanding = doubleValue;
2220 // access to internal state
2221 } else if (key == "speedGainProbabilityRight") {
2222 mySpeedGainProbabilityRight = (long long int)(doubleValue * HYST_PRECISION);
2223 } else if (key == "speedGainProbabilityLeft") {
2224 mySpeedGainProbabilityLeft = (long long int)(doubleValue * HYST_PRECISION);
2225 } else if (key == "keepRightProbability") {
2226 myKeepRightProbability = (long long int)(-doubleValue * HYST_PRECISION);
2227 } else if (key == "lookAheadSpeed") {
2228 myLookAheadSpeed = doubleValue;
2229 } else {
2230 throw InvalidArgument("Setting parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
2231 }
2233}
2234
2235
2236void
2239 std::vector<long long int> lcState;
2240 lcState.push_back(mySpeedGainProbabilityLeft);
2241 lcState.push_back(mySpeedGainProbabilityRight);