1 package org.opentrafficsim.road.gtu.lane.changing;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.opentrafficsim.road.gtu.lane.RoadGTUTypes.CAR;
5
6 import java.util.Collection;
7 import java.util.HashSet;
8 import java.util.LinkedHashMap;
9 import java.util.LinkedHashSet;
10 import java.util.Map;
11 import java.util.Set;
12
13 import javax.naming.NamingException;
14
15 import org.djunits.unit.LengthUnit;
16 import org.djunits.unit.TimeUnit;
17 import org.djunits.unit.UNITS;
18 import org.djunits.value.vdouble.scalar.Acceleration;
19 import org.djunits.value.vdouble.scalar.Duration;
20 import org.djunits.value.vdouble.scalar.Length;
21 import org.djunits.value.vdouble.scalar.Speed;
22 import org.djunits.value.vdouble.scalar.Time;
23 import org.junit.Test;
24 import org.opentrafficsim.core.dsol.OTSModelInterface;
25 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
26 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
27 import org.opentrafficsim.core.geometry.OTSGeometryException;
28 import org.opentrafficsim.core.geometry.OTSLine3D;
29 import org.opentrafficsim.core.geometry.OTSPoint3D;
30 import org.opentrafficsim.core.gtu.GTUDirectionality;
31 import org.opentrafficsim.core.gtu.GTUType;
32 import org.opentrafficsim.core.gtu.RelativePosition;
33 import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
34 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
35 import org.opentrafficsim.core.network.LateralDirectionality;
36 import org.opentrafficsim.core.network.LinkType;
37 import org.opentrafficsim.core.network.LongitudinalDirectionality;
38 import org.opentrafficsim.core.network.Network;
39 import org.opentrafficsim.core.network.NetworkException;
40 import org.opentrafficsim.core.network.OTSNetwork;
41 import org.opentrafficsim.core.network.OTSNode;
42 import org.opentrafficsim.road.DefaultTestParameters;
43 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
44 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
45 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUSimple;
46 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCFLCTacticalPlanner;
47 import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM;
48 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
49 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.AbstractLaneChangeModel;
50 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Altruistic;
51 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
52 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneMovementStep;
53 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
54 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
55 import org.opentrafficsim.road.network.lane.CrossSectionLink;
56 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
57 import org.opentrafficsim.road.network.lane.Lane;
58 import org.opentrafficsim.road.network.lane.LaneType;
59 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
60 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
61 import org.opentrafficsim.simulationengine.SimpleSimulator;
62
63 import mockit.MockUp;
64 import nl.tudelft.simulation.dsol.SimRuntimeException;
65 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
66
67
68
69
70
71
72
73
74
75
76
77 public class LaneChangeModelTest implements OTSModelInterface, UNITS
78 {
79
80 private static final long serialVersionUID = 20150313;
81
82
83 private OTSNetwork network = new OTSNetwork("lane change model test network");
84
85
86
87
88
89
90
91
92
93
94
95
96
97 private static CrossSectionLink makeLink(final Network network, final String name, final OTSNode from, final OTSNode to,
98 final Length width) throws OTSGeometryException, NetworkException
99 {
100
101
102
103 OTSSimulatorInterface simulator = new MockUp<OTSSimulatorInterface>()
104 {
105
106 }.getMockInstance();
107 OTSPoint3D[] coordinates = new OTSPoint3D[] { new OTSPoint3D(from.getPoint().x, from.getPoint().y, 0),
108 new OTSPoint3D(to.getPoint().x, to.getPoint().y, 0) };
109 OTSLine3D line = new OTSLine3D(coordinates);
110 CrossSectionLink link = new CrossSectionLink(network, name, from, to, LinkType.ALL, line, simulator,
111 LongitudinalDirectionality.DIR_PLUS, LaneKeepingPolicy.KEEP_RIGHT);
112 return link;
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127 private static Lane makeLane(final CrossSectionLink link, final String id, final LaneType laneType, final Length latPos,
128 final Length width) throws NamingException, NetworkException, OTSGeometryException
129 {
130 Map<GTUType, LongitudinalDirectionality> directionalityMap = new LinkedHashMap<>();
131 directionalityMap.put(GTUType.ALL, LongitudinalDirectionality.DIR_PLUS);
132 Map<GTUType, Speed> speedMap = new LinkedHashMap<>();
133 speedMap.put(GTUType.ALL, new Speed(100, KM_PER_HOUR));
134
135 Lane result = new Lane(link, id, latPos, latPos, width, width, laneType, directionalityMap, speedMap,
136 new OvertakingConditions.LeftAndRight());
137 return result;
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151 public static Lane[] makeMultiLane(final Network network, final String name, final OTSNode from, final OTSNode to,
152 final LaneType laneType, final int laneCount) throws Exception
153 {
154 Length width = new Length(laneCount * 4.0, METER);
155 final CrossSectionLink link = makeLink(network, name, from, to, width);
156 Lane[] result = new Lane[laneCount];
157 width = new Length(4.0, METER);
158 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
159 {
160
161 Length latPos = new Length((-0.5 - laneIndex) * width.getSI(), METER);
162 result[laneIndex] = makeLane(link, "lane." + laneIndex, laneType, latPos, width);
163 }
164 return result;
165 }
166
167
168
169
170
171 @Test
172 public final void changeRight() throws Exception
173 {
174 GTUType gtuType = CAR;
175 Set<GTUType> compatibility = new HashSet<GTUType>();
176 compatibility.add(gtuType);
177 LaneType laneType = new LaneType("CarLane", compatibility);
178 int laneCount = 2;
179 Lane[] lanes =
180 makeMultiLane(this.network, "Road with two lanes", new OTSNode(this.network, "From", new OTSPoint3D(0, 0, 0)),
181 new OTSNode(this.network, "To", new OTSPoint3D(200, 0, 0)), laneType, laneCount);
182
183
184
185 lanes[0].accessibleAdjacentLanes(LateralDirectionality.RIGHT, gtuType);
186 assertEquals("Leftmost lane should not have accessible adjacent lanes on the LEFT side", 0,
187 lanes[0].accessibleAdjacentLanes(LateralDirectionality.LEFT, gtuType).size());
188 assertEquals("Leftmost lane should have one accessible adjacent lane on the RIGHT side", 1,
189 lanes[0].accessibleAdjacentLanes(LateralDirectionality.RIGHT, gtuType).size());
190 assertEquals("Rightmost lane should have one accessible adjacent lane on the LEFT side", 1,
191 lanes[1].accessibleAdjacentLanes(LateralDirectionality.LEFT, gtuType).size());
192 assertEquals("Rightmost lane should not have accessible adjacent lanes on the RIGHT side", 0,
193 lanes[1].accessibleAdjacentLanes(LateralDirectionality.RIGHT, gtuType).size());
194
195 Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
196 initialLongitudinalPositions
197 .add(new DirectedLanePosition(lanes[1], new Length(100, METER), GTUDirectionality.DIR_PLUS));
198 SimpleSimulator simpleSimulator = new SimpleSimulator(new Time(0, TimeUnit.BASE_SECOND), new Duration(0, SECOND),
199 new Duration(3600, SECOND), this);
200 AbstractLaneChangeModel laneChangeModel = new Egoistic();
201 BehavioralCharacteristics behavioralCharacteristics = DefaultTestParameters.create();
202
203
204
205 LaneBasedIndividualGTU car = new LaneBasedIndividualGTU("ReferenceCar", gtuType, new Length(4, METER),
206 new Length(2, METER), new Speed(150, KM_PER_HOUR), simpleSimulator, (OTSNetwork) this.network);
207 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
208 new LaneBasedCFLCTacticalPlanner(new IDMPlusOld(), laneChangeModel, car), car);
209 car.init(strategicalPlanner, initialLongitudinalPositions, new Speed(100, KM_PER_HOUR));
210 car.getTacticalPlanner().getPerception().perceive();
211 Collection<Headway> sameLaneGTUs = new LinkedHashSet<Headway>();
212 sameLaneGTUs
213 .add(new HeadwayGTUSimple(car.getId(), car.getGTUType(), Length.ZERO, car.getLength(), car.getSpeed(), null));
214 Collection<Headway> preferredLaneGTUs = new LinkedHashSet<Headway>();
215 Collection<Headway> nonPreferredLaneGTUs = new LinkedHashSet<Headway>();
216 LaneMovementStep laneChangeModelResult = laneChangeModel.computeLaneChangeAndAcceleration(car, sameLaneGTUs,
217 preferredLaneGTUs, nonPreferredLaneGTUs, new Speed(100, KM_PER_HOUR), new Acceleration(0.3, METER_PER_SECOND_2),
218 new Acceleration(0.1, METER_PER_SECOND_2), new Acceleration(-0.3, METER_PER_SECOND_2));
219
220 assertEquals("Vehicle want to change to the right lane", LateralDirectionality.RIGHT,
221 laneChangeModelResult.getLaneChangeDirection());
222 Length rear = car.position(lanes[0], car.getRear());
223 Length front = car.position(lanes[0], car.getFront());
224 Length reference = car.position(lanes[0], RelativePosition.REFERENCE_POSITION);
225
226
227
228 Length vehicleLength = front.minus(rear);
229 Length collisionStart = reference.minus(vehicleLength);
230 Length collisionEnd = reference.plus(vehicleLength);
231 for (double pos = collisionStart.getSI() + 0.01; pos < collisionEnd.getSI() - 0.01; pos += 0.1)
232 {
233 Set<DirectedLanePosition> otherLongitudinalPositions = new LinkedHashSet<>(1);
234 otherLongitudinalPositions
235 .add(new DirectedLanePosition(lanes[1], new Length(pos, METER), GTUDirectionality.DIR_PLUS));
236
237 behavioralCharacteristics = DefaultTestParameters.create();
238
239
240
241
242
243
244
245
246
247
248
249 LaneBasedIndividualGTU collisionCar =
250 new LaneBasedIndividualGTU("LaneChangeBlockingCarAt" + pos, gtuType, vehicleLength, new Length(2, METER),
251 new Speed(150, KM_PER_HOUR), simpleSimulator, (OTSNetwork) this.network);
252 strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
253 new LaneBasedCFLCTacticalPlanner(new IDMPlusOld(), laneChangeModel, collisionCar), collisionCar);
254 collisionCar.init(strategicalPlanner, otherLongitudinalPositions, new Speed(100, KM_PER_HOUR));
255 preferredLaneGTUs.clear();
256 HeadwayGTUSimple collisionHWGTU = new HeadwayGTUSimple(collisionCar.getId(), collisionCar.getGTUType(),
257 new Length(pos - reference.getSI(), LengthUnit.SI), collisionCar.getLength(), collisionCar.getSpeed(),
258 null);
259 preferredLaneGTUs.add(collisionHWGTU);
260 laneChangeModelResult = new Egoistic().computeLaneChangeAndAcceleration(car, sameLaneGTUs, preferredLaneGTUs,
261 nonPreferredLaneGTUs, new Speed(100, KM_PER_HOUR), new Acceleration(0.3, METER_PER_SECOND_2),
262 new Acceleration(0.1, METER_PER_SECOND_2), new Acceleration(-0.3, METER_PER_SECOND_2));
263
264 assertEquals("Vehicle cannot to change to the right lane because that would result in an immediate collision", null,
265 laneChangeModelResult.getLaneChangeDirection());
266 }
267 for (double pos = 0; pos < 180; pos += 5)
268 {
269 Set<DirectedLanePosition> otherLongitudinalPositions = new LinkedHashSet<>(1);
270 otherLongitudinalPositions
271 .add(new DirectedLanePosition(lanes[1], new Length(pos, METER), GTUDirectionality.DIR_PLUS));
272
273 behavioralCharacteristics = new BehavioralCharacteristics();
274 behavioralCharacteristics.setParameter(ParameterTypes.A, new Acceleration(1, METER_PER_SECOND_2));
275 behavioralCharacteristics.setParameter(ParameterTypes.B, new Acceleration(1.5, METER_PER_SECOND_2));
276 behavioralCharacteristics.setParameter(ParameterTypes.S0, new Length(2, METER));
277 behavioralCharacteristics.setParameter(ParameterTypes.T, new Duration(1, SECOND));
278 behavioralCharacteristics.setParameter(ParameterTypes.A, new Acceleration(1, METER_PER_SECOND_2));
279 behavioralCharacteristics.setDefaultParameter(ParameterTypes.LOOKAHEAD);
280 behavioralCharacteristics.setDefaultParameter(ParameterTypes.LOOKBACKOLD);
281 behavioralCharacteristics.setParameter(AbstractIDM.DELTA, 1d);
282
283
284
285
286 LaneBasedIndividualGTU otherCar = new LaneBasedIndividualGTU("OtherCarAt" + pos, gtuType, vehicleLength,
287 new Length(2, METER), new Speed(150, KM_PER_HOUR), simpleSimulator, (OTSNetwork) this.network);
288 strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
289 new LaneBasedCFLCTacticalPlanner(new IDMPlusOld(), laneChangeModel, otherCar), otherCar);
290 otherCar.init(strategicalPlanner, otherLongitudinalPositions, new Speed(100, KM_PER_HOUR));
291 preferredLaneGTUs.clear();
292 HeadwayGTUSimple collisionHWGTU = new HeadwayGTUSimple(otherCar.getId(), otherCar.getGTUType(),
293 new Length(pos - car.position(lanes[0], car.getReference()).getSI(), LengthUnit.SI), otherCar.getLength(),
294 otherCar.getSpeed(), null);
295 preferredLaneGTUs.add(collisionHWGTU);
296 laneChangeModelResult = new Egoistic().computeLaneChangeAndAcceleration(car, sameLaneGTUs, preferredLaneGTUs,
297 nonPreferredLaneGTUs, new Speed(100, KM_PER_HOUR), new Acceleration(0.3, METER_PER_SECOND_2),
298 new Acceleration(0.1, METER_PER_SECOND_2), new Acceleration(-0.3, METER_PER_SECOND_2));
299
300 laneChangeModelResult = new Altruistic().computeLaneChangeAndAcceleration(car, sameLaneGTUs, preferredLaneGTUs,
301 nonPreferredLaneGTUs, new Speed(100, KM_PER_HOUR), new Acceleration(0.3, METER_PER_SECOND_2),
302 new Acceleration(0.1, METER_PER_SECOND_2), new Acceleration(-0.3, METER_PER_SECOND_2));
303
304
305
306
307 }
308 }
309
310
311
312
313
314
315 @Override
316 public void constructModel(SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator) throws SimRuntimeException
317 {
318
319 }
320
321
322 @Override
323 public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
324
325 {
326 return null;
327 }
328
329
330 @Override
331 public OTSNetwork getNetwork()
332 {
333 return this.network;
334 }
335
336 }