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