View Javadoc
1   package 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.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.distributions.ConstantGenerator;
34  import org.opentrafficsim.core.distributions.Distribution;
35  import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
36  import org.opentrafficsim.core.distributions.Generator;
37  import org.opentrafficsim.core.distributions.ProbabilityException;
38  import org.opentrafficsim.core.gtu.GTUDirectionality;
39  import org.opentrafficsim.core.gtu.GTUException;
40  import org.opentrafficsim.core.gtu.GTUType;
41  import org.opentrafficsim.core.gtu.Try;
42  import org.opentrafficsim.core.gtu.animation.GTUColorer;
43  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterFactory;
44  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterFactoryByType;
45  import org.opentrafficsim.core.gtu.perception.DirectEgoPerception;
46  import org.opentrafficsim.core.gtu.perception.EgoPerception;
47  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
48  import org.opentrafficsim.core.idgenerator.IdGenerator;
49  import org.opentrafficsim.core.network.NetworkException;
50  import org.opentrafficsim.core.network.OTSNetwork;
51  import org.opentrafficsim.core.network.route.FixedRouteGenerator;
52  import org.opentrafficsim.core.network.route.Route;
53  import org.opentrafficsim.core.network.route.RouteGenerator;
54  import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
55  import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
56  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator;
57  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator.RoomChecker;
58  import org.opentrafficsim.road.gtu.generator.TTCRoomChecker;
59  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUType;
60  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUTypeDistribution;
61  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
62  import org.opentrafficsim.road.gtu.lane.perception.CategoricalLanePerception;
63  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
64  import org.opentrafficsim.road.gtu.lane.perception.PerceptionFactory;
65  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
66  import org.opentrafficsim.road.gtu.lane.perception.categories.Anticipation;
67  import org.opentrafficsim.road.gtu.lane.perception.categories.DelayedNeighborsPerception;
68  import org.opentrafficsim.road.gtu.lane.perception.categories.DirectInfrastructurePerception;
69  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
70  import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM;
71  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
72  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
73  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlus;
74  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
75  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveKeep;
76  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveRoute;
77  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSpeedWithCourtesy;
78  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRS;
79  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
80  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
81  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance;
82  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
83  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
84  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
85  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
86  import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
87  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
88  import org.opentrafficsim.road.network.lane.CrossSectionLink;
89  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
90  import org.opentrafficsim.road.network.lane.Lane;
91  
92  import nl.tudelft.simulation.dsol.SimRuntimeException;
93  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
94  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
95  import nl.tudelft.simulation.jstats.distributions.DistNormal;
96  import nl.tudelft.simulation.jstats.distributions.DistUniform;
97  import nl.tudelft.simulation.jstats.streams.MersenneTwister;
98  import nl.tudelft.simulation.jstats.streams.StreamInterface;
99  import nl.tudelft.simulation.language.Throw;
100 
101 /**
102  * <p>
103  * Copyright (c) 2013-2018 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 the network
125      * @param gtuColorer the GTU colorer
126      * @param simulator the simulator
127      * @param replication replication number
128      * @param anticipationStrategy anticipation strategy
129      * @param reactionTime reaction time
130      * @param anticipationTime anticipation time
131      * @param truckFraction truck fraction
132      * @param simulationTime simulation time
133      * @param leftDemand demand on left highway
134      * @param rightDemand demand on right highway
135      * @param leftFraction fraction of traffic generated on left lane
136      * @param distanceError distance error
137      * @param speedError speed error
138      * @param accelerationError 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 DEVSSimulatorInterface.TimeDoubleUnit 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 link
318      * @param id 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 the reference lane for this generator
335      * @param generationSpeed the speed of the GTU
336      * @param id the id of the generator itself
337      * @param idGenerator the generator for the ID
338      * @param simulator the simulator
339      * @param network the network
340      * @param distribution the type generator for the GTU
341      * @param headwayGenerator the headway generator for the GTU
342      * @param gtuColorer the GTU colorer for animation
343      * @param roomChecker the checker to see if there is room for the GTU
344      * @param bcFactory the factory to generate parameters for the GTU
345      * @param tacticalFactory the generator for the tactical planner
346      * @param simulationTime simulation time
347      * @param stream 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 DEVSSimulatorInterface.TimeDoubleUnit 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, gtuColorer, characteristicsGenerator,
366                 GeneratorPositions.create(initialLongitudinalPositions, stream), network, simulator, roomChecker, idGenerator);
367     }
368 
369     /**
370      * <p>
371      * Copyright (c) 2013-2018 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 factory of the car-following model
395          * @param defaultCarFollowingParameters default set of parameters for the car-following model
396          * @param perceptionFactory perception factory
397          * @throws GTUException if the supplied car-following model does not have an accessible empty constructor
398          */
399         LMRSFactoryAHFE(final CarFollowingModelFactory<? extends CarFollowingModel> carFollowingModelFactory,
400                 final Parameters defaultCarFollowingParameters, final PerceptionFactory perceptionFactory) throws GTUException
401         {
402             this.carFollowingModelFactory = carFollowingModelFactory;
403             this.defaultCarFollowingParameters = defaultCarFollowingParameters;
404             this.perceptionFactory = perceptionFactory;
405         }
406 
407         /** {@inheritDoc} */
408         @Override
409         public final Parameters getParameters()
410         {
411             ParameterSet parameters = new ParameterSet();
412             parameters.setDefaultParameters(ParameterTypes.class);
413             parameters.setDefaultParameters(LmrsParameters.class);
414             this.defaultCarFollowingParameters.setAllIn(parameters);
415             return parameters;
416         }
417 
418         /** {@inheritDoc} */
419         @Override
420         public final LMRS create(final LaneBasedGTU gtu) throws GTUException
421         {
422             LMRS lmrs = new LMRS(this.carFollowingModelFactory.generateCarFollowingModel(), gtu,
423                     this.perceptionFactory.generatePerception(gtu), Synchronization.PASSIVE, Cooperation.PASSIVE,
424                     GapAcceptance.INFORMED, Tailgating.NONE);
425             lmrs.addMandatoryIncentive(new IncentiveRoute());
426             lmrs.addVoluntaryIncentive(new IncentiveSpeedWithCourtesy());
427             if (gtu.getGTUType().getId().equals("car"))
428             {
429                 lmrs.addVoluntaryIncentive(new IncentiveKeep());
430             }
431             else
432             {
433                 lmrs.addVoluntaryIncentive(new KeepRightTruck());
434             }
435             return lmrs;
436         }
437 
438         /** {@inheritDoc} */
439         @Override
440         public final String toString()
441         {
442             return "LMRSFactory [car-following=" + this.carFollowingModelFactory + "]";
443         }
444 
445     }
446 
447     /**
448      * Perception factory with delay and anticipation for neighbors.
449      * <p>
450      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
451      * <br>
452      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
453      * <p>
454      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 2 mrt. 2017 <br>
455      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
456      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
457      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
458      */
459     private static class DelayedPerceptionFactory implements PerceptionFactory
460     {
461 
462         /** Anticipation form. */
463         private final Anticipation anticipation;
464 
465         /**
466          * Constructor.
467          * @param anticipation anticipation form.
468          */
469         DelayedPerceptionFactory(final Anticipation anticipation)
470         {
471             this.anticipation = anticipation;
472         }
473 
474         /** {@inheritDoc} */
475         @Override
476         public LanePerception generatePerception(final LaneBasedGTU gtu)
477         {
478             LanePerception perception = new CategoricalLanePerception(gtu);
479             perception.addPerceptionCategory(new DirectEgoPerception(perception));
480             // perception.addPerceptionCategory(new DirectDefaultSimplePerception(perception));
481             perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
482             // perception.addPerceptionCategory(new DirectNeighborsPerception(perception));
483             perception.addPerceptionCategory(new DelayedNeighborsPerception(perception, this.anticipation));
484             // perception.addPerceptionCategory(new DirectIntersectionPerception(perception));
485             return perception;
486         }
487 
488         /** {@inheritDoc} */
489         @Override
490         public Parameters getParameters()
491         {
492             return new ParameterSet();
493         }
494 
495     }
496 
497     /**
498      * <p>
499      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
500      * <br>
501      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
502      * <p>
503      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 3 mrt. 2017 <br>
504      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
505      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
506      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
507      */
508     private static class KeepRightTruck implements VoluntaryIncentive
509     {
510 
511         /**
512          * 
513          */
514         KeepRightTruck()
515         {
516         }
517 
518         /** {@inheritDoc} */
519         @Override
520         public Desire determineDesire(final Parameters parameters, final LanePerception perception,
521                 final CarFollowingModel carFollowingModel, final Desire mandatoryDesire, final Desire voluntaryDesire)
522                 throws ParameterException, OperationalPlanException
523         {
524             if (perception.getLaneStructure().getRootRecord().getRight() != null
525                     && perception.getLaneStructure().getRootRecord().getRight().getRight() != null
526                     && perception.getPerceptionCategory(EgoPerception.class).getSpeed()
527                             .gt(parameters.getParameter(ParameterTypes.VCONG)))
528             {
529                 // may not be on this lane
530                 return new Desire(0, 1);
531             }
532             if (mandatoryDesire.getRight() < 0 || voluntaryDesire.getRight() < 0
533                     || !perception.getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT))
534             {
535                 // no desire to go right if more dominant incentives provide a negative desire to go right
536                 return new Desire(0, 0);
537             }
538             // keep right with dFree
539             return new Desire(0, 1.0);
540         }
541 
542     }
543 
544     /**
545      * Generates headways based on demand.
546      * <p>
547      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
548      * <br>
549      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
550      * <p>
551      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 17 nov. 2016 <br>
552      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
553      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
554      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
555      */
556     // TODO replace with ArrivalsHeadwayGenerator and Arrivals
557     private static class HeadwayGeneratorDemand implements Generator<Duration>
558     {
559 
560         /** Interpolation of demand. */
561         private final Interpolation interpolation;
562 
563         /** Vector of time. */
564         private final TimeVector timeVector;
565 
566         /** Vector of flow values. */
567         private final FrequencyVector demandVector;
568 
569         /** Simulator. */
570         private final SimulatorInterface.TimeDoubleUnit simulator;
571 
572         /** Stream name of headway generation. */
573         private static final String HEADWAY_STREAM = "headwayGeneration";
574 
575         /**
576          * @param timeVector a time vector
577          * @param demandVector the corresponding demand vector
578          * @param simulator the simulator
579          */
580         public HeadwayGeneratorDemand(final TimeVector timeVector, final FrequencyVector demandVector,
581                 final SimulatorInterface.TimeDoubleUnit simulator)
582         {
583             this(timeVector, demandVector, simulator, Interpolation.STEPWISE);
584         }
585 
586         /**
587          * @param timeVector a time vector
588          * @param demandVector the corresponding demand vector
589          * @param simulator the simulator
590          * @param interpolation interpolation type
591          */
592         public HeadwayGeneratorDemand(final TimeVector timeVector, final FrequencyVector demandVector,
593                 final SimulatorInterface.TimeDoubleUnit simulator, final Interpolation interpolation)
594         {
595             Throw.whenNull(timeVector, "Time vector may not be null.");
596             Throw.whenNull(demandVector, "Demand vector may not be null.");
597             Throw.whenNull(simulator, "Simulator may not be null.");
598             Throw.whenNull(interpolation, "Interpolation may not be null.");
599             Throw.whenNull(simulator.getReplication().getStream(HEADWAY_STREAM),
600                     "Could not obtain random stream '" + HEADWAY_STREAM + "'.");
601             for (int i = 0; i < timeVector.size() - 1; i++)
602             {
603                 try
604                 {
605                     Throw.when(timeVector.get(i).ge(timeVector.get(i + 1)), IllegalArgumentException.class,
606                             "Time vector is not increasing.");
607                 }
608                 catch (ValueException exception)
609                 {
610                     throw new RuntimeException(
611                             "Value out of range of time vector. Note that HeadwayGenerator does not create a safe copy.",
612                             exception);
613                 }
614             }
615             Throw.when(timeVector.size() != demandVector.size(), IllegalArgumentException.class,
616                     "Time and flow vector should be of the same size.");
617             Throw.when(timeVector.size() < 2, IllegalArgumentException.class,
618                     "Time and flow vector should be at least of size 2.");
619             this.timeVector = timeVector;
620             this.demandVector = demandVector;
621             this.simulator = simulator;
622             this.interpolation = interpolation;
623         }
624 
625         /** {@inheritDoc} */
626         @Override
627         public final Duration draw() throws ProbabilityException, ParameterException
628         {
629             Time time = this.simulator.getSimulatorTime();
630             try
631             {
632                 Throw.when(time.lt(this.timeVector.get(0)), IllegalArgumentException.class,
633                         "Cannot return a headway at time before first time in vector.");
634 
635                 // get time period of current time
636                 int i = 0;
637                 while (this.timeVector.get(i + 1).lt(time) && i < this.timeVector.size() - 1)
638                 {
639                     i++;
640                 }
641                 try
642                 {
643                     return nextArrival(i, time.minus(this.timeVector.get(i)), 1.0).minus(time);
644                 }
645                 catch (RemoteException exception)
646                 {
647                     throw new RuntimeException("Could not obtain replication.", exception);
648                 }
649             }
650             catch (ValueException exception)
651             {
652                 throw new RuntimeException(
653                         "Value out of range of time or demand vector. Note that HeadwayGenerator does not create safe copies.",
654                         exception);
655             }
656         }
657 
658         /**
659          * Recursive determination of the next arrival time. Each recursion moves to the next time period. This occurs if a
660          * randomly determined arrival falls outside of a time period, or when demand in a time period is 0.
661          * @param i index of time period
662          * @param start reference time from start of period i, pertains to previous arrival, or zero during recursion
663          * @param fractionRemaining remaining fraction of headway to apply due to time in earlier time periods
664          * @return time of next arrival
665          * @throws ValueException in case of an illegal time vector
666          * @throws RemoteException in case of not being able to retrieve the replication
667          */
668         private Time nextArrival(final int i, final Duration start, final double fractionRemaining)
669                 throws ValueException, RemoteException
670         {
671 
672             // escape if beyond specified time by infinite next arrival (= no traffic)
673             if (i == this.timeVector.size() - 1)
674             {
675                 return new Time(Double.POSITIVE_INFINITY, TimeUnit.BASE);
676             }
677 
678             // skip zero-demand periods
679             if (this.demandVector.get(i).equals(Frequency.ZERO))
680             {
681                 // after zero-demand, the next headway is a random fraction of a random headway as there is no previous arrival
682                 return nextArrival(i + 1, Duration.ZERO,
683                         this.simulator.getReplication().getStream(HEADWAY_STREAM).nextDouble());
684             }
685 
686             // calculate headway from demand
687             Frequency demand;
688             if (this.interpolation.isStepWise())
689             {
690                 demand = this.demandVector.get(i);
691             }
692             else
693             {
694                 double f = start.si / (this.timeVector.get(i + 1).si - this.timeVector.get(i).si);
695                 demand = Frequency.interpolate(this.demandVector.get(i), this.demandVector.get(i + 1), f);
696             }
697             double t = -Math.log(this.simulator.getReplication().getStream(HEADWAY_STREAM).nextDouble()) / demand.si;
698 
699             // calculate arrival
700             Time arrival = new Time(this.timeVector.get(i).si + start.si + t * fractionRemaining, TimeUnit.BASE);
701 
702             // go to next period if arrival is beyond current period
703             if (arrival.gt(this.timeVector.get(i + 1)))
704             {
705                 double inStep = this.timeVector.get(i + 1).si - (this.timeVector.get(i).si + start.si);
706                 return nextArrival(i + 1, Duration.ZERO, fractionRemaining - inStep / t);
707             }
708 
709             return arrival;
710 
711         }
712 
713         /** {@inheritDoc} */
714         @Override
715         public final String toString()
716         {
717             return "HeadwayGeneratorDemand [interpolation=" + this.interpolation + ", timeVector=" + this.timeVector
718                     + ", demandVector=" + this.demandVector + ", simulator=" + this.simulator + "]";
719         }
720 
721     }
722 
723 }