View Javadoc
1   package org.opentrafficsim.demo;
2   
3   import java.awt.Color;
4   import java.awt.Dimension;
5   import java.rmi.RemoteException;
6   import java.util.ArrayList;
7   import java.util.LinkedHashSet;
8   import java.util.List;
9   import java.util.Map;
10  import java.util.Set;
11  import java.util.function.Supplier;
12  
13  import javax.naming.NamingException;
14  
15  import org.djunits.unit.FrequencyUnit;
16  import org.djunits.unit.SpeedUnit;
17  import org.djunits.value.vdouble.scalar.Acceleration;
18  import org.djunits.value.vdouble.scalar.Duration;
19  import org.djunits.value.vdouble.scalar.Length;
20  import org.djunits.value.vdouble.scalar.Speed;
21  import org.djunits.value.vdouble.scalar.Time;
22  import org.djunits.value.vdouble.vector.FrequencyVector;
23  import org.djunits.value.vdouble.vector.TimeVector;
24  import org.djutils.draw.line.Polygon2d;
25  import org.djutils.draw.point.OrientedPoint2d;
26  import org.djutils.exceptions.Throw;
27  import org.opentrafficsim.animation.colorer.FixedColor;
28  import org.opentrafficsim.animation.colorer.IncentiveColorer;
29  import org.opentrafficsim.animation.colorer.SocialPressureColorer;
30  import org.opentrafficsim.animation.colorer.TaskSaturationColorer;
31  import org.opentrafficsim.animation.gtu.colorer.AccelerationGtuColorer;
32  import org.opentrafficsim.animation.gtu.colorer.GtuColorer;
33  import org.opentrafficsim.animation.gtu.colorer.SpeedGtuColorer;
34  import org.opentrafficsim.base.geometry.OtsLine2d;
35  import org.opentrafficsim.base.parameters.ParameterException;
36  import org.opentrafficsim.base.parameters.ParameterSet;
37  import org.opentrafficsim.base.parameters.ParameterTypeDouble;
38  import org.opentrafficsim.base.parameters.ParameterTypeDuration;
39  import org.opentrafficsim.base.parameters.ParameterTypes;
40  import org.opentrafficsim.base.parameters.Parameters;
41  import org.opentrafficsim.base.parameters.constraint.DualBound;
42  import org.opentrafficsim.base.parameters.constraint.NumericConstraint;
43  import org.opentrafficsim.core.definitions.DefaultsNl;
44  import org.opentrafficsim.core.dsol.AbstractOtsModel;
45  import org.opentrafficsim.core.dsol.OtsAnimator;
46  import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
47  import org.opentrafficsim.core.geometry.FractionalLengthData;
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.Network;
53  import org.opentrafficsim.core.network.NetworkException;
54  import org.opentrafficsim.core.network.Node;
55  import org.opentrafficsim.core.parameters.ParameterFactoryByType;
56  import org.opentrafficsim.core.perception.HistoryManagerDevs;
57  import org.opentrafficsim.core.units.distributions.ContinuousDistSpeed;
58  import org.opentrafficsim.demo.HumanFactorsDemo.HumanFactorsModel;
59  import org.opentrafficsim.road.definitions.DefaultsRoadNl;
60  import org.opentrafficsim.road.gtu.generator.characteristics.DefaultLaneBasedGtuCharacteristicsGeneratorOd;
61  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuCharacteristicsGeneratorOd;
62  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
63  import org.opentrafficsim.road.gtu.lane.perception.CategoricalLanePerception;
64  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
65  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
66  import org.opentrafficsim.road.gtu.lane.perception.PerceptionFactory;
67  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
68  import org.opentrafficsim.road.gtu.lane.perception.categories.AnticipationTrafficPerception;
69  import org.opentrafficsim.road.gtu.lane.perception.categories.DirectInfrastructurePerception;
70  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.Anticipation;
71  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.DirectNeighborsPerception;
72  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.Estimation;
73  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType;
74  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType.PerceivedHeadwayGtuType;
75  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsPerception;
76  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.TaskHeadwayCollector;
77  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGtu;
78  import org.opentrafficsim.road.gtu.lane.perception.mental.AbstractTask;
79  import org.opentrafficsim.road.gtu.lane.perception.mental.AdaptationHeadway;
80  import org.opentrafficsim.road.gtu.lane.perception.mental.AdaptationSituationalAwareness;
81  import org.opentrafficsim.road.gtu.lane.perception.mental.AdaptationSpeed;
82  import org.opentrafficsim.road.gtu.lane.perception.mental.Fuller;
83  import org.opentrafficsim.road.gtu.lane.perception.mental.Fuller.BehavioralAdaptation;
84  import org.opentrafficsim.road.gtu.lane.perception.mental.Task;
85  import org.opentrafficsim.road.gtu.lane.perception.mental.TaskCarFollowing;
86  import org.opentrafficsim.road.gtu.lane.perception.mental.TaskManager;
87  import org.opentrafficsim.road.gtu.lane.perception.mental.TaskRoadSideDistraction;
88  import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIdm;
89  import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIdmFactory;
90  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
91  import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlus;
92  import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlusFactory;
93  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLmrsPerceptionFactory;
94  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveKeep;
95  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveRoute;
96  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSocioSpeed;
97  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSpeedWithCourtesy;
98  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory;
99  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.SocioDesiredSpeed;
100 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
101 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance;
102 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
103 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.MandatoryIncentive;
104 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
105 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
106 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
107 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
108 import org.opentrafficsim.road.network.RoadNetwork;
109 import org.opentrafficsim.road.network.lane.CrossSectionGeometry;
110 import org.opentrafficsim.road.network.lane.CrossSectionLink;
111 import org.opentrafficsim.road.network.lane.Lane;
112 import org.opentrafficsim.road.network.lane.LaneGeometryUtil;
113 import org.opentrafficsim.road.network.lane.Stripe;
114 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
115 import org.opentrafficsim.road.network.lane.object.Distraction;
116 import org.opentrafficsim.road.network.lane.object.Distraction.TrapezoidProfile;
117 import org.opentrafficsim.road.od.Categorization;
118 import org.opentrafficsim.road.od.Category;
119 import org.opentrafficsim.road.od.Interpolation;
120 import org.opentrafficsim.road.od.OdApplier;
121 import org.opentrafficsim.road.od.OdMatrix;
122 import org.opentrafficsim.road.od.OdOptions;
123 import org.opentrafficsim.swing.gui.OtsAnimationPanel;
124 import org.opentrafficsim.swing.gui.OtsSimulationApplication;
125 
126 import nl.tudelft.simulation.dsol.SimRuntimeException;
127 import nl.tudelft.simulation.jstats.distributions.DistLogNormal;
128 import nl.tudelft.simulation.jstats.distributions.DistTriangular;
129 import nl.tudelft.simulation.jstats.streams.StreamInterface;
130 import nl.tudelft.simulation.language.DsolException;
131 
132 /**
133  * This demo exists to show how the human factor models can be used in code. In particular see the
134  * {@code HumanFactorsModel.constructModel()} method. The included human factors are 1) social interactions regarding lane
135  * changes, tailgating and changes in speed, and 2) Anticipation Reliance in a mental task load framework of imperfect
136  * perception. The scenario includes a distraction halfway on the network.
137  * <p>
138  * Copyright (c) 2024-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
139  * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
140  * </p>
141  * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
142  * @see HumanFactorsModel#buildHumanFactorsModel()
143  * @see <a href="https://www.preprints.org/manuscript/202305.0193/v1">Schakel et al. (2023) Social Interactions on Multi-Lane
144  *      Motorways: Towards a Theory of Impacts</a>
145  * @see <a href="https://www.sciencedirect.com/science/article/pii/S0191261520303714">Calvert et al. (2020) A generic
146  *      multi-scale framework for microscopic traffic simulation part II – Anticipation Reliance as compensation mechanism for
147  *      potential task overload</a>
148  */
149 public final class HumanFactorsDemo extends OtsSimulationApplication<HumanFactorsModel>
150 {
151 
152     /** */
153     private static final long serialVersionUID = 20241012L;
154 
155     /**
156      * Constructor.
157      * @param model model
158      * @param panel panel
159      */
160     private HumanFactorsDemo(final HumanFactorsModel model, final OtsAnimationPanel panel)
161     {
162         super(model, panel, DefaultsFactory.GTU_TYPE_MARKERS.toMap());
163     }
164 
165     /**
166      * Main program.
167      * @param args the command line arguments (not used)
168      */
169     public static void main(final String[] args)
170     {
171         try
172         {
173             OtsAnimator simulator = new OtsAnimator("HFDemo");
174             final HumanFactorsModel junctionModel = new HumanFactorsModel(simulator);
175             simulator.initialize(Time.ZERO, Duration.ZERO, Duration.instantiateSI(3600.0), junctionModel,
176                     new HistoryManagerDevs(simulator, Duration.instantiateSI(3.0), Duration.instantiateSI(10.0)));
177             // Note some relevant colorers for social interactions and task saturation
178             List<GtuColorer> colorers = List.of(new FixedColor(Color.BLUE, "Blue"),
179                     new SpeedGtuColorer(new Speed(150.0, SpeedUnit.KM_PER_HOUR)),
180                     new AccelerationGtuColorer(Acceleration.instantiateSI(-4.0), Acceleration.instantiateSI(2.0)),
181                     new SocialPressureColorer(), new IncentiveColorer(IncentiveSocioSpeed.class), new TaskSaturationColorer());
182             OtsAnimationPanel animationPanel = new OtsAnimationPanel(junctionModel.getNetwork().getExtent(),
183                     new Dimension(800, 600), simulator, junctionModel, colorers, junctionModel.getNetwork());
184             new HumanFactorsDemo(junctionModel, animationPanel);
185             animationPanel.enableSimulationControlButtons();
186         }
187         catch (SimRuntimeException | NamingException | RemoteException | DsolException exception)
188         {
189             exception.printStackTrace();
190         }
191     }
192 
193     /**
194      * The simulation model object.
195      */
196     public static class HumanFactorsModel extends AbstractOtsModel
197     {
198 
199         /** */
200         private static final long serialVersionUID = 20241012L;
201 
202         /** The network. */
203         private RoadNetwork network;
204 
205         /** Characteristics generator. */
206         private LaneBasedGtuCharacteristicsGeneratorOd characteristics;
207 
208         /**
209          * Constructor.
210          * @param simulator simulator
211          */
212         public HumanFactorsModel(final OtsSimulatorInterface simulator)
213         {
214             super(simulator);
215         }
216 
217         @Override
218         public Network getNetwork()
219         {
220             return this.network;
221         }
222 
223         @Override
224         public void constructModel() throws SimRuntimeException
225         {
226             try
227             {
228                 buildNetwork();
229                 buildHumanFactorsModel();
230                 setDemand();
231             }
232             catch (NetworkException | ParameterException exception)
233             {
234                 throw new SimRuntimeException(exception);
235             }
236         }
237 
238         /**
239          * Builds the human factors model.
240          * @throws ParameterException if parameter has no default value
241          */
242         private void buildHumanFactorsModel() throws ParameterException
243         {
244             StreamInterface stream = getSimulator().getModel().getStream("generation");
245 
246             // social = social interactions, perception = imperfect perception
247             boolean social = true;
248             boolean perception = true;
249 
250             ParameterFactoryByType parameterFactory = new ParameterFactoryByType();
251             parameterFactory.addParameter(ParameterTypes.LOOKBACK, ParameterTypes.LOOKBACK.getDefaultValue());
252             parameterFactory.addParameter(ParameterTypes.LOOKAHEAD, ParameterTypes.LOOKAHEAD.getDefaultValue());
253             parameterFactory.addParameter(ParameterTypes.PERCEPTION, ParameterTypes.PERCEPTION.getDefaultValue());
254             if (social)
255             {
256                 /*
257                  * In case of social interactions we 1) introduce the RHO status variable of social pressure, value only
258                  * important at vehicle generation as the model sets this, 2) increase the TMAX value from a normal 1.2s to
259                  * 1.6s, as the tailgating phenomenon will reduce this, leading to an average at around 1.2s, but now dynamic
260                  * depending on social pressure, 3) we introduce a distributed SOCIO parameter to represent sensitivity to
261                  * social pressure, 4) we lower VGAIN to increase ego-speed sensitivity, and distribute it (we now have a
262                  * population of drivers distributed on a plain of socio and ego speed sensitivity, and 5) something similar but
263                  * simple for trucks.
264                  */
265                 parameterFactory.addParameter(Tailgating.RHO, 0.0);
266                 parameterFactory.addParameter(ParameterTypes.TMAX, Duration.instantiateSI(1.6));
267                 parameterFactory.addParameter(DefaultsNl.CAR, LmrsParameters.SOCIO, new DistTriangular(stream, 0.0, 0.25, 1.0));
268                 parameterFactory.addParameter(DefaultsNl.CAR, LmrsParameters.VGAIN, // mu =~ 3.3789, sigma = 0.4, mode = 25.0
269                         new ContinuousDistSpeed(new DistLogNormal(stream, Math.log(25.0) + 0.4 * 0.4, 0.4),
270                                 SpeedUnit.KM_PER_HOUR));
271                 parameterFactory.addParameter(DefaultsNl.TRUCK, LmrsParameters.SOCIO, 1.0);
272                 parameterFactory.addParameter(DefaultsNl.TRUCK, LmrsParameters.VGAIN, new Speed(50.0, SpeedUnit.KM_PER_HOUR));
273             }
274 
275             /*
276              * Car-following: In case of social interactions, the normal desired headway model is wrapped in a model that
277              * adjusts it as a response to social pressure from the following vehicle.
278              */
279             CarFollowingModelFactory<IdmPlus> cfModelFactory = social
280                     ? new AbstractIdmFactory<>(
281                             () -> new IdmPlus(AbstractIdm.HEADWAY, new SocioDesiredSpeed(AbstractIdm.DESIRED_SPEED)), stream)
282                     : new IdmPlusFactory(stream);
283 
284             // In case of imperfect perception we use the below, otherwise DefaultLmrsPerceptionFactory (see at bottom)
285             PerceptionFactory perceptionFactory = perception ? new PerceptionFactory()
286             {
287                 @Override
288                 public Parameters getParameters() throws ParameterException
289                 {
290                     /*
291                      * We need to include (default) values for 1) the Fuller task demand model of task demand, capacity and
292                      * saturation, 2) the anticipation reliance (AR) task manager based on a notion of a primary task and
293                      * auxiliary task, 3) situational awareness as it depends on task saturation, 4) car-following task
294                      * parameter of exponential relationship with task demand, 5) over or underestimation, and 6) sensitivity of
295                      * adapting the headway and desired speed based on high task saturation.
296                      */
297                     ParameterSet perceptionParams = new ParameterSet();
298                     perceptionParams.setDefaultParameters(Fuller.class);
299                     perceptionParams.setDefaultParameters(TaskManagerAr.class);
300                     perceptionParams.setDefaultParameters(AdaptationSituationalAwareness.class);
301                     perceptionParams.setDefaultParameter(CarFollowingTask.HEXP);
302                     perceptionParams.setDefaultParameter(Estimation.OVER_EST);
303                     perceptionParams.setDefaultParameter(AdaptationHeadway.BETA_T);
304                     perceptionParams.setDefaultParameter(AdaptationSpeed.BETA_V0);
305                     return perceptionParams;
306                 }
307 
308                 @Override
309                 public LanePerception generatePerception(final LaneBasedGtu gtu)
310                 {
311                     // Tasks that determine task demand
312                     Set<Task> tasks = new LinkedHashSet<>();
313                     tasks.add(new TaskCarFollowing());
314                     tasks.add(new LaneChangeTask());
315                     tasks.add(new TaskRoadSideDistraction()); // Level of distraction is defined in Distraction network object
316                     // Behavioral adaptations (AdaptationSituationalAwareness only sets situational awareness and reaction time)
317                     Set<BehavioralAdaptation> behavioralAdapatations = new LinkedHashSet<>();
318                     behavioralAdapatations.add(new AdaptationSituationalAwareness());
319                     behavioralAdapatations.add(new AdaptationHeadway());
320                     behavioralAdapatations.add(new AdaptationSpeed());
321                     // AR task manager, assuming lane changing to be primary
322                     TaskManager taskManager = new TaskManagerAr("lane-changing");
323                     // Fuller framework based on components
324                     CategoricalLanePerception perception =
325                             new CategoricalLanePerception(gtu, new Fuller(tasks, behavioralAdapatations, taskManager));
326                     // Imperfect estimation of distance and speed difference, with reaction time, and compensatory anticipation
327                     HeadwayGtuType headwayGtuType =
328                             new PerceivedHeadwayGtuType(Estimation.FACTOR_ESTIMATION, Anticipation.CONSTANT_SPEED);
329                     // Standard perception categories, using imperfect perception regarding neighbors with the HeadwayGtuType
330                     perception.addPerceptionCategory(new DirectEgoPerception<>(perception));
331                     perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
332                     perception.addPerceptionCategory(new DirectNeighborsPerception(perception, headwayGtuType));
333                     perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
334                     return perception;
335                 }
336             } : new DefaultLmrsPerceptionFactory();
337 
338             // Tailgating, in case of social interactions, reduces the headway based on exerted social pressure on the leader
339             Tailgating tailgating = social ? Tailgating.PRESSURE : Tailgating.NONE;
340 
341             // incentives: mandatory, voluntary
342             Supplier<Set<MandatoryIncentive>> mandatorySupplier = () ->
343             {
344                 Set<MandatoryIncentive> mandatoryIncentives = new LinkedHashSet<>();
345                 mandatoryIncentives.add(new IncentiveRoute());
346                 return mandatoryIncentives;
347             };
348             Supplier<Set<VoluntaryIncentive>> voluntarySupplier = () ->
349             {
350                 Set<VoluntaryIncentive> voluntaryIncentives = new LinkedHashSet<>();
351                 voluntaryIncentives.add(new IncentiveSpeedWithCourtesy());
352                 voluntaryIncentives.add(new IncentiveKeep());
353                 /*
354                  * Next to increasing speed, social interactions include a change in lane change desire to get or stay out of
355                  * the way of faster (potential) followers.
356                  */
357                 if (social)
358                 {
359                     voluntaryIncentives.add(new IncentiveSocioSpeed());
360                 }
361                 return voluntaryIncentives;
362             };
363 
364             // Layered factories (tactical, strategical, strategical in an OD context)
365             LmrsFactory lmrsFactory = new LmrsFactory(cfModelFactory, perceptionFactory, Synchronization.PASSIVE,
366                     Cooperation.PASSIVE, GapAcceptance.INFORMED, tailgating, mandatorySupplier, voluntarySupplier,
367                     () -> new LinkedHashSet<>());
368             LaneBasedStrategicalRoutePlannerFactory strategicalPlannerFactory =
369                     new LaneBasedStrategicalRoutePlannerFactory(lmrsFactory, parameterFactory);
370             this.characteristics =
371                     new DefaultLaneBasedGtuCharacteristicsGeneratorOd.Factory(strategicalPlannerFactory).create();
372         }
373 
374         /**
375          * Builds the network, a 3km 2-lane highway section.
376          * @throws NetworkException when the network is ill defined
377          */
378         private void buildNetwork() throws NetworkException
379         {
380             this.network = new RoadNetwork("HF network", getSimulator());
381 
382             OrientedPoint2d p1 = new OrientedPoint2d(0.0, 0.0, 0.0);
383             OrientedPoint2d p2 = new OrientedPoint2d(3000.0, 0.0, 0.0);
384 
385             Node nodeA = new Node(this.network, "A", p1);
386             Node nodeB = new Node(this.network, "B", p2);
387 
388             Map<GtuType, Speed> speedLimit = Map.of(DefaultsNl.VEHICLE, new Speed(130.0, SpeedUnit.KM_PER_HOUR));
389 
390             OtsLine2d centerLine = new OtsLine2d(p1, p2);
391             CrossSectionLink link = new CrossSectionLink(this.network, "AB", nodeA, nodeB, DefaultsNl.HIGHWAY, centerLine,
392                     FractionalLengthData.of(0.0, 0.0), LaneKeepingPolicy.KEEPRIGHT);
393 
394             double offset1 = 3.5;
395             double width1 = 0.2;
396             OtsLine2d offsetLine1 = centerLine.offsetLine(offset1);
397             new Stripe("1", DefaultsRoadNl.SOLID, link, new CrossSectionGeometry(offsetLine1, getContour(offsetLine1, width1),
398                     FractionalLengthData.of(0.0, offset1), FractionalLengthData.of(0.0, width1)));
399 
400             double offset2 = 1.75;
401             double width2 = 3.5;
402             OtsLine2d offsetLine2 = centerLine.offsetLine(offset2);
403             Lane left = new Lane(link, "LEFT",
404                     new CrossSectionGeometry(offsetLine2, getContour(offsetLine2, width2),
405                             FractionalLengthData.of(0.0, offset2), FractionalLengthData.of(0.0, width2)),
406                     DefaultsRoadNl.HIGHWAY, speedLimit);
407 
408             double offset3 = 0.0;
409             double width3 = 0.2;
410             OtsLine2d offsetLine3 = centerLine.offsetLine(offset3);
411             new Stripe("2", DefaultsRoadNl.DASHED, link, new CrossSectionGeometry(offsetLine3, getContour(offsetLine3, width3),
412                     FractionalLengthData.of(0.0, offset3), FractionalLengthData.of(0.0, width3)));
413 
414             double offset4 = -1.75;
415             double width4 = 3.5;
416             OtsLine2d offsetLine4 = centerLine.offsetLine(offset4);
417             Lane right = new Lane(link, "RIGHT",
418                     new CrossSectionGeometry(offsetLine4, getContour(offsetLine4, width4),
419                             FractionalLengthData.of(0.0, offset4), FractionalLengthData.of(0.0, width4)),
420                     DefaultsRoadNl.HIGHWAY, speedLimit);
421 
422             double offset5 = -3.5;
423             double width5 = 0.2;
424             OtsLine2d offsetLine5 = centerLine.offsetLine(offset5);
425             new Stripe("3", DefaultsRoadNl.SOLID, link, new CrossSectionGeometry(offsetLine5, getContour(offsetLine5, width5),
426                     FractionalLengthData.of(0.0, offset5), FractionalLengthData.of(0.0, width5)));
427 
428             // Add distraction halfway on the network, 0.3 on left lane, 0.2 on right lane, with distance profile
429             new Distraction("distractionLeft", left, Length.instantiateSI(1500.0), new TrapezoidProfile(0.3,
430                     Length.instantiateSI(-100.0), Length.instantiateSI(50.0), Length.instantiateSI(150.0)));
431             new Distraction("distractionRight", right, Length.instantiateSI(1500.0), new TrapezoidProfile(0.2,
432                     Length.instantiateSI(-100.0), Length.instantiateSI(50.0), Length.instantiateSI(150.0)));
433         }
434 
435         /**
436          * Creates contour from line based on width.
437          * @param line line
438          * @param width width
439          * @return contour from line based on width
440          */
441         private Polygon2d getContour(final OtsLine2d line, final double width)
442         {
443             return LaneGeometryUtil.getContour(line.offsetLine(width / 2, width / 2), line.offsetLine(-width / 2, -width / 2));
444         }
445 
446         /**
447          * Set demand in network.
448          * @throws SimRuntimeException sim exception
449          * @throws ParameterException parameter exception
450          */
451         private void setDemand() throws SimRuntimeException, ParameterException
452         {
453             Node nodeA = this.network.getNode("A");
454             Node nodeB = this.network.getNode("B");
455             Categorization categorization = new Categorization("GTU type", GtuType.class);
456             GtuType.registerTemplateSupplier(DefaultsNl.CAR, DefaultsNl.NL);
457             GtuType.registerTemplateSupplier(DefaultsNl.TRUCK, DefaultsNl.NL);
458             List<Node> origins = new ArrayList<>();
459             origins.add(nodeA);
460             List<Node> destinations = new ArrayList<>();
461             destinations.add(nodeB);
462             OdMatrix od = new OdMatrix("OD", origins, destinations, categorization,
463                     new TimeVector(new double[] {0.0, 1800.0, 3600.0}), Interpolation.LINEAR);
464             FrequencyVector demand = new FrequencyVector(new double[] {2000.0, 4000.0, 1000.0}, FrequencyUnit.PER_HOUR);
465             double truckFraction = 0.1;
466             od.putDemandVector(nodeA, nodeB, new Category(categorization, DefaultsNl.CAR), demand, 1.0 - truckFraction);
467             od.putDemandVector(nodeA, nodeB, new Category(categorization, DefaultsNl.TRUCK), demand, truckFraction);
468             OdOptions odOptions = new OdOptions();
469             odOptions.set(OdOptions.NO_LC_DIST, Length.instantiateSI(150.0));
470             odOptions.set(OdOptions.GTU_TYPE, this.characteristics);
471             odOptions.set(OdOptions.LANE_BIAS, DefaultsRoadNl.LANE_BIAS_CAR_TRUCK);
472             OdApplier.applyOd(this.network, od, odOptions, DefaultsNl.VEHICLES);
473         }
474     }
475 
476     /**
477      * Task manager implementation of anticipation reliance.
478      */
479     public static class TaskManagerAr implements TaskManager
480     {
481         /** Fraction of primary task that can be reduced by anticipation reliance. */
482         public static final ParameterTypeDouble ALPHA = new ParameterTypeDouble("alpha",
483                 "Fraction of primary task that can be reduced by anticipation reliance.", 0.8, DualBound.UNITINTERVAL);
484 
485         /** Fraction of auxiliary tasks that can be reduced by anticipation reliance. */
486         public static final ParameterTypeDouble BETA = new ParameterTypeDouble("beta",
487                 "Fraction of auxiliary tasks that can be reduced by anticipation reliance.", 0.6, DualBound.UNITINTERVAL);
488 
489         /** Primary task id. */
490         private final String primaryTaskId;
491 
492         /**
493          * Constructor.
494          * @param primaryTaskId String; primary task id.
495          */
496         public TaskManagerAr(final String primaryTaskId)
497         {
498             Throw.whenNull(primaryTaskId, "Primary task id may not be null.");
499             this.primaryTaskId = primaryTaskId;
500         }
501 
502         @Override
503         public void manage(final Set<Task> tasks, final LanePerception perception, final LaneBasedGtu gtu,
504                 final Parameters parameters) throws ParameterException, GtuException
505         {
506             Task primary = null;
507             Set<Task> auxiliaryTasks = new LinkedHashSet<>();
508             for (Task task : tasks)
509             {
510                 if (task.getId().equals(this.primaryTaskId))
511                 {
512                     primary = task;
513                 }
514                 else
515                 {
516                     auxiliaryTasks.add(task);
517                 }
518             }
519             Throw.whenNull(primary, "There is no task with id '%s'.", this.primaryTaskId);
520             double primaryTaskDemand = primary.calculateTaskDemand(perception, gtu, parameters);
521             primary.setTaskDemand(primaryTaskDemand);
522             // max AR is alpha of TD, actual AR approaches 0 for increasing TD
523             double a = parameters.getParameter(ALPHA);
524             double b = parameters.getParameter(BETA);
525             primary.setAnticipationReliance(a * primaryTaskDemand * (1.0 - primaryTaskDemand));
526             for (Task auxiliary : auxiliaryTasks)
527             {
528                 double auxiliaryTaskLoad = auxiliary.calculateTaskDemand(perception, gtu, parameters);
529                 auxiliary.setTaskDemand(auxiliaryTaskLoad);
530                 // max AR is beta of TD, actual AR approaches 0 as primary TD approaches 0
531                 auxiliary.setAnticipationReliance(b * auxiliaryTaskLoad * primaryTaskDemand);
532             }
533         }
534     }
535 
536     /**
537      * Car-following task demand based on headway.
538      */
539     public class CarFollowingTask extends AbstractTask
540     {
541 
542         /** Car-following task parameter. */
543         public static final ParameterTypeDuration HEXP = new ParameterTypeDuration("Hexp",
544                 "Exponential decay of car-following task by headway.", Duration.instantiateSI(4.0), NumericConstraint.POSITIVE);
545 
546         /**
547          * Constructor.
548          */
549         public CarFollowingTask()
550         {
551             super("car-following");
552         }
553 
554         @Override
555         public double calculateTaskDemand(final LanePerception perception, final LaneBasedGtu gtu, final Parameters parameters)
556                 throws ParameterException, GtuException
557         {
558             try
559             {
560                 NeighborsPerception neighbors = perception.getPerceptionCategory(NeighborsPerception.class);
561                 PerceptionCollectable<HeadwayGtu, LaneBasedGtu> leaders = neighbors.getLeaders(RelativeLane.CURRENT);
562                 Duration headway = leaders.collect(new TaskHeadwayCollector(gtu.getSpeed()));
563                 return headway == null ? 0.0 : Math.exp(-headway.si / parameters.getParameter(HEXP).si);
564             }
565             catch (OperationalPlanException ex)
566             {
567                 throw new GtuException(ex);
568             }
569         }
570     }
571 
572     /**
573      * Lane change task demand depending on lane change desire.
574      */
575     public static class LaneChangeTask extends AbstractTask
576     {
577         /**
578          * Constructor.
579          */
580         public LaneChangeTask()
581         {
582             super("lane-changing");
583         }
584 
585         @Override
586         public double calculateTaskDemand(final LanePerception perception, final LaneBasedGtu gtu, final Parameters parameters)
587                 throws ParameterException, GtuException
588         {
589             return Math.max(0.0,
590                     Math.max(parameters.getParameter(LmrsParameters.DLEFT), parameters.getParameter(LmrsParameters.DRIGHT)));
591         }
592     }
593 
594 }