View Javadoc
1   package org.opentrafficsim.ahfe;
2   
3   import java.rmi.RemoteException;
4   import java.util.LinkedHashMap;
5   import java.util.LinkedHashSet;
6   import java.util.Map;
7   import java.util.Random;
8   import java.util.Set;
9   
10  import org.djunits.unit.AccelerationUnit;
11  import org.djunits.unit.DurationUnit;
12  import org.djunits.unit.FrequencyUnit;
13  import org.djunits.unit.LengthUnit;
14  import org.djunits.unit.SpeedUnit;
15  import org.djunits.unit.TimeUnit;
16  import org.djunits.value.ValueRuntimeException;
17  import org.djunits.value.storage.StorageType;
18  import org.djunits.value.vdouble.scalar.Acceleration;
19  import org.djunits.value.vdouble.scalar.Duration;
20  import org.djunits.value.vdouble.scalar.Frequency;
21  import org.djunits.value.vdouble.scalar.Length;
22  import org.djunits.value.vdouble.scalar.Speed;
23  import org.djunits.value.vdouble.scalar.Time;
24  import org.djunits.value.vdouble.vector.FrequencyVector;
25  import org.djunits.value.vdouble.vector.TimeVector;
26  import org.djunits.value.vdouble.vector.base.DoubleVector;
27  import org.djutils.exceptions.Throw;
28  import org.djutils.exceptions.Try;
29  import org.opentrafficsim.base.parameters.ParameterException;
30  import org.opentrafficsim.base.parameters.ParameterSet;
31  import org.opentrafficsim.base.parameters.ParameterTypes;
32  import org.opentrafficsim.base.parameters.Parameters;
33  import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
34  import org.opentrafficsim.core.distributions.ConstantGenerator;
35  import org.opentrafficsim.core.distributions.Distribution;
36  import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
37  import org.opentrafficsim.core.distributions.Generator;
38  import org.opentrafficsim.core.distributions.ProbabilityException;
39  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
40  import org.opentrafficsim.core.gtu.GTUDirectionality;
41  import org.opentrafficsim.core.gtu.GTUException;
42  import org.opentrafficsim.core.gtu.GTUType;
43  import org.opentrafficsim.core.gtu.perception.DirectEgoPerception;
44  import org.opentrafficsim.core.gtu.perception.EgoPerception;
45  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
46  import org.opentrafficsim.core.idgenerator.IdGenerator;
47  import org.opentrafficsim.core.network.NetworkException;
48  import org.opentrafficsim.core.network.route.FixedRouteGenerator;
49  import org.opentrafficsim.core.network.route.Route;
50  import org.opentrafficsim.core.parameters.ParameterFactory;
51  import org.opentrafficsim.core.parameters.ParameterFactoryByType;
52  import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
53  import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
54  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator;
55  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator.RoomChecker;
56  import org.opentrafficsim.road.gtu.generator.TTCRoomChecker;
57  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUType;
58  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUTypeDistribution;
59  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
60  import org.opentrafficsim.road.gtu.lane.perception.CategoricalLanePerception;
61  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
62  import org.opentrafficsim.road.gtu.lane.perception.PerceptionFactory;
63  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
64  import org.opentrafficsim.road.gtu.lane.perception.categories.AnticipationTrafficPerception;
65  import org.opentrafficsim.road.gtu.lane.perception.categories.DirectInfrastructurePerception;
66  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.Anticipation;
67  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
68  import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM;
69  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
70  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
71  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlus;
72  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
73  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveKeep;
74  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveRoute;
75  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSpeedWithCourtesy;
76  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRS;
77  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
78  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
79  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance;
80  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
81  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
82  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
83  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
84  import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
85  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
86  import org.opentrafficsim.road.network.OTSRoadNetwork;
87  import org.opentrafficsim.road.network.lane.CrossSectionLink;
88  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
89  import org.opentrafficsim.road.network.lane.Lane;
90  
91  import nl.tudelft.simulation.dsol.SimRuntimeException;
92  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
93  import nl.tudelft.simulation.jstats.distributions.DistNormal;
94  import nl.tudelft.simulation.jstats.distributions.DistUniform;
95  import nl.tudelft.simulation.jstats.streams.MersenneTwister;
96  import nl.tudelft.simulation.jstats.streams.StreamInterface;
97  
98  /**
99   * <p>
100  * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
101  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
102  * <p>
103  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 2 mrt. 2017 <br>
104  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
105  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
106  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
107  */
108 
109 public final class AHFEUtil
110 {
111 
112     /**
113      * 
114      */
115     private AHFEUtil()
116     {
117         //
118     }
119 
120     /**
121      * @param network OTSRoadNetwork; the network
122      * @param gtuColorer GTUColorer; the GTU colorer
123      * @param simulator OTSSimulatorInterface; the simulator
124      * @param replication int; replication number
125      * @param anticipationStrategy String; anticipation strategy
126      * @param reactionTime Duration; reaction time
127      * @param anticipationTime Duration; anticipation time
128      * @param truckFraction double; truck fraction
129      * @param simulationTime Time; simulation time
130      * @param leftDemand Frequency; demand on left highway
131      * @param rightDemand Frequency; demand on right highway
132      * @param leftFraction double; fraction of traffic generated on left lane
133      * @param distanceError double; distance error
134      * @param speedError double; speed error
135      * @param accelerationError double; acceleration error
136      * @throws ValueRuntimeException on value error
137      * @throws ParameterException on parameter error
138      * @throws GTUException on gtu error
139      * @throws ProbabilityException on probability error
140      * @throws SimRuntimeException on sim runtime error
141      */
142     @SuppressWarnings("checkstyle:parameternumber")
143     public static void createDemand(final OTSRoadNetwork network, final GTUColorer gtuColorer,
144             final OTSSimulatorInterface simulator, final int replication, final String anticipationStrategy,
145             final Duration reactionTime, final Duration anticipationTime, final double truckFraction, final Time simulationTime,
146             final Frequency leftDemand, final Frequency rightDemand, final double leftFraction, final double distanceError,
147             final double speedError, final double accelerationError)
148             throws ValueRuntimeException, ParameterException, GTUException, SimRuntimeException, ProbabilityException
149     {
150 
151         Random seedGenerator = new Random(replication);
152         Map<String, StreamInterface> streams = new LinkedHashMap<>();
153         streams.put("headwayGeneration", new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1));
154         streams.put("gtuClass", new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1));
155         streams.put("perception", new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1));
156         simulator.getModel().getStreamInformation().addStream("headwayGeneration", streams.get("headwayGeneration"));
157         simulator.getModel().getStreamInformation().addStream("gtuClass", streams.get("gtuClass"));
158         simulator.getModel().getStreamInformation().addStream("perception", streams.get("perception"));
159 
160         TTCRoomChecker roomChecker = new TTCRoomChecker(new Duration(10.0, DurationUnit.SI));
161         IdGenerator idGenerator = new IdGenerator("");
162 
163         CarFollowingModelFactory<IDMPlus> idmPlusFactory = new IDMPlusFactory(streams.get("gtuClass"));
164         PerceptionFactory delayedPerceptionFactory = Try.assign(
165                 () -> new DelayedPerceptionFactory(
166                         (Anticipation) Anticipation.class.getDeclaredField(anticipationStrategy.toUpperCase()).get(null)),
167                 "Exception while obtaining anticipation value %s", anticipationStrategy);
168         ParameterSet params = new ParameterSet();
169         params.setDefaultParameter(AbstractIDM.DELTA);
170         params.setParameter(ParameterTypes.TR, reactionTime);
171         params.setParameter(DelayedNeighborsPerception.TA, anticipationTime);
172         params.setDefaultParameter(DelayedNeighborsPerception.TAUE);
173         params.setParameter(DelayedNeighborsPerception.SERROR, distanceError);
174         params.setParameter(DelayedNeighborsPerception.VERROR, speedError);
175         params.setParameter(DelayedNeighborsPerception.AERROR, accelerationError);
176         LaneBasedTacticalPlannerFactory<LMRS> tacticalFactory =
177                 new LMRSFactoryAHFE(idmPlusFactory, params, delayedPerceptionFactory);
178 
179         ParameterFactoryByType bcFactory = new ParameterFactoryByType();
180         // Length lookAhead = new Length(1000.0, LengthUnit.SI);
181         // Length lookAheadStdev = new Length(250.0, LengthUnit.SI);
182         Length perception = new Length(1.0, LengthUnit.KILOMETER);
183         Acceleration b = new Acceleration(2.09, AccelerationUnit.SI);
184         GTUType gtuType = new GTUType("car", network.getGtuType(GTUType.DEFAULTS.CAR));
185         bcFactory.addParameter(gtuType, ParameterTypes.FSPEED,
186                 new DistNormal(streams.get("gtuClass"), 123.7 / 120, 12.0 / 120));
187         bcFactory.addParameter(gtuType, ParameterTypes.B, b);
188         // bcFactory.addGaussianParameter(gtuType, ParameterTypes.LOOKAHEAD, lookAhead, lookAheadStdev,
189         // streams.get("gtuClass"));
190         bcFactory.addParameter(gtuType, ParameterTypes.PERCEPTION, perception);
191         gtuType = new GTUType("truck", network.getGtuType(GTUType.DEFAULTS.TRUCK));
192         bcFactory.addParameter(gtuType, ParameterTypes.A, new Acceleration(0.8, AccelerationUnit.SI));
193         bcFactory.addParameter(gtuType, ParameterTypes.B, b);
194         // bcFactory.addGaussianParameter(gtuType, ParameterTypes.LOOKAHEAD, lookAhead, lookAheadStdev,
195         // streams.get("gtuClass"));
196         bcFactory.addParameter(gtuType, ParameterTypes.PERCEPTION, perception);
197         bcFactory.addParameter(gtuType, ParameterTypes.FSPEED, 2.0);
198 
199         Route leftRoute = new Route("left");
200         Route rightRoute = new Route("right");
201         try
202         {
203             leftRoute.addNode(network.getNode("LEFTINPRE"));
204             leftRoute.addNode(network.getNode("LEFTIN"));
205             leftRoute.addNode(network.getNode("STARTCONVERGE"));
206             leftRoute.addNode(network.getNode("STARTWEAVING"));
207             leftRoute.addNode(network.getNode("NARROWING"));
208             leftRoute.addNode(network.getNode("EXIT"));
209             rightRoute.addNode(network.getNode("RIGHTINPRE"));
210             rightRoute.addNode(network.getNode("RIGHTIN"));
211             rightRoute.addNode(network.getNode("STARTWEAVING"));
212             rightRoute.addNode(network.getNode("NARROWING"));
213             rightRoute.addNode(network.getNode("EXIT"));
214         }
215         catch (NetworkException exception)
216         {
217             exception.printStackTrace();
218         }
219         Generator<Route> fixedRouteGeneratorLeft = new FixedRouteGenerator(leftRoute);
220         Generator<Route> fixedRouteGeneratorRight = new FixedRouteGenerator(rightRoute);
221 
222         LaneBasedStrategicalRoutePlannerFactory strategicalFactory =
223                 new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory, bcFactory);
224         ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedCar =
225                 new ContinuousDistDoubleScalar.Rel<>(new DistUniform(streams.get("gtuClass"), 160, 200), SpeedUnit.KM_PER_HOUR);
226         ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedTruck =
227                 new ContinuousDistDoubleScalar.Rel<>(new DistNormal(streams.get("gtuClass"), 80, 2.5), SpeedUnit.KM_PER_HOUR);
228 
229         LaneBasedTemplateGTUType carLeft =
230                 new LaneBasedTemplateGTUType(new GTUType("car", network.getGtuType(GTUType.DEFAULTS.CAR)),
231                         new ConstantGenerator<>(Length.instantiateSI(4.0)), new ConstantGenerator<>(Length.instantiateSI(2.0)),
232                         speedCar, strategicalFactory, fixedRouteGeneratorLeft);
233         LaneBasedTemplateGTUType truckLeft =
234                 new LaneBasedTemplateGTUType(new GTUType("truck", network.getGtuType(GTUType.DEFAULTS.TRUCK)),
235                         new ConstantGenerator<>(Length.instantiateSI(15.0)), new ConstantGenerator<>(Length.instantiateSI(2.5)),
236                         speedTruck, strategicalFactory, fixedRouteGeneratorLeft);
237         LaneBasedTemplateGTUType carRight =
238                 new LaneBasedTemplateGTUType(new GTUType("car", network.getGtuType(GTUType.DEFAULTS.CAR)),
239                         new ConstantGenerator<>(Length.instantiateSI(4.0)), new ConstantGenerator<>(Length.instantiateSI(2.0)),
240                         speedCar, strategicalFactory, fixedRouteGeneratorRight);
241         LaneBasedTemplateGTUType truckRight =
242                 new LaneBasedTemplateGTUType(new GTUType("truck", network.getGtuType(GTUType.DEFAULTS.TRUCK)),
243                         new ConstantGenerator<>(Length.instantiateSI(15.0)), new ConstantGenerator<>(Length.instantiateSI(2.5)),
244                         speedTruck, strategicalFactory, fixedRouteGeneratorRight);
245 
246         // GTUTypeGenerator gtuTypeGeneratorLeft = new GTUTypeGenerator(simulator, streams.get("gtuClass"));
247         // GTUTypeGenerator gtuTypeGeneratorRight = new GTUTypeGenerator(simulator, streams.get("gtuClass"));
248 
249         Distribution<LaneBasedTemplateGTUType> gtuTypeGeneratorLeftLeft = new Distribution<>(streams.get("gtuClass"));
250         Distribution<LaneBasedTemplateGTUType> gtuTypeGeneratorLeftRight = new Distribution<>(streams.get("gtuClass"));
251         Distribution<LaneBasedTemplateGTUType> gtuTypeGeneratorRightLeft = new Distribution<>(streams.get("gtuClass"));
252         Distribution<LaneBasedTemplateGTUType> gtuTypeGeneratorRightRight = new Distribution<>(streams.get("gtuClass"));
253         if (truckFraction < 1 - leftFraction)
254         {
255             double p = truckFraction / (1 - leftFraction);
256 
257             gtuTypeGeneratorLeftLeft.add(new FrequencyAndObject<>(1.0, carLeft));
258             gtuTypeGeneratorLeftRight.add(new FrequencyAndObject<>(1.0 - p, carLeft));
259             gtuTypeGeneratorLeftRight.add(new FrequencyAndObject<>(p, truckLeft));
260 
261             gtuTypeGeneratorRightLeft.add(new FrequencyAndObject<>(1.0, carRight));
262             gtuTypeGeneratorRightRight.add(new FrequencyAndObject<>(1.0 - p, carRight));
263             gtuTypeGeneratorRightRight.add(new FrequencyAndObject<>(p, truckRight));
264         }
265         else
266         {
267             double p = (truckFraction - (1 - leftFraction)) / leftFraction;
268             gtuTypeGeneratorLeftLeft.add(new FrequencyAndObject<>(1.0 - p, carLeft));
269             gtuTypeGeneratorLeftLeft.add(new FrequencyAndObject<>(p, truckLeft));
270             gtuTypeGeneratorLeftRight.add(new FrequencyAndObject<>(1.0, truckLeft));
271 
272             gtuTypeGeneratorRightLeft.add(new FrequencyAndObject<>(1.0 - p, carRight));
273             gtuTypeGeneratorRightLeft.add(new FrequencyAndObject<>(p, truckRight));
274             gtuTypeGeneratorRightRight.add(new FrequencyAndObject<>(1.0, truckRight));
275         }
276 
277         TimeVector timeVector =
278                 DoubleVector.instantiate(new double[] {0, 360, 1560, 2160, 3960}, TimeUnit.BASE_SECOND, StorageType.DENSE);
279         double leftLeft = leftDemand.si * leftFraction;
280         FrequencyVector leftLeftDemandPattern = DoubleVector.instantiate(
281                 new double[] {leftLeft * 0.5, leftLeft * 0.5, leftLeft, leftLeft, 0.0}, FrequencyUnit.SI, StorageType.DENSE);
282         double leftRight = leftDemand.si * (1 - leftFraction);
283         FrequencyVector leftRightDemandPattern =
284                 DoubleVector.instantiate(new double[] {leftRight * 0.5, leftRight * 0.5, leftRight, leftRight, 0.0},
285                         FrequencyUnit.SI, StorageType.DENSE);
286         double rightLeft = rightDemand.si * leftFraction;
287         FrequencyVector rightLeftDemandPattern =
288                 DoubleVector.instantiate(new double[] {rightLeft * 0.5, rightLeft * 0.5, rightLeft, rightLeft, 0.0},
289                         FrequencyUnit.SI, StorageType.DENSE);
290         double rightRight = rightDemand.si * (1 - leftFraction);
291         FrequencyVector rightRightDemandPattern =
292                 DoubleVector.instantiate(new double[] {rightRight * 0.5, rightRight * 0.5, rightRight, rightRight, 0.0},
293                         FrequencyUnit.SI, StorageType.DENSE);
294         // This defaults to stepwise interpolation, should have been linear.
295         HeadwayGeneratorDemand leftLeftHeadways = new HeadwayGeneratorDemand(timeVector, leftLeftDemandPattern, simulator);
296         HeadwayGeneratorDemand leftRightHeadways = new HeadwayGeneratorDemand(timeVector, leftRightDemandPattern, simulator);
297         HeadwayGeneratorDemand rightLeftHeadways = new HeadwayGeneratorDemand(timeVector, rightLeftDemandPattern, simulator);
298         HeadwayGeneratorDemand rightRightHeadways = new HeadwayGeneratorDemand(timeVector, rightRightDemandPattern, simulator);
299 
300         Speed genSpeed = new Speed(120.0, SpeedUnit.KM_PER_HOUR);
301         CrossSectionLink leftLink = (CrossSectionLink) network.getLink("LEFTINPRE");
302         CrossSectionLink rightLink = (CrossSectionLink) network.getLink("RIGHTINPRE");
303         makeGenerator(getLane(leftLink, "FORWARD1"), genSpeed, "LEFTLEFT", idGenerator, simulator, network,
304                 gtuTypeGeneratorLeftLeft, leftLeftHeadways, gtuColorer, roomChecker, bcFactory, tacticalFactory, simulationTime,
305                 streams.get("gtuClass"));
306         makeGenerator(getLane(leftLink, "FORWARD2"), genSpeed, "LEFTRIGHT", idGenerator, simulator, network,
307                 gtuTypeGeneratorLeftRight, leftRightHeadways, gtuColorer, roomChecker, bcFactory, tacticalFactory,
308                 simulationTime, streams.get("gtuClass"));
309         makeGenerator(getLane(rightLink, "FORWARD1"), genSpeed, "RIGHTLEFT", idGenerator, simulator, network,
310                 gtuTypeGeneratorRightLeft, rightLeftHeadways, gtuColorer, roomChecker, bcFactory, tacticalFactory,
311                 simulationTime, streams.get("gtuClass"));
312         makeGenerator(getLane(rightLink, "FORWARD2"), genSpeed, "RIGHTRIGHT", idGenerator, simulator, network,
313                 gtuTypeGeneratorRightRight, rightRightHeadways, gtuColorer, roomChecker, bcFactory, tacticalFactory,
314                 simulationTime, streams.get("gtuClass"));
315 
316     }
317 
318     /**
319      * Get lane from link by id.
320      * @param link CrossSectionLink; link
321      * @param id String; id
322      * @return lane
323      */
324     private static Lane getLane(final CrossSectionLink link, final String id)
325     {
326         for (Lane lane : link.getLanes())
327         {
328             if (lane.getId().equals(id))
329             {
330                 return lane;
331             }
332         }
333         throw new RuntimeException("Could not find lane " + id + " on link " + link.getId());
334     }
335 
336     /**
337      * @param lane Lane; the reference lane for this generator
338      * @param generationSpeed Speed; the speed of the GTU
339      * @param id String; the id of the generator itself
340      * @param idGenerator IdGenerator; the generator for the ID
341      * @param simulator OTSSimulatorInterface; the simulator
342      * @param network OTSRoadNetwork; the network
343      * @param distribution Distribution&lt;LaneBasedTemplateGTUType&gt;; the type generator for the GTU
344      * @param headwayGenerator HeadwayGeneratorDemand; the headway generator for the GTU
345      * @param gtuColorer GTUColorer; the GTU colorer for animation
346      * @param roomChecker RoomChecker; the checker to see if there is room for the GTU
347      * @param bcFactory ParameterFactory; the factory to generate parameters for the GTU
348      * @param tacticalFactory LaneBasedTacticalPlannerFactory&lt;?&gt;; the generator for the tactical planner
349      * @param simulationTime Time; simulation time
350      * @param stream StreamInterface; random number stream
351      * @throws SimRuntimeException in case of scheduling problems
352      * @throws ProbabilityException in case of an illegal probability distribution
353      * @throws GTUException in case the GTU is inconsistent
354      * @throws ParameterException in case a parameter for the perception is missing
355      */
356     private static void makeGenerator(final Lane lane, final Speed generationSpeed, final String id,
357             final IdGenerator idGenerator, final OTSSimulatorInterface simulator, final OTSRoadNetwork network,
358             final Distribution<LaneBasedTemplateGTUType> distribution, final HeadwayGeneratorDemand headwayGenerator,
359             final GTUColorer gtuColorer, final RoomChecker roomChecker, final ParameterFactory bcFactory,
360             final LaneBasedTacticalPlannerFactory<?> tacticalFactory, final Time simulationTime, final StreamInterface stream)
361             throws SimRuntimeException, ProbabilityException, GTUException, ParameterException
362     {
363         Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>();
364         // TODO DIR_MINUS
365         initialLongitudinalPositions
366                 .add(new DirectedLanePosition(lane, new Length(10.0, LengthUnit.SI), GTUDirectionality.DIR_PLUS));
367         LaneBasedTemplateGTUTypeDistribution characteristicsGenerator = new LaneBasedTemplateGTUTypeDistribution(distribution);
368         new LaneBasedGTUGenerator(id, headwayGenerator, characteristicsGenerator,
369                 GeneratorPositions.create(initialLongitudinalPositions, stream), network, simulator, roomChecker, idGenerator);
370     }
371 
372     /**
373      * <p>
374      * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
375      * <br>
376      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
377      * <p>
378      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 29 jan. 2017 <br>
379      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
380      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
381      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
382      */
383     private static class LMRSFactoryAHFE implements LaneBasedTacticalPlannerFactory<LMRS>
384     {
385 
386         /** Constructor for the car-following model. */
387         private final CarFollowingModelFactory<? extends CarFollowingModel> carFollowingModelFactory;
388 
389         /** Default set of parameters for the car-following model. */
390         private final Parameters defaultCarFollowingParameters;
391 
392         /** Factory for perception. */
393         private final PerceptionFactory perceptionFactory;
394 
395         /**
396          * Constructor with car-following model class. The class should have an accessible empty constructor.
397          * @param carFollowingModelFactory CarFollowingModelFactory&lt;? extends CarFollowingModel&gt;; factory of the
398          *            car-following model
399          * @param defaultCarFollowingParameters Parameters; default set of parameters for the car-following model
400          * @param perceptionFactory PerceptionFactory; perception factory
401          * @throws GTUException if the supplied car-following model does not have an accessible empty constructor
402          */
403         LMRSFactoryAHFE(final CarFollowingModelFactory<? extends CarFollowingModel> carFollowingModelFactory,
404                 final Parameters defaultCarFollowingParameters, final PerceptionFactory perceptionFactory) throws GTUException
405         {
406             this.carFollowingModelFactory = carFollowingModelFactory;
407             this.defaultCarFollowingParameters = defaultCarFollowingParameters;
408             this.perceptionFactory = perceptionFactory;
409         }
410 
411         /** {@inheritDoc} */
412         @Override
413         public final Parameters getParameters()
414         {
415             ParameterSet parameters = new ParameterSet();
416             parameters.setDefaultParameters(ParameterTypes.class);
417             parameters.setDefaultParameters(LmrsParameters.class);
418             this.defaultCarFollowingParameters.setAllIn(parameters);
419             return parameters;
420         }
421 
422         /** {@inheritDoc} */
423         @Override
424         public final LMRS create(final LaneBasedGTU gtu) throws GTUException
425         {
426             LMRS lmrs = new LMRS(this.carFollowingModelFactory.generateCarFollowingModel(), gtu,
427                     this.perceptionFactory.generatePerception(gtu), Synchronization.PASSIVE, Cooperation.PASSIVE,
428                     GapAcceptance.INFORMED, Tailgating.NONE);
429             lmrs.addMandatoryIncentive(new IncentiveRoute());
430             lmrs.addVoluntaryIncentive(new IncentiveSpeedWithCourtesy());
431             if (gtu.getGTUType().getId().equals("car"))
432             {
433                 lmrs.addVoluntaryIncentive(new IncentiveKeep());
434             }
435             else
436             {
437                 lmrs.addVoluntaryIncentive(new KeepRightTruck());
438             }
439             return lmrs;
440         }
441 
442         /** {@inheritDoc} */
443         @Override
444         public final String toString()
445         {
446             return "LMRSFactory [car-following=" + this.carFollowingModelFactory + "]";
447         }
448 
449     }
450 
451     /**
452      * Perception factory with delay and anticipation for neighbors.
453      * <p>
454      * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
455      * <br>
456      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
457      * <p>
458      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 2 mrt. 2017 <br>
459      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
460      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
461      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
462      */
463     private static class DelayedPerceptionFactory implements PerceptionFactory
464     {
465 
466         /** Anticipation form. */
467         private final Anticipation anticipation;
468 
469         /**
470          * Constructor.
471          * @param anticipation Anticipation; anticipation form.
472          */
473         DelayedPerceptionFactory(final Anticipation anticipation)
474         {
475             this.anticipation = anticipation;
476         }
477 
478         /** {@inheritDoc} */
479         @Override
480         public LanePerception generatePerception(final LaneBasedGTU gtu)
481         {
482             LanePerception perception = new CategoricalLanePerception(gtu);
483             perception.addPerceptionCategory(new DirectEgoPerception(perception));
484             // perception.addPerceptionCategory(new DirectDefaultSimplePerception(perception));
485             perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
486             // perception.addPerceptionCategory(new DirectNeighborsPerception(perception));
487             perception.addPerceptionCategory(new DelayedNeighborsPerception(perception, this.anticipation));
488             // perception.addPerceptionCategory(new DirectIntersectionPerception(perception));
489             perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
490             return perception;
491         }
492 
493         /** {@inheritDoc} */
494         @Override
495         public Parameters getParameters()
496         {
497             return new ParameterSet();
498         }
499 
500     }
501 
502     /**
503      * <p>
504      * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
505      * <br>
506      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
507      * <p>
508      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 3 mrt. 2017 <br>
509      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
510      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
511      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
512      */
513     private static class KeepRightTruck implements VoluntaryIncentive
514     {
515 
516         /**
517          * 
518          */
519         KeepRightTruck()
520         {
521         }
522 
523         /** {@inheritDoc} */
524         @Override
525         public Desire determineDesire(final Parameters parameters, final LanePerception perception,
526                 final CarFollowingModel carFollowingModel, final Desire mandatoryDesire, final Desire voluntaryDesire)
527                 throws ParameterException, OperationalPlanException
528         {
529             if (perception.getLaneStructure().getRootRecord().getRight() != null
530                     && perception.getLaneStructure().getRootRecord().getRight().getRight() != null
531                     && perception.getPerceptionCategory(EgoPerception.class).getSpeed()
532                             .gt(parameters.getParameter(ParameterTypes.VCONG)))
533             {
534                 // may not be on this lane
535                 return new Desire(0, 1);
536             }
537             if (mandatoryDesire.getRight() < 0 || voluntaryDesire.getRight() < 0
538                     || !perception.getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT))
539             {
540                 // no desire to go right if more dominant incentives provide a negative desire to go right
541                 return new Desire(0, 0);
542             }
543             // keep right with dFree
544             return new Desire(0, 1.0);
545         }
546 
547     }
548 
549     /**
550      * Generates headways based on demand.
551      * <p>
552      * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
553      * <br>
554      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
555      * <p>
556      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 17 nov. 2016 <br>
557      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
558      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
559      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
560      */
561     // TODO replace with ArrivalsHeadwayGenerator and Arrivals
562     private static class HeadwayGeneratorDemand implements Generator<Duration>
563     {
564 
565         /** Interpolation of demand. */
566         private final Interpolation interpolation;
567 
568         /** Vector of time. */
569         private final TimeVector timeVector;
570 
571         /** Vector of flow values. */
572         private final FrequencyVector demandVector;
573 
574         /** Simulator. */
575         private final OTSSimulatorInterface simulator;
576 
577         /** Stream name of headway generation. */
578         private static final String HEADWAY_STREAM = "headwayGeneration";
579 
580         /**
581          * @param timeVector TimeVector; a time vector
582          * @param demandVector FrequencyVector; the corresponding demand vector
583          * @param simulator OTSSimulatorInterface; the simulator
584          */
585         HeadwayGeneratorDemand(final TimeVector timeVector, final FrequencyVector demandVector,
586                 final OTSSimulatorInterface simulator)
587         {
588             this(timeVector, demandVector, simulator, Interpolation.STEPWISE);
589         }
590 
591         /**
592          * @param timeVector TimeVector; a time vector
593          * @param demandVector FrequencyVector; the corresponding demand vector
594          * @param simulator OTSSimulatorInterface; the simulator
595          * @param interpolation Interpolation; interpolation type
596          */
597         HeadwayGeneratorDemand(final TimeVector timeVector, final FrequencyVector demandVector,
598                 final OTSSimulatorInterface simulator, final Interpolation interpolation)
599         {
600             Throw.whenNull(timeVector, "Time vector may not be null.");
601             Throw.whenNull(demandVector, "Demand vector may not be null.");
602             Throw.whenNull(simulator, "Simulator may not be null.");
603             Throw.whenNull(interpolation, "Interpolation may not be null.");
604             Throw.whenNull(simulator.getModel().getStream(HEADWAY_STREAM),
605                     "Could not obtain random stream '" + HEADWAY_STREAM + "'.");
606             for (int i = 0; i < timeVector.size() - 1; i++)
607             {
608                 try
609                 {
610                     Throw.when(timeVector.get(i).ge(timeVector.get(i + 1)), IllegalArgumentException.class,
611                             "Time vector is not increasing.");
612                 }
613                 catch (ValueRuntimeException exception)
614                 {
615                     throw new RuntimeException(
616                             "Value out of range of time vector. Note that HeadwayGenerator does not create a safe copy.",
617                             exception);
618                 }
619             }
620             Throw.when(timeVector.size() != demandVector.size(), IllegalArgumentException.class,
621                     "Time and flow vector should be of the same size.");
622             Throw.when(timeVector.size() < 2, IllegalArgumentException.class,
623                     "Time and flow vector should be at least of size 2.");
624             this.timeVector = timeVector;
625             this.demandVector = demandVector;
626             this.simulator = simulator;
627             this.interpolation = interpolation;
628         }
629 
630         /** {@inheritDoc} */
631         @Override
632         public final Duration draw() throws ProbabilityException, ParameterException
633         {
634             Time time = this.simulator.getSimulatorAbsTime();
635             try
636             {
637                 Throw.when(time.lt(this.timeVector.get(0)), IllegalArgumentException.class,
638                         "Cannot return a headway at time before first time in vector.");
639 
640                 // get time period of current time
641                 int i = 0;
642                 while (this.timeVector.get(i + 1).lt(time) && i < this.timeVector.size() - 1)
643                 {
644                     i++;
645                 }
646                 try
647                 {
648                     return nextArrival(i, time.minus(this.timeVector.get(i)), 1.0).minus(time);
649                 }
650                 catch (RemoteException exception)
651                 {
652                     throw new RuntimeException("Could not obtain replication.", exception);
653                 }
654             }
655             catch (ValueRuntimeException exception)
656             {
657                 throw new RuntimeException(
658                         "Value out of range of time or demand vector. Note that HeadwayGenerator does not create safe copies.",
659                         exception);
660             }
661         }
662 
663         /**
664          * Recursive determination of the next arrival time. Each recursion moves to the next time period. This occurs if a
665          * randomly determined arrival falls outside of a time period, or when demand in a time period is 0.
666          * @param i int; index of time period
667          * @param start Duration; reference time from start of period i, pertains to previous arrival, or zero during recursion
668          * @param fractionRemaining double; remaining fraction of headway to apply due to time in earlier time periods
669          * @return time of next arrival
670          * @throws ValueRuntimeException in case of an illegal time vector
671          * @throws RemoteException in case of not being able to retrieve the replication
672          */
673         private Time nextArrival(final int i, final Duration start, final double fractionRemaining)
674                 throws ValueRuntimeException, RemoteException
675         {
676 
677             // escape if beyond specified time by infinite next arrival (= no traffic)
678             if (i == this.timeVector.size() - 1)
679             {
680                 return new Time(Double.POSITIVE_INFINITY, TimeUnit.DEFAULT);
681             }
682 
683             // skip zero-demand periods
684             if (this.demandVector.get(i).equals(Frequency.ZERO))
685             {
686                 // after zero-demand, the next headway is a random fraction of a random headway as there is no previous arrival
687                 return nextArrival(i + 1, Duration.ZERO,
688                         this.simulator.getModel().getStream(HEADWAY_STREAM).nextDouble());
689             }
690 
691             // calculate headway from demand
692             Frequency demand;
693             if (this.interpolation.isStepWise())
694             {
695                 demand = this.demandVector.get(i);
696             }
697             else
698             {
699                 double f = start.si / (this.timeVector.get(i + 1).si - this.timeVector.get(i).si);
700                 demand = Frequency.interpolate(this.demandVector.get(i), this.demandVector.get(i + 1), f);
701             }
702             double t = -Math.log(this.simulator.getModel().getStream(HEADWAY_STREAM).nextDouble()) / demand.si;
703 
704             // calculate arrival
705             Time arrival = new Time(this.timeVector.get(i).si + start.si + t * fractionRemaining, TimeUnit.DEFAULT);
706 
707             // go to next period if arrival is beyond current period
708             if (arrival.gt(this.timeVector.get(i + 1)))
709             {
710                 double inStep = this.timeVector.get(i + 1).si - (this.timeVector.get(i).si + start.si);
711                 return nextArrival(i + 1, Duration.ZERO, fractionRemaining - inStep / t);
712             }
713 
714             return arrival;
715 
716         }
717 
718         /** {@inheritDoc} */
719         @Override
720         public final String toString()
721         {
722             return "HeadwayGeneratorDemand [interpolation=" + this.interpolation + ", timeVector=" + this.timeVector
723                     + ", demandVector=" + this.demandVector + ", simulator=" + this.simulator + "]";
724         }
725 
726     }
727 
728 }