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