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