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 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 public final class AHFEUtil
113 {
114 
115     
116 
117 
118     private AHFEUtil()
119     {
120         
121     }
122 
123     
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
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         
182         
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         
190         
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         
196         
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         
244         
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         
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 
317 
318 
319 
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 
335 
336 
337 
338 
339 
340 
341 
342 
343 
344 
345 
346 
347 
348 
349 
350 
351 
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         
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 
371 
372 
373 
374 
375 
376 
377 
378 
379 
380     private static class LMRSFactoryAHFE implements LaneBasedTacticalPlannerFactory<LMRS>
381     {
382 
383         
384         private final CarFollowingModelFactory<? extends CarFollowingModel> carFollowingModelFactory;
385 
386         
387         private final Parameters defaultCarFollowingParameters;
388 
389         
390         private final PerceptionFactory perceptionFactory;
391 
392         
393 
394 
395 
396 
397 
398 
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         
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         
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         
440         @Override
441         public final String toString()
442         {
443             return "LMRSFactory [car-following=" + this.carFollowingModelFactory + "]";
444         }
445 
446     }
447 
448     
449 
450 
451 
452 
453 
454 
455 
456 
457 
458 
459 
460     private static class DelayedPerceptionFactory implements PerceptionFactory
461     {
462 
463         
464         private final Anticipation anticipation;
465 
466         
467 
468 
469 
470         DelayedPerceptionFactory(final Anticipation anticipation)
471         {
472             this.anticipation = anticipation;
473         }
474 
475         
476         @Override
477         public LanePerception generatePerception(final LaneBasedGTU gtu)
478         {
479             LanePerception perception = new CategoricalLanePerception(gtu);
480             perception.addPerceptionCategory(new DirectEgoPerception(perception));
481             
482             perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
483             
484             perception.addPerceptionCategory(new DelayedNeighborsPerception(perception, this.anticipation));
485             
486             perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
487             return perception;
488         }
489 
490         
491         @Override
492         public Parameters getParameters()
493         {
494             return new ParameterSet();
495         }
496 
497     }
498 
499     
500 
501 
502 
503 
504 
505 
506 
507 
508 
509 
510     private static class KeepRightTruck implements VoluntaryIncentive
511     {
512 
513         
514 
515 
516         KeepRightTruck()
517         {
518         }
519 
520         
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                 
532                 return new Desire(0, 1);
533             }
534             if (mandatoryDesire.getRight() < 0 || voluntaryDesire.getRight() < 0
535                     || !perception.getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT))
536             {
537                 
538                 return new Desire(0, 0);
539             }
540             
541             return new Desire(0, 1.0);
542         }
543 
544     }
545 
546     
547 
548 
549 
550 
551 
552 
553 
554 
555 
556 
557 
558     
559     private static class HeadwayGeneratorDemand implements Generator<Duration>
560     {
561 
562         
563         private final Interpolation interpolation;
564 
565         
566         private final TimeVector timeVector;
567 
568         
569         private final FrequencyVector demandVector;
570 
571         
572         private final SimulatorInterface.TimeDoubleUnit simulator;
573 
574         
575         private static final String HEADWAY_STREAM = "headwayGeneration";
576 
577         
578 
579 
580 
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 
590 
591 
592 
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         
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                 
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 
662 
663 
664 
665 
666 
667 
668 
669 
670         private Time nextArrival(final int i, final Duration start, final double fractionRemaining)
671                 throws ValueException, RemoteException
672         {
673 
674             
675             if (i == this.timeVector.size() - 1)
676             {
677                 return new Time(Double.POSITIVE_INFINITY, TimeUnit.BASE);
678             }
679 
680             
681             if (this.demandVector.get(i).equals(Frequency.ZERO))
682             {
683                 
684                 return nextArrival(i + 1, Duration.ZERO,
685                         this.simulator.getReplication().getStream(HEADWAY_STREAM).nextDouble());
686             }
687 
688             
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             
702             Time arrival = new Time(this.timeVector.get(i).si + start.si + t * fractionRemaining, TimeUnit.BASE);
703 
704             
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         
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 }