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