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