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 
108 
109 
110 
111 
112 
113 
114 
115 public class StrategiesDemo extends AbstractSimulationScript
116 {
117 
118     
119     private final Map<GTUType, LaneBasedStrategicalPlannerFactory<?>> factories = new HashMap<>();
120 
121     
122     private int gtuIdNum = 0;
123 
124     
125     private int gtuNum = 60;
126 
127     
128     private final StreamInterface stream = new MersenneTwister(1L);
129 
130     
131     private final List<Double> queue = new ArrayList<>();
132 
133     
134     private KmplcListener kmplcListener;
135 
136     
137     private double truckFraction = 0.1;
138 
139     
140     private GTUType nextGtuType;
141 
142     
143     private final Length truckLength;
144 
145     
146     private final Length truckMid;
147 
148     
149     private final Length carLength;
150 
151     
152     private final Length carMid;
153 
154     
155 
156 
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 
184 
185 
186     public static void main(final String[] args)
187     {
188         StrategiesDemo demo = new StrategiesDemo(args);
189         demo.start();
190     }
191 
192     
193     @Override
194     protected void setDefaultProperties()
195     {
196         setProperty("simulationTime", "360000");
197     }
198 
199     
200     @Override
201     protected void setupDemo(final OTSAnimationPanel animation, final OTSNetwork net)
202     {
203         
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         
211         animation.getDemoPanel().add(Box.createVerticalStrut(20));
212 
213         
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                     
235                     animation.getDemoPanel().getParent().repaint();
236                 }
237             }
238         });
239         animation.getDemoPanel().add(gtuSlider);
240 
241         
242         animation.getDemoPanel().add(Box.createVerticalStrut(20));
243 
244         
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         
283         animation.getDemoPanel().add(Box.createVerticalStrut(20));
284 
285         
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         
323         animation.getDemoPanel().add(Box.createVerticalStrut(20));
324 
325         
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 
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         
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                             
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     
440     private class KmplcListener implements EventListenerInterface
441     {
442         
443         private final JLabel label;
444 
445         
446         private final OTSNetwork network;
447 
448         
449 
450 
451 
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         
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     
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         
520         PerceptionFactory perceptionFactory = new LmrsStrategiesPerceptionFactory();
521         
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             
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             
548             CarFollowingModelFactory<?> cfFactory = 
549                     gtuType.equals(GTUType.CAR) ? new SocioIDMFactory() : new IDMPlusFactory(this.stream);
550             
551             Tailgating tlgt = Tailgating.PRESSURE;
552             
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 
602 
603 
604 
605 
606 
607 
608 
609 
610 
611 
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         
628         LaneBasedStrategicalPlanner strategicalPlanner = this.factories.get(gtuType).create(gtu, null, null, null);
629 
630         
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     
652     class SocioIDMFactory implements CarFollowingModelFactory<IDMPlus>
653     {
654         
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         
664         @Override
665         public IDMPlus generateCarFollowingModel()
666         {
667             return new IDMPlus(AbstractIDM.HEADWAY, new SocioDesiredSpeed(AbstractIDM.DESIRED_SPEED));
668         }
669     }
670 
671     
672     class LmrsStrategiesPerceptionFactory implements PerceptionFactory
673     {
674         
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         
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 }