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