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