View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception.mental.sdm;
2   
3   import java.rmi.RemoteException;
4   import java.util.LinkedHashMap;
5   import java.util.LinkedHashSet;
6   import java.util.LinkedList;
7   import java.util.List;
8   import java.util.Map;
9   import java.util.Queue;
10  import java.util.Set;
11  
12  import org.djutils.event.Event;
13  import org.djutils.event.EventListener;
14  import org.djutils.exceptions.Throw;
15  import org.djutils.exceptions.Try;
16  import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
17  import org.opentrafficsim.core.gtu.Gtu;
18  import org.opentrafficsim.core.network.Network;
19  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
20  import org.opentrafficsim.road.gtu.lane.perception.mental.Fuller;
21  import org.opentrafficsim.road.gtu.lane.perception.mental.Mental;
22  import org.opentrafficsim.road.gtu.lane.perception.mental.Task;
23  import org.opentrafficsim.road.network.RoadNetwork;
24  
25  import nl.tudelft.simulation.dsol.SimRuntimeException;
26  
27  /**
28   * Stochastic Distraction Model by Manuel Lindorfer.
29   * <p>
30   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
31   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
32   * </p>
33   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
34   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
35   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
36   */
37  public class StochasticDistractionModel implements EventListener
38  {
39  
40      /** Whether to allow multi-tasking. */
41      private final boolean allowMultiTasking;
42  
43      /** List of distractions. */
44      private final List<Distraction> distractions;
45  
46      /** Simulator. */
47      private final OtsSimulatorInterface simulator;
48  
49      /** Network. */
50      private final RoadNetwork network;
51  
52      /** Set of distracted GTUs. */
53      private final Set<String> distractedGTUs = new LinkedHashSet<>();
54  
55      /** Queue of distractions per GTU. */
56      private final Map<String, Queue<Distraction>> distractionQueues = new LinkedHashMap<>();
57  
58      /**
59       * Constructor. This model will react to GTU's being created in simulation and apply distractions.
60       * @param allowMultiTasking boolean; whether to allow multi-tasking
61       * @param distractions List&lt;Distraction&gt;; list of distractions
62       * @param simulator OtsSimulatorInterface; simulator
63       * @param network RoadNetwork; network
64       */
65      public StochasticDistractionModel(final boolean allowMultiTasking, final List<Distraction> distractions,
66              final OtsSimulatorInterface simulator, final RoadNetwork network)
67      {
68          Throw.whenNull(distractions, "List of tasks may not be null.");
69          Throw.whenNull(simulator, "Simulator may not be null.");
70          Throw.whenNull(network, "Network may not be null.");
71          this.allowMultiTasking = allowMultiTasking;
72          this.distractions = distractions;
73          this.simulator = simulator;
74          this.network = network;
75          network.addListener(this, Network.GTU_ADD_EVENT);
76          network.addListener(this, Network.GTU_REMOVE_EVENT);
77      }
78  
79      /**
80       * Start a distraction.
81       * @param gtu LaneBasedGtu; gtu to start the distraction on
82       * @param distraction Distraction; distraction
83       * @param scheduleNext boolean; whether to schedule the next distraction (not if starting from queue)
84       * @throws SimRuntimeException on time error
85       */
86      public void startDistraction(final LaneBasedGtu gtu, final Distraction distraction, final boolean scheduleNext)
87              throws SimRuntimeException
88      {
89          if (gtu.isDestroyed())
90          {
91              return;
92          }
93          String gtuId = gtu.getId();
94          if (this.allowMultiTasking || !this.distractedGTUs.contains(gtuId))
95          {
96              // start the distraction now
97              if (!this.allowMultiTasking)
98              {
99                  this.distractedGTUs.add(gtuId);
100             }
101             Task task = distraction.getTask(gtu);
102             ((Fuller) gtu.getTacticalPlanner().getPerception().getMental()).addTask(task);
103             // stop the distraction
104             this.simulator.scheduleEventRel(distraction.nextDuration(), this, "stopDistraction",
105                     new Object[] {gtu, task});
106         }
107         else
108         {
109             // need to queue distraction
110             if (!this.distractionQueues.containsKey(gtuId))
111             {
112                 this.distractionQueues.put(gtuId, new LinkedList<>());
113             }
114             this.distractionQueues.get(gtuId).add(distraction);
115         }
116         if (scheduleNext)
117         {
118             // schedule next distraction
119             this.simulator.scheduleEventRel(distraction.nextInterArrival(), this, "startDistraction",
120                     new Object[] {gtu, distraction, true});
121         }
122     }
123 
124     /**
125      * Stops a distraction task.
126      * @param gtu LaneBasedGtu; gtu to stop the task for
127      * @param task Task; task to stop
128      * @throws SimRuntimeException on time error
129      */
130     public void stopDistraction(final LaneBasedGtu gtu, final Task task) throws SimRuntimeException
131     {
132         if (gtu.isDestroyed())
133         {
134             return;
135         }
136         String gtuId = gtu.getId();
137         ((Fuller) gtu.getTacticalPlanner().getPerception().getMental()).removeTask(task);
138         // start next distraction if any in queue
139         if (!this.allowMultiTasking)
140         {
141             this.distractedGTUs.remove(gtuId);
142             if (this.distractionQueues.containsKey(gtuId))
143             {
144                 Queue<Distraction> queue = this.distractionQueues.get(gtuId);
145                 Distraction distraction = queue.poll();
146                 startDistraction(gtu, distraction, false);
147                 if (queue.isEmpty())
148                 {
149                     this.distractionQueues.remove(gtuId);
150                 }
151             }
152         }
153     }
154 
155     /** {@inheritDoc} */
156     @Override
157     public void notify(final Event event) throws RemoteException
158     {
159         if (event.getType().equals(Network.GTU_ADD_EVENT))
160         {
161             // The GTU is not initialized yet, so we can't obtain the tactical planner
162             String gtuId = (String) event.getContent();
163             Gtu gtu = this.network.getGTU(gtuId);
164             gtu.addListener(this, Gtu.MOVE_EVENT);
165         }
166         else if (event.getType().equals(Gtu.MOVE_EVENT))
167         {
168             String gtuId = (String) ((Object[]) event.getContent())[0];
169             LaneBasedGtu gtu = (LaneBasedGtu) this.network.getGTU(gtuId);
170             Mental mental = gtu.getTacticalPlanner().getPerception().getMental();
171             if (mental != null && mental instanceof Fuller)
172             {
173                 for (Distraction distraction : this.distractions)
174                 {
175                     if (distraction.nextExposure())
176                     {
177                         Try.execute(
178                                 () -> this.simulator.scheduleEventRel(distraction.nextInterArrival(), this, "startDistraction",
179                                         new Object[] {gtu, distraction, true}),
180                                 "Exception while scheduling distraction start.");
181                     }
182                 }
183             }
184             gtu.removeListener(this, Gtu.MOVE_EVENT);
185         }
186         else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
187         {
188             String gtuId = (String) event.getContent();
189             if (!this.allowMultiTasking)
190             {
191                 this.distractedGTUs.remove(gtuId);
192             }
193             this.distractionQueues.remove(gtuId);
194         }
195     }
196 
197 }