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 if (perception.getPerceptionCategory(InfrastructurePerception.class).getLegalLaneChangePossibility(RelativeLane.CURRENT,
69 LateralDirectionality.LEFT).si == 0
70 && perception.getPerceptionCategory(InfrastructurePerception.class)
71 .getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.RIGHT).si == 0)
72 {
73 return new Desire(0, 0);
74 }
75
76
77 Speed vCur = anticipationSpeed(RelativeLane.CURRENT, behavioralCharacteristics, perception, carFollowingModel);
78 Speed vGain = behavioralCharacteristics.getParameter(LmrsParameters.VGAIN);
79
80
81 Dimensionless aGain;
82
83
84
85
86
87 Acceleration aCur = perception.getPerceptionCategory(EgoPerception.class).getAcceleration();
88
89
90
91
92
93
94 if (aCur.si > 0)
95 {
96 Acceleration a = behavioralCharacteristics.getParameter(ParameterTypes.A);
97 aGain = a.minus(aCur).divideBy(a);
98 }
99 else
100 {
101 aGain = new Dimensionless(1, DimensionlessUnit.SI);
102 }
103
104
105 Dimensionless dLeft;
106 if (perception.getPerceptionCategory(InfrastructurePerception.class).getCrossSection().contains(RelativeLane.LEFT))
107 {
108 Speed vLeft = anticipationSpeed(RelativeLane.LEFT, behavioralCharacteristics, perception, carFollowingModel);
109 dLeft = aGain.multiplyBy(vLeft.minus(vCur)).divideBy(vGain);
110 }
111 else
112 {
113 dLeft = Dimensionless.ZERO;
114 }
115
116
117 Dimensionless dRight;
118 if (perception.getPerceptionCategory(InfrastructurePerception.class).getCrossSection().contains(RelativeLane.RIGHT))
119 {
120 Speed vRight = anticipationSpeed(RelativeLane.RIGHT, behavioralCharacteristics, perception, carFollowingModel);
121 dRight = aGain.multiplyBy(vRight.minus(vCur)).divideBy(vGain);
122 }
123 else
124 {
125 dRight = Dimensionless.ZERO;
126 }
127
128
129 return new Desire(dLeft, dRight);
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143 private Speed anticipationSpeed(final RelativeLane lane, final BehavioralCharacteristics bc,
144 final LanePerception perception, final CarFollowingModel cfm) throws ParameterException, OperationalPlanException
145 {
146
147 SpeedLimitInfo sli = perception.getPerceptionCategory(InfrastructurePerception.class).getSpeedLimitProspect(lane)
148 .getSpeedLimitInfo(Length.ZERO);
149 Speed anticipationSpeed = cfm.desiredSpeed(bc, sli);
150 Speed desiredSpeed = new Speed(anticipationSpeed);
151 Length x0 = bc.getParameter(ParameterTypes.LOOKAHEAD);
152
153
154 if (perception.getPerceptionCategory(InfrastructurePerception.class).getCrossSection().contains(lane.getLeft()))
155 {
156 for (HeadwayGTU headwayGTU : perception.getPerceptionCategory(NeighborsPerception.class)
157 .getLeaders(lane.getLeft()))
158 {
159
160 if (headwayGTU.isRightTurnIndicatorOn() && !lane.getLeft().equals(RelativeLane.CURRENT))
161 {
162 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayGTU);
163 }
164 }
165 }
166
167
168 if (perception.getPerceptionCategory(InfrastructurePerception.class).getCrossSection().contains(lane.getRight()))
169 {
170 for (HeadwayGTU headwayGTU : perception.getPerceptionCategory(NeighborsPerception.class)
171 .getLeaders(lane.getRight()))
172 {
173
174 if (headwayGTU.isLeftTurnIndicatorOn() && !lane.getRight().equals(RelativeLane.CURRENT))
175 {
176 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayGTU);
177 }
178 }
179 }
180
181
182 for (HeadwayGTU headwayGTU : perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(lane))
183 {
184 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayGTU);
185 }
186
187
188 if (perception.contains(DirectIntersectionPerception.class))
189 {
190 for (HeadwayConflict headwayConflict : perception.getPerceptionCategory(IntersectionPerception.class)
191 .getConflicts(lane))
192 {
193 Length vehicleLength = perception.getPerceptionCategory(EgoPerception.class).getLength();
194 Speed speed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
195 SortedSet<HeadwayGTU> leaders =
196 perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(lane);
197 if (!headwayConflict.getConflictType().isCrossing())
198 {
199
200 SortedSet<HeadwayGTU> conflictVehicles = headwayConflict.getDownstreamConflictingGTUs();
201 if (!conflictVehicles.isEmpty() && conflictVehicles.first().isParallel())
202 {
203 HeadwayGTU conflictingGtu = conflictVehicles.first();
204 Length distance = headwayConflict.getDistance().plus(headwayConflict.getLength())
205 .plus(conflictingGtu.getOverlapRear());
206 HeadwayGTU leadingGtu;
207 try
208 {
209 leadingGtu = new HeadwayGTUSimple(conflictingGtu.getId(), conflictingGtu.getGtuType(), distance,
210 conflictingGtu.getLength());
211 }
212 catch (GTUException exception)
213 {
214 throw new OperationalPlanException("Could not create HeadwayGTUSimple for GTU on split.",
215 exception);
216 }
217 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, leadingGtu);
218 }
219 }
220 switch (headwayConflict.getConflictPriority())
221 {
222 case SPLIT:
223 {
224
225 break;
226 }
227 case PRIORITY:
228 {
229 if (ConflictUtil.stopForPriorityConflict(headwayConflict, leaders, speed, vehicleLength, bc,
230 new ConflictPlans()))
231 {
232 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayConflict);
233 }
234 break;
235 }
236 case GIVE_WAY:
237 {
238 Acceleration acceleration = perception.getPerceptionCategory(EgoPerception.class).getAcceleration();
239 if (ConflictUtil.stopForGiveWayConflict(headwayConflict, leaders, speed, acceleration, vehicleLength,
240 bc, sli, cfm))
241 {
242 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayConflict);
243 }
244 break;
245 }
246 case STOP:
247 {
248 Acceleration acceleration = perception.getPerceptionCategory(EgoPerception.class).getAcceleration();
249 if (ConflictUtil.stopForStopConflict(headwayConflict, leaders, speed, acceleration, vehicleLength, bc,
250 sli, cfm))
251 {
252 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayConflict);
253 }
254 break;
255 }
256 case ALL_STOP:
257 {
258 if (ConflictUtil.stopForAllStopConflict(headwayConflict, new ConflictPlans()))
259 {
260 anticipationSpeed = anticipateSingle(anticipationSpeed, desiredSpeed, x0, headwayConflict);
261 }
262 break;
263 }
264 default:
265 throw new RuntimeException(
266 "Conflict priority " + headwayConflict.getConflictPriority() + " is unknown.");
267 }
268 }
269 }
270
271 return anticipationSpeed;
272 }
273
274
275
276
277
278
279
280
281
282 private Speed anticipateSingle(final Speed anticipationSpeed, final Speed desiredSpeed, final Length x0,
283 final Headway headway)
284 {
285 Speed speed = headway.getSpeed() == null ? Speed.ZERO : headway.getSpeed();
286 if (speed.gt(anticipationSpeed) || headway.getDistance().gt(x0))
287 {
288 return anticipationSpeed;
289 }
290 Speed vSingle = Speed.interpolate(speed, desiredSpeed, headway.getDistance().si / x0.si);
291 return anticipationSpeed.lt(vSingle) ? anticipationSpeed : vSingle;
292 }
293
294
295 @Override
296 public final String toString()
297 {
298 return "IncentiveSpeedWithCourtesy";
299 }
300
301 }