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  
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 public final class AHFEUtil
110 {
111 
112     
113 
114 
115     private AHFEUtil()
116     {
117         
118     }
119 
120     
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
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.getReplication().setStreams(streams);
157 
158         TTCRoomChecker roomChecker = new TTCRoomChecker(new Duration(10.0, DurationUnit.SI));
159         IdGenerator idGenerator = new IdGenerator("");
160 
161         CarFollowingModelFactory<IDMPlus> idmPlusFactory = new IDMPlusFactory(streams.get("gtuClass"));
162         PerceptionFactory delayedPerceptionFactory = Try.assign(
163                 () -> new DelayedPerceptionFactory(
164                         (Anticipation) Anticipation.class.getDeclaredField(anticipationStrategy.toUpperCase()).get(null)),
165                 "Exception while obtaining anticipation value %s", anticipationStrategy);
166         ParameterSet params = new ParameterSet();
167         params.setDefaultParameter(AbstractIDM.DELTA);
168         params.setParameter(ParameterTypes.TR, reactionTime);
169         params.setParameter(DelayedNeighborsPerception.TA, anticipationTime);
170         params.setDefaultParameter(DelayedNeighborsPerception.TAUE);
171         params.setParameter(DelayedNeighborsPerception.SERROR, distanceError);
172         params.setParameter(DelayedNeighborsPerception.VERROR, speedError);
173         params.setParameter(DelayedNeighborsPerception.AERROR, accelerationError);
174         LaneBasedTacticalPlannerFactory<LMRS> tacticalFactory =
175                 new LMRSFactoryAHFE(idmPlusFactory, params, delayedPerceptionFactory);
176 
177         ParameterFactoryByType bcFactory = new ParameterFactoryByType();
178         
179         
180         Length perception = new Length(1.0, LengthUnit.KILOMETER);
181         Acceleration b = new Acceleration(2.09, AccelerationUnit.SI);
182         GTUType gtuType = new GTUType("car", network.getGtuType(GTUType.DEFAULTS.CAR));
183         bcFactory.addParameter(gtuType, ParameterTypes.FSPEED,
184                 new DistNormal(streams.get("gtuClass"), 123.7 / 120, 12.0 / 120));
185         bcFactory.addParameter(gtuType, ParameterTypes.B, b);
186         
187         
188         bcFactory.addParameter(gtuType, ParameterTypes.PERCEPTION, perception);
189         gtuType = new GTUType("truck", network.getGtuType(GTUType.DEFAULTS.TRUCK));
190         bcFactory.addParameter(gtuType, ParameterTypes.A, new Acceleration(0.8, AccelerationUnit.SI));
191         bcFactory.addParameter(gtuType, ParameterTypes.B, b);
192         
193         
194         bcFactory.addParameter(gtuType, ParameterTypes.PERCEPTION, perception);
195         bcFactory.addParameter(gtuType, ParameterTypes.FSPEED, 2.0);
196 
197         Route leftRoute = new Route("left");
198         Route rightRoute = new Route("right");
199         try
200         {
201             leftRoute.addNode(network.getNode("LEFTINPRE"));
202             leftRoute.addNode(network.getNode("LEFTIN"));
203             leftRoute.addNode(network.getNode("STARTCONVERGE"));
204             leftRoute.addNode(network.getNode("STARTWEAVING"));
205             leftRoute.addNode(network.getNode("NARROWING"));
206             leftRoute.addNode(network.getNode("EXIT"));
207             rightRoute.addNode(network.getNode("RIGHTINPRE"));
208             rightRoute.addNode(network.getNode("RIGHTIN"));
209             rightRoute.addNode(network.getNode("STARTWEAVING"));
210             rightRoute.addNode(network.getNode("NARROWING"));
211             rightRoute.addNode(network.getNode("EXIT"));
212         }
213         catch (NetworkException exception)
214         {
215             exception.printStackTrace();
216         }
217         Generator<Route> fixedRouteGeneratorLeft = new FixedRouteGenerator(leftRoute);
218         Generator<Route> fixedRouteGeneratorRight = new FixedRouteGenerator(rightRoute);
219 
220         LaneBasedStrategicalRoutePlannerFactory strategicalFactory =
221                 new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory, bcFactory);
222         ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedCar =
223                 new ContinuousDistDoubleScalar.Rel<>(new DistUniform(streams.get("gtuClass"), 160, 200), SpeedUnit.KM_PER_HOUR);
224         ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedTruck =
225                 new ContinuousDistDoubleScalar.Rel<>(new DistNormal(streams.get("gtuClass"), 80, 2.5), SpeedUnit.KM_PER_HOUR);
226 
227         LaneBasedTemplateGTUType carLeft =
228                 new LaneBasedTemplateGTUType(new GTUType("car", network.getGtuType(GTUType.DEFAULTS.CAR)),
229                         new ConstantGenerator<>(Length.instantiateSI(4.0)), new ConstantGenerator<>(Length.instantiateSI(2.0)),
230                         speedCar, strategicalFactory, fixedRouteGeneratorLeft);
231         LaneBasedTemplateGTUType truckLeft =
232                 new LaneBasedTemplateGTUType(new GTUType("truck", network.getGtuType(GTUType.DEFAULTS.TRUCK)),
233                         new ConstantGenerator<>(Length.instantiateSI(15.0)), new ConstantGenerator<>(Length.instantiateSI(2.5)),
234                         speedTruck, strategicalFactory, fixedRouteGeneratorLeft);
235         LaneBasedTemplateGTUType carRight =
236                 new LaneBasedTemplateGTUType(new GTUType("car", network.getGtuType(GTUType.DEFAULTS.CAR)),
237                         new ConstantGenerator<>(Length.instantiateSI(4.0)), new ConstantGenerator<>(Length.instantiateSI(2.0)),
238                         speedCar, strategicalFactory, fixedRouteGeneratorRight);
239         LaneBasedTemplateGTUType truckRight =
240                 new LaneBasedTemplateGTUType(new GTUType("truck", network.getGtuType(GTUType.DEFAULTS.TRUCK)),
241                         new ConstantGenerator<>(Length.instantiateSI(15.0)), new ConstantGenerator<>(Length.instantiateSI(2.5)),
242                         speedTruck, strategicalFactory, fixedRouteGeneratorRight);
243 
244         
245         
246 
247         Distribution<LaneBasedTemplateGTUType> gtuTypeGeneratorLeftLeft = new Distribution<>(streams.get("gtuClass"));
248         Distribution<LaneBasedTemplateGTUType> gtuTypeGeneratorLeftRight = new Distribution<>(streams.get("gtuClass"));
249         Distribution<LaneBasedTemplateGTUType> gtuTypeGeneratorRightLeft = new Distribution<>(streams.get("gtuClass"));
250         Distribution<LaneBasedTemplateGTUType> gtuTypeGeneratorRightRight = new Distribution<>(streams.get("gtuClass"));
251         if (truckFraction < 1 - leftFraction)
252         {
253             double p = truckFraction / (1 - leftFraction);
254 
255             gtuTypeGeneratorLeftLeft.add(new FrequencyAndObject<>(1.0, carLeft));
256             gtuTypeGeneratorLeftRight.add(new FrequencyAndObject<>(1.0 - p, carLeft));
257             gtuTypeGeneratorLeftRight.add(new FrequencyAndObject<>(p, truckLeft));
258 
259             gtuTypeGeneratorRightLeft.add(new FrequencyAndObject<>(1.0, carRight));
260             gtuTypeGeneratorRightRight.add(new FrequencyAndObject<>(1.0 - p, carRight));
261             gtuTypeGeneratorRightRight.add(new FrequencyAndObject<>(p, truckRight));
262         }
263         else
264         {
265             double p = (truckFraction - (1 - leftFraction)) / leftFraction;
266             gtuTypeGeneratorLeftLeft.add(new FrequencyAndObject<>(1.0 - p, carLeft));
267             gtuTypeGeneratorLeftLeft.add(new FrequencyAndObject<>(p, truckLeft));
268             gtuTypeGeneratorLeftRight.add(new FrequencyAndObject<>(1.0, truckLeft));
269 
270             gtuTypeGeneratorRightLeft.add(new FrequencyAndObject<>(1.0 - p, carRight));
271             gtuTypeGeneratorRightLeft.add(new FrequencyAndObject<>(p, truckRight));
272             gtuTypeGeneratorRightRight.add(new FrequencyAndObject<>(1.0, truckRight));
273         }
274 
275         TimeVector timeVector =
276                 DoubleVector.instantiate(new double[] {0, 360, 1560, 2160, 3960}, TimeUnit.BASE_SECOND, StorageType.DENSE);
277         double leftLeft = leftDemand.si * leftFraction;
278         FrequencyVector leftLeftDemandPattern = DoubleVector.instantiate(
279                 new double[] {leftLeft * 0.5, leftLeft * 0.5, leftLeft, leftLeft, 0.0}, FrequencyUnit.SI, StorageType.DENSE);
280         double leftRight = leftDemand.si * (1 - leftFraction);
281         FrequencyVector leftRightDemandPattern =
282                 DoubleVector.instantiate(new double[] {leftRight * 0.5, leftRight * 0.5, leftRight, leftRight, 0.0},
283                         FrequencyUnit.SI, StorageType.DENSE);
284         double rightLeft = rightDemand.si * leftFraction;
285         FrequencyVector rightLeftDemandPattern =
286                 DoubleVector.instantiate(new double[] {rightLeft * 0.5, rightLeft * 0.5, rightLeft, rightLeft, 0.0},
287                         FrequencyUnit.SI, StorageType.DENSE);
288         double rightRight = rightDemand.si * (1 - leftFraction);
289         FrequencyVector rightRightDemandPattern =
290                 DoubleVector.instantiate(new double[] {rightRight * 0.5, rightRight * 0.5, rightRight, rightRight, 0.0},
291                         FrequencyUnit.SI, StorageType.DENSE);
292         
293         HeadwayGeneratorDemand leftLeftHeadways = new HeadwayGeneratorDemand(timeVector, leftLeftDemandPattern, simulator);
294         HeadwayGeneratorDemand leftRightHeadways = new HeadwayGeneratorDemand(timeVector, leftRightDemandPattern, simulator);
295         HeadwayGeneratorDemand rightLeftHeadways = new HeadwayGeneratorDemand(timeVector, rightLeftDemandPattern, simulator);
296         HeadwayGeneratorDemand rightRightHeadways = new HeadwayGeneratorDemand(timeVector, rightRightDemandPattern, simulator);
297 
298         Speed genSpeed = new Speed(120.0, SpeedUnit.KM_PER_HOUR);
299         CrossSectionLink leftLink = (CrossSectionLink) network.getLink("LEFTINPRE");
300         CrossSectionLink rightLink = (CrossSectionLink) network.getLink("RIGHTINPRE");
301         makeGenerator(getLane(leftLink, "FORWARD1"), genSpeed, "LEFTLEFT", idGenerator, simulator, network,
302                 gtuTypeGeneratorLeftLeft, leftLeftHeadways, gtuColorer, roomChecker, bcFactory, tacticalFactory, simulationTime,
303                 streams.get("gtuClass"));
304         makeGenerator(getLane(leftLink, "FORWARD2"), genSpeed, "LEFTRIGHT", idGenerator, simulator, network,
305                 gtuTypeGeneratorLeftRight, leftRightHeadways, gtuColorer, roomChecker, bcFactory, tacticalFactory,
306                 simulationTime, streams.get("gtuClass"));
307         makeGenerator(getLane(rightLink, "FORWARD1"), genSpeed, "RIGHTLEFT", idGenerator, simulator, network,
308                 gtuTypeGeneratorRightLeft, rightLeftHeadways, gtuColorer, roomChecker, bcFactory, tacticalFactory,
309                 simulationTime, streams.get("gtuClass"));
310         makeGenerator(getLane(rightLink, "FORWARD2"), genSpeed, "RIGHTRIGHT", idGenerator, simulator, network,
311                 gtuTypeGeneratorRightRight, rightRightHeadways, gtuColorer, roomChecker, bcFactory, tacticalFactory,
312                 simulationTime, streams.get("gtuClass"));
313 
314     }
315 
316     
317 
318 
319 
320 
321 
322     private static Lane getLane(final CrossSectionLink link, final String id)
323     {
324         for (Lane lane : link.getLanes())
325         {
326             if (lane.getId().equals(id))
327             {
328                 return lane;
329             }
330         }
331         throw new RuntimeException("Could not find lane " + id + " on link " + link.getId());
332     }
333 
334     
335 
336 
337 
338 
339 
340 
341 
342 
343 
344 
345 
346 
347 
348 
349 
350 
351 
352 
353 
354     private static void makeGenerator(final Lane lane, final Speed generationSpeed, final String id,
355             final IdGenerator idGenerator, final OTSSimulatorInterface simulator, final OTSRoadNetwork network,
356             final Distribution<LaneBasedTemplateGTUType> distribution, final HeadwayGeneratorDemand headwayGenerator,
357             final GTUColorer gtuColorer, final RoomChecker roomChecker, final ParameterFactory bcFactory,
358             final LaneBasedTacticalPlannerFactory<?> tacticalFactory, final Time simulationTime, final StreamInterface stream)
359             throws SimRuntimeException, ProbabilityException, GTUException, ParameterException
360     {
361         Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>();
362         
363         initialLongitudinalPositions
364                 .add(new DirectedLanePosition(lane, new Length(10.0, LengthUnit.SI), GTUDirectionality.DIR_PLUS));
365         LaneBasedTemplateGTUTypeDistribution characteristicsGenerator = new LaneBasedTemplateGTUTypeDistribution(distribution);
366         new LaneBasedGTUGenerator(id, headwayGenerator, characteristicsGenerator,
367                 GeneratorPositions.create(initialLongitudinalPositions, stream), network, simulator, roomChecker, idGenerator);
368     }
369 
370     
371 
372 
373 
374 
375 
376 
377 
378 
379 
380 
381     private static class LMRSFactoryAHFE implements LaneBasedTacticalPlannerFactory<LMRS>
382     {
383 
384         
385         private final CarFollowingModelFactory<? extends CarFollowingModel> carFollowingModelFactory;
386 
387         
388         private final Parameters defaultCarFollowingParameters;
389 
390         
391         private final PerceptionFactory perceptionFactory;
392 
393         
394 
395 
396 
397 
398 
399 
400 
401         LMRSFactoryAHFE(final CarFollowingModelFactory<? extends CarFollowingModel> carFollowingModelFactory,
402                 final Parameters defaultCarFollowingParameters, final PerceptionFactory perceptionFactory) throws GTUException
403         {
404             this.carFollowingModelFactory = carFollowingModelFactory;
405             this.defaultCarFollowingParameters = defaultCarFollowingParameters;
406             this.perceptionFactory = perceptionFactory;
407         }
408 
409         
410         @Override
411         public final Parameters getParameters()
412         {
413             ParameterSet parameters = new ParameterSet();
414             parameters.setDefaultParameters(ParameterTypes.class);
415             parameters.setDefaultParameters(LmrsParameters.class);
416             this.defaultCarFollowingParameters.setAllIn(parameters);
417             return parameters;
418         }
419 
420         
421         @Override
422         public final LMRS create(final LaneBasedGTU gtu) throws GTUException
423         {
424             LMRS lmrs = new LMRS(this.carFollowingModelFactory.generateCarFollowingModel(), gtu,
425                     this.perceptionFactory.generatePerception(gtu), Synchronization.PASSIVE, Cooperation.PASSIVE,
426                     GapAcceptance.INFORMED, Tailgating.NONE);
427             lmrs.addMandatoryIncentive(new IncentiveRoute());
428             lmrs.addVoluntaryIncentive(new IncentiveSpeedWithCourtesy());
429             if (gtu.getGTUType().getId().equals("car"))
430             {
431                 lmrs.addVoluntaryIncentive(new IncentiveKeep());
432             }
433             else
434             {
435                 lmrs.addVoluntaryIncentive(new KeepRightTruck());
436             }
437             return lmrs;
438         }
439 
440         
441         @Override
442         public final String toString()
443         {
444             return "LMRSFactory [car-following=" + this.carFollowingModelFactory + "]";
445         }
446 
447     }
448 
449     
450 
451 
452 
453 
454 
455 
456 
457 
458 
459 
460 
461     private static class DelayedPerceptionFactory implements PerceptionFactory
462     {
463 
464         
465         private final Anticipation anticipation;
466 
467         
468 
469 
470 
471         DelayedPerceptionFactory(final Anticipation anticipation)
472         {
473             this.anticipation = anticipation;
474         }
475 
476         
477         @Override
478         public LanePerception generatePerception(final LaneBasedGTU gtu)
479         {
480             LanePerception perception = new CategoricalLanePerception(gtu);
481             perception.addPerceptionCategory(new DirectEgoPerception(perception));
482             
483             perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
484             
485             perception.addPerceptionCategory(new DelayedNeighborsPerception(perception, this.anticipation));
486             
487             perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
488             return perception;
489         }
490 
491         
492         @Override
493         public Parameters getParameters()
494         {
495             return new ParameterSet();
496         }
497 
498     }
499 
500     
501 
502 
503 
504 
505 
506 
507 
508 
509 
510 
511     private static class KeepRightTruck implements VoluntaryIncentive
512     {
513 
514         
515 
516 
517         KeepRightTruck()
518         {
519         }
520 
521         
522         @Override
523         public Desire determineDesire(final Parameters parameters, final LanePerception perception,
524                 final CarFollowingModel carFollowingModel, final Desire mandatoryDesire, final Desire voluntaryDesire)
525                 throws ParameterException, OperationalPlanException
526         {
527             if (perception.getLaneStructure().getRootRecord().getRight() != null
528                     && perception.getLaneStructure().getRootRecord().getRight().getRight() != null
529                     && perception.getPerceptionCategory(EgoPerception.class).getSpeed()
530                             .gt(parameters.getParameter(ParameterTypes.VCONG)))
531             {
532                 
533                 return new Desire(0, 1);
534             }
535             if (mandatoryDesire.getRight() < 0 || voluntaryDesire.getRight() < 0
536                     || !perception.getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT))
537             {
538                 
539                 return new Desire(0, 0);
540             }
541             
542             return new Desire(0, 1.0);
543         }
544 
545     }
546 
547     
548 
549 
550 
551 
552 
553 
554 
555 
556 
557 
558 
559     
560     private static class HeadwayGeneratorDemand implements Generator<Duration>
561     {
562 
563         
564         private final Interpolation interpolation;
565 
566         
567         private final TimeVector timeVector;
568 
569         
570         private final FrequencyVector demandVector;
571 
572         
573         private final SimulatorInterface.TimeDoubleUnit simulator;
574 
575         
576         private static final String HEADWAY_STREAM = "headwayGeneration";
577 
578         
579 
580 
581 
582 
583         HeadwayGeneratorDemand(final TimeVector timeVector, final FrequencyVector demandVector,
584                 final SimulatorInterface.TimeDoubleUnit simulator)
585         {
586             this(timeVector, demandVector, simulator, Interpolation.STEPWISE);
587         }
588 
589         
590 
591 
592 
593 
594 
595         HeadwayGeneratorDemand(final TimeVector timeVector, final FrequencyVector demandVector,
596                 final SimulatorInterface.TimeDoubleUnit simulator, final Interpolation interpolation)
597         {
598             Throw.whenNull(timeVector, "Time vector may not be null.");
599             Throw.whenNull(demandVector, "Demand vector may not be null.");
600             Throw.whenNull(simulator, "Simulator may not be null.");
601             Throw.whenNull(interpolation, "Interpolation may not be null.");
602             Throw.whenNull(simulator.getReplication().getStream(HEADWAY_STREAM),
603                     "Could not obtain random stream '" + HEADWAY_STREAM + "'.");
604             for (int i = 0; i < timeVector.size() - 1; i++)
605             {
606                 try
607                 {
608                     Throw.when(timeVector.get(i).ge(timeVector.get(i + 1)), IllegalArgumentException.class,
609                             "Time vector is not increasing.");
610                 }
611                 catch (ValueRuntimeException exception)
612                 {
613                     throw new RuntimeException(
614                             "Value out of range of time vector. Note that HeadwayGenerator does not create a safe copy.",
615                             exception);
616                 }
617             }
618             Throw.when(timeVector.size() != demandVector.size(), IllegalArgumentException.class,
619                     "Time and flow vector should be of the same size.");
620             Throw.when(timeVector.size() < 2, IllegalArgumentException.class,
621                     "Time and flow vector should be at least of size 2.");
622             this.timeVector = timeVector;
623             this.demandVector = demandVector;
624             this.simulator = simulator;
625             this.interpolation = interpolation;
626         }
627 
628         
629         @Override
630         public final Duration draw() throws ProbabilityException, ParameterException
631         {
632             Time time = this.simulator.getSimulatorTime();
633             try
634             {
635                 Throw.when(time.lt(this.timeVector.get(0)), IllegalArgumentException.class,
636                         "Cannot return a headway at time before first time in vector.");
637 
638                 
639                 int i = 0;
640                 while (this.timeVector.get(i + 1).lt(time) && i < this.timeVector.size() - 1)
641                 {
642                     i++;
643                 }
644                 try
645                 {
646                     return nextArrival(i, time.minus(this.timeVector.get(i)), 1.0).minus(time);
647                 }
648                 catch (RemoteException exception)
649                 {
650                     throw new RuntimeException("Could not obtain replication.", exception);
651                 }
652             }
653             catch (ValueRuntimeException exception)
654             {
655                 throw new RuntimeException(
656                         "Value out of range of time or demand vector. Note that HeadwayGenerator does not create safe copies.",
657                         exception);
658             }
659         }
660 
661         
662 
663 
664 
665 
666 
667 
668 
669 
670 
671         private Time nextArrival(final int i, final Duration start, final double fractionRemaining)
672                 throws ValueRuntimeException, RemoteException
673         {
674 
675             
676             if (i == this.timeVector.size() - 1)
677             {
678                 return new Time(Double.POSITIVE_INFINITY, TimeUnit.DEFAULT);
679             }
680 
681             
682             if (this.demandVector.get(i).equals(Frequency.ZERO))
683             {
684                 
685                 return nextArrival(i + 1, Duration.ZERO,
686                         this.simulator.getReplication().getStream(HEADWAY_STREAM).nextDouble());
687             }
688 
689             
690             Frequency demand;
691             if (this.interpolation.isStepWise())
692             {
693                 demand = this.demandVector.get(i);
694             }
695             else
696             {
697                 double f = start.si / (this.timeVector.get(i + 1).si - this.timeVector.get(i).si);
698                 demand = Frequency.interpolate(this.demandVector.get(i), this.demandVector.get(i + 1), f);
699             }
700             double t = -Math.log(this.simulator.getReplication().getStream(HEADWAY_STREAM).nextDouble()) / demand.si;
701 
702             
703             Time arrival = new Time(this.timeVector.get(i).si + start.si + t * fractionRemaining, TimeUnit.DEFAULT);
704 
705             
706             if (arrival.gt(this.timeVector.get(i + 1)))
707             {
708                 double inStep = this.timeVector.get(i + 1).si - (this.timeVector.get(i).si + start.si);
709                 return nextArrival(i + 1, Duration.ZERO, fractionRemaining - inStep / t);
710             }
711 
712             return arrival;
713 
714         }
715 
716         
717         @Override
718         public final String toString()
719         {
720             return "HeadwayGeneratorDemand [interpolation=" + this.interpolation + ", timeVector=" + this.timeVector
721                     + ", demandVector=" + this.demandVector + ", simulator=" + this.simulator + "]";
722         }
723 
724     }
725 
726 }