View Javadoc
1   package strategies;
2   
3   import java.awt.Color;
4   import java.awt.Dimension;
5   import java.awt.Toolkit;
6   import java.io.BufferedWriter;
7   import java.io.IOException;
8   import java.rmi.RemoteException;
9   import java.util.ArrayList;
10  import java.util.HashMap;
11  import java.util.HashSet;
12  import java.util.LinkedHashSet;
13  import java.util.List;
14  import java.util.Map;
15  import java.util.Set;
16  
17  import javax.naming.NamingException;
18  
19  import org.djunits.unit.FrequencyUnit;
20  import org.djunits.unit.SpeedUnit;
21  import org.djunits.unit.TimeUnit;
22  import org.djunits.value.StorageType;
23  import org.djunits.value.ValueException;
24  import org.djunits.value.vdouble.scalar.Acceleration;
25  import org.djunits.value.vdouble.scalar.Duration;
26  import org.djunits.value.vdouble.scalar.Frequency;
27  import org.djunits.value.vdouble.scalar.Length;
28  import org.djunits.value.vdouble.scalar.Speed;
29  import org.djunits.value.vdouble.scalar.Time;
30  import org.djunits.value.vdouble.vector.FrequencyVector;
31  import org.djunits.value.vdouble.vector.TimeVector;
32  import org.djunits.value.vfloat.scalar.FloatDuration;
33  import org.djunits.value.vfloat.scalar.FloatLength;
34  import org.djunits.value.vfloat.scalar.FloatSpeed;
35  import org.djutils.exceptions.Throw;
36  import org.djutils.exceptions.Try;
37  import org.opentrafficsim.base.CompressedFileWriter;
38  import org.opentrafficsim.base.parameters.ParameterException;
39  import org.opentrafficsim.base.parameters.ParameterSet;
40  import org.opentrafficsim.base.parameters.ParameterTypes;
41  import org.opentrafficsim.base.parameters.Parameters;
42  import org.opentrafficsim.core.animation.gtu.colorer.AccelerationGTUColorer;
43  import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
44  import org.opentrafficsim.core.animation.gtu.colorer.IDGTUColorer;
45  import org.opentrafficsim.core.animation.gtu.colorer.SpeedGTUColorer;
46  import org.opentrafficsim.core.animation.gtu.colorer.SwitchableGTUColorer;
47  import org.opentrafficsim.core.dsol.AbstractOTSModel;
48  import org.opentrafficsim.core.dsol.AbstractOTSSimulationApplication;
49  import org.opentrafficsim.core.dsol.OTSAnimator;
50  import org.opentrafficsim.core.dsol.OTSModelInterface;
51  import org.opentrafficsim.core.dsol.OTSSimulator;
52  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
53  import org.opentrafficsim.core.geometry.OTSGeometryException;
54  import org.opentrafficsim.core.geometry.OTSLine3D;
55  import org.opentrafficsim.core.geometry.OTSPoint3D;
56  import org.opentrafficsim.core.gtu.GTU;
57  import org.opentrafficsim.core.gtu.GTUCharacteristics;
58  import org.opentrafficsim.core.gtu.GTUException;
59  import org.opentrafficsim.core.gtu.GTUType;
60  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterFactoryByType;
61  import org.opentrafficsim.core.gtu.perception.DirectEgoPerception;
62  import org.opentrafficsim.core.network.LateralDirectionality;
63  import org.opentrafficsim.core.network.LinkType;
64  import org.opentrafficsim.core.network.Network;
65  import org.opentrafficsim.core.network.NetworkException;
66  import org.opentrafficsim.core.network.Node;
67  import org.opentrafficsim.core.network.OTSLink;
68  import org.opentrafficsim.core.network.OTSNetwork;
69  import org.opentrafficsim.core.network.OTSNode;
70  import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
71  import org.opentrafficsim.core.units.distributions.ContinuousDistSpeed;
72  import org.opentrafficsim.draw.core.OTSDrawingException;
73  import org.opentrafficsim.draw.gtu.GTUGeneratorAnimation;
74  import org.opentrafficsim.draw.network.LinkAnimation;
75  import org.opentrafficsim.draw.network.NodeAnimation;
76  import org.opentrafficsim.draw.road.LaneAnimation;
77  import org.opentrafficsim.draw.road.StripeAnimation;
78  import org.opentrafficsim.draw.road.StripeAnimation.TYPE;
79  import org.opentrafficsim.kpi.sampling.KpiGtuDirectionality;
80  import org.opentrafficsim.kpi.sampling.KpiLaneDirection;
81  import org.opentrafficsim.kpi.sampling.Sampler;
82  import org.opentrafficsim.kpi.sampling.SpaceTimeRegion;
83  import org.opentrafficsim.kpi.sampling.data.ExtendedDataTypeDuration;
84  import org.opentrafficsim.kpi.sampling.data.ExtendedDataTypeLength;
85  import org.opentrafficsim.kpi.sampling.data.ExtendedDataTypeNumber;
86  import org.opentrafficsim.kpi.sampling.data.ExtendedDataTypeSpeed;
87  import org.opentrafficsim.road.gtu.colorer.DesiredHeadwayColorer;
88  import org.opentrafficsim.road.gtu.colorer.DesiredSpeedColorer;
89  import org.opentrafficsim.road.gtu.colorer.FixedColor;
90  import org.opentrafficsim.road.gtu.colorer.GTUTypeColorer;
91  import org.opentrafficsim.road.gtu.colorer.IncentiveColorer;
92  import org.opentrafficsim.road.gtu.colorer.SocialPressureColorer;
93  import org.opentrafficsim.road.gtu.colorer.SynchronizationColorer;
94  import org.opentrafficsim.road.gtu.colorer.TotalDesireColorer;
95  import org.opentrafficsim.road.gtu.generator.GTUGenerator;
96  import org.opentrafficsim.road.gtu.generator.GeneratorPositions.LaneBias;
97  import org.opentrafficsim.road.gtu.generator.GeneratorPositions.LaneBiases;
98  import org.opentrafficsim.road.gtu.generator.MarkovCorrelation;
99  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristics;
100 import org.opentrafficsim.road.gtu.generator.headway.ArrivalsHeadwayGenerator.HeadwayDistribution;
101 import org.opentrafficsim.road.gtu.generator.od.GTUCharacteristicsGeneratorOD;
102 import org.opentrafficsim.road.gtu.generator.od.ODApplier;
103 import org.opentrafficsim.road.gtu.generator.od.ODApplier.GeneratorObjects;
104 import org.opentrafficsim.road.gtu.generator.od.ODOptions;
105 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
106 import org.opentrafficsim.road.gtu.lane.VehicleModel;
107 import org.opentrafficsim.road.gtu.lane.perception.CategoricalLanePerception;
108 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
109 import org.opentrafficsim.road.gtu.lane.perception.PerceptionFactory;
110 import org.opentrafficsim.road.gtu.lane.perception.categories.AnticipationTrafficPerception;
111 import org.opentrafficsim.road.gtu.lane.perception.categories.DirectInfrastructurePerception;
112 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.DirectNeighborsPerception;
113 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType;
114 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneChange;
115 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneOperationalPlanBuilder;
116 import org.opentrafficsim.road.gtu.lane.tactical.DesireBased;
117 import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM;
118 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
119 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlus;
120 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
121 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationIncentive;
122 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveKeep;
123 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveRoute;
124 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSocioSpeed;
125 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSpeedWithCourtesy;
126 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveStayRight;
127 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory;
128 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.SocioDesiredSpeed;
129 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
130 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance;
131 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Incentive;
132 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
133 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.MandatoryIncentive;
134 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
135 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
136 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
137 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
138 import org.opentrafficsim.road.gtu.strategical.od.Categorization;
139 import org.opentrafficsim.road.gtu.strategical.od.Category;
140 import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
141 import org.opentrafficsim.road.gtu.strategical.od.ODMatrix;
142 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
143 import org.opentrafficsim.road.network.lane.CrossSectionLink;
144 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
145 import org.opentrafficsim.road.network.lane.Lane;
146 import org.opentrafficsim.road.network.lane.LaneType;
147 import org.opentrafficsim.road.network.lane.Stripe;
148 import org.opentrafficsim.road.network.lane.Stripe.Permeable;
149 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
150 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
151 import org.opentrafficsim.road.network.lane.object.SpeedSign;
152 import org.opentrafficsim.road.network.lane.object.sensor.Detector;
153 import org.opentrafficsim.road.network.lane.object.sensor.Detector.CompressionMethod;
154 import org.opentrafficsim.road.network.lane.object.sensor.Detector.DetectorMeasurement;
155 import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
156 import org.opentrafficsim.road.network.sampling.GtuData;
157 import org.opentrafficsim.road.network.sampling.LaneData;
158 import org.opentrafficsim.road.network.sampling.RoadSampler;
159 import org.opentrafficsim.swing.gui.AnimationToggles;
160 import org.opentrafficsim.swing.gui.OTSAnimationPanel;
161 import org.opentrafficsim.swing.gui.OTSSimulationApplication;
162 
163 import nl.tudelft.simulation.dsol.SimRuntimeException;
164 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
165 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
166 import nl.tudelft.simulation.event.EventInterface;
167 import nl.tudelft.simulation.event.EventListenerInterface;
168 import nl.tudelft.simulation.jstats.distributions.DistLogNormal;
169 import nl.tudelft.simulation.jstats.distributions.DistNormal;
170 import nl.tudelft.simulation.jstats.distributions.DistTriangular;
171 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
172 import nl.tudelft.simulation.jstats.streams.StreamInterface;
173 
174 /**
175  * Simulations regarding LMRS lane change strategies. This entails the base LMRS with:
176  * <ul>
177  * <li>Distributed Tmax</li>
178  * <li>Distributed vGain</li>
179  * <li>Distributed socio-speed sensitivity parameter (LmrsParameters.SOCIO)</li>
180  * <li>Altered gap-acceptance: use own Tmax (GapAcceptance.EGO_HEADWAY) [not required if Tmin/max not distributed]</li>
181  * <li>Altered desired speed: increase during overtaking (SocioDesiredSpeed)</li>
182  * <li>Lane change incentive to get out of the way (IncentiveSocioSpeed)</li>
183  * </ul>
184  * <p>
185  * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
186  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
187  * <p>
188  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 2 mrt. 2018 <br>
189  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
190  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
191  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
192  */
193 public class LmrsStrategies implements EventListenerInterface
194 {
195 
196     /** Simulation time. */
197     static final Time SIMTIME = Time.createSI(3900);
198 
199     /** Truck fraction. */
200     private double fTruck;
201 
202     /** Synchronization. */
203     static final Synchronization SYNCHRONIZATION = Synchronization.PASSIVE;
204 
205     /** Cooperation. */
206     static final Cooperation COOPERATION = Cooperation.PASSIVE;
207 
208     /** Gap-acceptance. */
209     static final GapAcceptance GAPACCEPTANCE = GapAcceptance.INFORMED;
210 
211     /** Use base LMRS. */
212     private boolean baseLMRS;
213 
214     /** Form of tailgating. */
215     private Tailgating tailgating;
216 
217     /** Seed. */
218     private long seed;
219 
220     /** Sigma. */
221     private double sigma;
222 
223     /** vGain [km/h] (after log-normal shift). */
224     private double vGain;
225 
226     /** Maximum headway [s]. */
227     private double tMax;
228 
229     /** Maximum flow [veh/h]. */
230     private double qMax;
231 
232     /** Suffix for file name. */
233     private String suffix;
234 
235     /** Folder to save files. */
236     private String folder;
237 
238     /** Strategical planner factories per GTU type. */
239     private final Map<GTUType, LaneBasedStrategicalPlannerFactory<?>> factories = new HashMap<>();
240 
241     /** The simulator. */
242     private DEVSSimulatorInterface.TimeDoubleUnit simulator;
243 
244     /** The network. */
245     private OTSNetwork network;
246 
247     /** Autorun. */
248     private boolean autorun;
249 
250     /** List of lane changes. */
251     private List<String> laneChanges = new ArrayList<>();
252 
253     /** Sample data or not. */
254     private boolean sampling;
255 
256     /** Sampler when sampling. */
257     private Sampler<GtuData> sampler;
258 
259     /** GTU colorer. */
260     private static final GTUColorer colorer = SwitchableGTUColorer.builder()
261             .addActiveColorer(new FixedColor(Color.BLUE, "Blue")).addColorer(GTUTypeColorer.DEFAULT)
262             .addColorer(new IDGTUColorer()).addColorer(new SpeedGTUColorer(new Speed(150, SpeedUnit.KM_PER_HOUR)))
263             .addColorer(new DesiredSpeedColorer(new Speed(80, SpeedUnit.KM_PER_HOUR), new Speed(150, SpeedUnit.KM_PER_HOUR)))
264             .addColorer(new AccelerationGTUColorer(Acceleration.createSI(-6.0), Acceleration.createSI(2)))
265             .addColorer(new SynchronizationColorer())
266             .addColorer(new DesiredHeadwayColorer(Duration.createSI(0.5), Duration.createSI(2.0)))
267             .addColorer(new TotalDesireColorer()).addColorer(new IncentiveColorer(IncentiveRoute.class))
268             .addColorer(new IncentiveColorer(IncentiveStayRight.class))
269             .addColorer(new IncentiveColorer(IncentiveSpeedWithCourtesy.class))
270             .addColorer(new IncentiveColorer(IncentiveKeep.class)).addColorer(new IncentiveColorer(IncentiveSocioSpeed.class))
271             .addColorer(new SocialPressureColorer()).build();
272 
273     /**
274      * Main method with command line arguments.
275      * @param args String[]; String[] command line arguments
276      */
277     @SuppressWarnings("unchecked")
278     public static void main(final String[] args)
279     {
280         LaneChange.MIN_LC_LENGTH_FACTOR = 1.0;
281         LaneOperationalPlanBuilder.INSTANT_LANE_CHANGES = true;
282 
283         // default properties
284         boolean autorun = false;
285         String suffix = "";
286         long seed = 1L;
287         double sigma = 0.1; // 0.25;
288         double vGain = 3.3789;
289         // 25km/h -> 3.3789
290         // 35km/h -> 3.7153
291         // 50km/h -> 4.072
292         // 70km/h -> 4.4085
293         // base: 69.6km/h
294         boolean baseLMRS = false;
295         double tMax = 1.6;
296         double fTruck = 0.1;
297         double qMax = 5500;
298         String folder = "D:/";
299         boolean sampling = false;
300         Tailgating tailgating = Tailgating.PRESSURE;
301 
302         boolean vGainSet = false;
303 
304         // parse args
305         for (String arg : args)
306         {
307             int equalsPos = arg.indexOf("=");
308             if (equalsPos >= 0)
309             {
310                 // set something
311                 String key = arg.substring(0, equalsPos);
312                 String value = arg.substring(equalsPos + 1);
313                 if ("autorun".equalsIgnoreCase(key))
314                 {
315                     autorun = Boolean.parseBoolean(value);
316                 }
317                 else if ("suffix".equalsIgnoreCase(key))
318                 {
319                     suffix = value;
320                 }
321                 else if ("seed".equalsIgnoreCase(key))
322                 {
323                     seed = Long.parseLong(value);
324                 }
325                 else if ("sigma".equalsIgnoreCase(key))
326                 {
327                     sigma = Double.parseDouble(value);
328                 }
329                 else if ("vgain".equalsIgnoreCase(key))
330                 {
331                     vGain = Double.parseDouble(value);
332                     vGainSet = true;
333                 }
334                 else if ("baselmrs".equalsIgnoreCase(key))
335                 {
336                     baseLMRS = Boolean.parseBoolean(value);
337                     if (baseLMRS && !vGainSet)
338                     {
339                         vGain = Try.assign(() -> LmrsParameters.VGAIN.getDefaultValue().getInUnit(SpeedUnit.KM_PER_HOUR), "");
340                     }
341                 }
342                 else if ("tmax".equalsIgnoreCase(key))
343                 {
344                     tMax = Double.parseDouble(value);
345                 }
346                 else if ("ftruck".equalsIgnoreCase(key))
347                 {
348                     fTruck = Double.parseDouble(value);
349                 }
350                 else if ("qmax".equalsIgnoreCase(key))
351                 {
352                     qMax = Double.parseDouble(value);
353                 }
354                 else if ("folder".equalsIgnoreCase(key))
355                 {
356                     folder = value;
357                 }
358                 else if ("sampling".equalsIgnoreCase(key))
359                 {
360                     sampling = Boolean.parseBoolean(value);
361                 }
362                 else if ("tailgating".equalsIgnoreCase(key))
363                 {
364                     // overrule for sensitivity analysis
365                     tailgating = value.equalsIgnoreCase("none") ? Tailgating.NONE
366                             : (value.equalsIgnoreCase("pressure") ? Tailgating.PRESSURE : Tailgating.RHO_ONLY);
367                 }
368                 else
369                 {
370                     throw new RuntimeException("Key " + key + " not supported.");
371                 }
372             }
373         }
374         Throw.whenNull(folder, "Provide a folder to save files using a command line argument named 'folder'.");
375 
376         // setup arguments
377         LmrsStrategies lmrsStrategies = new LmrsStrategies();
378         lmrsStrategies.autorun = autorun;
379         lmrsStrategies.suffix = suffix;
380         lmrsStrategies.seed = seed;
381         lmrsStrategies.sigma = sigma;
382         lmrsStrategies.vGain = vGain;
383         lmrsStrategies.baseLMRS = baseLMRS;
384         lmrsStrategies.tailgating = tailgating;
385         lmrsStrategies.tMax = tMax;
386         lmrsStrategies.fTruck = fTruck;
387         lmrsStrategies.qMax = qMax;
388         lmrsStrategies.folder = folder;
389         lmrsStrategies.sampling = sampling;
390         if (baseLMRS)
391         {
392             lmrsStrategies.incentives =
393                     new Class[] { IncentiveRoute.class, IncentiveSpeedWithCourtesy.class, IncentiveKeep.class };
394         }
395         else
396         {
397             lmrsStrategies.incentives = new Class[] { IncentiveRoute.class, IncentiveSpeedWithCourtesy.class,
398                     IncentiveKeep.class, IncentiveSocioSpeed.class };
399         }
400 
401         // run
402         if (autorun)
403         {
404             try
405             {
406                 OTSSimulator simulator = new OTSSimulator();
407                 final LmrsStrategiesModel lmrsModel = lmrsStrategies.new LmrsStrategiesModel(simulator);
408                 // + 1e-9 is a hack to allow step() to perform detector aggregation of more than 1 detectors -at- the sim end
409                 simulator.initialize(Time.ZERO, Duration.ZERO, Duration.createSI(SIMTIME.si + 1e-9), lmrsModel);
410                 lmrsStrategies.new LmrsStrategiesSimulation(lmrsModel);
411                 double tReport = 60.0;
412                 Time t = simulator.getSimulatorTime();
413                 while (t.le(SIMTIME))
414                 {
415                     simulator.step();
416                     t = simulator.getSimulatorTime();
417                     if (t.si >= tReport)
418                     {
419                         System.out.println("Simulation time is " + t);
420                         tReport += 60.0;
421                     }
422                 }
423                 simulator.stop(); // end of simulation event
424             }
425             catch (Exception exception)
426             {
427                 exception.printStackTrace();
428                 System.exit(-1);
429             }
430         }
431         else
432         {
433             try
434             {
435                 OTSAnimator simulator = new OTSAnimator();
436                 final LmrsStrategiesModel lmrsModel = lmrsStrategies.new LmrsStrategiesModel(simulator);
437                 // + 1e-9 is a hack to allow step() to perform detector aggregation of more than 1 detectors -at- the sim end
438                 simulator.initialize(Time.ZERO, Duration.ZERO, Duration.createSI(SIMTIME.si + 1e-9), lmrsModel);
439                 OTSAnimationPanel animationPanel = new OTSAnimationPanel(lmrsModel.getNetwork().getExtent(),
440                         new Dimension(800, 600), simulator, lmrsModel, LmrsStrategies.colorer, lmrsModel.getNetwork());
441                 lmrsStrategies.new LmrsStrategiesAnimation(lmrsModel, animationPanel);
442             }
443             catch (Exception exception)
444             {
445                 exception.printStackTrace();
446             }
447         }
448     }
449 
450     /**
451      * Simulation without visualization.
452      * <p>
453      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
454      * <br>
455      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
456      * <p>
457      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 mrt. 2018 <br>
458      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
459      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
460      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
461      */
462     class LmrsStrategiesSimulation extends AbstractOTSSimulationApplication
463     {
464         /** */
465         private static final long serialVersionUID = 1L;
466 
467         /**
468          * @param model OTSModelInterface; model
469          */
470         LmrsStrategiesSimulation(final OTSModelInterface model)
471         {
472             super(model);
473         }
474     }
475 
476     /**
477      * Animator.
478      * <p>
479      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
480      * <br>
481      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
482      * <p>
483      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 3 mrt. 2018 <br>
484      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
485      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
486      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
487      */
488     class LmrsStrategiesAnimation extends OTSSimulationApplication<OTSModelInterface>
489     {
490         /** */
491         private static final long serialVersionUID = 20180303L;
492 
493         /**
494          * @param model OTSModelInterface; the model
495          * @param panel OTSAnimationPanel; the animation panel
496          * @throws OTSDrawingException
497          */
498         LmrsStrategiesAnimation(final OTSModelInterface model, final OTSAnimationPanel panel) throws OTSDrawingException
499         {
500             super(model, panel);
501         }
502 
503         /** {@inheritDoc} */
504         @Override
505         protected void setAnimationToggles()
506         {
507             AnimationToggles.setIconAnimationTogglesFull(getAnimationPanel());
508             getAnimationPanel().getAnimationPanel().toggleClass(OTSLink.class);
509             getAnimationPanel().getAnimationPanel().toggleClass(OTSNode.class);
510             getAnimationPanel().getAnimationPanel().toggleClass(GTUGenerator.class);
511             getAnimationPanel().getAnimationPanel().showClass(SpeedSign.class);
512         }
513 
514     }
515 
516     /**
517      * LMRS model.
518      * <p>
519      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
520      * <br>
521      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
522      * <p>
523      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 3 mrt. 2018 <br>
524      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
525      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
526      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
527      */
528     class LmrsStrategiesModel extends AbstractOTSModel
529     {
530         /**
531          * @param simulator OTSSimulatorInterface; the simulator
532          */
533         LmrsStrategiesModel(final OTSSimulatorInterface simulator)
534         {
535             super(simulator);
536         }
537 
538         /** */
539         private static final long serialVersionUID = 20180303L;
540 
541         /** {@inheritDoc} */
542         @Override
543         @SuppressWarnings({ "synthetic-access", "checkstyle:methodlength" })
544         public void constructModel()
545         {
546             LmrsStrategies.this.simulator = getSimulator();
547             OTSNetwork net = new OTSNetwork("LMRS strategies");
548             try
549             {
550                 LmrsStrategies.this.simulator.addListener(LmrsStrategies.this, SimulatorInterface.END_REPLICATION_EVENT);
551             }
552             catch (RemoteException exception1)
553             {
554                 exception1.printStackTrace();
555             }
556             LmrsStrategies.this.network = net;
557             net.addListener(LmrsStrategies.this, Network.GTU_ADD_EVENT);
558             net.addListener(LmrsStrategies.this, Network.GTU_REMOVE_EVENT);
559             Map<String, StreamInterface> streams = new HashMap<>();
560             StreamInterface stream = new MersenneTwister(LmrsStrategies.this.seed);
561             streams.put("generation", stream);
562             getSimulator().getReplication().setStreams(streams);
563 
564             // Vehicle-driver classes
565             // characteristics generator using the input available in this context
566             /** Characteristics generator. */
567             class LmrsStrategyCharacteristicsGenerator implements GTUCharacteristicsGeneratorOD
568             {
569 
570                 /** Distributed maximum speed for trucks. */
571                 private ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> vTruck;
572 
573                 /**
574                  * Constructor.
575                  * @param strm StreamInterface;
576                  */
577                 LmrsStrategyCharacteristicsGenerator(final StreamInterface strm)
578                 {
579                     this.vTruck = new ContinuousDistDoubleScalar.Rel<>(new DistNormal(strm, 85.0, 2.5), SpeedUnit.KM_PER_HOUR);
580                 }
581 
582                 /** {@inheritDoc} */
583                 @Override
584                 public LaneBasedGTUCharacteristics draw(final Node origin, final Node destination, final Category category,
585                         final StreamInterface randomStream) throws GTUException
586                 {
587                     GTUType gtuType = category.get(GTUType.class);
588                     GTUCharacteristics gtuCharacteristics =
589                             Try.assign(() -> GTUType.defaultCharacteristics(gtuType, randomStream),
590                                     "Exception while applying default GTU characteristics.");
591                     if (gtuType.equals(GTUType.TRUCK))
592                     {
593                         gtuCharacteristics = new GTUCharacteristics(GTUType.TRUCK, gtuCharacteristics.getLength(),
594                                 gtuCharacteristics.getWidth(), this.vTruck.draw(), gtuCharacteristics.getMaximumAcceleration(),
595                                 gtuCharacteristics.getMaximumDeceleration(), gtuCharacteristics.getFront());
596                     }
597                     return new LaneBasedGTUCharacteristics(gtuCharacteristics, LmrsStrategies.this.factories.get(gtuType), null,
598                             origin, destination, VehicleModel.NONE);
599                 }
600             }
601             /** Perception factory. */
602             class LmrsStrategiesPerceptionFactory implements PerceptionFactory
603             {
604                 /** {@inheritDoc} */
605                 @Override
606                 public LanePerception generatePerception(final LaneBasedGTU gtu)
607                 {
608                     LanePerception perception = new CategoricalLanePerception(gtu);
609                     perception.addPerceptionCategory(new DirectEgoPerception<>(perception));
610                     perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
611                     perception.addPerceptionCategory(new DirectNeighborsPerception(perception, HeadwayGtuType.WRAP));
612                     perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
613                     return perception;
614                 }
615 
616                 /** {@inheritDoc} */
617                 @Override
618                 public Parameters getParameters() throws ParameterException
619                 {
620                     return new ParameterSet().setDefaultParameter(ParameterTypes.LOOKAHEAD)
621                             .setDefaultParameter(ParameterTypes.LOOKBACKOLD).setDefaultParameter(ParameterTypes.PERCEPTION)
622                             .setDefaultParameter(ParameterTypes.LOOKBACK);
623                 }
624             }
625             PerceptionFactory perceptionFactory = new LmrsStrategiesPerceptionFactory();
626             /** IDM factory with socio speed. */
627             class SocioIDMFactory implements CarFollowingModelFactory<IDMPlus>
628             {
629                 /** {@inheritDoc} */
630                 @Override
631                 public Parameters getParameters() throws ParameterException
632                 {
633                     ParameterSet parameters = new ParameterSet();
634                     parameters.setDefaultParameters(AbstractIDM.class);
635                     return parameters;
636                 }
637 
638                 /** {@inheritDoc} */
639                 @Override
640                 public IDMPlus generateCarFollowingModel()
641                 {
642                     return new IDMPlus(AbstractIDM.HEADWAY, new SocioDesiredSpeed(AbstractIDM.DESIRED_SPEED));
643                 }
644             }
645             // random parameters
646             ParameterFactoryByType parameterFactory = new ParameterFactoryByType();
647             parameterFactory.addParameter(Tailgating.RHO, 0.0);
648             if (!LmrsStrategies.this.baseLMRS)
649             {
650                 parameterFactory.addParameter(GTUType.CAR, LmrsParameters.SOCIO,
651                         new DistTriangular(stream, 0.0, LmrsStrategies.this.sigma, 1.0));
652                 parameterFactory.addCorrelation(GTUType.CAR, null, LmrsParameters.SOCIO,
653                         (first, then) -> then <= 1.0 ? then : 1.0);
654                 parameterFactory.addParameter(GTUType.TRUCK, LmrsParameters.SOCIO, 1.0);
655                 parameterFactory.addParameter(GTUType.CAR, LmrsParameters.VGAIN, new ContinuousDistSpeed(
656                         new DistLogNormal(stream, LmrsStrategies.this.vGain, 0.4), SpeedUnit.KM_PER_HOUR));
657                 parameterFactory.addParameter(GTUType.TRUCK, LmrsParameters.VGAIN, new Speed(50.0, SpeedUnit.KM_PER_HOUR));
658                 parameterFactory.addParameter(ParameterTypes.TMAX, Duration.createSI(LmrsStrategies.this.tMax));
659             }
660             else
661             {
662                 // overrule for sensitivity analysis
663                 parameterFactory.addParameter(GTUType.CAR, LmrsParameters.VGAIN,
664                         new Speed(LmrsStrategies.this.vGain, SpeedUnit.KM_PER_HOUR));
665             }
666             parameterFactory.addParameter(GTUType.CAR, ParameterTypes.FSPEED,
667                     new DistNormal(stream, 123.7 / 120.0, 12.0 / 120.0));
668             parameterFactory.addParameter(GTUType.TRUCK, ParameterTypes.A, Acceleration.createSI(0.4));
669             parameterFactory.addParameter(GTUType.TRUCK, ParameterTypes.FSPEED, 1.0);
670 
671             try
672             {
673                 // Strategical factories
674                 for (GTUType gtuType : new GTUType[] { GTUType.CAR, GTUType.TRUCK })
675                 {
676                     // incentives
677                     Set<MandatoryIncentive> mandatoryIncentives = new LinkedHashSet<>();
678                     Set<VoluntaryIncentive> voluntaryIncentives = new LinkedHashSet<>();
679                     Set<AccelerationIncentive> accelerationIncentives = new LinkedHashSet<>();
680                     mandatoryIncentives.add(new IncentiveRoute());
681                     voluntaryIncentives.add(new IncentiveSpeedWithCourtesy());
682                     voluntaryIncentives.add(new IncentiveKeep()); // before socio-speed and stay-right
683                     if (!LmrsStrategies.this.baseLMRS)
684                     {
685                         voluntaryIncentives.add(new IncentiveSocioSpeed());
686                     }
687                     // accelerationIncentives.add(new AccelerationNoRightOvertake());
688                     if (gtuType.equals(GTUType.TRUCK))
689                     {
690                         voluntaryIncentives.add(new IncentiveStayRight());
691                     }
692                     // car-following factory
693                     CarFollowingModelFactory<?> cfFactory = // trucks don't change their desired speed
694                             gtuType.equals(GTUType.CAR) && !LmrsStrategies.this.baseLMRS ? new SocioIDMFactory()
695                                     : new IDMPlusFactory(stream);
696                     // tailgating
697                     Tailgating tlgt = LmrsStrategies.this.baseLMRS ? Tailgating.NONE : LmrsStrategies.this.tailgating;
698                     // strategical and tactical factory
699                     LaneBasedStrategicalPlannerFactory<?> laneBasedStrategicalPlannerFactory =
700                             new LaneBasedStrategicalRoutePlannerFactory(
701                                     new LMRSFactory(cfFactory, perceptionFactory, SYNCHRONIZATION, COOPERATION, GAPACCEPTANCE,
702                                             tlgt, mandatoryIncentives, voluntaryIncentives, accelerationIncentives),
703                                     parameterFactory);
704                     LmrsStrategies.this.factories.put(gtuType, laneBasedStrategicalPlannerFactory);
705                 }
706 
707                 // Network
708                 OTSPoint3D pointA = new OTSPoint3D(0, 0, 0);
709                 OTSPoint3D pointB = new OTSPoint3D(4000, 0, 0);
710                 OTSPoint3D pointC = new OTSPoint3D(7400, 0, 0);
711                 OTSNode nodeA = new OTSNode(net, "A", pointA);
712                 OTSNode nodeB = new OTSNode(net, "B", pointB);
713                 OTSNode nodeC = new OTSNode(net, "C", pointC);
714                 CrossSectionLink linkAB = new CrossSectionLink(net, "AB", nodeA, nodeB, LinkType.FREEWAY,
715                         new OTSLine3D(pointA, pointB), getSimulator(), LaneKeepingPolicy.KEEP_RIGHT);
716                 CrossSectionLink linkBC = new CrossSectionLink(net, "BC", nodeB, nodeC, LinkType.FREEWAY,
717                         new OTSLine3D(pointB, pointC), getSimulator(), LaneKeepingPolicy.KEEP_RIGHT);
718                 Lane laneAB1 = new Lane(linkAB, "laneAB1", Length.createSI(0.0), Length.createSI(3.5), LaneType.HIGHWAY,
719                         new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
720                 Lane laneAB2 = new Lane(linkAB, "laneAB2", Length.createSI(3.5), Length.createSI(3.5), LaneType.HIGHWAY,
721                         new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
722                 Lane laneAB3 = new Lane(linkAB, "laneAB3", Length.createSI(7.0), Length.createSI(3.5), LaneType.HIGHWAY,
723                         new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
724                 Lane laneBC1 = new Lane(linkBC, "laneBC1", Length.createSI(0.0), Length.createSI(3.5), LaneType.HIGHWAY,
725                         new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
726                 Lane laneBC2 = new Lane(linkBC, "laneBC2", Length.createSI(3.5), Length.createSI(3.5), LaneType.HIGHWAY,
727                         new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
728                 Set<GTUType> gtuTypes = new HashSet<>();
729                 gtuTypes.add(GTUType.VEHICLE);
730                 Stripe stripeAB1 = new Stripe(linkAB, Length.createSI(-1.75), Length.createSI(-1.75), Length.createSI(0.2));
731                 Stripe stripeAB2 = new Stripe(linkAB, Length.createSI(1.75), Length.createSI(1.75), Length.createSI(0.2),
732                         gtuTypes, Permeable.BOTH);
733                 Stripe stripeAB3 = new Stripe(linkAB, Length.createSI(5.25), Length.createSI(5.25), Length.createSI(0.2),
734                         gtuTypes, Permeable.BOTH);
735                 Stripe stripeAB4 = new Stripe(linkAB, Length.createSI(8.75), Length.createSI(8.75), Length.createSI(0.2),
736                         gtuTypes, Permeable.BOTH);
737                 Stripe stripeBC1 = new Stripe(linkBC, Length.createSI(-1.75), Length.createSI(-1.75), Length.createSI(0.2),
738                         gtuTypes, Permeable.BOTH);
739                 Stripe stripeBC2 = new Stripe(linkBC, Length.createSI(1.75), Length.createSI(1.75), Length.createSI(0.2),
740                         gtuTypes, Permeable.BOTH);
741                 Stripe stripeBC3 = new Stripe(linkBC, Length.createSI(5.25), Length.createSI(5.25), Length.createSI(0.2),
742                         gtuTypes, Permeable.BOTH);
743                 new NodeAnimation(nodeA, getSimulator());
744                 new NodeAnimation(nodeB, getSimulator());
745                 new NodeAnimation(nodeC, getSimulator());
746                 new LinkAnimation(linkAB, getSimulator(), 0.5f);
747                 new LinkAnimation(linkBC, getSimulator(), 0.5f);
748                 new LaneAnimation(laneAB1, getSimulator(), Color.GRAY.brighter(), false);
749                 new LaneAnimation(laneAB2, getSimulator(), Color.GRAY.brighter(), false);
750                 new LaneAnimation(laneAB3, getSimulator(), Color.GRAY.brighter(), false);
751                 new LaneAnimation(laneBC1, getSimulator(), Color.GRAY.brighter(), false);
752                 new LaneAnimation(laneBC2, getSimulator(), Color.GRAY.brighter(), false);
753                 new StripeAnimation(stripeAB1, getSimulator(), TYPE.SOLID);
754                 new StripeAnimation(stripeAB2, getSimulator(), TYPE.DASHED);
755                 new StripeAnimation(stripeAB3, getSimulator(), TYPE.DASHED);
756                 new StripeAnimation(stripeAB4, getSimulator(), TYPE.SOLID);
757                 new StripeAnimation(stripeBC1, getSimulator(), TYPE.SOLID);
758                 new StripeAnimation(stripeBC2, getSimulator(), TYPE.DASHED);
759                 new StripeAnimation(stripeBC3, getSimulator(), TYPE.SOLID);
760                 // sensors
761                 new SinkSensor(laneBC1, laneBC1.getLength().minus(Length.createSI(100.0)), getSimulator());
762                 new SinkSensor(laneBC2, laneBC2.getLength().minus(Length.createSI(100.0)), getSimulator());
763 
764                 // detectors
765                 Lane[][] grid = new Lane[][] { new Lane[] { laneAB3 }, new Lane[] { laneAB2, laneBC2 },
766                         new Lane[] { laneAB1, laneBC1 } };
767                 Duration aggregationPeriod = Duration.createSI(60.0);
768                 DetectorMeasurement<?, ?>[] measurements = new DetectorMeasurement[] { Detector.MEAN_SPEED, Detector.PASSAGES,
769                         new VGainMeasurement(), new SigmaMeasurement(), new VDesMeasurement(), new VDes0Measurement() };
770                 String[] prefix = { "A", "B", "C" };
771                 for (int i = 0; i < grid.length; i++)
772                 {
773                     int num = 1;
774                     Length pos = Length.createSI(100.0);
775                     for (int j = 0; j < grid[i].length; j++)
776                     {
777                         while (pos.lt(grid[i][j].getLength()))
778                         {
779                             new Detector(String.format("%s%02d", prefix[i], num), grid[i][j], pos, Length.ZERO,
780                                     LmrsStrategies.this.simulator, aggregationPeriod, measurements);
781                             num++;
782                             pos = pos.plus(Length.createSI(100.0));
783                         }
784                         pos = pos.minus(grid[i][j].getLength());
785                     }
786                 }
787 
788                 // OD
789                 Categorization categorization = new Categorization("ODExample", GTUType.class);
790                 List<Node> origins = new ArrayList<>();
791                 origins.add(nodeA);
792                 List<Node> destinations = new ArrayList<>();
793                 destinations.add(nodeC);
794                 TimeVector timeVector =
795                         new TimeVector(new double[] { 0.0, 300.0, 2700.0, SIMTIME.si }, TimeUnit.BASE, StorageType.DENSE);
796                 ODMatrix od = new ODMatrix("LMRS strategies", origins, destinations, categorization, timeVector,
797                         Interpolation.LINEAR);
798                 double q = LmrsStrategies.this.qMax;
799                 FrequencyVector demand =
800                         new FrequencyVector(new double[] { q * .6, q * .6, q, 0.0 }, FrequencyUnit.PER_HOUR, StorageType.DENSE);
801                 Category category = new Category(categorization, GTUType.CAR);
802                 od.putDemandVector(nodeA, nodeC, category, demand, timeVector, Interpolation.LINEAR,
803                         1.0 - LmrsStrategies.this.fTruck);
804                 category = new Category(categorization, GTUType.TRUCK);
805                 od.putDemandVector(nodeA, nodeC, category, demand, timeVector, Interpolation.LINEAR,
806                         LmrsStrategies.this.fTruck);
807                 // options
808                 MarkovCorrelation<GTUType, Frequency> markov = new MarkovCorrelation<>();
809                 markov.addState(GTUType.TRUCK, 0.4);
810                 LaneBiases biases = new LaneBiases().addBias(GTUType.VEHICLE, LaneBias.bySpeed(140, 100)).addBias(GTUType.TRUCK,
811                         LaneBias.TRUCK_RIGHT);
812                 ODOptions odOptions = new ODOptions().set(ODOptions.MARKOV, markov).set(ODOptions.LANE_BIAS, biases)
813                         .set(ODOptions.NO_LC_DIST, Length.createSI(100.0))
814                         .set(ODOptions.GTU_TYPE, new LmrsStrategyCharacteristicsGenerator(stream))
815                         .set(ODOptions.HEADWAY_DIST, HeadwayDistribution.CONSTANT);
816                 Map<String, GeneratorObjects> generatedObjects = ODApplier.applyOD(net, od, getSimulator(), odOptions);
817                 for (String str : generatedObjects.keySet())
818                 {
819                     new GTUGeneratorAnimation(generatedObjects.get(str).getGenerator(), getSimulator());
820                 }
821 
822                 // Sampler
823                 if (LmrsStrategies.this.sampling)
824                 {
825                     LmrsStrategies.this.sampler = new RoadSampler(LmrsStrategies.this.simulator);
826                     addLaneToSampler(laneAB1);
827                     addLaneToSampler(laneAB2);
828                     addLaneToSampler(laneAB3);
829                     addLaneToSampler(laneBC1);
830                     addLaneToSampler(laneBC2);
831                     LmrsStrategies.this.sampler.registerExtendedDataType(new ExtendedDataTypeLength<GtuData>("Length")
832                     {
833                         @Override
834                         public FloatLength getValue(final GtuData gtu)
835                         {
836                             return FloatLength.createSI((float) gtu.getGtu().getLength().si);
837                         }
838                     });
839                     LmrsStrategies.this.sampler.registerExtendedDataType(new ExtendedDataTypeNumber<GtuData>("Rho")
840                     {
841                         @Override
842                         public Float getValue(final GtuData gtu)
843                         {
844                             try
845                             {
846                                 return gtu.getGtu().getParameters().getParameter(Tailgating.RHO).floatValue();
847                             }
848                             catch (ParameterException exception)
849                             {
850                                 throw new RuntimeException("Could not obtain rho for trajectory.", exception);
851                             }
852                         }
853                     });
854                     LmrsStrategies.this.sampler.registerExtendedDataType(new ExtendedDataTypeSpeed<GtuData>("V0")
855                     {
856                         @Override
857                         public FloatSpeed getValue(final GtuData gtu)
858                         {
859                             try
860                             {
861                                 return FloatSpeed.createSI(gtu.getGtu().getDesiredSpeed().floatValue());
862                             }
863                             catch (NullPointerException ex)
864                             {
865                                 return FloatSpeed.NaN;
866                             }
867                         }
868                     });
869                     LmrsStrategies.this.sampler.registerExtendedDataType(new ExtendedDataTypeDuration<GtuData>("T")
870                     {
871                         @Override
872                         public FloatDuration getValue(final GtuData gtu)
873                         {
874                             try
875                             {
876                                 return FloatDuration
877                                         .createSI(gtu.getGtu().getParameters().getParameter(ParameterTypes.T).floatValue());
878                             }
879                             catch (ParameterException exception)
880                             {
881                                 throw new RuntimeException("Could not obtain T for trajectory.", exception);
882                             }
883                         }
884                     });
885                 }
886             }
887             catch (NetworkException | OTSGeometryException | NamingException | ValueException | ParameterException
888                     | RemoteException | SimRuntimeException exception)
889             {
890                 exception.printStackTrace();
891             }
892         }
893 
894         /**
895          * Adds a lane to the sampler.
896          * @param lane Lane; lane
897          */
898         @SuppressWarnings("synthetic-access")
899         private void addLaneToSampler(final Lane lane)
900         {
901             LmrsStrategies.this.sampler.registerSpaceTimeRegion(
902                     new SpaceTimeRegion(new KpiLaneDirection(new LaneData(lane), KpiGtuDirectionality.DIR_PLUS), Length.ZERO,
903                             lane.getLength(), Time.createSI(300), SIMTIME));
904         }
905 
906         /** {@inheritDoc} */
907         @SuppressWarnings("synthetic-access")
908         @Override
909         public OTSNetwork getNetwork()
910         {
911             return LmrsStrategies.this.network;
912         }
913 
914     }
915 
916     /** Incentives. */
917     private Class<? extends Incentive>[] incentives;
918 
919     /** {@inheritDoc} */
920     @Override
921     public void notify(final EventInterface event) throws RemoteException
922     {
923         if (event.getType().equals(LaneBasedGTU.LANE_CHANGE_EVENT))
924         {
925             Object[] payload = (Object[]) event.getContent();
926             GTU gtu = this.network.getGTU((String) payload[0]);
927             LateralDirectionality dir = (LateralDirectionality) payload[1];
928             DirectedLanePosition from = (DirectedLanePosition) payload[2];
929             DesireBased desire = (DesireBased) gtu.getTacticalPlanner();
930             Double dMax = Double.NEGATIVE_INFINITY;
931             String cause = "Unknown";
932             for (Class<? extends Incentive> incentive : this.incentives)
933             {
934                 double d = desire.getLatestDesire(incentive).get(dir);
935                 if (d > dMax)
936                 {
937                     cause = incentive.getSimpleName();
938                     dMax = d;
939                 }
940             }
941             this.laneChanges.add(String.format("%.3f,%s,%.3f,%s,%s", this.simulator.getSimulatorTime().si,
942                     from.getLane().getFullId(), from.getPosition().si, dir, cause));
943         }
944         else if (event.getType().equals(Network.GTU_ADD_EVENT))
945         {
946             this.network.getGTU((String) event.getContent()).addListener(this, LaneBasedGTU.LANE_CHANGE_EVENT);
947         }
948         else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
949         {
950             this.network.getGTU((String) event.getContent()).removeListener(this, LaneBasedGTU.LANE_CHANGE_EVENT);
951         }
952         else if (event.getType().equals(SimulatorInterface.END_REPLICATION_EVENT))
953         {
954             CompressionMethod compression = this.autorun ? CompressionMethod.ZIP : CompressionMethod.NONE;
955             // write detector data
956             Detector.writeToFile(this.network, this.folder + "detsAggrData" + LmrsStrategies.this.suffix + ".txt", true, "%.3f",
957                     compression);
958             Detector.writeToFile(this.network, this.folder + "detsMesoData" + LmrsStrategies.this.suffix + ".txt", false,
959                     "%.3f", compression);
960             // write lane change data
961             this.laneChanges.add(0, "t[s],lane,x[m],dir,cause");
962             BufferedWriter bw = CompressedFileWriter.create(this.folder + "laneChanges" + LmrsStrategies.this.suffix + ".txt",
963                     this.autorun);
964             try
965             {
966                 for (String str : this.laneChanges)
967                 {
968                     bw.write(str);
969                     bw.newLine();
970                 }
971             }
972             catch (IOException exception)
973             {
974                 throw new RuntimeException("Could not write to file.", exception);
975             }
976             finally
977             {
978                 try
979                 {
980                     if (bw != null)
981                     {
982                         bw.close();
983                     }
984                 }
985                 catch (IOException ex)
986                 {
987                     ex.printStackTrace();
988                 }
989             }
990             // write sampler data
991             if (LmrsStrategies.this.sampling)
992             {
993                 LmrsStrategies.this.sampler.writeToFile(this.folder + "sampled" + LmrsStrategies.this.suffix + ".txt");
994             }
995             // solve bug that event is fired twice
996             LmrsStrategies.this.simulator.removeListener(LmrsStrategies.this, SimulatorInterface.END_REPLICATION_EVENT);
997             // beep
998             if (!this.autorun)
999             {
1000                 Toolkit.getDefaultToolkit().beep();
1001             }
1002             else
1003             {
1004                 System.exit(0);
1005             }
1006         }
1007     }
1008 
1009     /**
1010      * Class to store sigma value.
1011      * <p>
1012      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
1013      * <br>
1014      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
1015      * <p>
1016      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 3 mei 2018 <br>
1017      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
1018      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
1019      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
1020      */
1021     class SigmaMeasurement implements DetectorMeasurement<List<Double>, List<Double>>
1022     {
1023         /** {@inheritDoc} */
1024         @Override
1025         public List<Double> identity()
1026         {
1027             return new ArrayList<>();
1028         }
1029 
1030         /** {@inheritDoc} */
1031         @Override
1032         public List<Double> accumulateEntry(final List<Double> cumulative, final LaneBasedGTU gtu, final Detector loopDetector)
1033         {
1034             Double sig = gtu.getParameters().getParameterOrNull(LmrsParameters.SOCIO);
1035             if (sig == null)
1036             {
1037                 cumulative.add(Double.NaN);
1038             }
1039             else
1040             {
1041                 cumulative.add(sig);
1042             }
1043             return cumulative;
1044         }
1045 
1046         /** {@inheritDoc} */
1047         @Override
1048         public List<Double> accumulateExit(final List<Double> cumulative, final LaneBasedGTU gtu, final Detector loopDetector)
1049         {
1050             return cumulative;
1051         }
1052 
1053         /** {@inheritDoc} */
1054         @Override
1055         public boolean isPeriodic()
1056         {
1057             return false;
1058         }
1059 
1060         /** {@inheritDoc} */
1061         @Override
1062         public List<Double> aggregate(final List<Double> cumulative, final int count, final Duration aggregation)
1063         {
1064             return cumulative;
1065         }
1066 
1067         /** {@inheritDoc} */
1068         @Override
1069         public String getName()
1070         {
1071             return "sigma";
1072         }
1073 
1074         /** {@inheritDoc} */
1075         @Override
1076         public String stringValue(final List<Double> aggregate, final String format)
1077         {
1078             return Detector.printListDouble(aggregate, format);
1079         }
1080     }
1081 
1082     /**
1083      * Class to store vGain value.
1084      * <p>
1085      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
1086      * <br>
1087      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
1088      * <p>
1089      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 3 mei 2018 <br>
1090      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
1091      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
1092      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
1093      */
1094     class VGainMeasurement implements DetectorMeasurement<List<Double>, List<Double>>
1095     {
1096         /** {@inheritDoc} */
1097         @Override
1098         public List<Double> identity()
1099         {
1100             return new ArrayList<>();
1101         }
1102 
1103         /** {@inheritDoc} */
1104         @Override
1105         public List<Double> accumulateEntry(final List<Double> cumulative, final LaneBasedGTU gtu, final Detector loopDetector)
1106         {
1107             Speed vGn = gtu.getParameters().getParameterOrNull(LmrsParameters.VGAIN);
1108             if (vGn == null)
1109             {
1110                 cumulative.add(Double.NaN);
1111             }
1112             else
1113             {
1114                 cumulative.add(vGn.si);
1115             }
1116             return cumulative;
1117         }
1118 
1119         /** {@inheritDoc} */
1120         @Override
1121         public List<Double> accumulateExit(final List<Double> cumulative, final LaneBasedGTU gtu, final Detector loopDetector)
1122         {
1123             return cumulative;
1124         }
1125 
1126         /** {@inheritDoc} */
1127         @Override
1128         public boolean isPeriodic()
1129         {
1130             return false;
1131         }
1132 
1133         /** {@inheritDoc} */
1134         @Override
1135         public List<Double> aggregate(final List<Double> cumulative, final int count, final Duration aggregation)
1136         {
1137             return cumulative;
1138         }
1139 
1140         /** {@inheritDoc} */
1141         @Override
1142         public String getName()
1143         {
1144             return "vGain";
1145         }
1146 
1147         /** {@inheritDoc} */
1148         @Override
1149         public String stringValue(final List<Double> aggregate, final String format)
1150         {
1151             return Detector.printListDouble(aggregate, format);
1152         }
1153     }
1154 
1155     /**
1156      * Class to store vDes value.
1157      * <p>
1158      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
1159      * <br>
1160      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
1161      * <p>
1162      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 3 mei 2018 <br>
1163      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
1164      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
1165      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
1166      */
1167     class VDesMeasurement implements DetectorMeasurement<List<Double>, List<Double>>
1168     {
1169         /** {@inheritDoc} */
1170         @Override
1171         public List<Double> identity()
1172         {
1173             return new ArrayList<>();
1174         }
1175 
1176         /** {@inheritDoc} */
1177         @Override
1178         public List<Double> accumulateEntry(final List<Double> cumulative, final LaneBasedGTU gtu, final Detector loopDetector)
1179         {
1180             Speed vDes = gtu.getDesiredSpeed();
1181             if (vDes == null)
1182             {
1183                 cumulative.add(Double.NaN);
1184             }
1185             else
1186             {
1187                 cumulative.add(vDes.si);
1188             }
1189             return cumulative;
1190         }
1191 
1192         /** {@inheritDoc} */
1193         @Override
1194         public List<Double> accumulateExit(final List<Double> cumulative, final LaneBasedGTU gtu, final Detector loopDetector)
1195         {
1196             return cumulative;
1197         }
1198 
1199         /** {@inheritDoc} */
1200         @Override
1201         public boolean isPeriodic()
1202         {
1203             return false;
1204         }
1205 
1206         /** {@inheritDoc} */
1207         @Override
1208         public List<Double> aggregate(final List<Double> cumulative, final int count, final Duration aggregation)
1209         {
1210             return cumulative;
1211         }
1212 
1213         /** {@inheritDoc} */
1214         @Override
1215         public String getName()
1216         {
1217             return "vDes";
1218         }
1219 
1220         /** {@inheritDoc} */
1221         @Override
1222         public String stringValue(final List<Double> aggregate, final String format)
1223         {
1224             return Detector.printListDouble(aggregate, format);
1225         }
1226     }
1227 
1228     /**
1229      * Class to store vDes value.
1230      * <p>
1231      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
1232      * <br>
1233      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
1234      * <p>
1235      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 3 mei 2018 <br>
1236      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
1237      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
1238      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
1239      */
1240     class VDes0Measurement implements DetectorMeasurement<List<Double>, List<Double>>
1241     {
1242         /** {@inheritDoc} */
1243         @Override
1244         public List<Double> identity()
1245         {
1246             return new ArrayList<>();
1247         }
1248 
1249         /** {@inheritDoc} */
1250         @Override
1251         public List<Double> accumulateEntry(final List<Double> cumulative, final LaneBasedGTU gtu, final Detector loopDetector)
1252         {
1253             double vDes0;
1254             try
1255             {
1256                 vDes0 = Math.min(gtu.getMaximumSpeed().si, gtu.getParameters().getParameter(ParameterTypes.FSPEED)
1257                         * loopDetector.getLane().getSpeedLimit(gtu.getGTUType()).si);
1258             }
1259             catch (ParameterException | NetworkException exception)
1260             {
1261                 throw new RuntimeException(exception);
1262             }
1263             cumulative.add(vDes0);
1264             return cumulative;
1265         }
1266 
1267         /** {@inheritDoc} */
1268         @Override
1269         public List<Double> accumulateExit(final List<Double> cumulative, final LaneBasedGTU gtu, final Detector loopDetector)
1270         {
1271             return cumulative;
1272         }
1273 
1274         /** {@inheritDoc} */
1275         @Override
1276         public boolean isPeriodic()
1277         {
1278             return false;
1279         }
1280 
1281         /** {@inheritDoc} */
1282         @Override
1283         public List<Double> aggregate(final List<Double> cumulative, final int count, final Duration aggregation)
1284         {
1285             return cumulative;
1286         }
1287 
1288         /** {@inheritDoc} */
1289         @Override
1290         public String getName()
1291         {
1292             return "vDes0";
1293         }
1294 
1295         /** {@inheritDoc} */
1296         @Override
1297         public String stringValue(final List<Double> aggregate, final String format)
1298         {
1299             return Detector.printListDouble(aggregate, format);
1300         }
1301     }
1302 
1303 }