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