1 package org.opentrafficsim.road.gtu.lane.tactical.util.lmrs;
2
3 import java.util.SortedSet;
4
5 import org.djunits.unit.AccelerationUnit;
6 import org.djunits.value.vdouble.scalar.Acceleration;
7 import org.djunits.value.vdouble.scalar.Duration;
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.djunits.value.vdouble.scalar.Speed;
10 import org.djutils.exceptions.Try;
11 import org.opentrafficsim.base.parameters.ParameterException;
12 import org.opentrafficsim.base.parameters.ParameterTypes;
13 import org.opentrafficsim.base.parameters.Parameters;
14 import org.opentrafficsim.core.gtu.perception.EgoPerception;
15 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
16 import org.opentrafficsim.core.network.LateralDirectionality;
17 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
18 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
19 import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
20 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
21 import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
22 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsPerception;
23 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
24 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGtu;
25 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneChange;
26 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
27 import org.opentrafficsim.road.gtu.lane.tactical.util.CarFollowingUtil;
28 import org.opentrafficsim.road.network.LaneChangeInfo;
29 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
30
31
32
33
34
35
36
37
38
39
40
41 public interface Synchronization extends LmrsParameters
42 {
43
44
45 Synchronization DEADEND = new Synchronization()
46 {
47 @Override
48 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
49 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
50 final LaneChange laneChange, final LateralDirectionality initiatedLaneChange)
51 throws ParameterException, OperationalPlanException
52 {
53 Acceleration a = Acceleration.POSITIVE_INFINITY;
54
55 Length remainingDist = Length.POSITIVE_INFINITY;
56 int dn = laneChange.isChangingLane() ? -1 : 0;
57 Length lcLength = laneChange.getMinimumLaneChangeDistance();
58 for (LaneChangeInfo lcInfo : perception.getPerceptionCategory(InfrastructurePerception.class)
59 .getPhysicalLaneChangeInfo(RelativeLane.CURRENT))
60 {
61
62
63
64 remainingDist = Length.min(remainingDist,
65 lcInfo.remainingDistance().minus(lcLength.times(lcInfo.numberOfLaneChanges() + dn)));
66 }
67 Speed speed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
68 Acceleration bCrit = params.getParameter(ParameterTypes.BCRIT);
69 remainingDist = remainingDist.minus(params.getParameter(ParameterTypes.S0));
70 if (remainingDist.le0())
71 {
72 if (speed.gt0())
73 {
74 a = Acceleration.min(a, bCrit.neg());
75 }
76 else
77 {
78 a = Acceleration.ONE;
79 }
80 }
81 else
82 {
83 Acceleration bMin = new Acceleration(.5 * speed.si * speed.si / remainingDist.si, AccelerationUnit.SI);
84 if (bMin.ge(bCrit))
85 {
86 a = Acceleration.min(a, bMin.neg());
87 }
88 }
89 return a;
90 }
91
92 @Override
93 public String toString()
94 {
95 return "DEADEND";
96 }
97 };
98
99
100 Synchronization PASSIVE = new Synchronization()
101 {
102 @Override
103 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
104 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
105 final LaneChange laneChange, final LateralDirectionality initiatedLaneChange)
106 throws ParameterException, OperationalPlanException
107 {
108 Acceleration a =
109 DEADEND.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, laneChange, initiatedLaneChange);
110 if (a.lt(params.getParameter(ParameterTypes.BCRIT).neg()))
111 {
112 return a;
113 }
114 double dCoop = params.getParameter(DCOOP);
115 RelativeLane relativeLane = new RelativeLane(lat, 1);
116
117 PerceptionCollectable<HeadwayGtu, LaneBasedGtu> set =
118 perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(relativeLane);
119 HeadwayGtu leader = null;
120 if (set != null)
121 {
122 if (desire >= dCoop && !set.isEmpty())
123 {
124 leader = set.first();
125 }
126 else
127 {
128 for (HeadwayGtu gtu : set)
129 {
130 if (gtu.getSpeed().gt0())
131 {
132 leader = gtu;
133 break;
134 }
135 }
136 }
137 }
138 Speed ownSpeed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
139 if (leader != null)
140 {
141 Length headway = headwayWithLcSpace(leader, params, laneChange);
142 Acceleration aSingle =
143 LmrsUtil.singleAcceleration(headway, ownSpeed, leader.getSpeed(), desire, params, sli, cfm);
144 a = Acceleration.min(a, aSingle);
145 a = gentleUrgency(a, desire, params);
146 }
147
148 PerceptionCollectable<HeadwayGtu, LaneBasedGtu> leaders =
149 perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(RelativeLane.CURRENT);
150 if (!leaders.isEmpty() && leaders.first().getSpeed().lt(params.getParameter(ParameterTypes.VCONG)))
151 {
152 Length headway = leaders.first().getDistance().minus(laneChange.getMinimumLaneChangeDistance());
153 Acceleration aSingle =
154 LmrsUtil.singleAcceleration(headway, ownSpeed, leaders.first().getSpeed(), desire, params, sli, cfm);
155 aSingle = gentleUrgency(aSingle, desire, params);
156 a = Acceleration.min(a, aSingle);
157 }
158
159
160 Length xMerge =
161 getMergeDistance(perception, lat).minus(perception.getPerceptionCategory(EgoPerception.class).getLength());
162 if (xMerge.gt0())
163 {
164 Acceleration aMerge = LmrsUtil.singleAcceleration(xMerge, ownSpeed, Speed.ZERO, desire, params, sli, cfm);
165 a = Acceleration.max(a, aMerge);
166 }
167 return a;
168 }
169
170 @Override
171 public String toString()
172 {
173 return "PASSIVE";
174 }
175 };
176
177
178
179
180
181
182
183 Synchronization ALIGN_GAP = new Synchronization()
184 {
185 @Override
186 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
187 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
188 final LaneChange laneChange, final LateralDirectionality initiatedLaneChange)
189 throws ParameterException, OperationalPlanException
190 {
191 Acceleration a = Acceleration.POSITIVE_INFINITY;
192 EgoPerception<?, ?> ego = perception.getPerceptionCategory(EgoPerception.class);
193 Speed ownSpeed = ego.getSpeed();
194 RelativeLane relativeLane = new RelativeLane(lat, 1);
195 PerceptionCollectable<HeadwayGtu, LaneBasedGtu> leaders =
196 perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(relativeLane);
197 if (!leaders.isEmpty())
198 {
199 HeadwayGtu leader = leaders.first();
200 Length gap = leader.getDistance();
201 LmrsUtil.setDesiredHeadway(params, desire);
202 PerceptionCollectable<HeadwayGtu, LaneBasedGtu> followers =
203 perception.getPerceptionCategory(NeighborsPerception.class).getFollowers(relativeLane);
204 if (!followers.isEmpty())
205 {
206 HeadwayGtu follower = followers.first();
207 Length netGap = leader.getDistance().plus(follower.getDistance()).times(0.5);
208 gap = Length.max(gap, leader.getDistance().minus(netGap).plus(cfm.desiredHeadway(params, ownSpeed)));
209 }
210 a = CarFollowingUtil.followSingleLeader(cfm, params, ownSpeed, sli, gap, leader.getSpeed());
211 LmrsUtil.resetDesiredHeadway(params);
212
213 a = gentleUrgency(a, desire, params);
214 }
215 a = Acceleration.min(a,
216 DEADEND.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, laneChange, initiatedLaneChange));
217
218 Length xMerge = getMergeDistance(perception, lat);
219 if (xMerge.gt0())
220 {
221 Acceleration aMerge = LmrsUtil.singleAcceleration(xMerge, ownSpeed, Speed.ZERO, desire, params, sli, cfm);
222 a = Acceleration.max(a, aMerge);
223 }
224 return a;
225 }
226
227 @Override
228 public String toString()
229 {
230 return "ALIGN_GAP";
231 }
232 };
233
234
235 Synchronization PASSIVE_MOVING = new Synchronization()
236 {
237 @Override
238 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
239 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
240 final LaneChange laneChange, final LateralDirectionality initiatedLaneChange)
241 throws ParameterException, OperationalPlanException
242 {
243 double dCoop = params.getParameter(DCOOP);
244 Speed ownSpeed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
245 if (desire < dCoop && ownSpeed.si < params.getParameter(ParameterTypes.LOOKAHEAD).si
246 / params.getParameter(ParameterTypes.T0).si)
247 {
248 return DEADEND.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, laneChange,
249 initiatedLaneChange);
250 }
251 return PASSIVE.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, laneChange, initiatedLaneChange);
252 }
253
254 @Override
255 public String toString()
256 {
257 return "PASSIVE_MOVING";
258 }
259 };
260
261
262 Synchronization ACTIVE = new Synchronization()
263 {
264 @Override
265 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
266 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
267 final LaneChange laneChange, final LateralDirectionality initiatedLaneChange)
268 throws ParameterException, OperationalPlanException
269 {
270
271 Acceleration b = params.getParameter(ParameterTypes.B);
272 Duration tMin = params.getParameter(ParameterTypes.TMIN);
273 Duration tMax = params.getParameter(ParameterTypes.TMAX);
274 Speed vCong = params.getParameter(ParameterTypes.VCONG);
275 Length x0 = params.getParameter(ParameterTypes.LOOKAHEAD);
276 Duration t0 = params.getParameter(ParameterTypes.T0);
277 Duration lc = params.getParameter(ParameterTypes.LCDUR);
278 Speed tagSpeed = x0.divide(t0);
279 double dCoop = params.getParameter(DCOOP);
280 EgoPerception<?, ?> ego = perception.getPerceptionCategory(EgoPerception.class);
281 Speed ownSpeed = ego.getSpeed();
282 Length ownLength = ego.getLength();
283 Length dx = perception.getGtu().getFront().dx();
284
285
286 InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
287 SortedSet<LaneChangeInfo> info = infra.getLegalLaneChangeInfo(RelativeLane.CURRENT);
288
289
290 Length xMerge = getMergeDistance(perception, lat);
291 int nCur = 0;
292 Length xCur = Length.POSITIVE_INFINITY;
293 for (LaneChangeInfo lcInfo : info)
294 {
295 int nCurTmp = lcInfo.numberOfLaneChanges();
296
297 Length xCurTmp = lcInfo.remainingDistance().minus(ownLength.times(2.0 * nCurTmp)).minus(dx);
298 if (xCurTmp.lt(xCur))
299 {
300 nCur = nCurTmp;
301 xCur = xCurTmp;
302 }
303 }
304
305
306
307 Length xMergeSync = xCur.minus(Length.instantiateSI(.5 * ownSpeed.si * ownSpeed.si / b.si));
308 xMergeSync = Length.min(xMerge, xMergeSync);
309
310
311 NeighborsPerception neighbors = perception.getPerceptionCategory(NeighborsPerception.class);
312 RelativeLane lane = new RelativeLane(lat, 1);
313 PerceptionCollectable<HeadwayGtu, LaneBasedGtu> leaders = neighbors.getLeaders(lane);
314 HeadwayGtu syncVehicle = lmrsData.getSyncVehicle(leaders);
315 if (syncVehicle != null && ((syncVehicle.getSpeed().lt(vCong) && syncVehicle.getDistance().lt(xMergeSync))
316 || syncVehicle.getDistance().gt(xCur)))
317 {
318 syncVehicle = null;
319 }
320
321
322 if (leaders != null && syncVehicle == null)
323 {
324 Length maxDistance = Length.min(x0, xCur);
325 for (HeadwayGtu leader : leaders)
326 {
327 if (leader.getDistance().lt(maxDistance))
328 {
329 if ((leader.getDistance().gt(xMergeSync) || leader.getSpeed().gt(vCong))
330 && tagAlongAcceleration(leader, ownSpeed, ownLength, tagSpeed, desire, params, sli, cfm)
331 .gt(b.neg()))
332 {
333 syncVehicle = leader;
334 break;
335 }
336 }
337 else
338 {
339 break;
340 }
341 }
342 }
343
344
345 HeadwayGtu up;
346 PerceptionCollectable<HeadwayGtu, LaneBasedGtu> followers = neighbors.getFollowers(lane);
347 HeadwayGtu follower = followers == null || followers.isEmpty() ? null
348 : followers.first().moved(
349 followers.first().getDistance().plus(ownLength).plus(followers.first().getLength()).neg(),
350 followers.first().getSpeed(), followers.first().getAcceleration());
351 boolean upOk;
352 if (syncVehicle == null)
353 {
354 up = null;
355 upOk = false;
356 }
357 else
358 {
359 up = getFollower(syncVehicle, leaders, follower, ownLength);
360 upOk = up == null ? false
361 : tagAlongAcceleration(up, ownSpeed, ownLength, tagSpeed, desire, params, sli, cfm).gt(b.neg());
362 }
363 while (syncVehicle != null
364 && up != null && (upOk || (!canBeAhead(up, xCur, nCur, ownSpeed, ownLength, tagSpeed, dCoop, b, tMin, tMax,
365 x0, t0, lc, desire) && desire > dCoop))
366 && (up.getDistance().gt(xMergeSync) || up.getSpeed().gt(vCong)))
367 {
368 if (up.equals(follower))
369 {
370
371 syncVehicle = null;
372 up = null;
373 break;
374 }
375 syncVehicle = up;
376 up = getFollower(syncVehicle, leaders, follower, ownLength);
377 upOk = up == null ? false
378 : tagAlongAcceleration(up, ownSpeed, ownLength, tagSpeed, desire, params, sli, cfm).gt(b.neg());
379 }
380 lmrsData.setSyncVehicle(syncVehicle);
381
382
383 Acceleration a =
384 DEADEND.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, laneChange, initiatedLaneChange);
385 if (syncVehicle != null)
386 {
387 a = gentleUrgency(tagAlongAcceleration(syncVehicle, ownSpeed, ownLength, tagSpeed, desire, params, sli, cfm),
388 desire, params);
389 }
390 else if (nCur > 0 && (follower != null || (leaders != null && !leaders.isEmpty())))
391 {
392
393 if (follower != null && !canBeAhead(follower, xCur, nCur, ownSpeed, ownLength, tagSpeed, dCoop, b, tMin, tMax,
394 x0, t0, lc, desire))
395 {
396
397 double c = requiredBufferSpace(ownSpeed, nCur, x0, t0, lc, dCoop).si;
398 double t = (xCur.si - follower.getDistance().si - c) / follower.getSpeed().si;
399 double xGap = ownSpeed.si * (tMin.si + desire * (tMax.si - tMin.si));
400 Acceleration acc = Acceleration.instantiateSI(2 * (xCur.si - c - ownSpeed.si * t - xGap) / (t * t));
401 if (follower.getSpeed().eq0() || acc.si < -ownSpeed.si / t || t < 0)
402 {
403
404
405 a = stopForEnd(xCur, xMerge, params, ownSpeed, cfm, sli);
406 }
407 else
408 {
409 a = gentleUrgency(acc, desire, params);
410 }
411 }
412 else if (!LmrsUtil.acceptLaneChange(perception, params, sli, cfm, desire, ownSpeed, Acceleration.ZERO, lat,
413 lmrsData.getGapAcceptance(), laneChange))
414 {
415 a = stopForEnd(xCur, xMerge, params, ownSpeed, cfm, sli);
416
417 if (leaders != null && !leaders.isEmpty())
418 {
419 double c = requiredBufferSpace(ownSpeed, nCur, x0, t0, lc, dCoop).si;
420 double t = (xCur.si - leaders.first().getDistance().si - c) / leaders.first().getSpeed().si;
421 double xGap = ownSpeed.si * (tMin.si + desire * (tMax.si - tMin.si));
422 Acceleration acc = Acceleration.instantiateSI(2 * (xCur.si - c - ownSpeed.si * t - xGap) / (t * t));
423 if (!(leaders.first().getSpeed().eq0() || acc.si < -ownSpeed.si / t || t < 0))
424 {
425 a = Acceleration.max(a, acc);
426 }
427 }
428 }
429 }
430
431
432 if (nCur > 1)
433 {
434 if (xMerge.gt0())
435 {
436
437 Speed vMerge = xCur.lt(xMerge) ? Speed.ZERO
438 : xCur.minus(xMerge).divide(t0.times((1 - dCoop) * (nCur - 1)).plus(lc));
439 vMerge = Speed.max(vMerge, x0.divide(t0));
440 a = Acceleration.min(a, CarFollowingUtil.approachTargetSpeed(cfm, params, ownSpeed, sli, xMerge, vMerge));
441 }
442 else
443 {
444
445 Length c = requiredBufferSpace(ownSpeed, nCur, x0, t0, lc, dCoop);
446 if (xCur.lt(c))
447 {
448 a = Acceleration.min(a, b.neg());
449 }
450 }
451 }
452 return a;
453 }
454
455 @Override
456 public String toString()
457 {
458 return "ACTIVE";
459 }
460 };
461
462
463
464
465
466
467
468
469 public static Length getMergeDistance(final LanePerception perception, final LateralDirectionality lat)
470 throws OperationalPlanException
471 {
472 InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
473 Length dx = Try.assign(() -> perception.getGtu().getFront().dx(), "Could not obtain GTU.");
474 Length xMergeRef = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, lat);
475 if (xMergeRef.gt0() && xMergeRef.lt(dx))
476 {
477 return Length.ZERO;
478 }
479 Length xMerge = xMergeRef.minus(dx);
480 return xMerge.lt0() ? xMerge.neg() : Length.ZERO;
481 }
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498 Acceleration synchronize(LanePerception perception, Parameters params, SpeedLimitInfo sli, CarFollowingModel cfm,
499 double desire, LateralDirectionality lat, LmrsData lmrsData, LaneChange laneChange,
500 LateralDirectionality initiatedLaneChange) throws ParameterException, OperationalPlanException;
501
502
503
504
505
506
507
508
509
510 static Length headwayWithLcSpace(final Headway headway, final Parameters parameters, final LaneChange laneChange)
511 throws ParameterException
512 {
513 if (headway.getSpeed().gt(parameters.getParameter(ParameterTypes.VCONG)))
514 {
515 return headway.getDistance();
516 }
517 return headway.getDistance().minus(laneChange.getMinimumLaneChangeDistance());
518 }
519
520
521
522
523
524
525
526
527
528
529 static Acceleration gentleUrgency(final Acceleration a, final double desire, final Parameters params)
530 throws ParameterException
531 {
532 Acceleration b = params.getParameter(ParameterTypes.B);
533 if (a.si > -b.si)
534 {
535 return a;
536 }
537 double dCoop = params.getParameter(DCOOP);
538 if (desire < dCoop)
539 {
540 return b.neg();
541 }
542 Acceleration bCrit = params.getParameter(ParameterTypes.BCRIT);
543 double f = (desire - dCoop) / (1.0 - dCoop);
544 Acceleration lim = Acceleration.interpolate(b.neg(), bCrit.neg(), f);
545 return Acceleration.max(a, lim);
546 }
547
548
549
550
551
552
553
554
555
556 static HeadwayGtu getFollower(final HeadwayGtu gtu, final PerceptionCollectable<HeadwayGtu, LaneBasedGtu> leaders,
557 final HeadwayGtu follower, final Length ownLength)
558 {
559 HeadwayGtu last = null;
560 for (HeadwayGtu leader : leaders)
561 {
562 if (leader.equals(gtu))
563 {
564 return last == null ? follower : last;
565 }
566 last = leader;
567 }
568 return null;
569 }
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584 @SuppressWarnings("checkstyle:parameternumber")
585 static Acceleration tagAlongAcceleration(final HeadwayGtu leader, final Speed followerSpeed, final Length followerLength,
586 final Speed tagSpeed, final double desire, final Parameters params, final SpeedLimitInfo sli,
587 final CarFollowingModel cfm) throws ParameterException
588 {
589 double dCoop = params.getParameter(DCOOP);
590 double tagV = followerSpeed.lt(tagSpeed) ? 1.0 - followerSpeed.si / tagSpeed.si : 0.0;
591 double tagD = desire <= dCoop ? 1.0 : 1.0 - (desire - dCoop) / (1.0 - dCoop);
592 double tagExtent = tagV < tagD ? tagV : tagD;
593
594
595
596
597
598
599
600
601
602
603
604 Length headwayAdjustment = params.getParameter(ParameterTypes.S0)
605 .plus(Length.min(followerLength, leader.getLength()).times(0.5)).times(tagExtent);
606 Acceleration a = LmrsUtil.singleAcceleration(leader.getDistance().plus(headwayAdjustment), followerSpeed,
607 leader.getSpeed(), desire, params, sli, cfm);
608 return a;
609 }
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630 static boolean canBeAhead(final HeadwayGtu adjacentVehicle, final Length xCur, final int nCur, final Speed ownSpeed,
631 final Length ownLength, final Speed tagSpeed, final double dCoop, final Acceleration b, final Duration tMin,
632 final Duration tMax, final Length x0, final Duration t0, final Duration lc, final double desire)
633 throws ParameterException
634 {
635
636
637 boolean tmp = LmrsUtil
638 .singleAcceleration(adjacentVehicle.getDistance().neg().minus(adjacentVehicle.getLength()).minus(ownLength),
639 adjacentVehicle.getSpeed(), ownSpeed, desire, adjacentVehicle.getParameters(),
640 adjacentVehicle.getSpeedLimitInfo(), adjacentVehicle.getCarFollowingModel())
641 .gt(b.neg());
642 if (adjacentVehicle.getDistance().lt(ownLength.neg())
643 && ((desire > dCoop && tmp) || (ownSpeed.lt(tagSpeed) && adjacentVehicle.getSpeed().lt(tagSpeed))))
644 {
645 return true;
646 }
647
648
649
650
651
652
653
654
655
656
657
658
659
660 Length c = requiredBufferSpace(ownSpeed, nCur, x0, t0, lc, dCoop);
661 double t = (xCur.si - c.si) / ownSpeed.si;
662 double xGap = adjacentVehicle.getSpeed().si * (tMin.si + desire * (tMax.si - tMin.si));
663 return 0.0 < t && t < (xCur.si - adjacentVehicle.getDistance().si - ownLength.si - adjacentVehicle.getLength().si - c.si
664 - xGap) / adjacentVehicle.getSpeed().si;
665 }
666
667
668
669
670
671
672
673
674
675
676
677 static Length requiredBufferSpace(final Speed speed, final int nCur, final Length x0, final Duration t0, final Duration lc,
678 final double dCoop)
679 {
680 Length xCrit = speed.times(t0);
681 xCrit = Length.max(xCrit, x0);
682 return speed.times(lc).plus(xCrit.times((nCur - 1.0) * (1.0 - dCoop)));
683 }
684
685
686
687
688
689
690
691
692
693
694
695
696 static Acceleration stopForEnd(final Length xCur, final Length xMerge, final Parameters params, final Speed ownSpeed,
697 final CarFollowingModel cfm, final SpeedLimitInfo sli) throws ParameterException
698 {
699 if (xCur.lt0())
700 {
701
702 return Acceleration.max(params.getParameter(ParameterTypes.BCRIT).neg(),
703 CarFollowingUtil.stop(cfm, params, ownSpeed, sli, xMerge));
704 }
705 LmrsUtil.setDesiredHeadway(params, 1.0);
706 Acceleration a = CarFollowingUtil.stop(cfm, params, ownSpeed, sli, xCur);
707 if (a.lt0())
708 {
709
710 a = Acceleration.min(a, params.getParameter(ParameterTypes.B).neg());
711
712 if (xMerge.gt0())
713 {
714 a = Acceleration.max(a, CarFollowingUtil.stop(cfm, params, ownSpeed, sli, xMerge));
715 }
716 }
717 else
718 {
719 a = Acceleration.POSITIVE_INFINITY;
720 }
721 LmrsUtil.resetDesiredHeadway(params);
722 return a;
723 }
724
725
726
727
728
729
730
731 static HeadwayGtu getTargetLeader(final HeadwayGtu gtu, final SortedSet<HeadwayGtu> leaders)
732 {
733 for (HeadwayGtu leader : leaders)
734 {
735 if (leader.getDistance().gt(gtu.getDistance()))
736 {
737 return leader;
738 }
739 }
740 return null;
741 }
742
743 }