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