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