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