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