View Javadoc
1   package strategies;
2   
3   import java.awt.Color;
4   import java.awt.Component;
5   import java.awt.Dimension;
6   import java.rmi.RemoteException;
7   import java.util.ArrayList;
8   import java.util.HashMap;
9   import java.util.Hashtable;
10  import java.util.Iterator;
11  import java.util.LinkedHashSet;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Set;
15  
16  import javax.naming.NamingException;
17  import javax.swing.Box;
18  import javax.swing.JLabel;
19  import javax.swing.JSlider;
20  import javax.swing.SwingConstants;
21  import javax.swing.event.ChangeEvent;
22  import javax.swing.event.ChangeListener;
23  
24  import org.djunits.unit.SpeedUnit;
25  import org.djunits.value.vdouble.scalar.Acceleration;
26  import org.djunits.value.vdouble.scalar.Duration;
27  import org.djunits.value.vdouble.scalar.Length;
28  import org.djunits.value.vdouble.scalar.Speed;
29  import org.djutils.exceptions.Try;
30  import org.opentrafficsim.base.parameters.ParameterException;
31  import org.opentrafficsim.base.parameters.ParameterSet;
32  import org.opentrafficsim.base.parameters.ParameterTypes;
33  import org.opentrafficsim.base.parameters.Parameters;
34  import org.opentrafficsim.core.animation.gtu.colorer.AccelerationGTUColorer;
35  import org.opentrafficsim.core.animation.gtu.colorer.SpeedGTUColorer;
36  import org.opentrafficsim.core.animation.gtu.colorer.SwitchableGTUColorer;
37  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
38  import org.opentrafficsim.core.geometry.OTSGeometryException;
39  import org.opentrafficsim.core.geometry.OTSLine3D;
40  import org.opentrafficsim.core.geometry.OTSPoint3D;
41  import org.opentrafficsim.core.gtu.GTU;
42  import org.opentrafficsim.core.gtu.GTUCharacteristics;
43  import org.opentrafficsim.core.gtu.GTUDirectionality;
44  import org.opentrafficsim.core.gtu.GTUException;
45  import org.opentrafficsim.core.gtu.GTUType;
46  import org.opentrafficsim.core.gtu.perception.DirectEgoPerception;
47  import org.opentrafficsim.core.network.Link;
48  import org.opentrafficsim.core.network.LinkType;
49  import org.opentrafficsim.core.network.NetworkException;
50  import org.opentrafficsim.core.network.OTSNode;
51  import org.opentrafficsim.core.parameters.ParameterFactoryByType;
52  import org.opentrafficsim.road.gtu.colorer.DesiredHeadwayColorer;
53  import org.opentrafficsim.road.gtu.colorer.FixedColor;
54  import org.opentrafficsim.road.gtu.colorer.IncentiveColorer;
55  import org.opentrafficsim.road.gtu.colorer.SocialPressureColorer;
56  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
57  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
58  import org.opentrafficsim.road.gtu.lane.perception.CategoricalLanePerception;
59  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
60  import org.opentrafficsim.road.gtu.lane.perception.PerceptionFactory;
61  import org.opentrafficsim.road.gtu.lane.perception.categories.AnticipationTrafficPerception;
62  import org.opentrafficsim.road.gtu.lane.perception.categories.DirectInfrastructurePerception;
63  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.DirectNeighborsPerception;
64  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType;
65  import org.opentrafficsim.road.gtu.lane.plan.operational.LaneOperationalPlanBuilder;
66  import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM;
67  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
68  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlus;
69  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
70  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationIncentive;
71  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveKeep;
72  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveRoute;
73  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSocioSpeed;
74  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSpeedWithCourtesy;
75  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveStayRight;
76  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory;
77  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.SocioDesiredSpeed;
78  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
79  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance;
80  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
81  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.MandatoryIncentive;
82  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
83  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
84  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
85  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
86  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
87  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
88  import org.opentrafficsim.road.network.OTSRoadNetwork;
89  import org.opentrafficsim.road.network.factory.LaneFactory;
90  import org.opentrafficsim.road.network.lane.CrossSectionLink;
91  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
92  import org.opentrafficsim.road.network.lane.Lane;
93  import org.opentrafficsim.road.network.lane.LaneType;
94  import org.opentrafficsim.road.network.lane.Stripe.Permeable;
95  import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
96  import org.opentrafficsim.swing.gui.OTSAnimationPanel;
97  import org.opentrafficsim.swing.script.AbstractSimulationScript;
98  
99  import nl.tudelft.simulation.dsol.SimRuntimeException;
100 import nl.tudelft.simulation.event.EventInterface;
101 import nl.tudelft.simulation.event.EventListenerInterface;
102 import nl.tudelft.simulation.jstats.distributions.DistNormal;
103 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
104 import nl.tudelft.simulation.jstats.streams.StreamInterface;
105 
106 /**
107  * Demo of lane change strategies.
108  * <p>
109  * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
110  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
111  * <p>
112  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 4 jun. 2018 <br>
113  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
114  */
115 public class StrategiesDemo extends AbstractSimulationScript
116 {
117     /** Factories. */
118     private final Map<GTUType, LaneBasedStrategicalPlannerFactory<?>> factories = new HashMap<>();
119 
120     /** GTU id number. */
121     private int gtuIdNum = 0;
122 
123     /** Number of GTUs. */
124     private int gtuNum = 60;
125 
126     /** Random stream. */
127     private final StreamInterface stream = new MersenneTwister(1L);
128 
129     /** Queue of cumulative odometers. */
130     private final List<Double> queue = new ArrayList<>();
131 
132     /** Lane change listener. */
133     private KmplcListener kmplcListener;
134 
135     /** Truck fraction. */
136     private double truckFraction = 0.1;
137 
138     /** Next GTU type. */
139     private GTUType nextGtuType;
140 
141     /** Truck length. */
142     private Length truckLength;
143 
144     /** Truck mid. */
145     private Length truckMid;
146 
147     /** Car length. */
148     private Length carLength;
149 
150     /** Car mid. */
151     private Length carMid;
152 
153     /**
154      * Constructor.
155      * @param properties String[]; properties
156      */
157     protected StrategiesDemo(final String[] properties)
158     {
159         super("Strategies demo", "Demo of driving strategies in LMRS.", properties);
160         setGtuColorer(SwitchableGTUColorer.builder().addColorer(new FixedColor(Color.BLUE, "Blue"))
161                 .addColorer(new SpeedGTUColorer(new Speed(150, SpeedUnit.KM_PER_HOUR)))
162                 .addColorer(new AccelerationGTUColorer(Acceleration.createSI(-6.0), Acceleration.createSI(2)))
163                 .addActiveColorer(new SocialPressureColorer())
164                 .addColorer(new DesiredHeadwayColorer(Duration.createSI(0.5), Duration.createSI(1.6)))
165                 .addColorer(new IncentiveColorer(IncentiveSocioSpeed.class)).build());
166     }
167 
168     /**
169      * Main method.
170      * @param args String[]; arguments
171      */
172     public static void main(final String[] args)
173     {
174         StrategiesDemo demo = new StrategiesDemo(args);
175         try
176         {
177             demo.start();
178         }
179         catch (Exception ex)
180         {
181             ex.printStackTrace();
182         }
183     }
184 
185     /** {@inheritDoc} */
186     @Override
187     protected void setDefaultProperties()
188     {
189         setProperty("simulationTime", "360000");
190     }
191 
192     /** {@inheritDoc} */
193     @Override
194     protected void setupDemo(final OTSAnimationPanel animation, final OTSRoadNetwork network)
195     {
196         // text
197         JLabel textLabel = new JLabel("<html><p align=\"justify\">"
198                 + "Adjust the sliders below to change the ego-speed sensitivity and socio-speed sensitivity of the drivers, "
199                 + "and observe how traffic is affected. Detailed instructions are in the attached read-me." + "</html>");
200         textLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
201         animation.getDemoPanel().add(textLabel);
202 
203         // spacer
204         animation.getDemoPanel().add(Box.createVerticalStrut(20));
205 
206         // number of vehicles
207         JLabel gtuLabel = new JLabel("<html>Number of vehicles</html>");
208         gtuLabel.setHorizontalAlignment(SwingConstants.CENTER);
209         gtuLabel.setPreferredSize(new Dimension(200, 0));
210         gtuLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
211         animation.getDemoPanel().add(gtuLabel);
212         JSlider gtuSlider = new JSlider(0, 120, this.gtuNum);
213         gtuSlider.setMinorTickSpacing(10);
214         gtuSlider.setMajorTickSpacing(30);
215         gtuSlider.setPaintTicks(true);
216         gtuSlider.setPaintLabels(true);
217         gtuSlider.setToolTipText("<html>Number of vehicles</html>");
218         gtuSlider.addChangeListener(new ChangeListener()
219         {
220             @SuppressWarnings("synthetic-access")
221             @Override
222             public void stateChanged(final ChangeEvent e)
223             {
224                 StrategiesDemo.this.gtuNum = ((JSlider) e.getSource()).getValue();
225                 if (!StrategiesDemo.this.getSimulator().isRunning())
226                 {
227                     // StrategiesDemo.this.checkVehicleNumber();
228                     animation.getDemoPanel().getParent().repaint();
229                 }
230             }
231         });
232         animation.getDemoPanel().add(gtuSlider);
233 
234         // spacer
235         animation.getDemoPanel().add(Box.createVerticalStrut(20));
236 
237         // ego
238         JLabel egoLabel = new JLabel("<html>Ego-speed sensitivity<sup>-1</sup> [km/h]</html>");
239         egoLabel.setHorizontalAlignment(SwingConstants.CENTER);
240         egoLabel.setPreferredSize(new Dimension(200, 0));
241         egoLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
242         animation.getDemoPanel().add(egoLabel);
243         int egoSteps = 70;
244         JSlider egoSlider = new JSlider(0, egoSteps, egoSteps / 2);
245         egoSlider.setMinorTickSpacing(2);
246         egoSlider.setMajorTickSpacing(egoSteps / 5);
247         egoSlider.setPaintTicks(true);
248         egoSlider.setPaintLabels(true);
249         Hashtable<Integer, JLabel> egoTable = new Hashtable<>();
250         for (int i = 0; i <= egoSteps; i += egoSteps / 5)
251         {
252             egoTable.put(i, new JLabel(String.format("%d", i)));
253         }
254         egoSlider.setLabelTable(egoTable);
255         egoSlider.setToolTipText("<html>Ego-speed sensitivity as 1/<i>v<sub>gain</sub></i></html>");
256         egoSlider.addChangeListener(new ChangeListener()
257         {
258             @Override
259             public void stateChanged(final ChangeEvent e)
260             {
261                 double v = Math.max(((JSlider) e.getSource()).getValue(), 0.01);
262                 Speed vGain = new Speed(v, SpeedUnit.KM_PER_HOUR);
263                 for (GTU gtu : getNetwork().getGTUs())
264                 {
265                     if (gtu.getGTUType().isOfType(GTUType.DEFAULTS.CAR))
266                     {
267                         Try.execute(() -> gtu.getParameters().setParameter(LmrsParameters.VGAIN, vGain),
268                                 "Exception while setting vGain");
269                     }
270                 }
271             }
272         });
273         animation.getDemoPanel().add(egoSlider);
274 
275         // spacer
276         animation.getDemoPanel().add(Box.createVerticalStrut(20));
277 
278         // socio
279         JLabel socioLabel = new JLabel("Socio-speed sensitivity [-]");
280         socioLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
281         animation.getDemoPanel().add(socioLabel);
282         int socioSteps = 20;
283         JSlider socioSlider = new JSlider(0, socioSteps, socioSteps / 2);
284         socioSlider.setMinorTickSpacing(1);
285         socioSlider.setMajorTickSpacing(socioSteps / 5);
286         socioSlider.setPaintTicks(true);
287         socioSlider.setPaintLabels(true);
288         Hashtable<Integer, JLabel> socioTable = new Hashtable<>();
289         for (int i = 0; i <= socioSteps; i += socioSteps / 5)
290         {
291             double val = (double) i / socioSteps;
292             socioTable.put(i, new JLabel(String.format("%.2f", val)));
293         }
294         socioSlider.setLabelTable(socioTable);
295         socioSlider.setToolTipText("Socio-speed sensitivity between 0 and 1");
296         socioSlider.addChangeListener(new ChangeListener()
297         {
298             @Override
299             public void stateChanged(final ChangeEvent e)
300             {
301                 JSlider slider = (JSlider) e.getSource();
302                 double sigma = ((double) slider.getValue()) / slider.getMaximum();
303                 for (GTU gtu : getNetwork().getGTUs())
304                 {
305                     if (gtu.getGTUType().isOfType(GTUType.DEFAULTS.CAR))
306                     {
307                         Try.execute(() -> gtu.getParameters().setParameter(LmrsParameters.SOCIO, sigma),
308                                 "Exception while setting vGain");
309                     }
310                 }
311             }
312         });
313         animation.getDemoPanel().add(socioSlider);
314 
315         // spacer
316         animation.getDemoPanel().add(Box.createVerticalStrut(20));
317 
318         // km/lc
319         JLabel kmplcLabel = new JLabel("Km between lane changes (last 0): -");
320         this.kmplcListener = new KmplcListener(kmplcLabel, network);
321         for (GTU gtu : network.getGTUs())
322         {
323             Try.execute(() -> gtu.addListener(this.kmplcListener, LaneBasedGTU.LANE_CHANGE_EVENT),
324                     "Exception while adding lane change listener");
325         }
326         kmplcLabel.setHorizontalAlignment(SwingConstants.LEFT);
327         kmplcLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
328         animation.getDemoPanel().add(kmplcLabel);
329     }
330 
331     /**
332      * Create or destroy vehicles.
333      */
334     @SuppressWarnings("unused")
335     private void checkVehicleNumber()
336     {
337         while (getNetwork().getGTUs().size() > this.gtuNum)
338         {
339             int i = StrategiesDemo.this.stream.nextInt(0, getNetwork().getGTUs().size());
340             Iterator<GTU> it = getNetwork().getGTUs().iterator();
341             GTU gtu = it.next();
342             for (int j = 0; j < i; j++)
343             {
344                 gtu = it.next();
345             }
346             gtu.destroy();
347             this.queue.clear();
348         }
349         // if: add one vehicle per cycle, so we limit the disturbance
350         if (getNetwork().getGTUs().size() < this.gtuNum)
351         {
352             Lane lane = null;
353             Length pos = null;
354             Speed initialSpeed = null;
355             Length gap = Length.ZERO;
356             for (Link link : getNetwork().getLinkMap().values())
357             {
358                 for (Lane l : ((CrossSectionLink) link).getLanes())
359                 {
360                     if (l.numberOfGtus() == 0)
361                     {
362                         lane = l;
363                         pos = lane.getLength().multiplyBy(0.5);
364                         gap = Length.POSITIVE_INFINITY;
365                         initialSpeed = Speed.ZERO;
366                     }
367                     for (int i = 0; i < l.numberOfGtus(); i++)
368                     {
369                         LaneBasedGTU gtu1 = l.getGtu(i);
370                         Length up = Try.assign(() -> gtu1.position(l, gtu1.getFront()), "");
371                         LaneBasedGTU gtu2;
372                         Length down;
373                         if (i < l.numberOfGtus() - 1)
374                         {
375                             gtu2 = l.getGtu(i + 1);
376                             down = Try.assign(() -> gtu2.position(l, gtu2.getRear()), "");
377                         }
378                         else
379                         {
380                             Lane nextLane =
381                                     l.nextLanes(getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE)).keySet().iterator().next();
382                             if (nextLane.numberOfGtus() == 0)
383                             {
384                                 continue;
385                             }
386                             gtu2 = nextLane.getGtu(0);
387                             down = l.getLength().plus(Try.assign(() -> gtu2.position(nextLane, gtu2.getRear()), ""));
388                         }
389                         Length tentativeGap =
390                                 down.minus(up).minus(this.nextGtuType.isOfType(getNetwork().getGtuType(GTUType.DEFAULTS.TRUCK))
391                                         ? this.truckLength : this.carLength);
392                         if (tentativeGap.gt(gap))
393                         {
394                             // check reasonable gap (0.3s)
395                             Speed maxSpeed = Speed.max(gtu1.getSpeed(), gtu2.getSpeed());
396                             if (maxSpeed.eq0() || tentativeGap.divideBy(maxSpeed).si * .5 > .3)
397                             {
398                                 gap = tentativeGap;
399                                 initialSpeed = Speed.interpolate(gtu1.getSpeed(), gtu2.getSpeed(), 0.5);
400                                 pos = up.plus(tentativeGap.multiplyBy(0.5))
401                                         .minus(this.nextGtuType.isOfType(getNetwork().getGtuType(GTUType.DEFAULTS.TRUCK))
402                                                 ? this.truckMid : this.carMid);
403                                 if (pos.gt(l.getLength()))
404                                 {
405                                     pos = pos.minus(l.getLength());
406                                     lane = l.nextLanes(getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE)).keySet().iterator()
407                                             .next();
408                                 }
409                                 else
410                                 {
411                                     lane = l;
412                                 }
413                             }
414                         }
415                     }
416                 }
417             }
418             if (lane != null)
419             {
420                 try
421                 {
422                     createGtu(lane, pos, this.nextGtuType, initialSpeed, getNetwork());
423                 }
424                 catch (NamingException | GTUException | NetworkException | SimRuntimeException | OTSGeometryException exception)
425                 {
426                     throw new RuntimeException(exception);
427                 }
428                 this.nextGtuType = this.stream.nextDouble() < this.truckFraction
429                         ? getNetwork().getGtuType(GTUType.DEFAULTS.TRUCK) : getNetwork().getGtuType(GTUType.DEFAULTS.CAR);
430                 this.queue.clear();
431             }
432         }
433         Try.execute(() -> getSimulator().scheduleEventRel(Duration.createSI(0.5), this, this, "checkVehicleNumber",
434                 new Object[] {}), "");
435     }
436 
437     /** Lane change listener. */
438     private class KmplcListener implements EventListenerInterface
439     {
440         /** Label to show statistic. */
441         private final JLabel label;
442 
443         /** Network. */
444         private final OTSRoadNetwork network;
445 
446         /**
447          * Constructor.
448          * @param label JLabel; label
449          * @param network OTSRoadNetwork; network
450          */
451         @SuppressWarnings("synthetic-access")
452         KmplcListener(final JLabel label, final OTSRoadNetwork network)
453         {
454             this.label = label;
455             this.network = network;
456             StrategiesDemo.this.queue.add(0.0);
457         }
458 
459         /** {@inheritDoc} */
460         @SuppressWarnings("synthetic-access")
461         @Override
462         public void notify(final EventInterface event) throws RemoteException
463         {
464             if (event.getType().equals(LaneBasedGTU.LANE_CHANGE_EVENT))
465             {
466                 double cumul = 0.0;
467                 for (GTU gtu : this.network.getGTUs())
468                 {
469                     cumul += gtu.getOdometer().si;
470                 }
471                 cumul /= 1000;
472                 StrategiesDemo.this.queue.add(cumul);
473                 while (StrategiesDemo.this.queue.size() > 51)
474                 {
475                     StrategiesDemo.this.queue.remove(0);
476                 }
477                 double val =
478                         (StrategiesDemo.this.queue.get(StrategiesDemo.this.queue.size() - 1) - StrategiesDemo.this.queue.get(0))
479                                 / (StrategiesDemo.this.queue.size() - 1.0);
480                 this.label.setText(
481                         String.format("Lane change rate (last %d): %.1f km/lc", StrategiesDemo.this.queue.size() - 1, val));
482             }
483         }
484     }
485 
486     /** {@inheritDoc} */
487     @Override
488     protected OTSRoadNetwork setupSimulation(final OTSSimulatorInterface sim) throws Exception
489     {
490         LaneOperationalPlanBuilder.INSTANT_LANE_CHANGES = true;
491 
492         OTSRoadNetwork network = new OTSRoadNetwork("Strategies demo", true);
493 
494         GTUCharacteristics truck =
495                 GTUType.defaultCharacteristics(network.getGtuType(GTUType.DEFAULTS.TRUCK), network, this.stream);
496         GTUCharacteristics car = GTUType.defaultCharacteristics(network.getGtuType(GTUType.DEFAULTS.CAR), network, this.stream);
497         this.truckLength = truck.getLength();
498         this.truckMid = truck.getLength().multiplyBy(0.5).minus(truck.getFront());
499         this.carLength = car.getLength();
500         this.carMid = car.getLength().multiplyBy(0.5).minus(car.getFront());
501 
502         double radius = 150;
503         Speed speedLimit = new Speed(120.0, SpeedUnit.KM_PER_HOUR);
504         OTSNode nodeA = new OTSNode(network, "A", new OTSPoint3D(-radius, 0, 0));
505         OTSNode nodeB = new OTSNode(network, "B", new OTSPoint3D(radius, 0, 0));
506 
507         OTSPoint3D[] coordsHalf1 = new OTSPoint3D[127];
508         for (int i = 0; i < coordsHalf1.length; i++)
509         {
510             double angle = Math.PI * (i) / (coordsHalf1.length - 1);
511             coordsHalf1[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
512         }
513         List<Lane> lanes1 = new LaneFactory(network, nodeB, nodeA, network.getLinkType(LinkType.DEFAULTS.FREEWAY), sim,
514                 LaneKeepingPolicy.KEEPLEFT, new OTSLine3D(coordsHalf1))
515                         .leftToRight(0.0, Length.createSI(3.5), network.getLaneType(LaneType.DEFAULTS.FREEWAY), speedLimit)
516                         .addLanes(Permeable.BOTH).getLanes();
517         OTSPoint3D[] coordsHalf2 = new OTSPoint3D[127];
518         for (int i = 0; i < coordsHalf2.length; i++)
519         {
520             double angle = Math.PI + Math.PI * (i) / (coordsHalf2.length - 1);
521             coordsHalf2[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0);
522         }
523         List<Lane> lanes2 = new LaneFactory(network, nodeA, nodeB, network.getLinkType(LinkType.DEFAULTS.FREEWAY), sim,
524                 LaneKeepingPolicy.KEEPLEFT, new OTSLine3D(coordsHalf2))
525                         .leftToRight(0.0, Length.createSI(3.5), network.getLaneType(LaneType.DEFAULTS.FREEWAY), speedLimit)
526                         .addLanes(Permeable.BOTH).getLanes();
527 
528         // Strategical factories
529         PerceptionFactory perceptionFactory = new LmrsStrategiesPerceptionFactory();
530         // random parameters
531         ParameterFactoryByType parameterFactory = new ParameterFactoryByType();
532         parameterFactory.addParameter(Tailgating.RHO, 0.0);
533         parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.CAR), LmrsParameters.SOCIO, 0.5);
534         parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), LmrsParameters.SOCIO, 1.0);
535         parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.CAR), LmrsParameters.VGAIN,
536                 new Speed(35.0, SpeedUnit.KM_PER_HOUR));
537         parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), LmrsParameters.VGAIN,
538                 new Speed(50.0, SpeedUnit.KM_PER_HOUR));
539         parameterFactory.addParameter(ParameterTypes.TMAX, Duration.createSI(1.6));
540         parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.CAR), ParameterTypes.FSPEED,
541                 new DistNormal(this.stream, 123.7 / 120.0, 12.0 / 120.0));
542         parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), ParameterTypes.A, Acceleration.createSI(0.4));
543         parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), ParameterTypes.FSPEED, 1.0);
544         for (GTUType gtuType : new GTUType[] {network.getGtuType(GTUType.DEFAULTS.CAR),
545                 network.getGtuType(GTUType.DEFAULTS.TRUCK)})
546         {
547             // incentives
548             Set<MandatoryIncentive> mandatoryIncentives = new LinkedHashSet<>();
549             Set<VoluntaryIncentive> voluntaryIncentives = new LinkedHashSet<>();
550             Set<AccelerationIncentive> accelerationIncentives = new LinkedHashSet<>();
551             mandatoryIncentives.add(new IncentiveRoute());
552             voluntaryIncentives.add(new IncentiveSpeedWithCourtesy());
553             voluntaryIncentives.add(new IncentiveKeep());
554             voluntaryIncentives.add(new IncentiveSocioSpeed());
555             if (gtuType.equals(network.getGtuType(GTUType.DEFAULTS.TRUCK)))
556             {
557                 voluntaryIncentives.add(new IncentiveStayRight());
558             }
559             // car-following factory
560             CarFollowingModelFactory<?> cfFactory = // trucks don't change their desired speed
561                     gtuType.equals(network.getGtuType(GTUType.DEFAULTS.CAR)) ? new SocioIDMFactory()
562                             : new IDMPlusFactory(this.stream);
563             // tailgating
564             Tailgating tlgt = Tailgating.PRESSURE;
565             // strategical and tactical factory
566             LaneBasedStrategicalPlannerFactory<?> laneBasedStrategicalPlannerFactory =
567                     new LaneBasedStrategicalRoutePlannerFactory(new LMRSFactory(cfFactory, perceptionFactory,
568                             Synchronization.PASSIVE, Cooperation.PASSIVE, GapAcceptance.INFORMED, tlgt, mandatoryIncentives,
569                             voluntaryIncentives, accelerationIncentives), parameterFactory);
570             this.factories.put(gtuType, laneBasedStrategicalPlannerFactory);
571         }
572         for (int i = 0; i < lanes1.size(); i++)
573         {
574             Length pos = Length.createSI(10.0);
575             Length gap = lanes1.get(i).getLength().plus(lanes2.get(i).getLength()).divideBy(this.gtuNum / 2);
576             for (int j = 0; j < 2; j++)
577             {
578                 Lane lane = j == 0 ? lanes1.get(i) : lanes2.get(i);
579                 while (true)
580                 {
581                     GTUType gtuType;
582                     if (i == 0)
583                     {
584                         gtuType = network.getGtuType(GTUType.DEFAULTS.CAR);
585                     }
586                     else
587                     {
588                         gtuType = this.stream.nextDouble() < 2 * this.truckFraction ? network.getGtuType(GTUType.DEFAULTS.TRUCK)
589                                 : network.getGtuType(GTUType.DEFAULTS.CAR);
590                     }
591 
592                     Speed initialSpeed = Speed.ZERO;
593 
594                     createGtu(lane, pos, gtuType, initialSpeed, network);
595 
596                     pos = pos.plus(gap);
597                     if (pos.si > lane.getLength().si)
598                     {
599                         pos = pos.minus(lane.getLength());
600                         break;
601                     }
602                 }
603             }
604         }
605 
606         this.nextGtuType = this.stream.nextDouble() < this.truckFraction ? network.getGtuType(GTUType.DEFAULTS.TRUCK)
607                 : network.getGtuType(GTUType.DEFAULTS.CAR);
608         sim.scheduleEventNow(this, this, "checkVehicleNumber", new Object[] {});
609 
610         return network;
611     }
612 
613     /**
614      * Creates a GTU.
615      * @param lane Lane; lane
616      * @param pos Length; position
617      * @param gtuType GTUType; GTU type
618      * @param initialSpeed Speed; initial speed
619      * @param net OTSRoadNetwork; network
620      * @throws NamingException on exception
621      * @throws GTUException on exception
622      * @throws NetworkException on exception
623      * @throws SimRuntimeException on exception
624      * @throws OTSGeometryException on exception
625      */
626     public void createGtu(final Lane lane, final Length pos, final GTUType gtuType, final Speed initialSpeed,
627             final OTSRoadNetwork net)
628             throws NamingException, GTUException, NetworkException, SimRuntimeException, OTSGeometryException
629     {
630         GTUCharacteristics gtuCharacteristics = Try.assign(() -> GTUType.defaultCharacteristics(gtuType, net, this.stream),
631                 "Exception while applying default GTU characteristics.");
632 
633         LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.gtuIdNum), gtuType, gtuCharacteristics.getLength(),
634                 gtuCharacteristics.getWidth(), gtuCharacteristics.getMaximumSpeed(), gtuCharacteristics.getFront(),
635                 getSimulator(), net);
636         gtu.setMaximumAcceleration(gtuCharacteristics.getMaximumAcceleration());
637         gtu.setMaximumDeceleration(gtuCharacteristics.getMaximumDeceleration());
638         gtu.setNoLaneChangeDistance(Length.createSI(50));
639 
640         // strategical planner
641         LaneBasedStrategicalPlanner strategicalPlanner = this.factories.get(gtuType).create(gtu, null, null, null);
642 
643         // init
644         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
645         initialPositions.add(new DirectedLanePosition(lane, pos, GTUDirectionality.DIR_PLUS));
646         if (pos.plus(gtu.getFront().getDx()).gt(lane.getLength()))
647         {
648             Lane nextLane = lane.nextLanes(gtuType).keySet().iterator().next();
649             Length nextPos = pos.minus(lane.getLength());
650             initialPositions.add(new DirectedLanePosition(nextLane, nextPos, GTUDirectionality.DIR_PLUS));
651         }
652         if (pos.plus(gtu.getRear().getDx()).lt0())
653         {
654             Lane prevLane = lane.prevLanes(gtuType).keySet().iterator().next();
655             Length prevPos = prevLane.getLength().plus(pos.plus(gtu.getRear().getDx()));
656             initialPositions.add(new DirectedLanePosition(prevLane, prevPos, GTUDirectionality.DIR_PLUS));
657         }
658         gtu.init(strategicalPlanner, initialPositions, initialSpeed);
659 
660         Try.execute(() -> gtu.addListener(this.kmplcListener, LaneBasedGTU.LANE_CHANGE_EVENT),
661                 "Exception while adding lane change listener");
662     }
663 
664     /** IDM factory with socio speed. */
665     class SocioIDMFactory implements CarFollowingModelFactory<IDMPlus>
666     {
667         /** {@inheritDoc} */
668         @Override
669         public Parameters getParameters() throws ParameterException
670         {
671             ParameterSet parameters = new ParameterSet();
672             parameters.setDefaultParameters(AbstractIDM.class);
673             return parameters;
674         }
675 
676         /** {@inheritDoc} */
677         @Override
678         public IDMPlus generateCarFollowingModel()
679         {
680             return new IDMPlus(AbstractIDM.HEADWAY, new SocioDesiredSpeed(AbstractIDM.DESIRED_SPEED));
681         }
682     }
683 
684     /** Perception factory. */
685     class LmrsStrategiesPerceptionFactory implements PerceptionFactory
686     {
687         /** {@inheritDoc} */
688         @Override
689         public LanePerception generatePerception(final LaneBasedGTU gtu)
690         {
691             LanePerception perception = new CategoricalLanePerception(gtu);
692             perception.addPerceptionCategory(new DirectEgoPerception<>(perception));
693             perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
694             perception.addPerceptionCategory(new DirectNeighborsPerception(perception, HeadwayGtuType.WRAP));
695             perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
696             return perception;
697         }
698 
699         /** {@inheritDoc} */
700         @Override
701         public Parameters getParameters() throws ParameterException
702         {
703             return new ParameterSet().setDefaultParameter(ParameterTypes.LOOKAHEAD)
704                     .setDefaultParameter(ParameterTypes.LOOKBACKOLD).setDefaultParameter(ParameterTypes.PERCEPTION)
705                     .setDefaultParameter(ParameterTypes.LOOKBACK);
706         }
707     }
708 
709 }