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