View Javadoc
1   package org.opentrafficsim.ahfe;
2   
3   import java.awt.Color;
4   import java.io.BufferedWriter;
5   import java.io.IOException;
6   import java.net.URL;
7   import java.util.ArrayList;
8   import java.util.LinkedHashSet;
9   import java.util.List;
10  import java.util.Set;
11  
12  import org.djunits.unit.FrequencyUnit;
13  import org.djunits.unit.SpeedUnit;
14  import org.djunits.unit.TimeUnit;
15  import org.djunits.value.ValueRuntimeException;
16  import org.djunits.value.storage.StorageType;
17  import org.djunits.value.vdouble.scalar.Acceleration;
18  import org.djunits.value.vdouble.scalar.Duration;
19  import org.djunits.value.vdouble.scalar.Frequency;
20  import org.djunits.value.vdouble.scalar.Length;
21  import org.djunits.value.vdouble.scalar.Speed;
22  import org.djunits.value.vdouble.vector.FrequencyVector;
23  import org.djunits.value.vdouble.vector.TimeVector;
24  import org.djunits.value.vdouble.vector.base.DoubleVector;
25  import org.djutils.cli.CliException;
26  import org.djutils.cli.CliUtil;
27  import org.djutils.exceptions.Throw;
28  import org.djutils.exceptions.Try;
29  import org.djutils.io.URLResource;
30  import org.opentrafficsim.base.CompressedFileWriter;
31  import org.opentrafficsim.base.parameters.ParameterException;
32  import org.opentrafficsim.base.parameters.ParameterSet;
33  import org.opentrafficsim.base.parameters.ParameterTypeDouble;
34  import org.opentrafficsim.base.parameters.ParameterTypeDuration;
35  import org.opentrafficsim.base.parameters.ParameterTypes;
36  import org.opentrafficsim.base.parameters.Parameters;
37  import org.opentrafficsim.base.parameters.constraint.DualBound;
38  import org.opentrafficsim.base.parameters.constraint.NumericConstraint;
39  import org.opentrafficsim.core.animation.gtu.colorer.AccelerationGTUColorer;
40  import org.opentrafficsim.core.animation.gtu.colorer.SpeedGTUColorer;
41  import org.opentrafficsim.core.animation.gtu.colorer.SwitchableGTUColorer;
42  import org.opentrafficsim.core.distributions.Distribution;
43  import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
44  import org.opentrafficsim.core.distributions.Generator;
45  import org.opentrafficsim.core.distributions.ProbabilityException;
46  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
47  import org.opentrafficsim.core.gtu.AbstractGTU;
48  import org.opentrafficsim.core.gtu.GTUException;
49  import org.opentrafficsim.core.gtu.GTUType;
50  import org.opentrafficsim.core.gtu.perception.DirectEgoPerception;
51  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
52  import org.opentrafficsim.core.network.Node;
53  import org.opentrafficsim.core.network.OTSNetwork;
54  import org.opentrafficsim.core.parameters.ParameterFactoryByType;
55  import org.opentrafficsim.core.perception.HistoryManagerDEVS;
56  import org.opentrafficsim.core.units.distributions.ContinuousDistSpeed;
57  import org.opentrafficsim.draw.core.OTSDrawingException;
58  import org.opentrafficsim.draw.factory.DefaultAnimationFactory;
59  import org.opentrafficsim.kpi.interfaces.LaneDataInterface;
60  import org.opentrafficsim.kpi.sampling.KpiGtuDirectionality;
61  import org.opentrafficsim.kpi.sampling.KpiLaneDirection;
62  import org.opentrafficsim.kpi.sampling.SpaceTimeRegion;
63  import org.opentrafficsim.kpi.sampling.data.ExtendedDataTypeNumber;
64  import org.opentrafficsim.road.gtu.colorer.DesiredHeadwayColorer;
65  import org.opentrafficsim.road.gtu.colorer.DesiredSpeedColorer;
66  import org.opentrafficsim.road.gtu.colorer.FixedColor;
67  import org.opentrafficsim.road.gtu.colorer.GTUTypeColorer;
68  import org.opentrafficsim.road.gtu.colorer.IncentiveColorer;
69  import org.opentrafficsim.road.gtu.colorer.ReactionTimeColorer;
70  import org.opentrafficsim.road.gtu.colorer.SynchronizationColorer;
71  import org.opentrafficsim.road.gtu.colorer.TaskColorer;
72  import org.opentrafficsim.road.gtu.colorer.TaskSaturationColorer;
73  import org.opentrafficsim.road.gtu.colorer.TotalDesireColorer;
74  import org.opentrafficsim.road.gtu.generator.od.DefaultGTUCharacteristicsGeneratorOD;
75  import org.opentrafficsim.road.gtu.generator.od.ODApplier;
76  import org.opentrafficsim.road.gtu.generator.od.ODOptions;
77  import org.opentrafficsim.road.gtu.generator.od.StrategicalPlannerFactorySupplierOD;
78  import org.opentrafficsim.road.gtu.lane.CollisionDetector;
79  import org.opentrafficsim.road.gtu.lane.CollisionException;
80  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
81  import org.opentrafficsim.road.gtu.lane.perception.CategoricalLanePerception;
82  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
83  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
84  import org.opentrafficsim.road.gtu.lane.perception.PerceptionFactory;
85  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
86  import org.opentrafficsim.road.gtu.lane.perception.categories.AnticipationTrafficPerception;
87  import org.opentrafficsim.road.gtu.lane.perception.categories.DirectInfrastructurePerception;
88  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.Anticipation;
89  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.DirectNeighborsPerception;
90  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.Estimation;
91  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType.PerceivedHeadwayGtuType;
92  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsPerception;
93  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.TaskHeadwayCollector;
94  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
95  import org.opentrafficsim.road.gtu.lane.perception.mental.AbstractTask;
96  import org.opentrafficsim.road.gtu.lane.perception.mental.AdaptationHeadway;
97  import org.opentrafficsim.road.gtu.lane.perception.mental.AdaptationSituationalAwareness;
98  import org.opentrafficsim.road.gtu.lane.perception.mental.Fuller;
99  import org.opentrafficsim.road.gtu.lane.perception.mental.Fuller.BehavioralAdaptation;
100 import org.opentrafficsim.road.gtu.lane.perception.mental.Task;
101 import org.opentrafficsim.road.gtu.lane.perception.mental.TaskManager;
102 import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM;
103 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
104 import org.opentrafficsim.road.gtu.lane.tactical.following.DesiredSpeedModel;
105 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlus;
106 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationIncentive;
107 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLMRSPerceptionFactory;
108 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveCourtesy;
109 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveGetInLane;
110 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveKeep;
111 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveRoute;
112 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSocioSpeed;
113 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSpeed;
114 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSpeedWithCourtesy;
115 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveStayRight;
116 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory;
117 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.SocioDesiredSpeed;
118 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
119 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance;
120 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
121 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.MandatoryIncentive;
122 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
123 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
124 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
125 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
126 import org.opentrafficsim.road.gtu.strategical.od.Categorization;
127 import org.opentrafficsim.road.gtu.strategical.od.Category;
128 import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
129 import org.opentrafficsim.road.gtu.strategical.od.ODMatrix;
130 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
131 import org.opentrafficsim.road.network.OTSRoadNetwork;
132 import org.opentrafficsim.road.network.factory.xml.parser.XmlNetworkLaneParser;
133 import org.opentrafficsim.road.network.lane.CrossSectionLink;
134 import org.opentrafficsim.road.network.sampling.GtuData;
135 import org.opentrafficsim.road.network.sampling.LinkData;
136 import org.opentrafficsim.road.network.sampling.RoadSampler;
137 import org.opentrafficsim.road.network.sampling.data.LeaderId;
138 import org.opentrafficsim.road.network.sampling.data.ReactionTime;
139 import org.opentrafficsim.road.network.sampling.data.TimeToCollision;
140 import org.opentrafficsim.swing.script.AbstractSimulationScript;
141 
142 import nl.tudelft.simulation.jstats.distributions.DistLogNormal;
143 import nl.tudelft.simulation.jstats.distributions.DistNormal;
144 import nl.tudelft.simulation.jstats.distributions.DistTriangular;
145 import nl.tudelft.simulation.jstats.streams.StreamInterface;
146 import picocli.CommandLine.Option;
147 
148 /**
149  * Distraction simulation.
150  * <p>
151  * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
152  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
153  * <p>
154  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 9 apr. 2018 <br>
155  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
156  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
157  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
158  */
159 public final class AnticipationRelianceScript extends AbstractSimulationScript
160 {
161 
162     /** Car-following task parameter. */
163     static final ParameterTypeDuration HEXP = new ParameterTypeDuration("Hexp",
164             "Exponential decay of car-following task by headway.", Duration.instantiateSI(4.0), NumericConstraint.POSITIVE);
165 
166     /** Fraction of primary task that can be reduced by anticipation reliance. */
167     static final ParameterTypeDouble ALPHA = new ParameterTypeDouble("alpha",
168             "Fraction of primary task that can be reduced by anticipation reliance.", 0.8, DualBound.UNITINTERVAL);
169 
170     /** Fraction of auxiliary tasks that can be reduced by anticipation reliance. */
171     static final ParameterTypeDouble BETA = new ParameterTypeDouble("beta",
172             "Fraction of auxiliary tasks that can be reduced by anticipation reliance.", 0.6, DualBound.UNITINTERVAL);
173 
174     /** Distance to not consider at start of the network. */
175     private static Length ignoreStart = Length.instantiateSI(2900); // Not 100m on pre-link, so 3000 total
176 
177     /** Distance to not consider at end of the network. */
178     private static Length ignoreEnd = Length.instantiateSI(1000);
179 
180     /** Sampler. */
181     private RoadSampler sampler;
182 
183     /** Truck fraction. */
184     @Option(names = {"-f", "--fTruck"}, description = "Truck fraction", defaultValue = "0.05")
185     private double fTruck;
186 
187     /** Left demand. */
188     @Option(names = "--leftDemand", description = "Left demand", defaultValue = "3500/h")
189     private Frequency leftDemand;
190 
191     /** Right demand. */
192     @Option(names = "--rightDemand", description = "Right demand", defaultValue = "3200/h")
193     private Frequency rightDemand;
194 
195     /** Sampler. */
196     @Option(names = "--sampler", description = "Sampler", negatable = true, defaultValue = "false")
197     private boolean doSampler;
198 
199     /** Sampler. */
200     @Option(names = "--scenario", description = "Scenario", defaultValue = "test")
201     private String scenario;
202 
203     /** Output directory. */
204     @Option(names = "--outputDir", description = "Output directory", defaultValue = "")
205     private String outputDir;
206 
207     /** Tasks. */
208     @Option(names = "--tasks", description = "Use tasks", negatable = true, defaultValue = "false")
209     private boolean tasks;
210 
211     /** Strategies. */
212     @Option(names = "--strategies", description = "Use strategies", negatable = true, defaultValue = "false")
213     private boolean strategies;
214 
215     /** Adaptation. */
216     @Option(names = "--adaptation", description = "Use adaptation", negatable = true, defaultValue = "false")
217     private boolean adaptation;
218 
219     /** Alpha. */
220     @Option(names = "--alpha", description = "Alpha: maximum lane-change reduction", defaultValue = "0.8")
221     private double alpha;
222 
223     /** Beta. */
224     @Option(names = "--beta", description = "Beta: maximum car-following reduction", defaultValue = "0.6")
225     private double beta;
226 
227     /** Fraction of underestimation. */
228     @Option(names = "--fUnderestimate", description = "Fraction underestimation", defaultValue = "0.75")
229     private double fractionUnderestimation;
230 
231     /**
232      * Main method.
233      * @param args String[]; command line arguments
234      */
235     public static void main(final String... args)
236     {
237         // Long start = System.currentTimeMillis();
238         AnticipationRelianceScripthtml#AnticipationRelianceScript">AnticipationRelianceScript script = new AnticipationRelianceScript();
239         if (script.isAutorun())
240         {
241             System.out.println("Running " + script.scenario + "_" + script.getSeed());
242         }
243         // script.setProperty("sampler", true);
244         // script.setProperty("autorun", false);
245         // script.setProperty("tasks", true);
246         // script.setProperty("strategies", false);
247         // script.setProperty("adaptation", false);
248         // script.setProperty("alpha", 0.0);
249         // script.setProperty("beta", 0.0);
250         try
251         {
252             CliUtil.execute(script, args); // XX from old version
253             script.start();
254         }
255         catch (Throwable throwable)
256         {
257             // Note: we only get here if we autorun
258             Throwable original = throwable;
259             while (throwable != null)
260             {
261                 if (throwable instanceof CollisionException)
262                 {
263                     double tCollision = script.getSimulator().getSimulatorTime().si;
264                     script.onSimulationEnd();
265                     String file = script.getOutputFileStart() + "_collision.txt";
266                     BufferedWriter writer = CompressedFileWriter.create(file, false);
267                     try
268                     {
269                         writer.write(String.format("Collision at: %.6f", tCollision));
270                         writer.newLine();
271                         writer.write(throwable.getMessage());
272                         writer.close();
273                     }
274                     catch (IOException ex)
275                     {
276                         System.err.println("Unable to write to file.");
277                     }
278                     System.exit(0);
279                 }
280                 throwable = throwable.getCause();
281             }
282             throw new RuntimeException(original);
283         }
284     }
285 
286     /**
287      * Returns the start for output files, which can be amended with some name of contained data and extension.
288      * @return String; start for output files, which can be amended with some name of contained data and extension
289      */
290     private String getOutputFileStart()
291     {
292         return this.outputDir + this.scenario + "_" + getSeed();
293     }
294 
295     /**
296      * Constructor.
297      */
298     private AnticipationRelianceScript()
299     {
300         super("Distraction", "Distraction simulation");
301         setGtuColorer(SwitchableGTUColorer.builder().addActiveColorer(new FixedColor(Color.BLUE, "Blue"))
302                 .addColorer(new TaskColorer("car-following")).addColorer(new TaskColorer("lane-changing"))
303                 .addColorer(new TaskSaturationColorer()).addColorer(new ReactionTimeColorer(Duration.instantiateSI(1.0)))
304                 .addColorer(GTUTypeColorer.DEFAULT).addColorer(new SpeedGTUColorer(new Speed(150, SpeedUnit.KM_PER_HOUR)))
305                 .addColorer(
306                         new DesiredSpeedColorer(new Speed(50, SpeedUnit.KM_PER_HOUR), new Speed(150, SpeedUnit.KM_PER_HOUR)))
307                 .addColorer(new AccelerationGTUColorer(Acceleration.instantiateSI(-6.0), Acceleration.instantiateSI(2)))
308                 .addColorer(new SynchronizationColorer())
309                 .addColorer(new DesiredHeadwayColorer(Duration.instantiateSI(0.56), Duration.instantiateSI(2.4)))
310                 .addColorer(new TotalDesireColorer()).addColorer(new IncentiveColorer(IncentiveRoute.class))
311                 .addColorer(new IncentiveColorer(IncentiveSpeedWithCourtesy.class))
312                 .addColorer(new IncentiveColorer(IncentiveSpeed.class)).addColorer(new IncentiveColorer(IncentiveKeep.class))
313                 .addColorer(new IncentiveColorer(IncentiveGetInLane.class))
314                 .addColorer(new IncentiveColorer(IncentiveCourtesy.class))
315                 .addColorer(new IncentiveColorer(IncentiveSocioSpeed.class)).build());
316         try
317         {
318             CliUtil.changeOptionDefault(this, "warmupTime", "360s");
319             CliUtil.changeOptionDefault(this, "simulationTime", "3960s");
320         }
321         catch (NoSuchFieldException | IllegalStateException | IllegalArgumentException | CliException exception)
322         {
323             throw new RuntimeException(exception);
324         }
325     }
326 
327     /** {@inheritDoc} */
328     @Override
329     protected void onSimulationEnd()
330     {
331         if (this.sampler != null)
332         {
333             this.sampler.writeToFile(getOutputFileStart() + ".csv");
334         }
335     }
336 
337     /** {@inheritDoc} */
338     @Override
339     protected OTSRoadNetwork setupSimulation(final OTSSimulatorInterface sim) throws Exception
340     {
341         AbstractGTU.ALIGNED = true;
342 
343         // Network
344         URL xmlURL = URLResource.getResource("/AHFE/Network.xml");
345         OTSRoadNetwork network = new OTSRoadNetwork("Distraction", true);
346         new CollisionDetector(network); // XXX: is this needed here? was in old version...
347         XmlNetworkLaneParser.build(xmlURL, network, sim, false);
348 
349         // new Distraction("distraction", ((CrossSectionLink) network.getLink("END")).getLanes().get(0),
350         // Length.instantiateSI(1000),
351         // sim, new TrapezoidProfile(0.2, Length.instantiateSI(-400), Length.instantiateSI(200), Length.instantiateSI(400)));
352 
353         // OD
354         List<Node> origins = new ArrayList<>();
355         origins.add(network.getNode("LEFTINPRE"));
356         origins.add(network.getNode("RIGHTINPRE"));
357         List<Node> destinations = new ArrayList<>();
358         destinations.add(network.getNode("EXIT"));
359         Categorization categorization = new Categorization("Distraction", GTUType.class);
360         TimeVector globalTime =
361                 DoubleVector.instantiate(new double[] {0, 360, 1560, 2160, 3960}, TimeUnit.BASE_SECOND, StorageType.DENSE);
362         ODMatrix od = new ODMatrix("Distraction", origins, destinations, categorization, globalTime, Interpolation.LINEAR);
363         Category carCategory = new Category(categorization, network.getGtuType(GTUType.DEFAULTS.CAR));
364         Category truckCategory = new Category(categorization, network.getGtuType(GTUType.DEFAULTS.TRUCK));
365         FrequencyVector leftDemandPatternCar =
366                 getDemand(this.leftDemand.getInUnit(FrequencyUnit.PER_HOUR) * (1.0 - this.fTruck));
367         FrequencyVector leftDemandPatternTruck = getDemand(this.leftDemand.getInUnit(FrequencyUnit.PER_HOUR) * this.fTruck);
368         FrequencyVector rightDemandPatternCar =
369                 getDemand(this.rightDemand.getInUnit(FrequencyUnit.PER_HOUR) * (1.0 - this.fTruck));
370         FrequencyVector rightDemandPatternTruck = getDemand(this.rightDemand.getInUnit(FrequencyUnit.PER_HOUR) * this.fTruck);
371         od.putDemandVector(network.getNode("LEFTINPRE"), network.getNode("EXIT"), carCategory, leftDemandPatternCar);
372         od.putDemandVector(network.getNode("LEFTINPRE"), network.getNode("EXIT"), truckCategory, leftDemandPatternTruck);
373         od.putDemandVector(network.getNode("RIGHTINPRE"), network.getNode("EXIT"), carCategory, rightDemandPatternCar);
374         od.putDemandVector(network.getNode("RIGHTINPRE"), network.getNode("EXIT"), truckCategory, rightDemandPatternTruck);
375         ODOptions odOptions = new ODOptions()
376                 .set(ODOptions.GTU_TYPE, new DefaultGTUCharacteristicsGeneratorOD(new DistractionFactorySupplier()))
377                 .set(ODOptions.INSTANT_LC, true);
378         ODApplier.applyOD(network, od, sim, odOptions);
379 
380         // History
381         sim.getReplication()
382                 .setHistoryManager(new HistoryManagerDEVS(sim, Duration.instantiateSI(2.0), Duration.instantiateSI(1.0)));
383 
384         // Sampler
385         if (this.doSampler)
386         {
387             this.sampler = new RoadSampler(sim);
388             this.sampler.registerExtendedDataType(new TimeToCollision());
389             this.sampler.registerExtendedDataType(new TaskSaturationDataType());
390             this.sampler.registerExtendedDataType(new LeaderId());
391             this.sampler.registerExtendedDataType(new ReactionTime());
392             this.sampler.registerExtendedDataType(new SituationalAwarenessDataType());
393             if (this.tasks)
394             {
395                 this.sampler.registerExtendedDataType(new TaskAnticipationRelianceDataType("car-following"));
396                 this.sampler.registerExtendedDataType(new TaskDemandDataType("car-following"));
397                 this.sampler.registerExtendedDataType(new TaskAnticipationRelianceDataType("lane-changing"));
398                 this.sampler.registerExtendedDataType(new TaskDemandDataType("lane-changing"));
399             }
400 
401             LinkData linkData = new LinkData((CrossSectionLink) network.getLink("LEFTIN"));
402             registerLinkToSampler(linkData, ignoreStart, linkData.getLength());
403             linkData = new LinkData((CrossSectionLink) network.getLink("RIGHTIN"));
404             registerLinkToSampler(linkData, ignoreStart, linkData.getLength());
405             linkData = new LinkData((CrossSectionLink) network.getLink("CONVERGE"));
406             registerLinkToSampler(linkData, Length.ZERO, linkData.getLength());
407             linkData = new LinkData((CrossSectionLink) network.getLink("WEAVING"));
408             registerLinkToSampler(linkData, Length.ZERO, linkData.getLength());
409             linkData = new LinkData((CrossSectionLink) network.getLink("END"));
410             registerLinkToSampler(linkData, Length.ZERO, linkData.getLength().minus(ignoreEnd));
411         }
412 
413         // return
414         return network;
415     }
416 
417     /**
418      * Register a link to the sampler, so data is sampled there.
419      * @param linkData LinkData; link data
420      * @param startDistance Length; start distance on link
421      * @param endDistance Length; end distance on link
422      */
423     private void registerLinkToSampler(final LinkData linkData, final Length startDistance, final Length endDistance)
424     {
425         for (LaneDataInterface laneData : linkData.getLaneDatas())
426         {
427             Length start = laneData.getLength().times(startDistance.si / linkData.getLength().si);
428             Length end = laneData.getLength().times(endDistance.si / linkData.getLength().si);
429             this.sampler
430                     .registerSpaceTimeRegion(new SpaceTimeRegion(new KpiLaneDirection(laneData, KpiGtuDirectionality.DIR_PLUS),
431                             start, end, getStartTime().plus(getWarmupTime()), getStartTime().plus(getSimulationTime())));
432         }
433     }
434 
435     /**
436      * Compose demand vector.
437      * @param demand double; maximum demand value
438      * @return FrequencyVector demand vector
439      * @throws ValueRuntimeException on value exception
440      */
441     private static FrequencyVector getDemand(final double demand) throws ValueRuntimeException
442     {
443         return DoubleVector.instantiate(new double[] {demand * 0.5, demand * 0.5, demand, demand, 0.0}, FrequencyUnit.PER_HOUR,
444                 StorageType.DENSE);
445     }
446 
447     /** {@inheritDoc} */
448     @Override
449     protected void animateNetwork(final OTSNetwork net)
450     {
451         try
452         {
453             DefaultAnimationFactory.animateXmlNetwork(net, getSimulator(), getGtuColorer());
454         }
455         catch (OTSDrawingException exception)
456         {
457             throw new RuntimeException("Exception while creating network animation.", exception);
458         }
459     }
460 
461     /////////////////////
462     ////// FACTORY //////
463     /////////////////////
464 
465     /**
466      * Supplier of strategical factory.
467      * <p>
468      * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
469      * <br>
470      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
471      * <p>
472      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 9 apr. 2018 <br>
473      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
474      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
475      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
476      */
477     private class DistractionFactorySupplier implements StrategicalPlannerFactorySupplierOD
478     {
479 
480         /** Factory cars. */
481         private LaneBasedStrategicalRoutePlannerFactory factoryCar = null;
482 
483         /** Factory trucks. */
484         private LaneBasedStrategicalRoutePlannerFactory factoryTruck = null;
485 
486         /** */
487         DistractionFactorySupplier()
488         {
489         }
490 
491         /** {@inheritDoc} */
492         @SuppressWarnings("synthetic-access")
493         @Override
494         public LaneBasedStrategicalPlannerFactory<?> getFactory(final Node origin, final Node destination,
495                 final Category category, final StreamInterface randomStream) throws GTUException
496         {
497             OTSRoadNetwork network = (OTSRoadNetwork) origin.getNetwork();
498             if (this.factoryCar == null)
499             {
500                 // car-following model, with different desired speed models
501                 CarFollowingModelFactory<IDMPlus> cfFactoryCar =
502                         new IdmPlusFactoryAR(() -> AnticipationRelianceScript.this.strategies
503                                 ? new SocioDesiredSpeed(AbstractIDM.DESIRED_SPEED) : AbstractIDM.DESIRED_SPEED);
504                 CarFollowingModelFactory<IDMPlus> cfFactoryTruck = new IdmPlusFactoryAR(() -> AbstractIDM.DESIRED_SPEED);
505 
506                 // perception factory with estimation distribution (i.e. over- vs. underestimation)
507                 Distribution<Estimation> estimation;
508                 try
509                 {
510                     estimation = new Distribution<>(randomStream);
511                     estimation.add(new FrequencyAndObject<>(AnticipationRelianceScript.this.fractionUnderestimation,
512                             Estimation.UNDERESTIMATION));
513                     estimation.add(new FrequencyAndObject<>(1.0 - AnticipationRelianceScript.this.fractionUnderestimation,
514                             Estimation.OVERESTIMATION));
515                 }
516                 catch (ProbabilityException ex)
517                 {
518                     throw new GTUException("Random stream is null.", ex);
519                 }
520                 PerceptionFactory perceptionFactory = new LmrsPerceptionFactoryAR(estimation);
521 
522                 // tailgating
523                 Tailgating tailgating = AnticipationRelianceScript.this.strategies ? Tailgating.PRESSURE : Tailgating.NONE;
524 
525                 // incentives
526                 Set<MandatoryIncentive> mandatoryIncentives = new LinkedHashSet<>();
527                 mandatoryIncentives.add(new IncentiveRoute());
528                 Set<VoluntaryIncentive> voluntaryIncentivesCar = new LinkedHashSet<>();
529                 Set<VoluntaryIncentive> voluntaryIncentivesTruck = new LinkedHashSet<>();
530                 voluntaryIncentivesCar.add(new IncentiveSpeedWithCourtesy());
531                 voluntaryIncentivesCar.add(new IncentiveKeep());
532                 if (AnticipationRelianceScript.this.strategies)
533                 {
534                     voluntaryIncentivesCar.add(new IncentiveSocioSpeed());
535                 }
536                 voluntaryIncentivesTruck.addAll(voluntaryIncentivesCar);
537                 voluntaryIncentivesTruck.add(new IncentiveStayRight());
538 
539                 // acceleration incentives (none, nothing on the freeway)
540                 Set<AccelerationIncentive> accelerationIncentives = new LinkedHashSet<>();
541 
542                 // parameter factory
543                 ParameterFactoryByType params = new ParameterFactoryByType();
544                 params.addParameter(network.getGtuType(GTUType.DEFAULTS.CAR), ParameterTypes.FSPEED,
545                         new DistNormal(randomStream, 123.7 / 120.0, 12.0 / 120.0));
546                 params.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), ParameterTypes.A,
547                         Acceleration.instantiateSI(0.4));
548                 if (AnticipationRelianceScript.this.strategies)
549                 {
550                     params.addParameter(Tailgating.RHO, 0.0);
551                     params.addParameter(network.getGtuType(GTUType.DEFAULTS.CAR), LmrsParameters.SOCIO,
552                             new DistTriangular(randomStream, 0.0, 0.25, 1.0));
553                     params.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), LmrsParameters.SOCIO, 1.0);
554                     params.addParameter(network.getGtuType(GTUType.DEFAULTS.CAR), LmrsParameters.VGAIN,
555                             new ContinuousDistSpeed(new DistLogNormal(randomStream, 3.3789, 0.4), SpeedUnit.KM_PER_HOUR));
556                     params.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), LmrsParameters.VGAIN,
557                             new Speed(50.0, SpeedUnit.KM_PER_HOUR));
558                     params.addParameter(ParameterTypes.TMAX, Duration.instantiateSI(1.6));
559                 }
560                 if (AnticipationRelianceScript.this.adaptation)
561                 {
562                     params.addParameter(AdaptationHeadway.BETA_T, 1.0); // T := T * (1.0 + this value)
563                 }
564 
565                 // factories
566                 this.factoryCar = new LaneBasedStrategicalRoutePlannerFactory(new LMRSFactory(cfFactoryCar, perceptionFactory,
567                         Synchronization.PASSIVE, Cooperation.PASSIVE, GapAcceptance.INFORMED, tailgating, mandatoryIncentives,
568                         voluntaryIncentivesCar, accelerationIncentives), params);
569                 this.factoryTruck = new LaneBasedStrategicalRoutePlannerFactory(new LMRSFactory(cfFactoryTruck,
570                         perceptionFactory, Synchronization.PASSIVE, Cooperation.PASSIVE, GapAcceptance.INFORMED, tailgating,
571                         mandatoryIncentives, voluntaryIncentivesTruck, accelerationIncentives), params);
572             }
573             return category.get(GTUType.class).isOfType(network.getGtuType(GTUType.DEFAULTS.TRUCK)) ? this.factoryTruck
574                     : this.factoryCar;
575         }
576     }
577 
578     ////////////////////////////////////
579     ////// FACTORY HELPER CLASSES //////
580     ////////////////////////////////////
581 
582     /** Car-following task. */
583     private class CarFollowingTaskAR extends AbstractTask
584     {
585         /** Constructor. */
586         CarFollowingTaskAR()
587         {
588             super("car-following");
589         }
590 
591         /** {@inheritDoc} */
592         @Override
593         public double calculateTaskDemand(final LanePerception perception, final LaneBasedGTU gtuCF,
594                 final Parameters parameters) throws ParameterException, GTUException
595         {
596             try
597             {
598                 NeighborsPerception neighbors = perception.getPerceptionCategory(NeighborsPerception.class);
599                 PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders = neighbors.getLeaders(RelativeLane.CURRENT);
600                 Duration headway = leaders.collect(new TaskHeadwayCollector(gtuCF.getSpeed()));
601                 return headway == null ? 0.0 : Math.exp(-headway.si / parameters.getParameter(HEXP).si);
602             }
603             catch (OperationalPlanException ex)
604             {
605                 throw new GTUException(ex);
606             }
607         }
608     }
609 
610     /** Lane change task. */
611     private class LaneChangeTaskAR extends AbstractTask
612     {
613         /** Constructor. */
614         LaneChangeTaskAR()
615         {
616             super("lane-changing");
617         }
618 
619         /** {@inheritDoc} */
620         @Override
621         public double calculateTaskDemand(final LanePerception perception, final LaneBasedGTU gtuLC,
622                 final Parameters parameters) throws ParameterException, GTUException
623         {
624             return Math.max(0.0,
625                     Math.max(parameters.getParameter(LmrsParameters.DLEFT), parameters.getParameter(LmrsParameters.DRIGHT)));
626         }
627     }
628 
629     /** LMRS perception factory with AR. */
630     private class LmrsPerceptionFactoryAR extends DefaultLMRSPerceptionFactory
631     {
632         /** Estimation distribution. */
633         private final Distribution<Estimation> estimation;
634 
635         /**
636          * Constructor.
637          * @param estimation Distribution&lt;Estimation&gt;; estimation distribution
638          */
639         LmrsPerceptionFactoryAR(final Distribution<Estimation> estimation)
640         {
641             this.estimation = estimation;
642         }
643 
644         /** {@inheritDoc} */
645         @SuppressWarnings("synthetic-access")
646         @Override
647         public LanePerception generatePerception(final LaneBasedGTU gtu)
648         {
649             Set<Task> tasksSet = new LinkedHashSet<>();
650             if (AnticipationRelianceScript.this.tasks)
651             {
652                 tasksSet.add(new CarFollowingTaskAR());
653                 tasksSet.add(new LaneChangeTaskAR());
654             }
655 
656             Set<BehavioralAdaptation> behavioralAdapatations = new LinkedHashSet<>();
657             behavioralAdapatations.add(new AdaptationSituationalAwareness());
658             if (AnticipationRelianceScript.this.adaptation)
659             {
660                 behavioralAdapatations.add(new AdaptationHeadway());
661             }
662             LanePerception perception;
663             if (AnticipationRelianceScript.this.tasks)
664             {
665                 Fuller fuller = new Fuller(tasksSet, behavioralAdapatations, new TaskManagerAR());
666                 perception = new CategoricalLanePerception(gtu, fuller);
667             }
668             else
669             {
670                 perception = new CategoricalLanePerception(gtu);
671             }
672             perception.addPerceptionCategory(new DirectEgoPerception<>(perception));
673             perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
674             Estimation est = Try.assign(() -> this.estimation.draw(), "Probability exception while drawing estimation.");
675             perception.addPerceptionCategory(
676                     new DirectNeighborsPerception(perception, new PerceivedHeadwayGtuType(est, Anticipation.CONSTANT_SPEED)));
677             perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
678             return perception;
679         }
680 
681         /** {@inheritDoc} */
682         @SuppressWarnings("synthetic-access")
683         @Override
684         public Parameters getParameters() throws ParameterException
685         {
686             Parameters params = super.getParameters();
687             params.setParameter(HEXP, Duration.instantiateSI(4.0));
688             params.setParameter(ALPHA, AnticipationRelianceScript.this.alpha);
689             params.setParameter(BETA, AnticipationRelianceScript.this.beta);
690             params.setParameter(Fuller.TC, 1.0);
691             params.setParameter(Fuller.TS_CRIT, 1.0); // Was not changed!
692             params.setParameter(Fuller.TS_MAX, 2.0);
693             params.setParameter(AdaptationSituationalAwareness.SA, 1.0);
694             params.setParameter(AdaptationSituationalAwareness.SA_MAX, 1.0);
695             params.setParameter(AdaptationSituationalAwareness.SA_MIN, 0.5);
696             params.setParameter(AdaptationSituationalAwareness.TR_MAX, Duration.instantiateSI(2.0));
697             params.setParameter(ParameterTypes.TR, Duration.ZERO);
698             params.setParameter(AdaptationHeadway.BETA_T, 1.0); // Increase?
699             return params;
700         }
701     }
702 
703     /** Task manager for AR. */
704     private class TaskManagerAR implements TaskManager
705     {
706         /** {@inheritDoc} */
707         @Override
708         public void manage(final Set<Task> tasksMan, final LanePerception perception, final LaneBasedGTU gtu,
709                 final Parameters parameters) throws ParameterException, GTUException
710         {
711             Task primary = null;
712             Set<Task> auxiliaryTasks = new LinkedHashSet<>();
713             for (Task task : tasksMan)
714             {
715                 if (task.getId().equals("lane-changing"))
716                 {
717                     primary = task;
718                 }
719                 else
720                 {
721                     auxiliaryTasks.add(task);
722                 }
723             }
724             Throw.whenNull(primary, "There is no task with id 'lane-changing'.");
725             double primaryTaskDemand = primary.calculateTaskDemand(perception, gtu, parameters);
726             primary.setTaskDemand(primaryTaskDemand);
727             // max AR is alpha of TD, actual AR approaches 0 for increasing TD
728             double a = parameters.getParameter(ALPHA);
729             double b = parameters.getParameter(BETA);
730             primary.setAnticipationReliance(a * primaryTaskDemand * (1.0 - primaryTaskDemand));
731             for (Task auxiliary : auxiliaryTasks)
732             {
733                 double auxiliaryTaskLoad = auxiliary.calculateTaskDemand(perception, gtu, parameters);
734                 auxiliary.setTaskDemand(auxiliaryTaskLoad);
735                 // max AR is beta of TD, actual AR approaches 0 as primary TD approaches 0
736                 auxiliary.setAnticipationReliance(b * auxiliaryTaskLoad * primaryTaskDemand);
737             }
738         }
739     }
740 
741     /** Car-following model factory. */
742     private class IdmPlusFactoryAR implements CarFollowingModelFactory<IDMPlus>
743     {
744         /** Generator for desired speed model. */
745         private final Generator<DesiredSpeedModel> desiredSpeedModelGenerator;
746 
747         /**
748          * Constructor.
749          * @param desiredSpeedModelGenerator Generator&lt;DesiredSpeedModel&gt;; generator for desired speed model
750          */
751         IdmPlusFactoryAR(final Generator<DesiredSpeedModel> desiredSpeedModelGenerator)
752         {
753             this.desiredSpeedModelGenerator = desiredSpeedModelGenerator;
754         }
755 
756         /** {@inheritDoc} */
757         @Override
758         public Parameters getParameters() throws ParameterException
759         {
760             ParameterSet parameters = new ParameterSet();
761             parameters.setDefaultParameters(AbstractIDM.class);
762             return parameters;
763         }
764 
765         /** {@inheritDoc} */
766         @Override
767         public IDMPlus generateCarFollowingModel()
768         {
769             return new IDMPlus(AbstractIDM.HEADWAY,
770                     Try.assign(() -> this.desiredSpeedModelGenerator.draw(), "Unexpected exception."));
771         }
772     }
773 
774     /** Task saturation trajectory data. */
775     private class TaskSaturationDataType extends ExtendedDataTypeNumber<GtuData>
776     {
777 
778         /**
779          * Constructor.
780          */
781         TaskSaturationDataType()
782         {
783             super("TS");
784         }
785 
786         /** {@inheritDoc} */
787         @Override
788         public Float getValue(final GtuData gtu)
789         {
790             Double ts = gtu.getGtu().getParameters().getParameterOrNull(Fuller.TS);
791             if (ts != null)
792             {
793                 return (float) (double) ts;
794             }
795             return Float.NaN;
796         }
797 
798     }
799 
800     /** Task adaptation reliance trajectory data. */
801     private class TaskAnticipationRelianceDataType extends ExtendedDataTypeNumber<GtuData>
802     {
803 
804         /** Task id. */
805         private String taskId;
806 
807         /**
808          * Constructor.
809          * @param taskId String; task id
810          */
811         TaskAnticipationRelianceDataType(final String taskId)
812         {
813             super(taskId + "_AR");
814             this.taskId = taskId;
815         }
816 
817         /** {@inheritDoc} */
818         @Override
819         public Float getValue(final GtuData gtu)
820         {
821             return (float) ((Fuller) gtu.getGtu().getTacticalPlanner().getPerception().getMental())
822                     .getAnticipationReliance(this.taskId);
823         }
824 
825     }
826 
827     /** Task demand trajectory data. */
828     private class TaskDemandDataType extends ExtendedDataTypeNumber<GtuData>
829     {
830 
831         /** Task id. */
832         private String taskId;
833 
834         /**
835          * Constructor.
836          * @param taskId String; task id
837          */
838         TaskDemandDataType(final String taskId)
839         {
840             super(taskId + "_TD");
841             this.taskId = taskId;
842         }
843 
844         /** {@inheritDoc} */
845         @Override
846         public Float getValue(final GtuData gtu)
847         {
848             return (float) ((Fuller) gtu.getGtu().getTacticalPlanner().getPerception().getMental()).getTaskDemand(this.taskId);
849         }
850 
851     }
852 
853     /** Situational awareness trajectory data. */
854     private class SituationalAwarenessDataType extends ExtendedDataTypeNumber<GtuData>
855     {
856 
857         /**
858          * Constructor.
859          */
860         SituationalAwarenessDataType()
861         {
862             super("SA");
863         }
864 
865         /** {@inheritDoc} */
866         @Override
867         public Float getValue(final GtuData gtu)
868         {
869             Double ts = gtu.getGtu().getParameters().getParameterOrNull(AdaptationSituationalAwareness.SA);
870             if (ts != null)
871             {
872                 return (float) (double) ts;
873             }
874             return Float.NaN;
875         }
876 
877     }
878 
879 }