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