Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSLCM_LC2013.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Friedemann Wesner
18 : /// @author Sascha Krieg
19 : /// @author Michael Behrisch
20 : /// @author Laura Bieker
21 : /// @author Leonhard Luecken
22 : /// @date Fri, 08.10.2013
23 : ///
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>
30 : #include <utils/common/RandHelper.h>
31 : #include <utils/common/StringUtils.h>
32 : #include <microsim/transportables/MSPModel.h>
33 : #include <microsim/transportables/MSTransportableControl.h>
34 : #include <microsim/MSEdge.h>
35 : #include <microsim/MSLane.h>
36 : #include <microsim/MSLink.h>
37 : #include <microsim/MSDriverState.h>
38 : #include <microsim/MSNet.h>
39 : #include <microsim/MSStop.h>
40 : #include "MSLCHelper.h"
41 : #include "MSLCM_LC2013.h"
42 :
43 :
44 : // ===========================================================================
45 : // variable definitions
46 : // ===========================================================================
47 : #define MAGIC_OFFSET 1.
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 : // ===========================================================================
79 : // debug defines
80 : // ===========================================================================
81 : //#define DEBUG_CONSTRUCTOR
82 : //#define DEBUG_PATCH_SPEED
83 : //#define DEBUG_INFORMED
84 : //#define DEBUG_INFORMER
85 : //#define DEBUG_WANTS_CHANGE
86 : //#define DEBUG_SLOW_DOWN
87 : //#define DEBUG_COOPERATE
88 : //#define DEBUG_SAVE_BLOCKER_LENGTH
89 :
90 : //#define DEBUG_COND (myVehicle.getID() == "disabled")
91 : #define DEBUG_COND (myVehicle.isSelected())
92 : //#define DEBUG_COND (false)
93 :
94 : // ===========================================================================
95 : // member method definitions
96 : // ===========================================================================
97 3588371 : MSLCM_LC2013::MSLCM_LC2013(MSVehicle& v) :
98 : MSAbstractLaneChangeModel(v, LaneChangeModel::LC2013),
99 3588371 : mySpeedGainProbability(0),
100 3588371 : myKeepRightProbability(0),
101 3588371 : myLeadingBlockerLength(0),
102 3588371 : myLeftSpace(0),
103 3588371 : myLookAheadSpeed(LOOK_AHEAD_MIN_SPEED),
104 3588371 : myStrategicParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_STRATEGIC_PARAM, 1)),
105 3588371 : myCooperativeParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_PARAM, 1)),
106 3588371 : mySpeedGainParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAIN_PARAM, 1)),
107 3588371 : myKeepRightParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_KEEPRIGHT_PARAM, 1)),
108 3588371 : myOppositeParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_OPPOSITE_PARAM, 1)),
109 3588371 : myLookaheadLeft(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_LOOKAHEADLEFT, 2.0)),
110 3588371 : mySpeedGainRight(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAINRIGHT, 0.1)),
111 3588371 : myAssertive(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_ASSERTIVE, 1)),
112 3588371 : mySpeedGainLookahead(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD, 0)),
113 3588371 : myRoundaboutBonus(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT, myCooperativeParam)),
114 3588371 : myCooperativeSpeed(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_SPEED, myCooperativeParam)),
115 3588371 : myKeepRightAcceptanceTime(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME, -1)),
116 3588371 : myOvertakeDeltaSpeedFactor(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR, 0)),
117 7176742 : myExperimentalParam1(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_EXPERIMENTAL1, 0)) {
118 3588371 : initDerivedParameters();
119 : #ifdef DEBUG_CONSTRUCTOR
120 : if (DEBUG_COND) {
121 : std::cout << SIMTIME
122 : << " create lcModel veh=" << myVehicle.getID()
123 : << " lcStrategic=" << myStrategicParam
124 : << " lcCooperative=" << myCooperativeParam
125 : << " lcSpeedGain=" << mySpeedGainParam
126 : << " lcKeepRight=" << myKeepRightParam
127 : << "\n";
128 : }
129 : #endif
130 3588371 : }
131 :
132 7176606 : MSLCM_LC2013::~MSLCM_LC2013() {
133 3588303 : changed();
134 7176606 : }
135 :
136 :
137 : void
138 3593803 : MSLCM_LC2013::initDerivedParameters() {
139 3593803 : if (mySpeedGainParam <= 0) {
140 7096 : myChangeProbThresholdRight = std::numeric_limits<double>::max();
141 7096 : myChangeProbThresholdLeft = std::numeric_limits<double>::max();
142 : } else {
143 3586707 : myChangeProbThresholdRight = (0.2 / mySpeedGainRight) / mySpeedGainParam;
144 3586707 : myChangeProbThresholdLeft = 0.2 / mySpeedGainParam;
145 : }
146 3593803 : }
147 :
148 :
149 : bool
150 3267 : MSLCM_LC2013::debugVehicle() const {
151 3267 : return DEBUG_COND;
152 : }
153 :
154 :
155 : int
156 185824726 : MSLCM_LC2013::wantsChange(
157 : int laneOffset,
158 : MSAbstractLaneChangeModel::MSLCMessager& msgPass,
159 : int blocked,
160 : const std::pair<MSVehicle*, double>& leader,
161 : const std::pair<MSVehicle*, double>& follower,
162 : const std::pair<MSVehicle*, double>& neighLead,
163 : const std::pair<MSVehicle*, double>& neighFollow,
164 : const MSLane& neighLane,
165 : const std::vector<MSVehicle::LaneQ>& preb,
166 : MSVehicle** lastBlocked,
167 : MSVehicle** firstBlocked) {
168 :
169 : #ifdef DEBUG_WANTS_CHANGE
170 : if (DEBUG_COND) {
171 : std::cout << "\nWANTS_CHANGE\n" << SIMTIME
172 : << std::setprecision(gPrecision)
173 : << " veh=" << myVehicle.getID()
174 : << " lane=" << myVehicle.getLane()->getID()
175 : << " pos=" << myVehicle.getPositionOnLane()
176 : << " posLat=" << myVehicle.getLateralPositionOnLane()
177 : << " speed=" << myVehicle.getSpeed()
178 : << " considerChangeTo=" << (laneOffset == -1 ? "right" : "left")
179 : << "\n";
180 : }
181 : #endif
182 :
183 185824726 : const int result = _wantsChange(laneOffset, msgPass, blocked, leader, follower, neighLead, neighFollow, neighLane, preb, lastBlocked, firstBlocked);
184 :
185 : #ifdef DEBUG_WANTS_CHANGE
186 : if (DEBUG_COND) {
187 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " result=" << toString((LaneChangeAction)result) << " blocked=" << toString((LaneChangeAction)blocked) << "\n\n\n";
188 : }
189 : #endif
190 :
191 185824726 : return result;
192 : }
193 :
194 :
195 : double
196 471469415 : MSLCM_LC2013::patchSpeed(const double min, const double wanted, const double max, const MSCFModel& cfModel) {
197 :
198 : #ifdef DEBUG_PATCH_SPEED
199 : if (DEBUG_COND) {
200 : std::cout << "\nPATCH_SPEED\n"
201 : << SIMTIME
202 : << " veh=" << myVehicle.getID()
203 : << " lane=" << myVehicle.getLane()->getID()
204 : << " pos=" << myVehicle.getPositionOnLane()
205 : << " v=" << myVehicle.getSpeed()
206 : << " min=" << min
207 : << " wanted=" << wanted
208 : << " max=" << max
209 : << "\n";
210 : }
211 : #endif
212 :
213 : // negative min speed may be passed when using ballistic updated
214 471469415 : const double newSpeed = _patchSpeed(MAX2(min, 0.0), wanted, max, cfModel);
215 :
216 : #ifdef DEBUG_PATCH_SPEED
217 : if (DEBUG_COND) {
218 : const std::string patched = (wanted != newSpeed ? " patched=" + toString(newSpeed) : "");
219 : std::cout << patched
220 : << "\n";
221 : }
222 : #endif
223 :
224 471469415 : return newSpeed;
225 : }
226 :
227 :
228 : double
229 471469415 : MSLCM_LC2013::_patchSpeed(double min, const double wanted, double max, const MSCFModel& cfModel) {
230 471469415 : int state = myOwnState;
231 : #ifdef DEBUG_PATCH_SPEED
232 : if (DEBUG_COND) {
233 : std::cout
234 : << "\n" << SIMTIME << std::setprecision(gPrecision)
235 : << " patchSpeed state=" << toString((LaneChangeAction)state) << " myLCAccelerationAdvices=" << toString(myLCAccelerationAdvices)
236 : << "\n speed=" << myVehicle.getSpeed() << " min=" << min << " wanted=" << wanted
237 : << "\n myLeadingBlockerLength=" << myLeadingBlockerLength
238 : << "\n";
239 : }
240 : #endif
241 :
242 : // letting vehicles merge in at the end of the lane in case of counter-lane change, step#2
243 : double nVSafe = wanted;
244 : bool gotOne = false;
245 : // if we want to change and have a blocking leader and there is enough room for him in front of us
246 471469415 : if (myLeadingBlockerLength != 0) {
247 584177 : double space = myLeftSpace - myLeadingBlockerLength - MAGIC_OFFSET - myVehicle.getVehicleType().getMinGap();
248 : #ifdef DEBUG_PATCH_SPEED
249 : if (DEBUG_COND) {
250 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " myLeftSpace=" << myLeftSpace << " myLeadingBlockerLength=" << myLeadingBlockerLength << " space=" << space << "\n";
251 : }
252 : #endif
253 584177 : if (space > 0) { // XXX space > -MAGIC_OFFSET
254 : // compute speed for decelerating towards a place which allows the blocking leader to merge in in front
255 418338 : const double vMinEmergency = myVehicle.getCarFollowModel().minNextSpeedEmergency(myVehicle.getSpeed(), &myVehicle);
256 418338 : double safe = cfModel.stopSpeed(&myVehicle, myVehicle.getSpeed(), space, MSCFModel::CalcReason::LANE_CHANGE);
257 : max = MIN2(max, MAX2(safe, vMinEmergency));
258 : // if we are approaching this place
259 418338 : if (safe < wanted) {
260 : // return this speed as the speed to use
261 45435 : if (safe < min) {
262 8479 : if (safe >= vMinEmergency) {
263 : // permit harder braking if needed and helpful
264 : min = MAX2(vMinEmergency, safe);
265 : }
266 : }
267 : #ifdef DEBUG_PATCH_SPEED
268 : if (DEBUG_COND) {
269 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " slowing down for leading blocker, safe=" << safe << (safe + NUMERICAL_EPS < min ? " (not enough)" : "") << "\n";
270 : }
271 : #endif
272 : nVSafe = MAX2(min, safe);
273 : gotOne = true;
274 : }
275 : }
276 : }
277 :
278 471469415 : const double coopWeight = MAX2(0.0, MIN2(1.0, myCooperativeSpeed));
279 492320761 : for (auto i : myLCAccelerationAdvices) {
280 : double a = i.first;
281 20851346 : double v = myVehicle.getSpeed() + ACCEL2SPEED(a);
282 :
283 20851346 : if (v >= min && v <= max && (MSGlobals::gSemiImplicitEulerUpdate
284 : // ballistic update: (negative speeds may appear, e.g. min<0, v<0), BUT:
285 : // XXX: LaneChanging returns -1 to indicate no restrictions, which leads to probs here (Leo), refs. #2577
286 : // As a quick fix, we just dismiss cases where v=-1
287 : // VERY rarely (whenever a requested help-acceleration is really indicated by v=-1)
288 : // this can lead to failing lane-change attempts, though)
289 271346 : || v != -1)) {
290 5613026 : if (i.second) {
291 : // own advice, no scaling needed
292 : nVSafe = MIN2(v, nVSafe);
293 : } else {
294 2963381 : nVSafe = MIN2(v * coopWeight + (1 - coopWeight) * wanted, nVSafe);
295 : }
296 : gotOne = true;
297 : #ifdef DEBUG_PATCH_SPEED
298 : if (DEBUG_COND) {
299 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " got nVSafe=" << nVSafe << " isOwn: " << i.second << " rawV=" << v << "\n";
300 : }
301 : #endif
302 : } else {
303 : if (v < min) {
304 : #ifdef DEBUG_PATCH_SPEED
305 : if (DEBUG_COND) {
306 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " ignoring low nVSafe=" << v << " min=" << min << "\n";
307 : }
308 : #endif
309 : } else {
310 : #ifdef DEBUG_PATCH_SPEED
311 : if (DEBUG_COND) {
312 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " ignoring high nVSafe=" << v << " max=" << max << "\n";
313 : }
314 : #endif
315 : }
316 : }
317 : }
318 : // myDontBrake is used in counter-lane-change situations with relief connection
319 471469415 : if (gotOne && !myDontBrake) {
320 : #ifdef DEBUG_PATCH_SPEED
321 : if (DEBUG_COND) {
322 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " got vSafe\n";
323 : }
324 : #endif
325 : return nVSafe;
326 : }
327 :
328 : // check whether the vehicle is blocked
329 466722561 : if ((state & LCA_WANTS_LANECHANGE) != 0 && (state & LCA_BLOCKED) != 0) {
330 11107813 : if ((state & LCA_STRATEGIC) != 0) {
331 : // necessary decelerations are controlled via vSafe. If there are
332 : // none it means we should speed up
333 : #ifdef DEBUG_PATCH_SPEED
334 : if (DEBUG_COND) {
335 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_WANTS_LANECHANGE (strat, no vSafe)\n";
336 : }
337 : #endif
338 2648113 : return (max + wanted) / 2.0;
339 8459700 : } else if ((state & LCA_COOPERATIVE) != 0) {
340 : // only minor adjustments in speed should be done
341 772876 : if ((state & LCA_BLOCKED_BY_LEADER) != 0) {
342 : #ifdef DEBUG_PATCH_SPEED
343 : if (DEBUG_COND) {
344 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_BLOCKED_BY_LEADER (coop)\n";
345 : }
346 : #endif
347 596969 : if (wanted >= 0.) {
348 596969 : return (MAX2(0., min) + wanted) / 2.0;
349 : } else {
350 : return wanted;
351 : }
352 : }
353 175907 : if ((state & LCA_BLOCKED_BY_FOLLOWER) != 0) {
354 : #ifdef DEBUG_PATCH_SPEED
355 : if (DEBUG_COND) {
356 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_BLOCKED_BY_FOLLOWER (coop)\n";
357 : }
358 : #endif
359 175907 : return (max + wanted) / 2.0;
360 : }
361 : //} else { // VARIANT_16
362 : // // only accelerations should be performed
363 : // if ((state & LCA_BLOCKED_BY_FOLLOWER) != 0) {
364 : // if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_BLOCKED_BY_FOLLOWER\n";
365 : // return (max + wanted) / 2.0;
366 : // }
367 : }
368 : }
369 :
370 : /*
371 : // decelerate if being a blocking follower
372 : // (and does not have to change lanes)
373 : if ((state & LCA_AMBLOCKINGFOLLOWER) != 0) {
374 : if (fabs(max - myVehicle.getCarFollowModel().maxNextSpeed(myVehicle.getSpeed(), &myVehicle)) < 0.001 && min == 0) { // !!! was standing
375 : if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGFOLLOWER (standing)\n";
376 : return 0;
377 : }
378 : if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGFOLLOWER\n";
379 :
380 : //return min; // VARIANT_3 (brakeStrong)
381 : return (min + wanted) / 2.0;
382 : }
383 : if ((state & LCA_AMBACKBLOCKER) != 0) {
384 : if (max <= myVehicle.getCarFollowModel().maxNextSpeed(myVehicle.getSpeed(), &myVehicle) && min == 0) { // !!! was standing
385 : if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBACKBLOCKER (standing)\n";
386 : //return min; VARIANT_9 (backBlockVSafe)
387 : return nVSafe;
388 : }
389 : }
390 : if ((state & LCA_AMBACKBLOCKER_STANDING) != 0) {
391 : if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBACKBLOCKER_STANDING\n";
392 : //return min;
393 : return nVSafe;
394 : }
395 : */
396 :
397 : // accelerate if being a blocking leader or blocking follower not able to brake
398 : // (and does not have to change lanes)
399 463301572 : if ((state & LCA_AMBLOCKINGLEADER) != 0 && myCooperativeSpeed >= 0) {
400 : #ifdef DEBUG_PATCH_SPEED
401 : if (DEBUG_COND) {
402 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGLEADER\n";
403 : }
404 : #endif
405 1317756 : return (max + wanted) / 2.0;
406 : }
407 :
408 : if ((state & LCA_AMBLOCKINGFOLLOWER_DONTBRAKE) != 0) {
409 : #ifdef DEBUG_PATCH_SPEED
410 : if (DEBUG_COND) {
411 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGFOLLOWER_DONTBRAKE\n";
412 : }
413 : #endif
414 : /*
415 : // VARIANT_4 (dontbrake)
416 : if (max <= myVehicle.getCarFollowModel().maxNextSpeed(myVehicle.getSpeed(), &myVehicle) && min == 0) { // !!! was standing
417 : return wanted;
418 : }
419 : return (min + wanted) / 2.0;
420 : */
421 : }
422 461983816 : if (!myVehicle.getLane()->getEdge().hasLaneChanger()) {
423 : // remove chaning information if on a road with a single lane
424 278900677 : changed();
425 : }
426 : return wanted;
427 : }
428 :
429 :
430 : void*
431 4802134 : MSLCM_LC2013::inform(void* info, MSVehicle* sender) {
432 : UNUSED_PARAMETER(sender);
433 : Info* pinfo = (Info*)info;
434 : assert(pinfo->first >= 0 || !MSGlobals::gSemiImplicitEulerUpdate);
435 4802134 : addLCSpeedAdvice(pinfo->first, false);
436 4802134 : myOwnState |= pinfo->second;
437 : #ifdef DEBUG_INFORMED
438 : if (DEBUG_COND) {
439 : std::cout << SIMTIME
440 : << " veh=" << myVehicle.getID()
441 : << " informedBy=" << sender->getID()
442 : << " info=" << pinfo->second
443 : << " vSafe=" << pinfo->first
444 : << "\n";
445 : }
446 : #endif
447 4802134 : delete pinfo;
448 4802134 : return (void*) true;
449 : }
450 :
451 : double
452 3929423 : MSLCM_LC2013::overtakeDistance(const MSVehicle* follower, const MSVehicle* leader, const double gap, double followerSpeed, double leaderSpeed) {
453 3929423 : followerSpeed = followerSpeed == INVALID_SPEED ? follower->getSpeed() : followerSpeed;
454 3929423 : leaderSpeed = leaderSpeed == INVALID_SPEED ? leader->getSpeed() : leaderSpeed;
455 : double overtakeDist = (gap // drive to back of leader
456 3929423 : + leader->getVehicleType().getLengthWithGap() // drive to front of leader
457 3929423 : + follower->getVehicleType().getLength() // follower back reaches leader front
458 3929423 : + leader->getCarFollowModel().getSecureGap( // save gap to leader
459 3929423 : leader, follower, leaderSpeed, followerSpeed, follower->getCarFollowModel().getMaxDecel()));
460 3929423 : return MAX2(overtakeDist, 0.);
461 : }
462 :
463 :
464 : double
465 4072251 : MSLCM_LC2013::informLeader(MSAbstractLaneChangeModel::MSLCMessager& msgPass,
466 : int blocked,
467 : int dir,
468 : const std::pair<MSVehicle*, double>& neighLead,
469 : double remainingSeconds) {
470 4072251 : double plannedSpeed = myVehicle.getSpeed();
471 4072251 : if (!isOpposite()) {
472 3974993 : plannedSpeed = MIN2(plannedSpeed,
473 3974993 : myVehicle.getCarFollowModel().stopSpeed(&myVehicle, myVehicle.getSpeed(), myLeftSpace - myLeadingBlockerLength));
474 : }
475 4729061 : for (auto i : myLCAccelerationAdvices) {
476 : const double a = i.first;
477 656810 : if (a >= -myVehicle.getCarFollowModel().getMaxDecel()) {
478 656786 : plannedSpeed = MIN2(plannedSpeed, myVehicle.getSpeed() + ACCEL2SPEED(a));
479 : }
480 : }
481 : #ifdef DEBUG_INFORMER
482 : if (DEBUG_COND) {
483 : std::cout << "\nINFORM_LEADER"
484 : << "\nspeed=" << myVehicle.getSpeed() << " planned=" << plannedSpeed << "\n";
485 : }
486 : #endif
487 :
488 4072251 : const MSVehicle* const nv = neighLead.first;
489 4072251 : if (nv == nullptr) {
490 : // not overtaking
491 : return plannedSpeed;
492 : }
493 3850482 : const double neighNextSpeed = nv->getSpeed() - ACCEL2SPEED(MAX2(1.0, -nv->getAcceleration()));
494 : double neighNextGap;
495 3850482 : if (MSGlobals::gSemiImplicitEulerUpdate) {
496 3624222 : neighNextGap = neighLead.second + SPEED2DIST(neighNextSpeed - plannedSpeed);
497 : } else {
498 226260 : neighNextGap = neighLead.second + SPEED2DIST((nv->getSpeed() + neighNextSpeed) / 2) - SPEED2DIST((myVehicle.getSpeed() + plannedSpeed) / 2);
499 : }
500 3850482 : if ((blocked & LCA_BLOCKED_BY_LEADER) != 0) {
501 3192828 : if (MSLCHelper::divergentRoute(myVehicle, *nv)) {
502 : //std::cout << SIMTIME << " ego=" << myVehicle.getID() << " ignoresDivergentBlockingLeader=" << nv->getID() << "\n";
503 : return plannedSpeed;
504 : }
505 : #ifdef DEBUG_INFORMER
506 : if (DEBUG_COND) {
507 : std::cout << " blocked by leader nv=" << nv->getID() << " nvSpeed=" << nv->getSpeed() << " needGap="
508 : << myVehicle.getCarFollowModel().getSecureGap(&myVehicle, nv, myVehicle.getSpeed(), nv->getSpeed(), nv->getCarFollowModel().getMaxDecel()) << "\n";
509 : }
510 : #endif
511 : // decide whether we want to overtake the leader or follow it
512 : double overtakeTime;
513 3188544 : const double overtakeDist = overtakeDistance(&myVehicle, nv, neighLead.second);
514 3188544 : const double dv = plannedSpeed - nv->getSpeed();
515 :
516 3188544 : if (dv > myOvertakeDeltaSpeedFactor * myVehicle.getLane()->getSpeedLimit()) {
517 1643918 : overtakeTime = overtakeDist / dv;
518 : } else if (nv->getWaitingSeconds() > BLOCKER_IS_BLOCKED_TIME_THRESHOLD
519 874638 : && !isOpposite()
520 2394845 : && (myVehicle.getVehicleType().getLengthWithGap() + nv->getVehicleType().getLengthWithGap()) <= myLeftSpace) {
521 : // -> set overtakeTime to indicate possibility of overtaking (only if there is enough space)
522 789838 : overtakeTime = remainingSeconds - 1;
523 : } else {
524 : // -> set overtakeTime to something indicating impossibility of overtaking
525 754788 : overtakeTime = remainingSeconds + 1;
526 : }
527 :
528 : #ifdef DEBUG_INFORMER
529 : if (DEBUG_COND) {
530 : std::cout << SIMTIME << " informLeader() of " << myVehicle.getID()
531 : << "\nnv = " << nv->getID()
532 : << "\nplannedSpeed = " << plannedSpeed
533 : << "\nleaderSpeed = " << nv->getSpeed()
534 : << "\nmyLeftSpace = " << myLeftSpace
535 : << "\nremainingSeconds = " << remainingSeconds
536 : << "\novertakeDist = " << overtakeDist
537 : << "\novertakeTime = " << overtakeTime
538 : << std::endl;
539 : }
540 : #endif
541 :
542 3188544 : if ((dv < myOvertakeDeltaSpeedFactor * myVehicle.getLane()->getSpeedLimit()
543 : // overtaking on the right on an uncongested highway is forbidden (noOvertakeLCLeft)
544 2568939 : || (dir == LCA_MLEFT && !myVehicle.congested() && !myAllowOvertakingRight)
545 : // not enough space to overtake?
546 4990393 : || (MSGlobals::gSemiImplicitEulerUpdate && myLeftSpace - myLeadingBlockerLength - myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed()) < overtakeDist)
547 : // 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).
548 2453330 : || (!MSGlobals::gSemiImplicitEulerUpdate && myLeftSpace - myLeadingBlockerLength - myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed(), getCarFollowModel().getMaxDecel(), 0.) < overtakeDist)
549 : // 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)
550 2441020 : || (remainingSeconds < overtakeTime && (MSGlobals::gSemiImplicitEulerUpdate || !nv->isStopped())))
551 : // opposite driving and must overtake
552 3767754 : && (!neighLead.first->isStopped() || (isOpposite() && neighLead.second >= 0))) {
553 : // cannot overtake
554 1196151 : msgPass.informNeighLeader(new Info(std::numeric_limits<double>::max(), dir | LCA_AMBLOCKINGLEADER), &myVehicle);
555 : // slow down smoothly to follow leader
556 : // account for minor decelerations by the leader (dawdling)
557 2392302 : const double targetSpeed = MAX2(
558 1196151 : myVehicle.getCarFollowModel().minNextSpeed(myVehicle.getSpeed(), &myVehicle),
559 1196151 : getCarFollowModel().followSpeed(&myVehicle, myVehicle.getSpeed(), neighNextGap, neighNextSpeed, nv->getCarFollowModel().getMaxDecel()));
560 1196151 : if (targetSpeed < myVehicle.getSpeed()) {
561 : // slow down smoothly to follow leader
562 456618 : const double decel = remainingSeconds == 0. ? myVehicle.getCarFollowModel().getMaxDecel() :
563 456618 : MIN2(myVehicle.getCarFollowModel().getMaxDecel(),
564 456618 : MAX2(MIN_FALLBEHIND, (myVehicle.getSpeed() - targetSpeed) / remainingSeconds));
565 456618 : const double nextSpeed = MIN2(plannedSpeed, MAX2(0.0, myVehicle.getSpeed() - ACCEL2SPEED(decel)));
566 : #ifdef DEBUG_INFORMER
567 : if (DEBUG_COND) {
568 : std::cout << SIMTIME
569 : << " cannot overtake leader nv=" << nv->getID()
570 : << " dv=" << dv
571 : << " myLookAheadSpeed=" << myLookAheadSpeed
572 : << " myLeftSpace=" << myLeftSpace
573 : << " overtakeDist=" << overtakeDist
574 : << " overtakeTime=" << overtakeTime
575 : << " remainingSeconds=" << remainingSeconds
576 : << " currentGap=" << neighLead.second
577 : << " brakeGap=" << myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed(), getCarFollowModel().getMaxDecel(), 0.)
578 : << " neighNextSpeed=" << neighNextSpeed
579 : << " neighNextGap=" << neighNextGap
580 : << " targetSpeed=" << targetSpeed
581 : << " nextSpeed=" << nextSpeed
582 : << "\n";
583 : }
584 : #endif
585 456618 : addLCSpeedAdvice(nextSpeed);
586 456618 : return nextSpeed;
587 : } else {
588 : // leader is fast enough anyway
589 : #ifdef DEBUG_INFORMER
590 : if (DEBUG_COND) {
591 : std::cout << SIMTIME
592 : << " cannot overtake fast leader nv=" << nv->getID()
593 : << " dv=" << dv
594 : << " myLookAheadSpeed=" << myLookAheadSpeed
595 : << " myLeftSpace=" << myLeftSpace
596 : << " overtakeDist=" << overtakeDist
597 : << " myLeadingBlockerLength=" << myLeadingBlockerLength
598 : << " overtakeTime=" << overtakeTime
599 : << " remainingSeconds=" << remainingSeconds
600 : << " currentGap=" << neighLead.second
601 : << " neighNextSpeed=" << neighNextSpeed
602 : << " neighNextGap=" << neighNextGap
603 : << " targetSpeed=" << targetSpeed
604 : << "\n";
605 : }
606 : #endif
607 739533 : addLCSpeedAdvice(targetSpeed);
608 739533 : return plannedSpeed;
609 : }
610 : } else {
611 : // overtaking, leader should not accelerate
612 : #ifdef DEBUG_INFORMER
613 : if (DEBUG_COND) {
614 : std::cout << SIMTIME
615 : << " wants to overtake leader nv=" << nv->getID()
616 : << " dv=" << dv
617 : << " overtakeDist=" << overtakeDist
618 : << " remainingSeconds=" << remainingSeconds
619 : << " overtakeTime=" << overtakeTime
620 : << " currentGap=" << neighLead.second
621 : << " secureGap=" << nv->getCarFollowModel().getSecureGap(nv, &myVehicle, nv->getSpeed(), myVehicle.getSpeed(), myVehicle.getCarFollowModel().getMaxDecel())
622 : << "\n";
623 : }
624 : #endif
625 1992393 : msgPass.informNeighLeader(new Info(nv->getSpeed(), dir | LCA_AMBLOCKINGLEADER), &myVehicle);
626 : 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
627 : }
628 : } else { // (remainUnblocked)
629 : // we are not blocked now. make sure we stay far enough from the leader
630 1315308 : const double targetSpeed = MAX2(
631 657654 : myVehicle.getCarFollowModel().minNextSpeed(myVehicle.getSpeed(), &myVehicle),
632 657654 : getCarFollowModel().followSpeed(&myVehicle, myVehicle.getSpeed(), neighNextGap, neighNextSpeed, nv->getCarFollowModel().getMaxDecel()));
633 657654 : addLCSpeedAdvice(targetSpeed);
634 : #ifdef DEBUG_INFORMER
635 : if (DEBUG_COND) {
636 : std::cout << " not blocked by leader nv=" << nv->getID()
637 : << " nvSpeed=" << nv->getSpeed()
638 : << " gap=" << neighLead.second
639 : << " neighNextSpeed=" << neighNextSpeed
640 : << " neighNextGap=" << neighNextGap
641 : << " needGap=" << myVehicle.getCarFollowModel().getSecureGap(&myVehicle, nv, myVehicle.getSpeed(), nv->getSpeed(), nv->getCarFollowModel().getMaxDecel())
642 : << " targetSpeed=" << targetSpeed
643 : << "\n";
644 : }
645 : #endif
646 : return MIN2(targetSpeed, plannedSpeed);
647 : }
648 : }
649 :
650 : void
651 2076444 : MSLCM_LC2013::informFollower(MSAbstractLaneChangeModel::MSLCMessager& msgPass,
652 : int blocked,
653 : int dir,
654 : const std::pair<MSVehicle*, double>& neighFollow,
655 : double remainingSeconds,
656 : double plannedSpeed) {
657 :
658 2076444 : MSVehicle* nv = neighFollow.first;
659 2076444 : const double plannedAccel = SPEED2ACCEL(MAX2(MIN2(getCarFollowModel().getMaxAccel(), plannedSpeed - myVehicle.getSpeed()), -getCarFollowModel().getMaxDecel()));
660 :
661 : #ifdef DEBUG_INFORMER
662 : if (DEBUG_COND) {
663 : std::cout << "\nINFORM_FOLLOWER"
664 : << "\nspeed=" << myVehicle.getSpeed() << " planned=" << plannedSpeed << "\n";
665 : }
666 :
667 : #endif
668 2076444 : if ((blocked & LCA_BLOCKED_BY_FOLLOWER) != 0 && nv != nullptr) {
669 1243293 : if (MSLCHelper::divergentRoute(myVehicle, *nv)) {
670 : //std::cout << SIMTIME << " ego=" << myVehicle.getID() << " ignoresDivergentBlockingFollower=" << nv->getID() << "\n";
671 : return;
672 : }
673 : #ifdef DEBUG_INFORMER
674 : if (DEBUG_COND) {
675 : std::cout << " blocked by follower nv=" << nv->getID() << " nvSpeed=" << nv->getSpeed() << " needGap="
676 : << nv->getCarFollowModel().getSecureGap(nv, &myVehicle, nv->getSpeed(), myVehicle.getSpeed(), myVehicle.getCarFollowModel().getMaxDecel()) << " planned=" << plannedSpeed << "\n";
677 : }
678 : #endif
679 :
680 : // are we fast enough to cut in without any help?
681 1243200 : if (MAX2(plannedSpeed, 0.) - nv->getSpeed() >= HELP_OVERTAKE) {
682 75779 : const double neededGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, nv->getSpeed(), plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel());
683 75779 : if ((neededGap - neighFollow.second) / remainingSeconds < (MAX2(plannedSpeed, 0.) - nv->getSpeed())) {
684 : #ifdef DEBUG_INFORMER
685 : if (DEBUG_COND) {
686 : std::cout << " wants to cut in before nv=" << nv->getID() << " without any help." << "\nneededGap = " << neededGap << "\n";
687 : }
688 : #endif
689 : // follower might even accelerate but not to much
690 : // XXX: I don't understand this. The needed gap was determined for nv->getSpeed(), not for (plannedSpeed - HELP_OVERTAKE)?! (Leo), refs. #2578
691 66388 : msgPass.informNeighFollower(new Info(MAX2(plannedSpeed, 0.) - HELP_OVERTAKE, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
692 66388 : return;
693 : }
694 : }
695 :
696 : // decide whether we will request help to cut in before the follower or allow to be overtaken
697 :
698 : // PARAMETERS
699 : // assume other vehicle will assume the equivalent of 1 second of
700 : // maximum deceleration to help us (will probably be spread over
701 : // multiple seconds)
702 : // -----------
703 : const double helpDecel = nv->getCarFollowModel().getMaxDecel() * HELP_DECEL_FACTOR;
704 :
705 : // follower's new speed in next step
706 : double neighNewSpeed;
707 : // follower's new speed after 1s.
708 : double neighNewSpeed1s;
709 : // velocity difference, gap after follower-deceleration
710 : double dv, decelGap;
711 :
712 1176812 : if (MSGlobals::gSemiImplicitEulerUpdate) {
713 : // euler
714 1067854 : neighNewSpeed = MAX2(0., nv->getSpeed() - ACCEL2SPEED(helpDecel));
715 1067854 : neighNewSpeed1s = MAX2(0., nv->getSpeed() - helpDecel); // TODO: consider introduction of a configurable anticipationTime here (see far below in the !blocked part). Refs. #2578
716 : // change in the gap between ego and blocker over 1 second (not STEP!)
717 : // XXX: though here it is calculated as if it were one step!? (Leo) Refs. #2578
718 1067854 : dv = plannedSpeed - neighNewSpeed1s; // XXX: what is this quantity (if TS!=1)?
719 : // new gap between follower and self in case the follower does brake for 1s
720 : // XXX: if the step-length is not 1s., this is not the gap after 1s. deceleration!
721 : // And this formula overestimates the real gap. Isn't that problematic? (Leo)
722 : // Below, it seems that decelGap > secureGap is taken to indicate the possibility
723 : // to cut in within the next time-step. However, this is not the case, if TS<1s.,
724 : // since decelGap is (not exactly, though!) the gap after 1s. Refs. #2578
725 1067854 : decelGap = neighFollow.second + dv;
726 : } else {
727 : // ballistic
728 : // negative newSpeed-extrapolation possible, if stop lies within the next time-step
729 : // XXX: this code should work for the euler case as well, since gapExtrapolation() takes
730 : // care of this, but for TS!=1 we will have different behavior (see previous remark) Refs. #2578
731 108958 : neighNewSpeed = nv->getSpeed() - ACCEL2SPEED(helpDecel);
732 108958 : neighNewSpeed1s = nv->getSpeed() - helpDecel;
733 :
734 108958 : dv = myVehicle.getSpeed() - nv->getSpeed(); // current velocity difference
735 217916 : decelGap = getCarFollowModel().gapExtrapolation(1., neighFollow.second, myVehicle.getSpeed(),
736 108958 : nv->getSpeed(), plannedAccel, -helpDecel, myVehicle.getMaxSpeedOnLane(), nv->getMaxSpeedOnLane());
737 : }
738 :
739 1176812 : const double secureGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, MAX2(neighNewSpeed1s, 0.),
740 1176812 : MAX2(plannedSpeed, 0.), myVehicle.getCarFollowModel().getMaxDecel());
741 :
742 1176812 : const double onRampThreshold = myVehicle.getLane()->getSpeedLimit() * 0.8 * myExperimentalParam1 * (1 - myVehicle.getImpatience());
743 :
744 : #ifdef DEBUG_INFORMER
745 : if (DEBUG_COND) {
746 : std::cout << SIMTIME
747 : << " speed=" << myVehicle.getSpeed()
748 : << " plannedSpeed=" << plannedSpeed
749 : << " threshold=" << onRampThreshold
750 : << " neighNewSpeed=" << neighNewSpeed
751 : << " neighNewSpeed1s=" << neighNewSpeed1s
752 : << " dv=" << dv
753 : << " gap=" << neighFollow.second
754 : << " decelGap=" << decelGap
755 : << " secureGap=" << secureGap
756 : << "\n";
757 : }
758 : #endif
759 : // prevent vehicles on an on ramp stopping the main flow
760 : if (dir == LCA_MLEFT
761 379987 : && myVehicle.getLane()->isAccelLane()
762 1233499 : && neighNewSpeed1s < onRampThreshold) {
763 : return;
764 : }
765 :
766 1152734 : if (decelGap > 0 && decelGap >= secureGap) {
767 : // XXX: This does not assure that the leader can cut in in the next step if TS < 1 (see above)
768 : // this seems to be supposed in the following (euler code)...?! (Leo) Refs. #2578
769 :
770 : // if the blocking follower brakes it could help
771 : // how hard does it actually need to be?
772 : // to be safe in the next step the following equation has to hold for the follower's vsafe:
773 : // vsafe <= followSpeed(gap=currentGap - SPEED2DIST(vsafe), ...)
774 : double vsafe, vsafe1;
775 :
776 83357 : if (MSGlobals::gSemiImplicitEulerUpdate) {
777 : // euler
778 : // we compute an upper bound on vsafe by doing the computation twice
779 74284 : vsafe1 = MAX2(neighNewSpeed, nv->getCarFollowModel().followSpeed(
780 74284 : nv, nv->getSpeed(), neighFollow.second + SPEED2DIST(plannedSpeed), plannedSpeed, getCarFollowModel().getMaxDecel()));
781 74284 : vsafe = MAX2(neighNewSpeed, nv->getCarFollowModel().followSpeed(
782 74284 : nv, nv->getSpeed(), neighFollow.second + SPEED2DIST(plannedSpeed - vsafe1), plannedSpeed, getCarFollowModel().getMaxDecel()));
783 : //assert(vsafe <= vsafe1); assertion does not hold for models with randomness in followSpeed (W99)
784 : } else {
785 : // ballistic
786 :
787 : // XXX: This block should actually do as well for euler update (TODO: test!), refs #2575
788 : // we compute an upper bound on vsafe
789 : // next step's gap without help deceleration (nv's speed assumed constant)
790 9073 : double nextGap = getCarFollowModel().gapExtrapolation(TS,
791 9073 : neighFollow.second, myVehicle.getSpeed(),
792 9073 : nv->getSpeed(), plannedAccel, 0,
793 9073 : myVehicle.getMaxSpeedOnLane(), nv->getMaxSpeedOnLane());
794 : #ifdef DEBUG_INFORMER
795 : if (DEBUG_COND) {
796 : std::cout << "nextGap=" << nextGap << " (without help decel) \n";
797 : }
798 : #endif
799 :
800 : // NOTE: the second argument of MIN2() can get larger than nv->getSpeed()
801 18146 : vsafe1 = MIN2(nv->getSpeed(), MAX2(neighNewSpeed,
802 9073 : nv->getCarFollowModel().followSpeed(nv,
803 9073 : nv->getSpeed(), nextGap,
804 : MAX2(0., plannedSpeed),
805 : getCarFollowModel().getMaxDecel())));
806 :
807 :
808 : // next step's gap with possibly less than maximal help deceleration (in case vsafe1 > neighNewSpeed)
809 9073 : double decel2 = SPEED2ACCEL(nv->getSpeed() - vsafe1);
810 9073 : nextGap = getCarFollowModel().gapExtrapolation(TS,
811 9073 : neighFollow.second, myVehicle.getSpeed(),
812 9073 : nv->getSpeed(), plannedAccel, -decel2,
813 9073 : myVehicle.getMaxSpeedOnLane(), nv->getMaxSpeedOnLane());
814 :
815 : // vsafe = MAX(neighNewSpeed, safe speed assuming next_gap)
816 : // Thus, the gap resulting from vsafe is larger or equal to next_gap
817 : // in contrast to the euler case, where nv's follow speed doesn't depend on the actual speed,
818 : // we need to assure, that nv doesn't accelerate
819 18146 : vsafe = MIN2(nv->getSpeed(), MAX2(neighNewSpeed,
820 9073 : nv->getCarFollowModel().followSpeed(nv,
821 9073 : nv->getSpeed(), nextGap,
822 : MAX2(0., plannedSpeed),
823 : getCarFollowModel().getMaxDecel())));
824 :
825 : assert(vsafe >= vsafe1 - NUMERICAL_EPS);
826 :
827 : #ifdef DEBUG_INFORMER
828 : if (DEBUG_COND) {
829 : std::cout << "nextGap=" << nextGap
830 : << " (with vsafe1 and help decel) \nvsafe1=" << vsafe1
831 : << " vsafe=" << vsafe
832 : << "\n";
833 : }
834 : #endif
835 :
836 : // For subsecond simulation, this might not lead to secure gaps for a long time,
837 : // we seek to establish a secure gap as soon as possible
838 9073 : double nextSecureGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, vsafe, plannedSpeed, getCarFollowModel().getMaxDecel());
839 :
840 9073 : if (nextGap < nextSecureGap) {
841 : // establish a secureGap as soon as possible
842 : vsafe = neighNewSpeed;
843 : }
844 :
845 : #ifdef DEBUG_INFORMER
846 : if (DEBUG_COND) {
847 : std::cout << "nextGap=" << nextGap
848 : << " minNextSecureGap=" << nextSecureGap
849 : << " vsafe=" << vsafe << "\n";
850 : }
851 : #endif
852 :
853 : }
854 83357 : msgPass.informNeighFollower(
855 83357 : new Info(vsafe, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
856 :
857 : #ifdef DEBUG_INFORMER
858 : if (DEBUG_COND) {
859 : std::cout << " wants to cut in before nv=" << nv->getID()
860 : << " vsafe1=" << vsafe1 << " vsafe=" << vsafe
861 : << " newSecGap="
862 : << nv->getCarFollowModel().getSecureGap(nv, &myVehicle, vsafe,
863 : plannedSpeed,
864 : myVehicle.getCarFollowModel().getMaxDecel())
865 : << "\n";
866 : }
867 : #endif
868 1069377 : } else if ((MSGlobals::gSemiImplicitEulerUpdate && dv > 0 && dv * remainingSeconds > (secureGap - decelGap + POSITION_EPS))
869 1003280 : || (!MSGlobals::gSemiImplicitEulerUpdate && dv > 0 && dv * (remainingSeconds - 1) > secureGap - decelGap + POSITION_EPS)
870 : ) {
871 :
872 : // XXX: Alternative formulation (encapsulating differences of euler and ballistic) TODO: test, refs. #2575
873 : // double eventualGap = getCarFollowModel().gapExtrapolation(remainingSeconds - 1., decelGap, plannedSpeed, neighNewSpeed1s);
874 : // } else if (eventualGap > secureGap + POSITION_EPS) {
875 :
876 :
877 : // NOTE: This case corresponds to the situation, where some time is left to perform the lc
878 : // For the ballistic case this is interpreted as follows:
879 : // If the follower breaks with helpDecel for one second, this vehicle maintains the plannedSpeed,
880 : // and both continue with their speeds for remainingSeconds seconds the gap will suffice for a laneChange
881 : // For the euler case we had the following comment:
882 : // 'decelerating once is sufficient to open up a large enough gap in time', but:
883 : // XXX: 1) Decelerating *once* does not necessarily lead to the gap decelGap! (if TS<1s.) (Leo)
884 : // 2) Probably, the if() for euler should test for dv * (remainingSeconds-1) > ..., too ?!, refs. #2578
885 69087 : msgPass.informNeighFollower(new Info(neighNewSpeed, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
886 : #ifdef DEBUG_INFORMER
887 : if (DEBUG_COND) {
888 : std::cout << " wants to cut in before nv=" << nv->getID() << " (eventually)\n";
889 : }
890 : #endif
891 1000290 : } else if (dir == LCA_MRIGHT && !myAllowOvertakingRight && !nv->congested()) {
892 : // XXX: check if this requires a special treatment for the ballistic update, refs. #2575
893 : const double vhelp = MAX2(neighNewSpeed, HELP_OVERTAKE);
894 922 : msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
895 : #ifdef DEBUG_INFORMER
896 : if (DEBUG_COND) {
897 : std::cout << " wants to cut in before nv=" << nv->getID() << " (nv cannot overtake right)\n";
898 : }
899 : #endif
900 : } else {
901 999368 : double vhelp = MAX2(nv->getSpeed(), myVehicle.getSpeed() + HELP_OVERTAKE);
902 : //if (dir == LCA_MRIGHT && myVehicle.getWaitingSeconds() > LCA_RIGHT_IMPATIENCE &&
903 : // nv->getSpeed() > myVehicle.getSpeed()) {
904 999368 : if (nv->getSpeed() > myVehicle.getSpeed() &&
905 283421 : ((dir == LCA_MRIGHT && myVehicle.getWaitingSeconds() > LCA_RIGHT_IMPATIENCE) // NOTE: it might be considered to use myVehicle.getAccumulatedWaitingSeconds() > LCA_RIGHT_IMPATIENCE instead (Leo). Refs. #2578
906 133216 : || (dir == LCA_MLEFT && plannedSpeed > CUT_IN_LEFT_SPEED_THRESHOLD) // VARIANT_22 (slowDownLeft)
907 : // XXX this is a hack to determine whether the vehicles is on an on-ramp. This information should be retrieved from the network itself
908 133166 : || (dir == LCA_MLEFT && myVehicle.getLane()->getLength() > MAX_ONRAMP_LENGTH)
909 : )) {
910 : // let the follower slow down to increase the likelihood that later vehicles will be slow enough to help
911 : // follower should still be fast enough to open a gap
912 : // XXX: The probability for that success would be larger if the slow down of the appropriate following vehicle
913 : // would take place without the immediate follower slowing down. We might consider to model reactions of
914 : // vehicles that are not immediate followers. (Leo) -> see ticket #2532
915 314785 : vhelp = MAX2(neighNewSpeed, myVehicle.getSpeed() + HELP_OVERTAKE);
916 : #ifdef DEBUG_INFORMER
917 : if (DEBUG_COND) {
918 : // NOTE: the condition labeled "VARIANT_22" seems to imply that this could as well concern the *left* follower?! (Leo)
919 : // Further, vhelp might be larger than nv->getSpeed(), so the request issued below is not to slow down!? (see below) Refs. #2578
920 : std::cout << " wants right follower to slow down a bit\n";
921 : }
922 : #endif
923 314785 : if (MSGlobals::gSemiImplicitEulerUpdate) {
924 : // euler
925 262372 : if ((nv->getSpeed() - myVehicle.getSpeed()) / helpDecel < remainingSeconds) {
926 :
927 : #ifdef DEBUG_INFORMER
928 : if (DEBUG_COND) {
929 : // NOTE: the condition labeled "VARIANT_22" seems to imply that this could as well concern the *left* follower?! Refs. #2578
930 : std::cout << " wants to cut in before right follower nv=" << nv->getID() << " (eventually)\n";
931 : }
932 : #endif
933 : // XXX: I don't understand. This vhelp might be larger than nv->getSpeed() but the above condition seems to rely
934 : // on the reasoning that if nv breaks with helpDecel for remaining Seconds, nv will be so slow, that this
935 : // vehicle will be able to cut in. But nv might have overtaken this vehicle already (or am I missing sth?). (Leo)
936 : // Ad: To my impression, the intention behind allowing larger speeds for the blocking follower is to prevent a
937 : // situation, where an overlapping follower keeps blocking the ego vehicle. Refs. #2578
938 249666 : msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
939 249666 : return;
940 : }
941 : } else {
942 :
943 : // 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)
944 : // estimate gap after remainingSeconds.
945 : // Assumptions:
946 : // (A1) leader continues with currentSpeed. (XXX: That might be wrong: Think of accelerating on an on-ramp or of a congested region ahead!)
947 : // (A2) follower breaks with helpDecel.
948 52413 : const double gapAfterRemainingSecs = getCarFollowModel().gapExtrapolation(
949 52413 : remainingSeconds, neighFollow.second, myVehicle.getSpeed(), nv->getSpeed(), 0, -helpDecel, myVehicle.getMaxSpeedOnLane(), nv->getMaxSpeedOnLane());
950 52413 : const double secureGapAfterRemainingSecs = nv->getCarFollowModel().getSecureGap(nv, &myVehicle,
951 52413 : MAX2(nv->getSpeed() - remainingSeconds * helpDecel, 0.), myVehicle.getSpeed(), myVehicle.getCarFollowModel().getMaxDecel());
952 52413 : 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
953 : #ifdef DEBUG_INFORMER
954 : if (DEBUG_COND) {
955 : std::cout << " wants to cut in before follower nv=" << nv->getID() << " (eventually)\n";
956 : }
957 : #endif
958 : // NOTE: ballistic uses neighNewSpeed instead of vhelp, see my note above. (Leo)
959 : // TODO: recheck if this might cause suboptimal behaviour in some LC-situations. Refs. #2578
960 8823 : msgPass.informNeighFollower(new Info(neighNewSpeed, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
961 8823 : return;
962 : }
963 : }
964 :
965 :
966 : }
967 :
968 : #ifdef DEBUG_INFORMER
969 : if (DEBUG_COND) {
970 : std::cout << SIMTIME
971 : << " veh=" << myVehicle.getID()
972 : << " informs follower " << nv->getID()
973 : << " vhelp=" << vhelp
974 : << "\n";
975 : }
976 : #endif
977 :
978 740879 : msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
979 : // This follower is supposed to overtake us. Slow down smoothly to allow this.
980 740879 : const double overtakeDist = overtakeDistance(nv, &myVehicle, neighFollow.second, vhelp, plannedSpeed);
981 : // speed difference to create a sufficiently large gap
982 740879 : const double needDV = overtakeDist / remainingSeconds;
983 : // 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
984 827367 : addLCSpeedAdvice(MAX2(vhelp - needDV, myVehicle.getSpeed() - ACCEL2SPEED(myVehicle.getCarFollowModel().getMaxDecel())));
985 :
986 : #ifdef DEBUG_INFORMER
987 : if (DEBUG_COND) {
988 : std::cout << SIMTIME
989 : << " veh=" << myVehicle.getID()
990 : << " wants to be overtaken by=" << nv->getID()
991 : << " overtakeDist=" << overtakeDist
992 : << " vneigh=" << nv->getSpeed()
993 : << " vhelp=" << vhelp
994 : << " needDV=" << needDV
995 : << " vsafe=" << myLCAccelerationAdvices.back().first
996 : << "\n";
997 : }
998 : #endif
999 : }
1000 833151 : } else if (neighFollow.first != nullptr && (blocked & LCA_BLOCKED_BY_LEADER)) {
1001 : // we are not blocked by the follower now, make sure it remains that way
1002 394468 : const double vsafe = MSLCHelper::getSpeedPreservingSecureGap(myVehicle, *neighFollow.first, neighFollow.second, plannedSpeed);
1003 394468 : msgPass.informNeighFollower(new Info(vsafe, dir), &myVehicle);
1004 :
1005 : #ifdef DEBUG_INFORMER
1006 : if (DEBUG_COND) {
1007 : std::cout << " wants to cut in before non-blocking follower nv=" << nv->getID() << "\n";
1008 : }
1009 : #endif
1010 : }
1011 : }
1012 :
1013 :
1014 : void
1015 469189604 : MSLCM_LC2013::prepareStep() {
1016 469189604 : MSAbstractLaneChangeModel::prepareStep();
1017 : // keep information about strategic change direction
1018 469189604 : if (!isChangingLanes()) {
1019 468667497 : myOwnState = (myOwnState & LCA_STRATEGIC) ? (myOwnState & LCA_WANTS_LANECHANGE) : 0;
1020 : }
1021 469189604 : myLeadingBlockerLength = 0;
1022 469189604 : myLeftSpace = 0;
1023 : myLCAccelerationAdvices.clear();
1024 469189604 : myDontBrake = false;
1025 : // truncate to work around numerical instability between different builds
1026 469189604 : mySpeedGainProbability = ceil(mySpeedGainProbability * 100000.0) * 0.00001;
1027 469189604 : myKeepRightProbability = ceil(myKeepRightProbability * 100000.0) * 0.00001;
1028 469189604 : if (mySigma > 0 && !isChangingLanes()) {
1029 : // disturb lateral position directly
1030 1154 : const double maxDist = SPEED2DIST(myVehicle.getVehicleType().getMaxSpeedLat());
1031 1154 : const double oldPosLat = myVehicle.getLateralPositionOnLane();
1032 1154 : const double overlap = myVehicle.getLateralOverlap();
1033 : double scaledDelta;
1034 1154 : if (overlap > 0) {
1035 : // return to within lane boundary
1036 : scaledDelta = MIN2(overlap, maxDist);
1037 23 : if (myVehicle.getLateralPositionOnLane() > 0) {
1038 7 : scaledDelta *= -1;
1039 : }
1040 : } else {
1041 : // random drift
1042 1131 : double deltaPosLat = OUProcess::step(oldPosLat,
1043 1131 : myVehicle.getActionStepLengthSecs(),
1044 1131 : MAX2(NUMERICAL_EPS, (1 - mySigma) * 100), mySigma) - oldPosLat;
1045 1131 : deltaPosLat = MAX2(MIN2(deltaPosLat, maxDist), -maxDist);
1046 1131 : scaledDelta = deltaPosLat * myVehicle.getSpeed() / myVehicle.getLane()->getSpeedLimit();
1047 : }
1048 1154 : myVehicle.setLateralPositionOnLane(oldPosLat + scaledDelta);
1049 1154 : setSpeedLat(DIST2SPEED(scaledDelta));
1050 : } else {
1051 469188450 : resetSpeedLat();
1052 : }
1053 469189604 : }
1054 :
1055 :
1056 : double
1057 2411815 : MSLCM_LC2013::getExtraReservation(int bestLaneOffset) const {
1058 2411815 : if (bestLaneOffset < -1) {
1059 : return 20;
1060 2406532 : } else if (bestLaneOffset > 1) {
1061 10734 : return 40;
1062 : }
1063 : return 0;
1064 : }
1065 :
1066 : void
1067 283154906 : MSLCM_LC2013::changed() {
1068 283154906 : myOwnState = 0;
1069 283154906 : mySpeedGainProbability = 0;
1070 283154906 : myKeepRightProbability = 0;
1071 283154906 : if (myVehicle.getBestLaneOffset() == 0) {
1072 : // if we are not yet on our best lane there might still be unseen blockers
1073 : // (during patchSpeed)
1074 282754997 : myLeadingBlockerLength = 0;
1075 282754997 : myLeftSpace = 0;
1076 : }
1077 283154906 : myLookAheadSpeed = LOOK_AHEAD_MIN_SPEED;
1078 : myLCAccelerationAdvices.clear();
1079 283154906 : myDontBrake = false;
1080 283154906 : }
1081 :
1082 :
1083 : void
1084 4175 : MSLCM_LC2013::resetState() {
1085 4175 : myOwnState = 0;
1086 4175 : mySpeedGainProbability = 0;
1087 4175 : myKeepRightProbability = 0;
1088 4175 : myLeadingBlockerLength = 0;
1089 4175 : myLeftSpace = 0;
1090 4175 : myLookAheadSpeed = LOOK_AHEAD_MIN_SPEED;
1091 : myLCAccelerationAdvices.clear();
1092 4175 : myDontBrake = false;
1093 4175 : }
1094 :
1095 :
1096 : int
1097 185824726 : MSLCM_LC2013::_wantsChange(
1098 : int laneOffset,
1099 : MSAbstractLaneChangeModel::MSLCMessager& msgPass,
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 185824726 : 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 185824726 : const bool checkOpposite = &neighLane.getEdge() != &myVehicle.getLane()->getEdge();
1122 185824726 : const MSLane* prebLane = myVehicle.getLane();
1123 185824726 : if (prebLane->getEdge().isInternal()) {
1124 : // internal edges are not kept inside the bestLanes structure
1125 1022646 : if (isOpposite()) {
1126 534 : prebLane = prebLane->getNormalPredecessorLane();
1127 : } else {
1128 1022112 : prebLane = prebLane->getLinkCont()[0]->getLane();
1129 : }
1130 : }
1131 : // special case: vehicle considers changing to the opposite direction edge
1132 : const int prebOffset = laneOffset;
1133 318272385 : 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 318272385 : if (preb[p].lane == prebLane && p + laneOffset >= 0) {
1138 : assert(p + prebOffset < (int)preb.size());
1139 : curr = preb[p];
1140 185824726 : neigh = preb[p + prebOffset];
1141 185824726 : currentDist = curr.length;
1142 185824726 : neighDist = neigh.length;
1143 185824726 : bestLaneOffset = curr.bestLaneOffset;
1144 185824726 : 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 185824726 : 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 185824726 : const bool right = (laneOffset == -1);
1166 185824726 : const double posOnLane = getForwardPos();
1167 : double driveToNextStop = -std::numeric_limits<double>::max();
1168 185824726 : if (myVehicle.nextStopDist() < std::numeric_limits<double>::max()
1169 185824726 : && &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 497116 : driveToNextStop = myVehicle.nextStopDist();
1174 497116 : 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 185824726 : 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 185824726 : bool changeToBest = (right && bestLaneOffset < 0) || (!right && bestLaneOffset > 0);
1193 : // keep information about being a leader/follower
1194 185824726 : int ret = (myOwnState & 0xffff0000);
1195 : int req = 0; // the request to change or stay
1196 :
1197 185824726 : ret = slowDownForBlocked(lastBlocked, ret);
1198 185824726 : if (lastBlocked != firstBlocked) {
1199 185824726 : 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 185824726 : if (myVehicle.getSpeed() > myLookAheadSpeed) {
1236 34725713 : myLookAheadSpeed = myVehicle.getSpeed();
1237 : } else {
1238 : // memory decay factor for this action step
1239 151099013 : const double memoryFactor = 1. - (1. - LOOK_AHEAD_SPEED_MEMORY) * myVehicle.getActionStepLengthSecs();
1240 : assert(memoryFactor > 0.);
1241 151099013 : myLookAheadSpeed = MAX2(LOOK_AHEAD_MIN_SPEED,
1242 151099013 : (memoryFactor * myLookAheadSpeed + (1 - memoryFactor) * myVehicle.getSpeed()));
1243 : }
1244 185824726 : double laDist = myLookAheadSpeed * LOOK_FORWARD * myStrategicParam * (right ? 1 : myLookaheadLeft);
1245 185824726 : laDist += myVehicle.getVehicleType().getLengthWithGap() * 2.;
1246 185824726 : const bool hasStoppedLeader = leader.first != 0 && leader.first->isStopped() && leader.second < (currentDist - posOnLane);
1247 185824726 : const bool hasBidiLeader = myVehicle.getLane()->getBidiLane() != nullptr && MSLCHelper::isBidiLeader(leader.first, curr.bestContinuations);
1248 185824726 : const bool hasBidiNeighLeader = neighLane.getBidiLane() != nullptr && MSLCHelper::isBidiLeader(neighLead.first, neigh.bestContinuations);
1249 :
1250 185824726 : if (bestLaneOffset == 0 && hasBidiLeader) {
1251 : // getting out of the way is enough to clear the blockage
1252 : laDist = 0;
1253 185822767 : } 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 65193 : laDist = 0.5 * (myVehicle.getVehicleType().getLengthWithGap()
1258 65193 : + leader.first->getVehicleType().getLengthWithGap()
1259 65193 : + leader.second);
1260 185757574 : } 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 287748 : if (isOpposite()) {
1263 : // always allow changing back
1264 52411 : laDist = (myVehicle.getVehicleType().getLengthWithGap()
1265 52411 : + neighLead.first->getVehicleType().getLengthWithGap()
1266 52411 : + neighLead.second);
1267 235337 : } else if (!hasStoppedLeader &&
1268 221251 : ((neighLead.second + myVehicle.getVehicleType().getLengthWithGap() + neighLead.first->getVehicleType().getLengthWithGap()) < (currentDist - posOnLane)
1269 4621 : || 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 185824726 : 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 185824726 : const double roundaboutBonus = MSLCHelper::getRoundaboutDistBonus(myVehicle, myRoundaboutBonus, curr, neigh, best);
1291 185824726 : currentDist += roundaboutBonus;
1292 185824726 : neighDist += roundaboutBonus;
1293 :
1294 185824726 : const double usableDist = MAX2(currentDist - posOnLane - best.occupation * JAM_FACTOR, driveToNextStop);
1295 : //- (best.lane->getVehicleNumber() * neighSpeed)); // VARIANT 9 jfSpeed
1296 185824726 : const double maxJam = MAX2(preb[currIdx + prebOffset].occupation, preb[currIdx].occupation);
1297 185824726 : const double vMax = myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle);
1298 185824726 : const double neighVMax = neighLane.getVehicleMaxSpeed(&myVehicle);
1299 : // upper bound which will be restricted successively
1300 185824726 : double thisLaneVSafe = vMax;
1301 185824726 : const bool checkOverTakeRight = avoidOvertakeRight();
1302 :
1303 185824726 : double neighLeftPlace = MAX2(0.0, neighDist - posOnLane - maxJam);
1304 185824726 : if (neighLead.first != 0 && neighLead.first->isStopped()) {
1305 259124 : 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 149450691 : if (changeToBest && bestLaneOffset == curr.bestLaneOffset
1331 195760244 : && currentDistDisallows(usableDist, bestLaneOffset, laDist)) {
1332 : /// @brief we urgently need to change lanes to follow our route
1333 4027642 : ret = ret | lca | LCA_STRATEGIC | LCA_URGENT;
1334 : } else {
1335 : // VARIANT_20 (noOvertakeRight)
1336 181797084 : 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 : MSVehicle* nv = neighLead.first;
1340 10803239 : const double deltaV = MAX2(vMax - neighLane.getVehicleMaxSpeed(nv),
1341 10803239 : myVehicle.getSpeed() - nv->getSpeed());
1342 10803239 : if (deltaV > 0) {
1343 2016919 : const double vMaxDecel = getCarFollowModel().getSpeedAfterMaxDecel(myVehicle.getSpeed());
1344 2016919 : const double vSafeFollow = getCarFollowModel().followSpeed(
1345 2016919 : &myVehicle, myVehicle.getSpeed(), neighLead.second, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
1346 2016919 : const double vStayBehind = nv->getSpeed() - HELP_OVERTAKE;
1347 : double vSafe;
1348 2016919 : if (vSafeFollow >= vMaxDecel) {
1349 : vSafe = vSafeFollow;
1350 : } else {
1351 : vSafe = MAX2(vMaxDecel, vStayBehind);
1352 : }
1353 2016919 : if (mySpeedGainProbability < myChangeProbThresholdLeft) {
1354 1354896 : vSafe = MAX2(vSafe, nv->getSpeed());
1355 : }
1356 2016919 : thisLaneVSafe = MIN2(thisLaneVSafe, vSafe);
1357 2016919 : addLCSpeedAdvice(vSafe);
1358 : // only generate impulse for overtaking left shortly before braking would be necessary
1359 2016919 : const double deltaGapFuture = deltaV * 8;
1360 2016919 : const double vSafeFuture = getCarFollowModel().followSpeed(
1361 2016919 : &myVehicle, myVehicle.getSpeed(), neighLead.second - deltaGapFuture, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
1362 2016919 : if (vSafeFuture < vSafe) {
1363 : const double relativeGain = deltaV / MAX2(vMax,
1364 1674429 : RELGAIN_NORMALIZATION_MIN_SPEED);
1365 1674429 : mySpeedGainProbability += myVehicle.getActionStepLengthSecs() * relativeGain;
1366 : changeLeftToAvoidOvertakeRight = true;
1367 : }
1368 : #ifdef DEBUG_WANTS_CHANGE
1369 : if (DEBUG_COND) {
1370 : std::cout << STEPS2TIME(currentTime)
1371 : << " avoid overtaking on the right nv=" << nv->getID()
1372 : << " deltaV=" << deltaV
1373 : << " nvSpeed=" << nv->getSpeed()
1374 : << " mySpeedGainProbability=" << mySpeedGainProbability
1375 : << " planned acceleration =" << myLCAccelerationAdvices.back().first
1376 : << "\n";
1377 : }
1378 : #endif
1379 : }
1380 : }
1381 181797084 : const bool currFreeUntilNeighEnd = leader.first == nullptr || neighDist - posOnLane <= leader.second;
1382 351219268 : const double overtakeDist = (leader.first == 0 || hasBidiLeader ? -1 :
1383 169422184 : leader.second + myVehicle.getVehicleType().getLength() + leader.first->getVehicleType().getLengthWithGap());
1384 169428898 : if (leader.first != 0 && (leader.first->isStopped() || hasBidiLeader) && leader.second < REACT_TO_STOPPED_DISTANCE
1385 : // current destination leaves enough space to overtake the leader
1386 90571 : && MIN2(neighDist, currentDist) - posOnLane > overtakeDist
1387 : // maybe do not overtake on the right at high speed
1388 60033 : && (!checkOverTakeRight || !right)
1389 59958 : && myStrategicParam >= 0
1390 181856454 : && (neighLead.first == 0 || !neighLead.first->isStopped()
1391 : // neighboring stopped vehicle leaves enough space to overtake leader
1392 16369 : || neighLead.second > overtakeDist)) {
1393 : // avoid becoming stuck behind a stopped leader
1394 44922 : currentDist = myVehicle.getPositionOnLane() + leader.second;
1395 : #ifdef DEBUG_WANTS_CHANGE
1396 : if (DEBUG_COND) {
1397 : std::cout << " veh=" << myVehicle.getID() << " overtake stopped leader=" << leader.first->getID()
1398 : << " overtakeDist=" << overtakeDist
1399 : << " remaining=" << MIN2(neighDist, currentDist) - posOnLane
1400 : << "\n";
1401 : }
1402 : #endif
1403 44922 : ret = ret | lca | LCA_STRATEGIC | LCA_URGENT;
1404 181752162 : } else if (!changeToBest && currentDistDisallows(neighLeftPlace, abs(bestLaneOffset) + 2, laDist) && !hasBidiLeader) {
1405 : // the opposite lane-changing direction should be done than the one examined herein
1406 : // we'll check whether we assume we could change anyhow and get back in time...
1407 : //
1408 : // this rule prevents the vehicle from moving in opposite direction of the best lane
1409 : // unless the way till the end where the vehicle has to be on the best lane
1410 : // is long enough
1411 : #ifdef DEBUG_WANTS_CHANGE
1412 : if (DEBUG_COND) {
1413 : std::cout << " veh=" << myVehicle.getID() << " could not change back and forth in time (1) neighLeftPlace=" << neighLeftPlace << "\n";
1414 : }
1415 : #endif
1416 32366408 : ret = ret | LCA_STAY | LCA_STRATEGIC;
1417 149385754 : } else if (bestLaneOffset == 0 && (neighLeftPlace * 2. < laDist)) {
1418 : // the current lane is the best and a lane-changing would cause a situation
1419 : // of which we assume we will not be able to return to the lane we have to be on.
1420 : // this rule prevents the vehicle from leaving the current, best lane when it is
1421 : // close to this lane's end
1422 : #ifdef DEBUG_WANTS_CHANGE
1423 : if (DEBUG_COND) {
1424 : std::cout << " veh=" << myVehicle.getID() << " could not change back and forth in time (2) neighLeftPlace=" << neighLeftPlace << "\n";
1425 : }
1426 : #endif
1427 0 : ret = ret | LCA_STAY | LCA_STRATEGIC;
1428 : } else if (bestLaneOffset == 0
1429 3532563 : && (leader.first == 0 || !leader.first->isStopped())
1430 3523107 : && !hasBidiLeader
1431 3523104 : && neigh.bestContinuations.back()->getLinkCont().size() != 0
1432 2058919 : && roundaboutBonus == 0
1433 711957 : && !checkOpposite
1434 608470 : && ((myStrategicParam >= 0 && neighDist < TURN_LANE_DIST)
1435 : // lane changing cannot possibly help
1436 569279 : || (myStrategicParam < 0 && currFreeUntilNeighEnd))
1437 : ) {
1438 : // VARIANT_21 (stayOnBest)
1439 : // we do not want to leave the best lane for a lane which leads elsewhere
1440 : // unless our leader is stopped or we are approaching a roundabout
1441 : #ifdef DEBUG_WANTS_CHANGE
1442 : if (DEBUG_COND) {
1443 : std::cout << " veh=" << myVehicle.getID() << " does not want to leave the bestLane (neighDist=" << neighDist << ")\n";
1444 : }
1445 : #endif
1446 39268 : ret = ret | LCA_STAY | LCA_STRATEGIC;
1447 : }
1448 : }
1449 : // check for overriding TraCI requests
1450 : #ifdef DEBUG_WANTS_CHANGE
1451 : if (DEBUG_COND) {
1452 : std::cout << STEPS2TIME(currentTime) << " veh=" << myVehicle.getID() << " ret=" << toString((LaneChangeAction)ret);
1453 : }
1454 : #endif
1455 : // store state before canceling
1456 185824726 : getCanceledState(laneOffset) |= ret | blocked;
1457 185824726 : ret = myVehicle.influenceChangeDecision(ret);
1458 185824726 : if ((ret & lcaCounter) != 0) {
1459 : // we are not interested in traci requests for the opposite direction here
1460 30 : ret &= ~(LCA_TRACI | lcaCounter | LCA_URGENT);
1461 : }
1462 : #ifdef DEBUG_WANTS_CHANGE
1463 : if (DEBUG_COND) {
1464 : std::cout << " retAfterInfluence=" << toString((LaneChangeAction)ret) << "\n";
1465 : }
1466 : #endif
1467 :
1468 185824726 : if ((ret & LCA_STAY) != 0) {
1469 : // remove TraCI flags because it should not be included in "state-without-traci"
1470 32484463 : ret = getCanceledState(laneOffset);
1471 32484463 : return ret;
1472 : }
1473 153340263 : if ((ret & LCA_URGENT) != 0) {
1474 : // prepare urgent lane change maneuver
1475 : // save the left space
1476 4072284 : myLeftSpace = currentDist - posOnLane;
1477 4072284 : if (changeToBest && abs(bestLaneOffset) > 1) {
1478 : // there might be a vehicle which needs to counter-lane-change one lane further and we cannot see it yet
1479 666040 : myLeadingBlockerLength = MAX2((right ? 20.0 : 40.0), myLeadingBlockerLength);
1480 : #ifdef DEBUG_WANTS_CHANGE
1481 : if (DEBUG_COND) {
1482 : std::cout << " reserving space for unseen blockers myLeadingBlockerLength=" << myLeadingBlockerLength << "\n";
1483 : }
1484 : #endif
1485 : }
1486 :
1487 : // letting vehicles merge in at the end of the lane in case of counter-lane change, step#1
1488 : // if there is a leader and he wants to change to the opposite direction
1489 4072284 : const bool canContinue = curr.bestContinuations.size() > 1;
1490 4072284 : bool canReserve = MSLCHelper::updateBlockerLength(myVehicle, neighLead.first, lcaCounter, myLeftSpace - MAGIC_OFFSET, canContinue, myLeadingBlockerLength);
1491 4072284 : if (*firstBlocked != neighLead.first) {
1492 3825244 : canReserve &= MSLCHelper::updateBlockerLength(myVehicle, *firstBlocked, lcaCounter, myLeftSpace - MAGIC_OFFSET, canContinue, myLeadingBlockerLength);
1493 : }
1494 : #ifdef DEBUG_SAVE_BLOCKER_LENGTH
1495 : if (DEBUG_COND) {
1496 : std::cout << SIMTIME << " canReserve=" << canReserve << " canContinue=" << canContinue << "\n";
1497 : }
1498 : #endif
1499 4072284 : if (!canReserve && !isOpposite()) {
1500 : // we have a low-priority relief connection
1501 : // std::cout << SIMTIME << " veh=" << myVehicle.getID() << " cannotReserve for blockers\n";
1502 4653 : myDontBrake = canContinue;
1503 : }
1504 :
1505 4072284 : const int remainingLanes = MAX2(1, abs(bestLaneOffset));
1506 4072284 : const double urgency = isOpposite() ? OPPOSITE_URGENCY : URGENCY;
1507 4072284 : const double remainingSeconds = ((ret & LCA_TRACI) == 0 ?
1508 : //MAX2(STEPS2TIME(TS), (myLeftSpace-myLeadingBlockerLength) / MAX2(myLookAheadSpeed, NUMERICAL_EPS) / remainingLanes / urgency) :
1509 4195416 : MAX2(STEPS2TIME(TS), myLeftSpace / MAX2(myLookAheadSpeed, NUMERICAL_EPS) / remainingLanes / urgency) :
1510 220 : myVehicle.getInfluencer().changeRequestRemainingSeconds(currentTime));
1511 4072284 : if (!hasBidiNeighLeader) {
1512 4072251 : const double plannedSpeed = informLeader(msgPass, blocked, myLca, neighLead, remainingSeconds);
1513 : // NOTE: for the ballistic update case negative speeds may indicate a stop request,
1514 : // while informLeader returns -1 in that case. Refs. #2577
1515 4072251 : if (plannedSpeed >= 0 || (!MSGlobals::gSemiImplicitEulerUpdate && plannedSpeed != -1)) {
1516 : // maybe we need to deal with a blocking follower
1517 2079858 : const bool hasBidiNeighFollower = neighLane.getBidiLane() != nullptr && MSLCHelper::isBidiFollower(&myVehicle, neighFollow.first);
1518 : if (!hasBidiNeighFollower) {
1519 2076444 : informFollower(msgPass, blocked, myLca, neighFollow, remainingSeconds, plannedSpeed);
1520 : }
1521 : }
1522 : #ifdef DEBUG_WANTS_CHANGE
1523 : if (DEBUG_COND) {
1524 : std::cout << STEPS2TIME(currentTime)
1525 : << " veh=" << myVehicle.getID()
1526 : << " myLeftSpace=" << myLeftSpace
1527 : << " remainingSeconds=" << remainingSeconds
1528 : << " plannedSpeed=" << plannedSpeed
1529 : << "\n";
1530 : }
1531 : #endif
1532 : } else {
1533 : #ifdef DEBUG_WANTS_CHANGE
1534 : if (DEBUG_COND) {
1535 : std::cout << STEPS2TIME(currentTime)
1536 : << " veh=" << myVehicle.getID()
1537 : << " myLeftSpace=" << myLeftSpace
1538 : << " remainingSeconds=" << remainingSeconds
1539 : << " hasBidiNeighLeader\n";
1540 : }
1541 : #endif
1542 : }
1543 :
1544 :
1545 : // remove TraCI flags because it should not be included in "state-without-traci"
1546 4072284 : ret = getCanceledState(laneOffset);
1547 4072284 : return ret;
1548 : }
1549 :
1550 : // we wish to anticipate future speeds. This is difficult when the leading
1551 : // vehicles are still accelerating so we resort to comparing speeds for the near future (1s) in this case
1552 138776441 : const bool acceleratingLeader = (neighLead.first != 0 && neighLead.first->getAcceleration() > 0)
1553 217672098 : || (leader.first != 0 && leader.first->getAcceleration() > 0);
1554 149267979 : double neighLaneVSafe = MIN2(neighVMax, anticipateFollowSpeed(neighLead, neighDist, neighVMax, acceleratingLeader));
1555 149267979 : thisLaneVSafe = MIN2(thisLaneVSafe, anticipateFollowSpeed(leader, currentDist, vMax, acceleratingLeader));
1556 : //std::cout << SIMTIME << " veh=" << myVehicle.getID() << " thisLaneVSafe=" << thisLaneVSafe << " neighLaneVSafe=" << neighLaneVSafe << "\n";
1557 :
1558 :
1559 : // a high inconvenience prevents cooperative changes and the following things are inconvenient:
1560 : // - a desire to change in the opposite direction for speedGain
1561 : // - low anticipated speed on the neighboring lane
1562 : // - high occupancy on the neighboring lane while in a roundabout
1563 :
1564 : double inconvenience = laneOffset < 0
1565 149267979 : ? mySpeedGainProbability / myChangeProbThresholdRight
1566 77106604 : : -mySpeedGainProbability / myChangeProbThresholdLeft;
1567 :
1568 195412578 : const double relSpeedDiff = thisLaneVSafe == 0 ? 0 : (thisLaneVSafe - neighLaneVSafe) / MAX2(thisLaneVSafe, neighLaneVSafe);
1569 : inconvenience = MAX2(relSpeedDiff, inconvenience);
1570 : inconvenience = MIN2(1.0, inconvenience);
1571 :
1572 149267979 : const bool speedGainInconvenient = inconvenience > myCooperativeParam;
1573 149267979 : const bool neighOccupancyInconvenient = neigh.lane->getBruttoOccupancy() > curr.lane->getBruttoOccupancy();
1574 : #ifdef DEBUG_WANTS_CHANGE
1575 : if (DEBUG_COND) {
1576 : std::cout << STEPS2TIME(currentTime)
1577 : << " veh=" << myVehicle.getID()
1578 : << " speedGainProb=" << mySpeedGainProbability
1579 : << " neighSpeedFactor=" << (thisLaneVSafe / neighLaneVSafe - 1)
1580 : << " inconvenience=" << inconvenience
1581 : << " speedInconv=" << speedGainInconvenient
1582 : << " occInconv=" << neighOccupancyInconvenient
1583 : << "\n";
1584 : }
1585 : #endif
1586 :
1587 : // VARIANT_15
1588 149267979 : if (roundaboutBonus > 0) {
1589 :
1590 : #ifdef DEBUG_WANTS_CHANGE
1591 : if (DEBUG_COND) {
1592 : std::cout << STEPS2TIME(currentTime)
1593 : << " veh=" << myVehicle.getID()
1594 : << " roundaboutBonus=" << roundaboutBonus
1595 : << " myLeftSpace=" << myLeftSpace
1596 : << "\n";
1597 : }
1598 : #endif
1599 : // try to use the inner lanes of a roundabout to increase throughput
1600 : // unless we are approaching the exit
1601 4549972 : if (lca == LCA_LEFT) {
1602 : // if inconvenience is not too high, request collaborative change (currently only for ballistic update)
1603 : // TODO: test this for euler update! Refs. #2575
1604 836003 : if (MSGlobals::gSemiImplicitEulerUpdate || !neighOccupancyInconvenient) {
1605 : // if(MSGlobals::gSemiImplicitEulerUpdate || !speedGainInconvenient){
1606 836003 : req = ret | lca | LCA_COOPERATIVE;
1607 : }
1608 : } else {
1609 : // if inconvenience is not too high, request collaborative change (currently only for ballistic update)
1610 3713969 : if (MSGlobals::gSemiImplicitEulerUpdate || neighOccupancyInconvenient) {
1611 : // if(MSGlobals::gSemiImplicitEulerUpdate || speedGainInconvenient){
1612 3713969 : req = ret | LCA_STAY | LCA_COOPERATIVE;
1613 : }
1614 : }
1615 4549972 : if (!cancelRequest(req, laneOffset)) {
1616 4549972 : return ret | req;
1617 : }
1618 : }
1619 :
1620 : // let's also regard the case where the vehicle is driving on a highway...
1621 : // in this case, we do not want to get to the dead-end of an on-ramp
1622 144718007 : if (right) {
1623 68447406 : if (bestLaneOffset == 0 && myVehicle.getLane()->getSpeedLimit() > 80. / 3.6 && myLookAheadSpeed > SUMO_const_haltingSpeed) {
1624 : #ifdef DEBUG_WANTS_CHANGE
1625 : if (DEBUG_COND) {
1626 : std::cout << " veh=" << myVehicle.getID() << " does not want to get stranded on the on-ramp of a highway\n";
1627 : }
1628 : #endif
1629 86887 : req = ret | LCA_STAY | LCA_STRATEGIC;
1630 86887 : if (!cancelRequest(req, laneOffset)) {
1631 : return ret | req;
1632 : }
1633 : }
1634 : }
1635 : // --------
1636 :
1637 : // -------- make place on current lane if blocking follower
1638 : //if (amBlockingFollowerPlusNB()) {
1639 : // std::cout << myVehicle.getID() << ", " << currentDistAllows(neighDist, bestLaneOffset, laDist)
1640 : // << " neighDist=" << neighDist
1641 : // << " currentDist=" << currentDist
1642 : // << "\n";
1643 : //}
1644 :
1645 : if (amBlockingFollowerPlusNB()
1646 105810 : && (!speedGainInconvenient)
1647 105285 : && ((myOwnState & myLca) != 0) // VARIANT_6 : counterNoHelp
1648 144656049 : && (changeToBest || currentDistAllows(neighDist, abs(bestLaneOffset) + 1, laDist))) {
1649 :
1650 : // VARIANT_2 (nbWhenChangingToHelp)
1651 : #ifdef DEBUG_COOPERATE
1652 : if (DEBUG_COND) {
1653 : std::cout << STEPS2TIME(currentTime)
1654 : << " veh=" << myVehicle.getID()
1655 : << " wantsChangeToHelp=" << (right ? "right" : "left")
1656 : << " state=" << myOwnState
1657 : << (((myOwnState & myLca) == 0) ? " (counter)" : "")
1658 : << "\n";
1659 : }
1660 : #endif
1661 24904 : req = ret | lca | LCA_COOPERATIVE | LCA_URGENT ;//| LCA_CHANGE_TO_HELP;
1662 24904 : if (!cancelRequest(req, laneOffset)) {
1663 24898 : return ret | req;
1664 : }
1665 : }
1666 :
1667 : // --------
1668 :
1669 :
1670 : //// -------- security checks for krauss
1671 : //// (vsafe fails when gap<0)
1672 : //if ((blocked & LCA_BLOCKED) != 0) {
1673 : // return ret;
1674 : //}
1675 : //// --------
1676 :
1677 : // -------- higher speed
1678 : //if ((congested(neighLead.first) && neighLead.second < 20) || predInteraction(leader.first)) { //!!!
1679 : // return ret;
1680 : //}
1681 :
1682 144606247 : if (neighLane.getEdge().getPersons().size() > 0) {
1683 : // react to pedestrians
1684 46379 : adaptSpeedToPedestrians(myVehicle.getLane(), thisLaneVSafe);
1685 46379 : adaptSpeedToPedestrians(&neighLane, neighLaneVSafe);
1686 : }
1687 :
1688 144606247 : const double relativeGain = (neighLaneVSafe - thisLaneVSafe) / MAX2(neighLaneVSafe,
1689 144606247 : RELGAIN_NORMALIZATION_MIN_SPEED);
1690 :
1691 : #ifdef DEBUG_WANTS_CHANGE
1692 : if (DEBUG_COND) {
1693 : std::cout << STEPS2TIME(currentTime)
1694 : << " veh=" << myVehicle.getID()
1695 : << " currentDist=" << currentDist
1696 : << " neighDist=" << neighDist
1697 : << " thisVSafe=" << thisLaneVSafe
1698 : << " neighVSafe=" << neighLaneVSafe
1699 : << " relGain=" << toString(relativeGain, 8)
1700 : << "\n";
1701 : }
1702 : #endif
1703 :
1704 144606247 : if (right) {
1705 : // ONLY FOR CHANGING TO THE RIGHT
1706 68359798 : if (thisLaneVSafe - 5 / 3.6 > neighLaneVSafe) {
1707 : // ok, the current lane is faster than the right one...
1708 45094537 : if (mySpeedGainProbability < 0) {
1709 5235810 : mySpeedGainProbability *= pow(0.5, myVehicle.getActionStepLengthSecs());
1710 : //myKeepRightProbability /= 2.0;
1711 : }
1712 : } else {
1713 : // ok, the current lane is not (much) faster than the right one
1714 : // @todo recheck the 5 km/h discount on thisLaneVSafe, refs. #2068
1715 :
1716 : // do not promote changing to the left just because changing to the right is bad
1717 : // XXX: The following code may promote it, though!? (recheck!)
1718 : // (Think of small negative mySpeedGainProbability and larger negative relativeGain)
1719 : // One might think of replacing '||' by '&&' to exclude that possibility...
1720 : // Still, for negative relativeGain, we might want to decrease the inclination for
1721 : // changing to the left. Another solution could be the seperation of mySpeedGainProbability into
1722 : // two variables (one for left and one for right). Refs #2578
1723 23265261 : if (mySpeedGainProbability < 0 || relativeGain > 0) {
1724 8656659 : mySpeedGainProbability -= myVehicle.getActionStepLengthSecs() * relativeGain;
1725 : }
1726 :
1727 : // honor the obligation to keep right (Rechtsfahrgebot)
1728 23265261 : const double roadSpeedFactor = vMax / myVehicle.getLane()->getSpeedLimit(); // differse from speedFactor if vMax < speedLimit
1729 : double acceptanceTime;
1730 23265261 : if (myKeepRightAcceptanceTime == -1) {
1731 : // legacy behavior: scale acceptance time with current speed and
1732 : // use old hard-coded constant
1733 46527914 : acceptanceTime = 7 * roadSpeedFactor * MAX2(1.0, myVehicle.getSpeed());
1734 : } else {
1735 1304 : acceptanceTime = myKeepRightAcceptanceTime * roadSpeedFactor;
1736 1511 : if (follower.first != nullptr && follower.second < 2 * follower.first->getCarFollowModel().brakeGap(follower.first->getSpeed())) {
1737 : // reduce acceptanceTime if the follower vehicle is faster or wants to drive faster
1738 207 : if (follower.first->getSpeed() >= myVehicle.getSpeed()) {
1739 380 : acceptanceTime *= MAX2(1.0, myVehicle.getSpeed()) / MAX2(1.0, follower.first->getSpeed());
1740 190 : const double fRSF = follower.first->getLane()->getVehicleMaxSpeed(follower.first) / follower.first->getLane()->getSpeedLimit();
1741 190 : if (fRSF > roadSpeedFactor) {
1742 120 : acceptanceTime /= fRSF;
1743 : }
1744 : }
1745 : }
1746 : }
1747 23265261 : double fullSpeedGap = MAX2(0., neighDist - myVehicle.getCarFollowModel().brakeGap(vMax));
1748 23265261 : double fullSpeedDrivingSeconds = MIN2(acceptanceTime, fullSpeedGap / vMax);
1749 23265261 : if (neighLead.first != 0 && neighLead.first->getSpeed() < vMax) {
1750 18120550 : fullSpeedGap = MAX2(0., MIN2(fullSpeedGap,
1751 18120550 : neighLead.second - myVehicle.getCarFollowModel().getSecureGap(&myVehicle, neighLead.first,
1752 18120550 : vMax, neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel())));
1753 18120550 : fullSpeedDrivingSeconds = MIN2(fullSpeedDrivingSeconds, fullSpeedGap / (vMax - neighLead.first->getSpeed()));
1754 : }
1755 : // stay on the current lane if we cannot overtake a slow leader on the right
1756 4393263 : if (checkOverTakeRight && leader.first != 0
1757 27158858 : && leader.first->getLane()->getVehicleMaxSpeed(leader.first) < vMax) {
1758 1212582 : fullSpeedGap = MIN2(fullSpeedGap, leader.second);
1759 1212582 : fullSpeedDrivingSeconds = MIN2(fullSpeedDrivingSeconds, fullSpeedGap / (vMax - leader.first->getSpeed()));
1760 1212582 : const double relGain = (vMax - leader.first->getLane()->getVehicleMaxSpeed(leader.first)) / MAX2(vMax,
1761 1212582 : RELGAIN_NORMALIZATION_MIN_SPEED);
1762 : // tiebraker to avoid buridans paradox see #1312
1763 1212582 : mySpeedGainProbability += myVehicle.getActionStepLengthSecs() * relGain;
1764 : }
1765 :
1766 23265261 : const double deltaProb = (myChangeProbThresholdRight * (fullSpeedDrivingSeconds / acceptanceTime) / KEEP_RIGHT_TIME);
1767 23265261 : myKeepRightProbability -= myVehicle.getActionStepLengthSecs() * deltaProb;
1768 :
1769 : //std::cout << STEPS2TIME(currentTime)
1770 : // << " veh=" << myVehicle.getID()
1771 : // << " acceptanceTime=" << acceptanceTime
1772 : // << " fullSpeedDrivingSeconds=" << fullSpeedDrivingSeconds
1773 : // << " dProb=" << deltaProb
1774 : // << " myKeepRightProbability=" << myKeepRightProbability
1775 : // << "\n";
1776 :
1777 : #ifdef DEBUG_WANTS_CHANGE
1778 : if (DEBUG_COND) {
1779 : std::cout << STEPS2TIME(currentTime)
1780 : << " veh=" << myVehicle.getID()
1781 : << " vMax=" << vMax
1782 : << " neighDist=" << neighDist
1783 : << " brakeGap=" << myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed())
1784 : << " leaderSpeed=" << (neighLead.first == 0 ? -1 : neighLead.first->getSpeed())
1785 : << " secGap=" << (neighLead.first == 0 ? -1 : myVehicle.getCarFollowModel().getSecureGap(&myVehicle, neighLead.first,
1786 : myVehicle.getSpeed(), neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel()))
1787 : << " acceptanceTime=" << acceptanceTime
1788 : << " fullSpeedGap=" << fullSpeedGap
1789 : << " fullSpeedDrivingSeconds=" << fullSpeedDrivingSeconds
1790 : << " dProb=" << deltaProb
1791 : << " myKeepRightProbability=" << myKeepRightProbability
1792 : << "\n";
1793 : }
1794 : #endif
1795 23265261 : if (myKeepRightProbability * myKeepRightParam < -myChangeProbThresholdRight) {
1796 2400212 : req = ret | lca | LCA_KEEPRIGHT;
1797 2400212 : if (!cancelRequest(req, laneOffset)) {
1798 2399787 : return ret | req;
1799 : }
1800 : }
1801 : }
1802 :
1803 : #ifdef DEBUG_WANTS_CHANGE
1804 : if (DEBUG_COND) {
1805 : std::cout << STEPS2TIME(currentTime)
1806 : << " veh=" << myVehicle.getID()
1807 : << " speed=" << myVehicle.getSpeed()
1808 : << " mySpeedGainProbability=" << mySpeedGainProbability
1809 : << " thisLaneVSafe=" << thisLaneVSafe
1810 : << " neighLaneVSafe=" << neighLaneVSafe
1811 : << " relativeGain=" << relativeGain
1812 : << " blocked=" << blocked
1813 : << "\n";
1814 : }
1815 : #endif
1816 :
1817 65960011 : if (mySpeedGainProbability < -myChangeProbThresholdRight
1818 66424723 : && neighDist / MAX2(.1, myVehicle.getSpeed()) > 20.) { //./MAX2( .1, myVehicle.getSpeed())) { // -.1
1819 448035 : req = ret | lca | LCA_SPEEDGAIN;
1820 448035 : if (!cancelRequest(req, laneOffset)) {
1821 448035 : return ret | req;
1822 : }
1823 : }
1824 : } else {
1825 : // ONLY FOR CHANGING TO THE LEFT
1826 76246449 : if (thisLaneVSafe > neighLaneVSafe) {
1827 : // this lane is better
1828 43544166 : if (mySpeedGainProbability > 0) {
1829 23947341 : mySpeedGainProbability *= pow(0.5, myVehicle.getActionStepLengthSecs());
1830 : }
1831 32702283 : } else if (thisLaneVSafe == neighLaneVSafe) {
1832 16667082 : if (mySpeedGainProbability > 0) {
1833 4636435 : mySpeedGainProbability *= pow(0.8, myVehicle.getActionStepLengthSecs());
1834 : }
1835 : } else {
1836 : // left lane is better
1837 16035201 : mySpeedGainProbability += myVehicle.getActionStepLengthSecs() * relativeGain;
1838 : }
1839 : // VARIANT_19 (stayRight)
1840 : //if (neighFollow.first != 0) {
1841 : // MSVehicle* nv = neighFollow.first;
1842 : // const double secGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, nv->getSpeed(), myVehicle.getSpeed(), myVehicle.getCarFollowModel().getMaxDecel());
1843 : // if (neighFollow.second < secGap * KEEP_RIGHT_HEADWAY) {
1844 : // // do not change left if it would inconvenience faster followers
1845 : // return ret | LCA_STAY | LCA_SPEEDGAIN;
1846 : // }
1847 : //}
1848 :
1849 : #ifdef DEBUG_WANTS_CHANGE
1850 : if (DEBUG_COND) {
1851 : std::cout << STEPS2TIME(currentTime)
1852 : << " veh=" << myVehicle.getID()
1853 : << " speed=" << myVehicle.getSpeed()
1854 : << " mySpeedGainProbability=" << mySpeedGainProbability
1855 : << " thisLaneVSafe=" << thisLaneVSafe
1856 : << " neighLaneVSafe=" << neighLaneVSafe
1857 : << " relativeGain=" << relativeGain
1858 : << " blocked=" << blocked
1859 : << "\n";
1860 : }
1861 : #endif
1862 :
1863 76246449 : if (mySpeedGainProbability > myChangeProbThresholdLeft
1864 8028543 : && (relativeGain > NUMERICAL_EPS || changeLeftToAvoidOvertakeRight)
1865 88495027 : && neighDist / MAX2(.1, myVehicle.getSpeed()) > 20.) { // .1
1866 5853483 : req = ret | lca | LCA_SPEEDGAIN;
1867 5853483 : if (!cancelRequest(req, laneOffset)) {
1868 5853367 : return ret | req;
1869 : }
1870 : }
1871 : }
1872 : // --------
1873 135905058 : if (changeToBest && bestLaneOffset == curr.bestLaneOffset
1874 2243009 : && myStrategicParam >= 0
1875 2236414 : && relativeGain >= 0
1876 826131 : && (right ? mySpeedGainProbability < 0 : mySpeedGainProbability > 0)) {
1877 : // change towards the correct lane, speedwise it does not hurt
1878 111581 : req = ret | lca | LCA_STRATEGIC;
1879 111581 : if (!cancelRequest(req, laneOffset)) {
1880 111581 : return ret | req;
1881 : }
1882 : }
1883 : #ifdef DEBUG_WANTS_CHANGE
1884 : if (DEBUG_COND) {
1885 : std::cout << STEPS2TIME(currentTime)
1886 : << " veh=" << myVehicle.getID()
1887 : << " mySpeedGainProbability=" << mySpeedGainProbability
1888 : << " myKeepRightProbability=" << myKeepRightProbability
1889 : << " thisLaneVSafe=" << thisLaneVSafe
1890 : << " neighLaneVSafe=" << neighLaneVSafe
1891 : << "\n";
1892 : }
1893 : #endif
1894 :
1895 : return ret;
1896 : }
1897 :
1898 :
1899 : double
1900 298535958 : MSLCM_LC2013::anticipateFollowSpeed(const std::pair<MSVehicle*, double>& leaderDist, double dist, double vMax, bool acceleratingLeader) {
1901 298535958 : const MSVehicle* leader = leaderDist.first;
1902 298535958 : const double gap = leaderDist.second;
1903 : double futureSpeed;
1904 298535958 : if (acceleratingLeader) {
1905 : // XXX see #6562
1906 205295612 : const double maxSpeed1s = (myVehicle.getSpeed() + myVehicle.getCarFollowModel().getMaxAccel()
1907 205295612 : - ACCEL2SPEED(myVehicle.getCarFollowModel().getMaxAccel()));
1908 205295612 : if (leader == nullptr) {
1909 4365807 : if (hasBlueLight()) {
1910 : // can continue from any lane if necessary
1911 : futureSpeed = vMax;
1912 : } else {
1913 4365765 : futureSpeed = getCarFollowModel().followSpeed(&myVehicle, maxSpeed1s, dist, 0, 0);
1914 : }
1915 : } else {
1916 200929805 : futureSpeed = getCarFollowModel().followSpeed(&myVehicle, maxSpeed1s, gap, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
1917 : }
1918 : } else {
1919 : // onInsertion = true because the vehicle has already moved
1920 93240346 : if (leader == nullptr) {
1921 14750591 : if (hasBlueLight()) {
1922 : // can continue from any lane if necessary
1923 : futureSpeed = vMax;
1924 : } else {
1925 14749250 : futureSpeed = getCarFollowModel().maximumSafeStopSpeed(dist, getCarFollowModel().getMaxDecel(), myVehicle.getSpeed(), true);
1926 : }
1927 : } else {
1928 78489755 : futureSpeed = getCarFollowModel().maximumSafeFollowSpeed(gap, myVehicle.getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel(), true);
1929 : }
1930 : }
1931 : futureSpeed = MIN2(vMax, futureSpeed);
1932 298535958 : if (leader != nullptr && gap > 0 && mySpeedGainLookahead > 0) {
1933 983 : const double futureLeaderSpeed = acceleratingLeader ? leader->getLane()->getVehicleMaxSpeed(leader) : leader->getSpeed();
1934 983 : const double deltaV = vMax - futureLeaderSpeed;
1935 983 : if (deltaV > 0 && gap > 0) {
1936 965 : const double secGap = getCarFollowModel().getSecureGap(&myVehicle, leader, futureSpeed, leader->getSpeed(), getCarFollowModel().getMaxDecel());
1937 965 : const double fullSpeedGap = gap - secGap;
1938 965 : if (fullSpeedGap / deltaV < mySpeedGainLookahead) {
1939 : // anticipate future braking by computing the average
1940 : // speed over the next few seconds
1941 : const double gapClosingTime = MAX2(0.0, fullSpeedGap / deltaV);
1942 169 : const double foreCastTime = mySpeedGainLookahead * 2;
1943 : //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " leader=" << leader->getID() << " gap=" << gap << " deltaV=" << deltaV << " futureSpeed=" << futureSpeed << " futureLeaderSpeed=" << futureLeaderSpeed;
1944 169 : futureSpeed = MIN2(futureSpeed, (gapClosingTime * futureSpeed + (foreCastTime - gapClosingTime) * futureLeaderSpeed) / foreCastTime);
1945 : //if (DEBUG_COND) std::cout << " newFutureSpeed=" << futureSpeed << "\n";
1946 : }
1947 : }
1948 : }
1949 298535958 : return futureSpeed;
1950 : }
1951 :
1952 :
1953 : int
1954 371649452 : MSLCM_LC2013::slowDownForBlocked(MSVehicle** blocked, int state) {
1955 : // if this vehicle is blocking someone in front, we maybe decelerate to let him in
1956 371649452 : if ((*blocked) != nullptr) {
1957 17332652 : double gap = (*blocked)->getPositionOnLane() - (*blocked)->getVehicleType().getLength() - myVehicle.getPositionOnLane() - myVehicle.getVehicleType().getMinGap();
1958 : #ifdef DEBUG_SLOW_DOWN
1959 : if (DEBUG_COND) {
1960 : std::cout << SIMTIME
1961 : << " veh=" << myVehicle.getID()
1962 : << " blocked=" << Named::getIDSecure(*blocked)
1963 : << " gap=" << gap
1964 : << "\n";
1965 : }
1966 : #endif
1967 17332652 : if (gap > POSITION_EPS) {
1968 : //const bool blockedWantsUrgentRight = (((*blocked)->getLaneChangeModel().getOwnState() & LCA_RIGHT != 0)
1969 : // && ((*blocked)->getLaneChangeModel().getOwnState() & LCA_URGENT != 0));
1970 :
1971 13391473 : if (myVehicle.getSpeed() < myVehicle.getCarFollowModel().getMaxDecel()
1972 : //|| blockedWantsUrgentRight // VARIANT_10 (helpblockedRight)
1973 : ) {
1974 11703694 : if ((*blocked)->getSpeed() < SUMO_const_haltingSpeed) {
1975 5738444 : state |= LCA_AMBACKBLOCKER_STANDING;
1976 : } else {
1977 5965250 : state |= LCA_AMBACKBLOCKER;
1978 : }
1979 23407388 : addLCSpeedAdvice(getCarFollowModel().followSpeed(
1980 11703694 : &myVehicle, myVehicle.getSpeed(),
1981 11703694 : gap - POSITION_EPS, (*blocked)->getSpeed(),
1982 11703694 : (*blocked)->getCarFollowModel().getMaxDecel()), false);
1983 :
1984 : //(*blocked) = 0; // VARIANT_14 (furtherBlock)
1985 : #ifdef DEBUG_SLOW_DOWN
1986 : if (DEBUG_COND) {
1987 : std::cout << SIMTIME
1988 : << " veh=" << myVehicle.getID()
1989 : << " slowing down for"
1990 : << " blocked=" << Named::getIDSecure(*blocked)
1991 : << " helpSpeed=" << myLCAccelerationAdvices.back().first
1992 : << "\n";
1993 : }
1994 : #endif
1995 : } /*else if ((*blocked)->getWaitingSeconds() > 30 && gap > myVehicle.getBrakeGap()) {
1996 : // experimental else-branch...
1997 :
1998 : state |= LCA_AMBACKBLOCKER;
1999 : addLCSpeedAdvice(getCarFollowModel().followSpeed(
2000 : &myVehicle, myVehicle.getSpeed(),
2001 : (gap - POSITION_EPS), (*blocked)->getSpeed(),
2002 : (*blocked)->getCarFollowModel().getMaxDecel()));
2003 : } */
2004 : }
2005 : }
2006 371649452 : return state;
2007 : }
2008 :
2009 :
2010 : void
2011 92758 : MSLCM_LC2013::adaptSpeedToPedestrians(const MSLane* lane, double& v) {
2012 92758 : if (lane->hasPedestrians()) {
2013 : #ifdef DEBUG_WANTS_CHANGE
2014 : if (DEBUG_COND) {
2015 : std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << "\n";
2016 : }
2017 : #endif
2018 19903 : PersonDist leader = lane->nextBlocking(myVehicle.getPositionOnLane(),
2019 19903 : myVehicle.getRightSideOnLane(), myVehicle.getRightSideOnLane() + myVehicle.getVehicleType().getWidth(),
2020 19903 : ceil(myVehicle.getSpeed() / myVehicle.getCarFollowModel().getMaxDecel()));
2021 19903 : if (leader.first != 0) {
2022 5978 : const double stopSpeed = myVehicle.getCarFollowModel().stopSpeed(&myVehicle, myVehicle.getSpeed(), leader.second - myVehicle.getVehicleType().getMinGap());
2023 10193 : v = MIN2(v, stopSpeed);
2024 : #ifdef DEBUG_WANTS_CHANGE
2025 : if (DEBUG_COND) {
2026 : std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2027 : }
2028 : #endif
2029 : }
2030 : }
2031 92758 : }
2032 :
2033 :
2034 : double
2035 612608 : MSLCM_LC2013::computeSpeedLat(double latDist, double& maneuverDist, bool urgent) const {
2036 612608 : double result = MSAbstractLaneChangeModel::computeSpeedLat(latDist, maneuverDist, urgent);
2037 : #ifdef DEBUG_WANTS_CHANGE
2038 : if (DEBUG_COND) {
2039 : std::cout << SIMTIME << " veh=" << myVehicle.getID() << " myLeftSpace=" << myLeftSpace << " latDist=" << latDist << " maneuverDist=" << maneuverDist << " result=" << result << "\n";
2040 : }
2041 : #endif
2042 612608 : if (myLeftSpace > POSITION_EPS || !urgent) {
2043 497561 : double speedBound = myMaxSpeedLatStanding + myMaxSpeedLatFactor * myVehicle.getSpeed();
2044 497561 : if (isChangingLanes()) {
2045 : speedBound = MAX2(LC_RESOLUTION_SPEED_LAT, speedBound);
2046 : }
2047 497561 : result = MAX2(-speedBound, MIN2(speedBound, result));
2048 : }
2049 612608 : return result;
2050 : }
2051 :
2052 :
2053 : double
2054 385820008 : MSLCM_LC2013::getSafetyFactor() const {
2055 385820008 : return 1 / myAssertive;
2056 : }
2057 :
2058 : double
2059 9111953 : MSLCM_LC2013::getOppositeSafetyFactor() const {
2060 9111953 : return myOppositeParam <= 0 ? std::numeric_limits<double>::max() : 1 / myOppositeParam;
2061 : }
2062 :
2063 : bool
2064 180904 : MSLCM_LC2013::saveBlockerLength(double length, double foeLeftSpace) {
2065 180904 : const bool canReserve = MSLCHelper::canSaveBlockerLength(myVehicle, length, myLeftSpace);
2066 180904 : if (!isOpposite() && (canReserve || myLeftSpace > foeLeftSpace)) {
2067 176209 : myLeadingBlockerLength = MAX2(length, myLeadingBlockerLength);
2068 : #ifdef DEBUG_SAVE_BLOCKER_LENGTH
2069 : if (DEBUG_COND) {
2070 : std::cout << SIMTIME << " saveBlockerLength veh=" << myVehicle.getID() << " canReserve=" << canReserve << " myLeftSpace=" << myLeftSpace << " foeLeftSpace=" << foeLeftSpace << "\n";
2071 : }
2072 : #endif
2073 176209 : if (myLeftSpace == 0 && foeLeftSpace < 0) {
2074 : // called from opposite overtaking, myLeftSpace must be initialized
2075 169711 : myLeftSpace = myVehicle.getBestLanes()[myVehicle.getLane()->getIndex()].length - myVehicle.getPositionOnLane();
2076 : }
2077 176209 : return true;
2078 : } else {
2079 : return false;
2080 : }
2081 : }
2082 :
2083 : std::string
2084 144 : MSLCM_LC2013::getParameter(const std::string& key) const {
2085 144 : if (key == toString(SUMO_ATTR_LCA_STRATEGIC_PARAM)) {
2086 36 : return toString(myStrategicParam);
2087 108 : } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
2088 36 : return toString(myCooperativeParam);
2089 72 : } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
2090 36 : return toString(mySpeedGainParam);
2091 36 : } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
2092 0 : return toString(myKeepRightParam);
2093 36 : } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
2094 0 : return toString(myOppositeParam);
2095 36 : } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
2096 0 : return toString(myLookaheadLeft);
2097 36 : } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
2098 0 : return toString(mySpeedGainRight);
2099 36 : } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
2100 0 : return toString(myAssertive);
2101 36 : } else if (key == toString(SUMO_ATTR_LCA_OVERTAKE_RIGHT)) {
2102 0 : return toString(myOvertakeRightParam);
2103 36 : } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
2104 0 : return toString(mySigma);
2105 36 : } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME)) {
2106 0 : return toString(myKeepRightAcceptanceTime);
2107 36 : } else if (key == toString(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR)) {
2108 0 : return toString(myOvertakeDeltaSpeedFactor);
2109 36 : } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
2110 0 : return toString(mySpeedGainLookahead);
2111 36 : } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT)) {
2112 0 : return toString(myRoundaboutBonus);
2113 36 : } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
2114 0 : return toString(myCooperativeSpeed);
2115 36 : } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
2116 0 : return toString(myMaxSpeedLatStanding);
2117 36 : } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
2118 0 : return toString(myMaxSpeedLatFactor);
2119 36 : } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
2120 0 : return toString(myMaxDistLatStanding);
2121 : // access to internal state for debugging in sumo-gui (not documented since it may change at any time)
2122 36 : } else if (key == "speedGainProbabilityRight") {
2123 0 : return toString(-mySpeedGainProbability);
2124 36 : } else if (key == "speedGainProbabilityLeft") {
2125 0 : return toString(mySpeedGainProbability);
2126 36 : } else if (key == "keepRightProbability") {
2127 0 : return toString(-myKeepRightProbability);
2128 36 : } else if (key == "lookAheadSpeed") {
2129 0 : return toString(myLookAheadSpeed);
2130 : // motivation relative to threshold
2131 36 : } else if (key == "speedGainRP") {
2132 0 : return toString(-mySpeedGainProbability / myChangeProbThresholdRight);
2133 36 : } else if (key == "speedGainLP") {
2134 0 : return toString(mySpeedGainProbability / myChangeProbThresholdLeft);
2135 36 : } else if (key == "keepRightP") {
2136 0 : return toString(myKeepRightProbability * myKeepRightParam / -myChangeProbThresholdRight);
2137 : }
2138 108 : throw InvalidArgument("Parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
2139 : }
2140 :
2141 :
2142 : void
2143 8085 : MSLCM_LC2013::setParameter(const std::string& key, const std::string& value) {
2144 : double doubleValue;
2145 : try {
2146 8085 : doubleValue = StringUtils::toDouble(value);
2147 0 : } catch (NumberFormatException&) {
2148 0 : throw InvalidArgument("Setting parameter '" + key + "' requires a number for laneChangeModel of type '" + toString(myModel) + "'");
2149 0 : }
2150 8085 : if (key == toString(SUMO_ATTR_LCA_STRATEGIC_PARAM)) {
2151 2783 : myStrategicParam = doubleValue;
2152 5302 : } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
2153 0 : myCooperativeParam = doubleValue;
2154 5302 : } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
2155 0 : mySpeedGainParam = doubleValue;
2156 5302 : } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
2157 0 : myKeepRightParam = doubleValue;
2158 5302 : } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
2159 0 : myOppositeParam = doubleValue;
2160 5302 : } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
2161 0 : myLookaheadLeft = doubleValue;
2162 5302 : } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
2163 0 : mySpeedGainRight = doubleValue;
2164 5302 : } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
2165 0 : myAssertive = doubleValue;
2166 5302 : } else if (key == toString(SUMO_ATTR_LCA_OVERTAKE_RIGHT)) {
2167 0 : myOvertakeRightParam = doubleValue;
2168 5302 : } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
2169 0 : mySigma = doubleValue;
2170 5302 : } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME)) {
2171 0 : myKeepRightAcceptanceTime = doubleValue;
2172 5302 : } else if (key == toString(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR)) {
2173 0 : myOvertakeDeltaSpeedFactor = doubleValue;
2174 5302 : } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
2175 2649 : mySpeedGainLookahead = doubleValue;
2176 2653 : } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT)) {
2177 0 : myRoundaboutBonus = doubleValue;
2178 2653 : } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
2179 0 : myCooperativeSpeed = doubleValue;
2180 2653 : } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
2181 0 : myMaxSpeedLatStanding = doubleValue;
2182 2653 : } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
2183 0 : myMaxSpeedLatFactor = doubleValue;
2184 2653 : } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
2185 0 : myMaxDistLatStanding = doubleValue;
2186 : // access to internal state
2187 2653 : } else if (key == "speedGainProbabilityRight") {
2188 0 : mySpeedGainProbability = -doubleValue;
2189 2653 : } else if (key == "speedGainProbabilityLeft") {
2190 0 : mySpeedGainProbability = doubleValue;
2191 2653 : } else if (key == "keepRightProbability") {
2192 0 : myKeepRightProbability = -doubleValue;
2193 2653 : } else if (key == "lookAheadSpeed") {
2194 0 : myLookAheadSpeed = doubleValue;
2195 : } else {
2196 7959 : throw InvalidArgument("Setting parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
2197 : }
2198 5432 : initDerivedParameters();
2199 5432 : }
2200 :
2201 :
2202 : /****************************************************************************/
|