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