View Javadoc
1   package org.opentrafficsim.demo;
2   
3   import java.awt.Color;
4   import java.rmi.RemoteException;
5   import java.util.ArrayList;
6   import java.util.List;
7   import java.util.Map;
8   
9   import javax.naming.NamingException;
10  
11  import org.djunits.unit.FrequencyUnit;
12  import org.djunits.unit.SpeedUnit;
13  import org.djunits.value.vdouble.scalar.Duration;
14  import org.djunits.value.vdouble.scalar.Length;
15  import org.djunits.value.vdouble.scalar.Speed;
16  import org.djunits.value.vdouble.scalar.Time;
17  import org.djunits.value.vdouble.vector.DurationVector;
18  import org.djunits.value.vdouble.vector.FrequencyVector;
19  import org.djutils.draw.function.ContinuousPiecewiseLinearFunction;
20  import org.djutils.draw.line.Polygon2d;
21  import org.djutils.draw.point.DirectedPoint2d;
22  import org.opentrafficsim.animation.gtu.colorer.AccelerationGtuColorer;
23  import org.opentrafficsim.animation.gtu.colorer.AttentionGtuColorer;
24  import org.opentrafficsim.animation.gtu.colorer.IncentiveGtuColorer;
25  import org.opentrafficsim.animation.gtu.colorer.SocialPressureGtuColorer;
26  import org.opentrafficsim.animation.gtu.colorer.SpeedGtuColorer;
27  import org.opentrafficsim.animation.gtu.colorer.TaskSaturationGtuColorer;
28  import org.opentrafficsim.base.geometry.OtsLine2d;
29  import org.opentrafficsim.base.parameters.ParameterException;
30  import org.opentrafficsim.core.definitions.DefaultsNl;
31  import org.opentrafficsim.core.dsol.AbstractOtsModel;
32  import org.opentrafficsim.core.dsol.OtsAnimator;
33  import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
34  import org.opentrafficsim.core.gtu.Gtu;
35  import org.opentrafficsim.core.gtu.GtuType;
36  import org.opentrafficsim.core.network.LateralDirectionality;
37  import org.opentrafficsim.core.network.Network;
38  import org.opentrafficsim.core.network.NetworkException;
39  import org.opentrafficsim.core.network.Node;
40  import org.opentrafficsim.core.perception.HistoryManagerDevs;
41  import org.opentrafficsim.demo.HumanFactorsDemo.HumanFactorsModel;
42  import org.opentrafficsim.draw.colorer.Colorer;
43  import org.opentrafficsim.draw.colorer.FixedColorer;
44  import org.opentrafficsim.road.definitions.DefaultsRoadNl;
45  import org.opentrafficsim.road.gtu.generator.characteristics.DefaultLaneBasedGtuCharacteristicsGeneratorOd;
46  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuCharacteristicsGeneratorOd;
47  import org.opentrafficsim.road.gtu.lane.LaneBookkeeping;
48  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSocioSpeed;
49  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.Lmrs;
50  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory;
51  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory.FullerImplementation;
52  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory.Setting;
53  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
54  import org.opentrafficsim.road.network.LaneKeepingPolicy;
55  import org.opentrafficsim.road.network.RoadNetwork;
56  import org.opentrafficsim.road.network.lane.CrossSectionGeometry;
57  import org.opentrafficsim.road.network.lane.CrossSectionLink;
58  import org.opentrafficsim.road.network.lane.Lane;
59  import org.opentrafficsim.road.network.lane.LaneGeometryUtil;
60  import org.opentrafficsim.road.network.lane.Stripe;
61  import org.opentrafficsim.road.network.lane.object.RoadSideDistraction;
62  import org.opentrafficsim.road.network.lane.object.RoadSideDistraction.TrapezoidProfile;
63  import org.opentrafficsim.road.od.Categorization;
64  import org.opentrafficsim.road.od.Category;
65  import org.opentrafficsim.road.od.Interpolation;
66  import org.opentrafficsim.road.od.OdApplier;
67  import org.opentrafficsim.road.od.OdMatrix;
68  import org.opentrafficsim.road.od.OdOptions;
69  import org.opentrafficsim.swing.gui.OtsAnimationPanel;
70  import org.opentrafficsim.swing.gui.OtsSimulationApplication;
71  
72  import nl.tudelft.simulation.dsol.SimRuntimeException;
73  import nl.tudelft.simulation.language.DsolException;
74  
75  /**
76   * This demo exists to show how the human factor models can be used in code. In particular see the
77   * {@code HumanFactorsModel.constructModel()} method. The included human factors are 1) social interactions regarding lane
78   * changes, tailgating and changes in speed, and 2) Anticipation Reliance in a mental task load framework of imperfect
79   * perception. The scenario includes a distraction halfway on the network.
80   * <p>
81   * Copyright (c) 2024-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
82   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
83   * </p>
84   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
85   * @see HumanFactorsModel#buildHumanFactorsModel()
86   * @see <a href="https://www.preprints.org/manuscript/202305.0193/v1">Schakel et al. (2023) Social Interactions on Multi-Lane
87   *      Motorways: Towards a Theory of Impacts</a>
88   * @see <a href="https://www.sciencedirect.com/science/article/pii/S0191261520303714">Calvert et al. (2020) A generic
89   *      multi-scale framework for microscopic traffic simulation part II – Anticipation Reliance as compensation mechanism for
90   *      potential task overload</a>
91   */
92  public final class HumanFactorsDemo extends OtsSimulationApplication<HumanFactorsModel>
93  {
94  
95      /** */
96      private static final long serialVersionUID = 20241012L;
97  
98      /**
99       * Constructor.
100      * @param model model
101      * @param panel panel
102      */
103     private HumanFactorsDemo(final HumanFactorsModel model, final OtsAnimationPanel panel)
104     {
105         super(model, panel, DefaultsFactory.GTU_TYPE_MARKERS.toMap());
106     }
107 
108     /**
109      * Main program.
110      * @param args the command line arguments (not used)
111      */
112     public static void main(final String[] args)
113     {
114         try
115         {
116             OtsAnimator simulator = new OtsAnimator("HFDemo");
117             final HumanFactorsModel junctionModel = new HumanFactorsModel(simulator);
118             simulator.initialize(Time.ZERO, Duration.ZERO, Duration.ofSI(3600.0), junctionModel,
119                     new HistoryManagerDevs(simulator, Duration.ofSI(3.0), Duration.ofSI(10.0)));
120             // Note some relevant colorers for social interactions and task saturation
121             List<Colorer<? super Gtu>> colorers =
122                     List.of(new FixedColorer<>(Color.BLUE, "Blue"), new SpeedGtuColorer(), new AccelerationGtuColorer(),
123                             new SocialPressureGtuColorer(), new IncentiveGtuColorer(IncentiveSocioSpeed.class),
124                             new AttentionGtuColorer(), new TaskSaturationGtuColorer());
125             OtsAnimationPanel animationPanel = new OtsAnimationPanel(junctionModel.getNetwork().getExtent(), simulator,
126                     junctionModel, colorers, junctionModel.getNetwork());
127             new HumanFactorsDemo(junctionModel, animationPanel);
128             animationPanel.enableSimulationControlButtons();
129         }
130         catch (SimRuntimeException | NamingException | RemoteException | DsolException exception)
131         {
132             exception.printStackTrace();
133         }
134     }
135 
136     /**
137      * The simulation model object.
138      */
139     public static class HumanFactorsModel extends AbstractOtsModel
140     {
141 
142         /** The network. */
143         private RoadNetwork network;
144 
145         /** Characteristics generator. */
146         private LaneBasedGtuCharacteristicsGeneratorOd characteristics;
147 
148         /**
149          * Constructor.
150          * @param simulator simulator
151          */
152         public HumanFactorsModel(final OtsSimulatorInterface simulator)
153         {
154             super(simulator);
155         }
156 
157         @Override
158         public Network getNetwork()
159         {
160             return this.network;
161         }
162 
163         @Override
164         public void constructModel() throws SimRuntimeException
165         {
166             try
167             {
168                 buildNetwork();
169                 buildHumanFactorsModel();
170                 setDemand();
171             }
172             catch (NetworkException | ParameterException exception)
173             {
174                 throw new SimRuntimeException(exception);
175             }
176         }
177 
178         /**
179          * Builds the human factors model.
180          * @throws ParameterException if parameter has no default value
181          */
182         private void buildHumanFactorsModel() throws ParameterException
183         {
184             // social = social interactions, perception = imperfect perception
185             boolean social = true;
186             boolean perception = true;
187 
188             LmrsFactory<Lmrs> tacticalFactory = new LmrsFactory<>(List.of(DefaultsNl.CAR, DefaultsNl.TRUCK), Lmrs::new);
189             tacticalFactory.setStream(getSimulator().getModel().getStream("generation"));
190 
191             if (social)
192             {
193                 tacticalFactory.set(Setting.SOCIO_TAILGATING, true);
194                 tacticalFactory.set(Setting.SOCIO_LANE_CHANGE, true);
195                 tacticalFactory.set(Setting.SOCIO_SPEED, true);
196             }
197             if (perception)
198             {
199                 tacticalFactory.set(Setting.FULLER_IMPLEMENTATION, FullerImplementation.ATTENTION_MATRIX);
200                 tacticalFactory.set(Setting.TASK_ROADSIDE_DISTRACTION, true);
201             }
202 
203             // layered factories (tactical=parameterFactory, strategical, strategical in an OD context)
204             LaneBasedStrategicalRoutePlannerFactory strategicalPlannerFactory =
205                     new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory, tacticalFactory);
206             this.characteristics =
207                     new DefaultLaneBasedGtuCharacteristicsGeneratorOd.Factory(strategicalPlannerFactory).create();
208         }
209 
210         /**
211          * Builds the network, a 3km 2-lane highway section.
212          * @throws NetworkException when the network is ill defined
213          */
214         private void buildNetwork() throws NetworkException
215         {
216             this.network = new RoadNetwork("HF network", getSimulator());
217 
218             DirectedPoint2d p1 = new DirectedPoint2d(0.0, 0.0, 0.0);
219             DirectedPoint2d p2 = new DirectedPoint2d(3000.0, 0.0, 0.0);
220 
221             Node nodeA = new Node(this.network, "A", p1);
222             Node nodeB = new Node(this.network, "B", p2);
223 
224             Map<GtuType, Speed> speedLimit = Map.of(DefaultsNl.VEHICLE, new Speed(130.0, SpeedUnit.KM_PER_HOUR));
225 
226             OtsLine2d centerLine = new OtsLine2d(p1, p2);
227             CrossSectionLink link = new CrossSectionLink(this.network, "AB", nodeA, nodeB, DefaultsNl.HIGHWAY, centerLine,
228                     ContinuousPiecewiseLinearFunction.of(0.0, 0.0), LaneKeepingPolicy.KEEPRIGHT);
229 
230             double offset1 = 3.5;
231             double width1 = 0.2;
232             OtsLine2d offsetLine1 = centerLine.offsetLine(offset1);
233             new Stripe("1", DefaultsRoadNl.SOLID, link, new CrossSectionGeometry(offsetLine1, getContour(offsetLine1, width1),
234                     ContinuousPiecewiseLinearFunction.of(0.0, offset1), ContinuousPiecewiseLinearFunction.of(0.0, width1)));
235 
236             double offset2 = 1.75;
237             double width2 = 3.5;
238             OtsLine2d offsetLine2 = centerLine.offsetLine(offset2);
239             Lane left = new Lane(link, "LEFT", new CrossSectionGeometry(offsetLine2, getContour(offsetLine2, width2),
240                     ContinuousPiecewiseLinearFunction.of(0.0, offset2), ContinuousPiecewiseLinearFunction.of(0.0, width2)),
241                     DefaultsRoadNl.HIGHWAY, speedLimit);
242 
243             double offset3 = 0.0;
244             double width3 = 0.2;
245             OtsLine2d offsetLine3 = centerLine.offsetLine(offset3);
246             new Stripe("2", DefaultsRoadNl.DASHED, link, new CrossSectionGeometry(offsetLine3, getContour(offsetLine3, width3),
247                     ContinuousPiecewiseLinearFunction.of(0.0, offset3), ContinuousPiecewiseLinearFunction.of(0.0, width3)));
248 
249             double offset4 = -1.75;
250             double width4 = 3.5;
251             OtsLine2d offsetLine4 = centerLine.offsetLine(offset4);
252             Lane right = new Lane(link, "RIGHT", new CrossSectionGeometry(offsetLine4, getContour(offsetLine4, width4),
253                     ContinuousPiecewiseLinearFunction.of(0.0, offset4), ContinuousPiecewiseLinearFunction.of(0.0, width4)),
254                     DefaultsRoadNl.HIGHWAY, speedLimit);
255 
256             double offset5 = -3.5;
257             double width5 = 0.2;
258             OtsLine2d offsetLine5 = centerLine.offsetLine(offset5);
259             new Stripe("3", DefaultsRoadNl.SOLID, link, new CrossSectionGeometry(offsetLine5, getContour(offsetLine5, width5),
260                     ContinuousPiecewiseLinearFunction.of(0.0, offset5), ContinuousPiecewiseLinearFunction.of(0.0, width5)));
261 
262             // Add distraction halfway on the network, 0.7 on left lane, 0.5 on right lane, with distance profile
263             new RoadSideDistraction("distractionLeft", left, Length.ofSI(1500.0),
264                     new TrapezoidProfile(0.7, Length.ofSI(-100.0), Length.ofSI(50.0), Length.ofSI(150.0)),
265                     LateralDirectionality.LEFT);
266             new RoadSideDistraction("distractionRight", right, Length.ofSI(1500.0),
267                     new TrapezoidProfile(0.5, Length.ofSI(-100.0), Length.ofSI(50.0), Length.ofSI(150.0)),
268                     LateralDirectionality.LEFT);
269         }
270 
271         /**
272          * Creates contour from line based on width.
273          * @param line line
274          * @param width width
275          * @return contour from line based on width
276          */
277         private Polygon2d getContour(final OtsLine2d line, final double width)
278         {
279             return LaneGeometryUtil.getContour(line.offsetLine(width / 2, width / 2), line.offsetLine(-width / 2, -width / 2));
280         }
281 
282         /**
283          * Set demand in network.
284          * @throws SimRuntimeException sim exception
285          * @throws ParameterException parameter exception
286          */
287         private void setDemand() throws SimRuntimeException, ParameterException
288         {
289             Node nodeA = this.network.getNode("A").get();
290             Node nodeB = this.network.getNode("B").get();
291             Categorization categorization = new Categorization("GTU type", GtuType.class);
292             List<Node> origins = new ArrayList<>();
293             origins.add(nodeA);
294             List<Node> destinations = new ArrayList<>();
295             destinations.add(nodeB);
296             OdMatrix od = new OdMatrix("OD", origins, destinations, categorization,
297                     new DurationVector(new double[] {0.0, 1800.0, 3600.0}), Interpolation.LINEAR);
298             FrequencyVector demand = new FrequencyVector(new double[] {2000.0, 4000.0, 1000.0}, FrequencyUnit.PER_HOUR);
299             double truckFraction = 0.1;
300             od.putDemandVector(nodeA, nodeB, new Category(categorization, DefaultsNl.CAR), demand, 1.0 - truckFraction);
301             od.putDemandVector(nodeA, nodeB, new Category(categorization, DefaultsNl.TRUCK), demand, truckFraction);
302             OdOptions odOptions = new OdOptions();
303             odOptions.set(OdOptions.NO_LC_DIST, Length.ofSI(150.0));
304             odOptions.set(OdOptions.GTU_TYPE, this.characteristics);
305             odOptions.set(OdOptions.LANE_BIAS, DefaultsRoadNl.LANE_BIAS_CAR_TRUCK);
306             odOptions.set(OdOptions.BOOKKEEPING, LaneBookkeeping.START);
307             OdApplier.applyOd(this.network, od, odOptions, DefaultsNl.VEHICLES);
308         }
309     }
310 
311 }