1 package org.opentrafficsim.road.gtu.lane.changing;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.opentrafficsim.core.gtu.GTUType.CAR;
5
6 import java.util.Collection;
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 org.djunits.unit.LengthUnit;
15 import org.djunits.unit.TimeUnit;
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.base.parameters.ParameterSet;
24 import org.opentrafficsim.base.parameters.ParameterTypes;
25 import org.opentrafficsim.core.dsol.OTSModelInterface;
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.network.LateralDirectionality;
33 import org.opentrafficsim.core.network.LinkType;
34 import org.opentrafficsim.core.network.Network;
35 import org.opentrafficsim.core.network.NetworkException;
36 import org.opentrafficsim.core.network.OTSNetwork;
37 import org.opentrafficsim.core.network.OTSNode;
38 import org.opentrafficsim.road.DefaultTestParameters;
39 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
40 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
41 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUSimple;
42 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCFLCTacticalPlanner;
43 import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM;
44 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
45 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.AbstractLaneChangeModel;
46 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Altruistic;
47 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
48 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneMovementStep;
49 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
50 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
51 import org.opentrafficsim.road.network.lane.CrossSectionLink;
52 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
53 import org.opentrafficsim.road.network.lane.Lane;
54 import org.opentrafficsim.road.network.lane.LaneType;
55 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
56 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
57 import org.opentrafficsim.simulationengine.SimpleSimulator;
58
59 import nl.tudelft.simulation.dsol.SimRuntimeException;
60 import nl.tudelft.simulation.dsol.simtime.SimTimeDoubleUnit;
61 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
62 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
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("lane change model test network");
81
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, final DEVSSimulatorInterface.TimeDoubleUnit simulator) 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 =
104 new CrossSectionLink(network, name, from, to, LinkType.ROAD, line, simulator, 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, Speed> speedMap = new LinkedHashMap<>();
124 speedMap.put(GTUType.VEHICLE, new Speed(100, KM_PER_HOUR));
125
126 Lane result =
127 new Lane(link, id, latPos, latPos, width, width, laneType, speedMap, new OvertakingConditions.LeftAndRight());
128 return result;
129 }
130
131
132
133
134
135
136
137
138
139
140
141
142
143 public static Lane[] makeMultiLane(final Network network, final String name, final OTSNode from, final OTSNode to,
144 final LaneType laneType, final int laneCount, final DEVSSimulatorInterface.TimeDoubleUnit simulator) throws Exception
145 {
146 Length width = new Length(laneCount * 4.0, METER);
147 final CrossSectionLink link = makeLink(network, name, from, to, width, simulator);
148 Lane[] result = new Lane[laneCount];
149 width = new Length(4.0, METER);
150 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
151 {
152
153 Length latPos = new Length((-0.5 - laneIndex) * width.getSI(), METER);
154 result[laneIndex] = makeLane(link, "lane." + laneIndex, laneType, latPos, width);
155 }
156 return result;
157 }
158
159
160
161
162
163 @Test
164 public final void changeRight() throws Exception
165 {
166 GTUType gtuType = CAR;
167 LaneType laneType = LaneType.TWO_WAY_LANE;
168 int laneCount = 2;
169 SimpleSimulator simpleSimulator = new SimpleSimulator(new Time(0, TimeUnit.BASE_SECOND), new Duration(0, SECOND),
170 new Duration(3600, SECOND), this);
171 Lane[] lanes =
172 makeMultiLane(this.network, "Road with two lanes", new OTSNode(this.network, "From", new OTSPoint3D(0, 0, 0)),
173 new OTSNode(this.network, "To", new OTSPoint3D(200, 0, 0)), laneType, laneCount, simpleSimulator);
174
175
176
177 assertEquals("Leftmost lane should not have accessible adjacent lanes on the LEFT side", 0,
178 lanes[0].accessibleAdjacentLanesLegal(LateralDirectionality.LEFT, gtuType, GTUDirectionality.DIR_PLUS).size());
179 assertEquals("Leftmost lane should have one accessible adjacent lane on the RIGHT side", 1,
180 lanes[0].accessibleAdjacentLanesLegal(LateralDirectionality.RIGHT, gtuType, GTUDirectionality.DIR_PLUS).size());
181 assertEquals("Rightmost lane should have one accessible adjacent lane on the LEFT side", 1,
182 lanes[1].accessibleAdjacentLanesLegal(LateralDirectionality.LEFT, gtuType, GTUDirectionality.DIR_PLUS).size());
183 assertEquals("Rightmost lane should not have accessible adjacent lanes on the RIGHT side", 0,
184 lanes[1].accessibleAdjacentLanesLegal(LateralDirectionality.RIGHT, gtuType, GTUDirectionality.DIR_PLUS).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 AbstractLaneChangeModel laneChangeModel = new Egoistic();
190 ParameterSet parameters = DefaultTestParameters.create();
191
192
193
194 LaneBasedIndividualGTU car = new LaneBasedIndividualGTU("ReferenceCar", gtuType, new Length(4, METER),
195 new Length(2, METER), new Speed(150, KM_PER_HOUR), Length.createSI(2.0), simpleSimulator, this.network);
196 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(
197 new LaneBasedCFLCTacticalPlanner(new IDMPlusOld(), laneChangeModel, car), car);
198 car.setParameters(parameters);
199 car.init(strategicalPlanner, initialLongitudinalPositions, new Speed(100, KM_PER_HOUR));
200 car.getTacticalPlanner().getPerception().perceive();
201 Collection<Headway> sameLaneGTUs = new LinkedHashSet<>();
202 sameLaneGTUs.add(new HeadwayGTUSimple(car.getId(), car.getGTUType(), Length.ZERO, Length.ZERO, car.getLength(),
203 car.getSpeed(), car.getAcceleration(), null));
204 Collection<Headway> preferredLaneGTUs = new LinkedHashSet<>();
205 Collection<Headway> nonPreferredLaneGTUs = new LinkedHashSet<>();
206 LaneMovementStep laneChangeModelResult = laneChangeModel.computeLaneChangeAndAcceleration(car, sameLaneGTUs,
207 preferredLaneGTUs, nonPreferredLaneGTUs, new Speed(100, KM_PER_HOUR), new Acceleration(0.3, METER_PER_SECOND_2),
208 new Acceleration(0.1, METER_PER_SECOND_2), new Acceleration(-0.3, METER_PER_SECOND_2));
209
210 assertEquals("Vehicle want to change to the right lane", LateralDirectionality.RIGHT,
211 laneChangeModelResult.getLaneChangeDirection());
212 Length rear = car.position(lanes[0], car.getRear());
213 Length front = car.position(lanes[0], car.getFront());
214 Length reference = car.position(lanes[0], RelativePosition.REFERENCE_POSITION);
215
216
217
218 Length vehicleLength = front.minus(rear);
219 Length collisionStart = reference.minus(vehicleLength);
220 Length collisionEnd = reference.plus(vehicleLength);
221 for (double pos = collisionStart.getSI() + 0.01; pos < collisionEnd.getSI() - 0.01; pos += 0.1)
222 {
223 Set<DirectedLanePosition> otherLongitudinalPositions = new LinkedHashSet<>(1);
224 otherLongitudinalPositions
225 .add(new DirectedLanePosition(lanes[1], new Length(pos, METER), GTUDirectionality.DIR_PLUS));
226
227 parameters = DefaultTestParameters.create();
228
229
230
231
232
233
234
235
236
237
238
239 LaneBasedIndividualGTU collisionCar =
240 new LaneBasedIndividualGTU("LaneChangeBlockingCarAt" + pos, gtuType, vehicleLength, new Length(2, METER),
241 new Speed(150, KM_PER_HOUR), vehicleLength.multiplyBy(0.5), simpleSimulator, this.network);
242 strategicalPlanner = new LaneBasedStrategicalRoutePlanner(
243 new LaneBasedCFLCTacticalPlanner(new IDMPlusOld(), laneChangeModel, collisionCar), collisionCar);
244 collisionCar.setParameters(parameters);
245 collisionCar.init(strategicalPlanner, otherLongitudinalPositions, new Speed(100, KM_PER_HOUR));
246 preferredLaneGTUs.clear();
247 HeadwayGTUSimple collisionHWGTU = new HeadwayGTUSimple(collisionCar.getId(), collisionCar.getGTUType(),
248 new Length(pos - reference.getSI(), LengthUnit.SI), collisionCar.getLength(), collisionCar.getWidth(),
249 collisionCar.getSpeed(), collisionCar.getAcceleration(), null);
250 preferredLaneGTUs.add(collisionHWGTU);
251 laneChangeModelResult = new Egoistic().computeLaneChangeAndAcceleration(car, sameLaneGTUs, preferredLaneGTUs,
252 nonPreferredLaneGTUs, new Speed(100, KM_PER_HOUR), new Acceleration(0.3, METER_PER_SECOND_2),
253 new Acceleration(0.1, METER_PER_SECOND_2), new Acceleration(-0.3, METER_PER_SECOND_2));
254
255 assertEquals("Vehicle cannot to change to the right lane because that would result in an immediate collision", null,
256 laneChangeModelResult.getLaneChangeDirection());
257 }
258 for (double pos = 0; pos < 180; pos += 5)
259 {
260 Set<DirectedLanePosition> otherLongitudinalPositions = new LinkedHashSet<>(1);
261 otherLongitudinalPositions
262 .add(new DirectedLanePosition(lanes[1], new Length(pos, METER), GTUDirectionality.DIR_PLUS));
263
264 parameters = new ParameterSet();
265 parameters.setParameter(ParameterTypes.A, new Acceleration(1, METER_PER_SECOND_2));
266 parameters.setParameter(ParameterTypes.B, new Acceleration(1.5, METER_PER_SECOND_2));
267 parameters.setParameter(ParameterTypes.S0, new Length(2, METER));
268 parameters.setParameter(ParameterTypes.T, new Duration(1, SECOND));
269 parameters.setParameter(ParameterTypes.A, new Acceleration(1, METER_PER_SECOND_2));
270 parameters.setDefaultParameter(ParameterTypes.LOOKAHEAD);
271 parameters.setDefaultParameter(ParameterTypes.LOOKBACKOLD);
272 parameters.setParameter(AbstractIDM.DELTA, 1d);
273
274
275
276
277 LaneBasedIndividualGTU otherCar =
278 new LaneBasedIndividualGTU("OtherCarAt" + pos, gtuType, vehicleLength, new Length(2, METER),
279 new Speed(150, KM_PER_HOUR), vehicleLength.multiplyBy(0.5), simpleSimulator, this.network);
280 strategicalPlanner = new LaneBasedStrategicalRoutePlanner(
281 new LaneBasedCFLCTacticalPlanner(new IDMPlusOld(), laneChangeModel, otherCar), otherCar);
282 otherCar.setParameters(parameters);
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.getWidth(), otherCar.getSpeed(), otherCar.getAcceleration(), 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(final SimulatorInterface<Time, Duration, SimTimeDoubleUnit> simulator) throws SimRuntimeException
310 {
311
312 }
313
314
315 @Override
316 public final SimulatorInterface<Time, Duration, SimTimeDoubleUnit> getSimulator()
317
318 {
319 return null;
320 }
321
322
323 @Override
324 public final OTSNetwork getNetwork()
325 {
326 return this.network;
327 }
328
329 }