1 package org.opentrafficsim.road.gtu.lane.tactical.lmrs;
2
3 import java.util.SortedSet;
4
5 import org.djunits.unit.DimensionlessUnit;
6 import org.djunits.value.vdouble.scalar.Acceleration;
7 import org.djunits.value.vdouble.scalar.Dimensionless;
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.djunits.value.vdouble.scalar.Speed;
10 import org.opentrafficsim.core.gtu.GTUException;
11 import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
12 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
13 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
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.perception.LanePerception;
18 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
19 import org.opentrafficsim.road.gtu.lane.perception.categories.DirectIntersectionPerception;
20 import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
21 import org.opentrafficsim.road.gtu.lane.perception.categories.IntersectionPerception;
22 import org.opentrafficsim.road.gtu.lane.perception.categories.NeighborsPerception;
23 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
24 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayConflict;
25 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
26 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUSimple;
27 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
28 import org.opentrafficsim.road.gtu.lane.tactical.util.ConflictUtil;
29 import org.opentrafficsim.road.gtu.lane.tactical.util.ConflictUtil.ConflictPlans;
30 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
31 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
32 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
33 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class IncentiveSpeedWithCourtesy implements VoluntaryIncentive
58 {
59
60
61 @Override
62 public final Desire determineDesire(final BehavioralCharacteristics behavioralCharacteristics,
63 final LanePerception perception, final CarFollowingModel carFollowingModel, final Desire mandatoryDesire,
64 final Desire voluntaryDesire) throws ParameterException, OperationalPlanException
65 {
66
67
68 double leftDist = perception.getPerceptionCategory(InfrastructurePerception.class)
69 .getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.LEFT).si;
70 double rightDist = perception.getPerceptionCategory(InfrastructurePerception.class)
71 .getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.RIGHT).si;
72
73
74 Speed vCur = anticipationSpeed(RelativeLane.CURRENT, behavioralCharacteristics, perception, carFollowingModel);
75 Speed vGain = behavioralCharacteristics.getParameter(LmrsParameters.VGAIN);
76
77
78 Dimensionless aGain;
79
80
81
82
83
84 Acceleration aCur = perception.getPerceptionCategory(EgoPerception.class).getAcceleration();
85 if (aCur.si > 0)
86 {
87 Acceleration a = behavioralCharacteristics.getParameter(ParameterTypes.A);
88 aGain = a.minus(aCur).divideBy(a);
89 }
90 else
91 {
92 aGain = new Dimensionless(1, DimensionlessUnit.SI);
93 }
94
95
96 Dimensionless dLeft;
97 if (leftDist > 0.0 && perception.getPerceptionCategory(InfrastructurePerception.class).getCrossSection()
98 .contains(RelativeLane.LEFT))
99 {
100 Speed vLeft = anticipationSpeed(RelativeLane.LEFT, behavioralCharacteristics, perception, carFollowingModel);
101 dLeft = aGain.multiplyBy(vLeft.minus(vCur)).divideBy(vGain);
102 }
103 else
104 {
105 dLeft = Dimensionless.ZERO;
106 }
107
108
109 Dimensionless dRight;
110 if (rightDist > 0.0 && perception.getPerceptionCategory(InfrastructurePerception.class).getCrossSection()
111 .contains(RelativeLane.RIGHT))
112 {
113 Speed vRight = anticipationSpeed(RelativeLane.RIGHT, behavioralCharacteristics, perception, carFollowingModel);
114 dRight = aGain.multiplyBy(vRight.minus(vCur)).divideBy(vGain);
115 }
116 else
117 {
118 dRight = Dimensionless.ZERO;
119 }
120
121
122 return new Desire(dLeft, dRight);
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136 private Speed anticipationSpeed(final RelativeLane lane, final BehavioralCharacteristics bc,
137 final LanePerception perception, final CarFollowingModel cfm) throws ParameterException, OperationalPlanException
138 {
139
140 SpeedLimitInfo sli = perception.getPerceptionCategory(InfrastructurePerception.class).getSpeedLimitProspect(lane)
141 .getSpeedLimitInfo(Length.ZERO);
142 Speed anticipationSpeed = cfm.desiredSpeed(bc, sli);
143 Speed desiredSpeed = new Speed(anticipationSpeed);
144 Length x0 = bc.getParameter(ParameterTypes.LOOKAHEAD);
145
146
147 if (perception.getPerceptionCategory(InfrastructurePerception.class).getCrossSection().contains(lane.getLeft()))
148 {
149 for (HeadwayGTU headwayGTU : perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(lane.getLeft()))
150 {
151
152 if (headwayGTU.isRightTurnIndicatorOn() && !lane.getLeft().equals(RelativeLane.CURRENT))
153 {
154 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayGTU);
155 }
156 }
157 }
158
159
160 if (perception.getPerceptionCategory(InfrastructurePerception.class).getCrossSection().contains(lane.getRight()))
161 {
162 for (HeadwayGTU headwayGTU : perception.getPerceptionCategory(NeighborsPerception.class)
163 .getLeaders(lane.getRight()))
164 {
165
166 if (headwayGTU.isLeftTurnIndicatorOn() && !lane.getRight().equals(RelativeLane.CURRENT))
167 {
168 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayGTU);
169 }
170 }
171 }
172
173
174 for (HeadwayGTU headwayGTU : perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(lane))
175 {
176 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayGTU);
177 }
178
179
180 if (perception.contains(DirectIntersectionPerception.class))
181 {
182 for (HeadwayConflict headwayConflict : perception.getPerceptionCategory(IntersectionPerception.class)
183 .getConflicts(lane))
184 {
185 Length vehicleLength = perception.getPerceptionCategory(EgoPerception.class).getLength();
186 Speed speed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
187 SortedSet<HeadwayGTU> leaders = perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(lane);
188 if (!headwayConflict.getConflictType().isCrossing())
189 {
190
191 SortedSet<HeadwayGTU> conflictVehicles = headwayConflict.getDownstreamConflictingGTUs();
192 if (!conflictVehicles.isEmpty() && conflictVehicles.first().isParallel())
193 {
194 HeadwayGTU conflictingGtu = conflictVehicles.first();
195 Length distance = headwayConflict.getDistance().plus(headwayConflict.getLength())
196 .plus(conflictingGtu.getOverlapRear());
197 HeadwayGTU leadingGtu;
198 try
199 {
200 leadingGtu = new HeadwayGTUSimple(conflictingGtu.getId(), conflictingGtu.getGtuType(), distance,
201 conflictingGtu.getLength());
202 }
203 catch (GTUException exception)
204 {
205 throw new OperationalPlanException("Could not create HeadwayGTUSimple for GTU on split.",
206 exception);
207 }
208 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, leadingGtu);
209 }
210 }
211 switch (headwayConflict.getConflictPriority())
212 {
213 case SPLIT:
214 {
215
216 break;
217 }
218 case PRIORITY:
219 {
220 if (ConflictUtil.stopForPriorityConflict(headwayConflict, leaders, speed, vehicleLength, bc,
221 new ConflictPlans()))
222 {
223 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayConflict);
224 }
225 break;
226 }
227 case GIVE_WAY:
228 {
229 Acceleration acceleration = perception.getPerceptionCategory(EgoPerception.class).getAcceleration();
230 if (ConflictUtil.stopForGiveWayConflict(headwayConflict, leaders, speed, acceleration, vehicleLength,
231 bc, sli, cfm))
232 {
233 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayConflict);
234 }
235 break;
236 }
237 case STOP:
238 {
239 Acceleration acceleration = perception.getPerceptionCategory(EgoPerception.class).getAcceleration();
240 if (ConflictUtil.stopForStopConflict(headwayConflict, leaders, speed, acceleration, vehicleLength, bc,
241 sli, cfm))
242 {
243 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayConflict);
244 }
245 break;
246 }
247 case ALL_STOP:
248 {
249 if (ConflictUtil.stopForAllStopConflict(headwayConflict, new ConflictPlans()))
250 {
251 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayConflict);
252 }
253 break;
254 }
255 default:
256 throw new RuntimeException(
257 "Conflict priority " + headwayConflict.getConflictPriority() + " is unknown.");
258 }
259 }
260 }
261
262 return anticipationSpeed;
263 }
264
265
266
267
268
269
270
271
272
273 private Speed anticipateSingle(final Speed anticipationSpeed, final Speed desiredSpeed, final Length x0,
274 final Headway headway)
275 {
276 Speed speed = headway.getSpeed() == null ? Speed.ZERO : headway.getSpeed();
277 if (speed.gt(anticipationSpeed) || headway.getDistance().gt(x0))
278 {
279 return anticipationSpeed;
280 }
281 Speed vSingle = Speed.interpolate(speed, desiredSpeed, headway.getDistance().si / x0.si);
282 return anticipationSpeed.lt(vSingle) ? anticipationSpeed : vSingle;
283 }
284
285
286 @Override
287 public final String toString()
288 {
289 return "IncentiveSpeedWithCourtesy";
290 }
291
292 }