View Javadoc
1   package org.opentrafficsim.demo;
2   
3   import java.awt.Dimension;
4   import java.net.URL;
5   import java.rmi.RemoteException;
6   import java.util.ArrayList;
7   import java.util.LinkedHashMap;
8   import java.util.LinkedHashSet;
9   import java.util.List;
10  import java.util.Map;
11  import java.util.Random;
12  import java.util.Set;
13  
14  import javax.naming.NamingException;
15  
16  import org.djunits.unit.AccelerationUnit;
17  import org.djunits.unit.DurationUnit;
18  import org.djunits.unit.FrequencyUnit;
19  import org.djunits.unit.LengthUnit;
20  import org.djunits.unit.SpeedUnit;
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.djutils.io.URLResource;
28  import org.opentrafficsim.animation.GraphLaneUtil;
29  import org.opentrafficsim.animation.colorer.LmrsSwitchableColorer;
30  import org.opentrafficsim.animation.gtu.colorer.GtuColorer;
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.core.definitions.DefaultsNl;
35  import org.opentrafficsim.core.distributions.ConstantGenerator;
36  import org.opentrafficsim.core.distributions.Distribution;
37  import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
38  import org.opentrafficsim.core.distributions.Generator;
39  import org.opentrafficsim.core.distributions.ProbabilityException;
40  import org.opentrafficsim.core.dsol.AbstractOtsModel;
41  import org.opentrafficsim.core.dsol.OtsAnimator;
42  import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
43  import org.opentrafficsim.core.gtu.GtuException;
44  import org.opentrafficsim.core.gtu.GtuType;
45  import org.opentrafficsim.core.idgenerator.IdGenerator;
46  import org.opentrafficsim.core.network.Link;
47  import org.opentrafficsim.core.network.NetworkException;
48  import org.opentrafficsim.core.network.Node;
49  import org.opentrafficsim.core.network.route.ProbabilisticRouteGenerator;
50  import org.opentrafficsim.core.network.route.Route;
51  import org.opentrafficsim.core.parameters.ParameterFactory;
52  import org.opentrafficsim.core.parameters.ParameterFactoryByType;
53  import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
54  import org.opentrafficsim.demo.ShortMerge.ShortMergeModel;
55  import org.opentrafficsim.draw.OtsDrawingException;
56  import org.opentrafficsim.draw.graphs.GraphPath;
57  import org.opentrafficsim.draw.graphs.PlotScheduler;
58  import org.opentrafficsim.draw.graphs.TrajectoryPlot;
59  import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
60  import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator;
61  import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator.RoomChecker;
62  import org.opentrafficsim.road.gtu.generator.TtcRoomChecker;
63  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuTemplate;
64  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuTemplateDistribution;
65  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
66  import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIdm;
67  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
68  import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlus;
69  import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlusFactory;
70  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationConflicts;
71  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationIncentive;
72  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationSpeedLimitTransition;
73  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationTrafficLights;
74  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLmrsPerceptionFactory;
75  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveCourtesy;
76  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveKeep;
77  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveRoute;
78  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSocioSpeed;
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.lmrs.LmrsFactory;
82  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
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.MandatoryIncentive;
86  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
87  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
88  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
89  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
90  import org.opentrafficsim.road.network.RoadNetwork;
91  import org.opentrafficsim.road.network.factory.xml.parser.XmlParser;
92  import org.opentrafficsim.road.network.lane.CrossSectionLink;
93  import org.opentrafficsim.road.network.lane.Lane;
94  import org.opentrafficsim.road.network.lane.LanePosition;
95  import org.opentrafficsim.road.network.lane.object.SpeedSign;
96  import org.opentrafficsim.road.network.sampling.LaneDataRoad;
97  import org.opentrafficsim.road.network.sampling.RoadSampler;
98  import org.opentrafficsim.swing.graphs.OtsPlotScheduler;
99  import org.opentrafficsim.swing.graphs.SwingPlot;
100 import org.opentrafficsim.swing.graphs.SwingTrajectoryPlot;
101 import org.opentrafficsim.swing.gui.AnimationToggles;
102 import org.opentrafficsim.swing.gui.OtsAnimationPanel;
103 import org.opentrafficsim.swing.gui.OtsSimulationApplication;
104 
105 import nl.tudelft.simulation.dsol.SimRuntimeException;
106 import nl.tudelft.simulation.jstats.distributions.DistNormal;
107 import nl.tudelft.simulation.jstats.distributions.DistUniform;
108 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
109 import nl.tudelft.simulation.jstats.streams.StreamInterface;
110 import nl.tudelft.simulation.language.DsolException;
111 
112 /**
113  * <p>
114  * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
115  * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
116  * </p>
117  * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
118  * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
119  * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
120  */
121 public class ShortMerge extends OtsSimulationApplication<ShortMergeModel>
122 {
123     /** */
124     private static final long serialVersionUID = 20170407L;
125 
126     /** Network. */
127     static final String NETWORK = "shortMerge";
128 
129     /** Truck fraction. */
130     static final double TRUCK_FRACTION = 0.15;
131 
132     /** Left traffic fraction. */
133     static final double LEFT_FRACTION = 0.3;
134 
135     /** Main demand per lane. */
136     static final Frequency MAIN_DEMAND = new Frequency(1000, FrequencyUnit.PER_HOUR);
137 
138     /** Ramp demand. */
139     static final Frequency RAMP_DEMAND = new Frequency(500, FrequencyUnit.PER_HOUR);
140 
141     /** Synchronization. */
142     static final Synchronization SYNCHRONIZATION = Synchronization.ALIGN_GAP;
143 
144     /** Cooperation. */
145     static final Cooperation COOPERATION = Cooperation.PASSIVE_MOVING;
146 
147     /** Use additional incentives. */
148     static final boolean ADDITIONAL_INCENTIVES = true;
149 
150     /** Simulation time. */
151     public static final Time SIMTIME = Time.instantiateSI(3600);
152 
153     /**
154      * Create a ShortMerge Swing application.
155      * @param title String; the title of the Frame
156      * @param panel OtsAnimationPanel; the tabbed panel to display
157      * @param model ShortMergeModel; the model
158      * @throws OtsDrawingException on animation error
159      */
160     public ShortMerge(final String title, final OtsAnimationPanel panel, final ShortMergeModel model) throws OtsDrawingException
161     {
162         super(model, panel);
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     protected void setAnimationToggles()
168     {
169         AnimationToggles.setTextAnimationTogglesFull(getAnimationPanel());
170         getAnimationPanel().getAnimationPanel().toggleClass(Link.class);
171         getAnimationPanel().getAnimationPanel().toggleClass(Node.class);
172         getAnimationPanel().getAnimationPanel().showClass(SpeedSign.class);
173     }
174 
175     /** {@inheritDoc} */
176     @Override
177     protected void addTabs()
178     {
179         GraphPath<LaneDataRoad> path;
180         try
181         {
182             Lane start = ((CrossSectionLink) getModel().getNetwork().getLink("AB")).getLanes().get(1);
183             path = GraphLaneUtil.createPath("Right lane", start);
184         }  
185         catch (NetworkException exception)
186         {
187             throw new RuntimeException("Could not create a path as a lane has no set speed limit.", exception);
188         }
189         RoadSampler sampler = new RoadSampler(getModel().getNetwork());
190         GraphPath.initRecording(sampler, path);
191         PlotScheduler scheduler = new OtsPlotScheduler(getModel().getSimulator());
192         Duration updateInterval = Duration.instantiateSI(10.0);
193         SwingPlot plot = new SwingTrajectoryPlot(
194                 new TrajectoryPlot("Trajectory right lane", updateInterval, scheduler, sampler.getSamplerData(), path));
195         getAnimationPanel().getTabbedPane().addTab(getAnimationPanel().getTabbedPane().getTabCount(), "Trajectories",
196                 plot.getContentPane());
197     }
198 
199     /**
200      * Main program.
201      * @param args String[]; the command line arguments (not used)
202      */
203     public static void main(final String[] args)
204     {
205         demo(true);
206     }
207 
208     /**
209      * Start the demo.
210      * @param exitOnClose boolean; when running stand-alone: true; when running as part of a demo: false
211      */
212     public static void demo(final boolean exitOnClose)
213     {
214         try
215         {
216             OtsAnimator simulator = new OtsAnimator("ShortMerge");
217             final ShortMergeModel otsModel = new ShortMergeModel(simulator);
218             simulator.initialize(Time.ZERO, Duration.ZERO, Duration.instantiateSI(3600.0), otsModel);
219             OtsAnimationPanel animationPanel = new OtsAnimationPanel(otsModel.getNetwork().getExtent(), new Dimension(800, 600),
220                     simulator, otsModel, new LmrsSwitchableColorer(DefaultsNl.GTU_TYPE_COLORS.toMap()), otsModel.getNetwork());
221             ShortMerge app = new ShortMerge("ShortMerge", animationPanel, otsModel);
222             app.setExitOnClose(exitOnClose);
223             animationPanel.enableSimulationControlButtons();
224         }
225         catch (SimRuntimeException | NamingException | RemoteException | OtsDrawingException | IndexOutOfBoundsException
226                 | DsolException exception)
227         {
228             exception.printStackTrace();
229         }
230     }
231 
232     /**
233      * <p>
234      * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
235      * <br>
236      * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
237      * </p>
238      * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
239      * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
240      * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
241      */
242     public static class ShortMergeModel extends AbstractOtsModel
243     {
244         /** */
245         private static final long serialVersionUID = 20170407L;
246 
247         /** The network. */
248         private RoadNetwork network;
249 
250         /**
251          * @param simulator OtsSimulatorInterface; the simulator
252          */
253         public ShortMergeModel(final OtsSimulatorInterface simulator)
254         {
255             super(simulator);
256         }
257 
258         /**
259          * @param network RoadNetwork; set network.
260          */
261         public void setNetwork(final RoadNetwork network)
262         {
263             this.network = network;
264         }
265 
266         /** {@inheritDoc} */
267         @Override
268         public void constructModel() throws SimRuntimeException
269         {
270             try
271             {
272                 URL xmlURL = URLResource.getResource("/resources/lmrs/" + NETWORK + ".xml");
273                 this.network = new RoadNetwork("ShortMerge", getSimulator());
274                 new XmlParser(this.network).setUrl(xmlURL).build();
275                 addGenerator();
276 
277             }
278             catch (Exception exception)
279             {
280                 exception.printStackTrace();
281             }
282         }
283 
284         /** {@inheritDoc} */
285         @Override
286         public RoadNetwork getNetwork()
287         {
288             return this.network;
289         }
290 
291         /**
292          * Create generators.
293          * @throws ParameterException on parameter exception
294          * @throws GtuException on GTU exception
295          * @throws NetworkException if not does not exist
296          * @throws ProbabilityException negative probability
297          * @throws SimRuntimeException in case of sim run time exception
298          * @throws RemoteException if no simulator
299          */
300         private void addGenerator() throws ParameterException, GtuException, NetworkException, ProbabilityException,
301                 SimRuntimeException, RemoteException
302         {
303 
304             Random seedGenerator = new Random(1L);
305             Map<String, StreamInterface> streams = new LinkedHashMap<>();
306             StreamInterface stream = new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1);
307             streams.put("headwayGeneration", stream);
308             streams.put("gtuClass", new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1));
309             getStreamInformation().addStream("headwayGeneration", stream);
310             getStreamInformation().addStream("gtuClass", streams.get("gtuClass"));
311 
312             TtcRoomChecker roomChecker = new TtcRoomChecker(new Duration(10.0, DurationUnit.SI));
313             IdGenerator idGenerator = new IdGenerator("");
314 
315             CarFollowingModelFactory<IdmPlus> idmPlusFactory = new IdmPlusFactory(streams.get("gtuClass"));
316             ParameterSet params = new ParameterSet();
317             params.setDefaultParameter(AbstractIdm.DELTA);
318 
319             Set<MandatoryIncentive> mandatoryIncentives = new LinkedHashSet<>();
320             Set<VoluntaryIncentive> voluntaryIncentives = new LinkedHashSet<>();
321             Set<AccelerationIncentive> accelerationIncentives = new LinkedHashSet<>();
322             mandatoryIncentives.add(new IncentiveRoute());
323             if (ADDITIONAL_INCENTIVES)
324             {
325                 // mandatoryIncentives.add(new IncentiveGetInLane());
326             }
327             voluntaryIncentives.add(new IncentiveSpeedWithCourtesy());
328             voluntaryIncentives.add(new IncentiveKeep());
329             if (ADDITIONAL_INCENTIVES)
330             {
331                 voluntaryIncentives.add(new IncentiveCourtesy());
332                 voluntaryIncentives.add(new IncentiveSocioSpeed());
333             }
334             accelerationIncentives.add(new AccelerationSpeedLimitTransition());
335             accelerationIncentives.add(new AccelerationTrafficLights());
336             accelerationIncentives.add(new AccelerationConflicts());
337             LaneBasedTacticalPlannerFactory<Lmrs> tacticalFactory = new LmrsFactory(idmPlusFactory,
338                     new DefaultLmrsPerceptionFactory(), SYNCHRONIZATION, COOPERATION, GapAcceptance.INFORMED, Tailgating.NONE,
339                     mandatoryIncentives, voluntaryIncentives, accelerationIncentives);
340 
341             GtuType car = DefaultsNl.CAR;
342             GtuType truck = DefaultsNl.TRUCK;
343             Route routeAE = this.network.getShortestRouteBetween(car, this.network.getNode("A"), this.network.getNode("E"));
344             Route routeAG = !NETWORK.equals("shortWeave") ? null
345                     : this.network.getShortestRouteBetween(car, this.network.getNode("A"), this.network.getNode("G"));
346             Route routeFE = this.network.getShortestRouteBetween(car, this.network.getNode("F"), this.network.getNode("E"));
347             Route routeFG = !NETWORK.equals("shortWeave") ? null
348                     : this.network.getShortestRouteBetween(car, this.network.getNode("F"), this.network.getNode("G"));
349 
350             double leftFraction = NETWORK.equals("shortWeave") ? LEFT_FRACTION : 0.0;
351             List<FrequencyAndObject<Route>> routesA = new ArrayList<>();
352             routesA.add(new FrequencyAndObject<>(1.0 - leftFraction, routeAE));
353             routesA.add(new FrequencyAndObject<>(leftFraction, routeAG));
354             List<FrequencyAndObject<Route>> routesF = new ArrayList<>();
355             routesF.add(new FrequencyAndObject<>(1.0 - leftFraction, routeFE));
356             routesF.add(new FrequencyAndObject<>(leftFraction, routeFG));
357             Generator<Route> routeGeneratorA = new ProbabilisticRouteGenerator(routesA, stream);
358             Generator<Route> routeGeneratorF = new ProbabilisticRouteGenerator(routesF, stream);
359 
360             Speed speedA = new Speed(120.0, SpeedUnit.KM_PER_HOUR);
361             Speed speedF = new Speed(20.0, SpeedUnit.KM_PER_HOUR);
362 
363             CrossSectionLink linkA = (CrossSectionLink) this.network.getLink("AB");
364             CrossSectionLink linkF = (CrossSectionLink) this.network.getLink("FF2");
365 
366             ParameterFactoryByType bcFactory = new ParameterFactoryByType();
367             bcFactory.addParameter(car, ParameterTypes.FSPEED, new DistNormal(stream, 123.7 / 120, 12.0 / 120));
368             bcFactory.addParameter(car, LmrsParameters.SOCIO, new DistNormal(stream, 0.5, 0.1));
369             bcFactory.addParameter(truck, ParameterTypes.A, new Acceleration(0.8, AccelerationUnit.SI));
370             bcFactory.addParameter(truck, LmrsParameters.SOCIO, new DistNormal(stream, 0.5, 0.1));
371             bcFactory.addParameter(Tailgating.RHO, Tailgating.RHO.getDefaultValue());
372 
373             Generator<Duration> headwaysA1 = new HeadwayGenerator(getSimulator(), MAIN_DEMAND);
374             Generator<Duration> headwaysA2 = new HeadwayGenerator(getSimulator(), MAIN_DEMAND);
375             Generator<Duration> headwaysA3 = new HeadwayGenerator(getSimulator(), MAIN_DEMAND);
376             Generator<Duration> headwaysF = new HeadwayGenerator(getSimulator(), RAMP_DEMAND);
377 
378             // speed generators
379             ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedCar =
380                     new ContinuousDistDoubleScalar.Rel<>(new DistUniform(stream, 160, 200), SpeedUnit.KM_PER_HOUR);
381             ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedTruck =
382                     new ContinuousDistDoubleScalar.Rel<>(new DistUniform(stream, 80, 95), SpeedUnit.KM_PER_HOUR);
383             // strategical planner factory
384             LaneBasedStrategicalRoutePlannerFactory strategicalFactory =
385                     new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory, bcFactory);
386             // vehicle templates, with routes
387             LaneBasedGtuTemplate carA = new LaneBasedGtuTemplate(car, new ConstantGenerator<>(Length.instantiateSI(4.0)),
388                     new ConstantGenerator<>(Length.instantiateSI(2.0)), speedCar, strategicalFactory, routeGeneratorA);
389             LaneBasedGtuTemplate carF = new LaneBasedGtuTemplate(car, new ConstantGenerator<>(Length.instantiateSI(4.0)),
390                     new ConstantGenerator<>(Length.instantiateSI(2.0)), speedCar, strategicalFactory, routeGeneratorF);
391             LaneBasedGtuTemplate truckA = new LaneBasedGtuTemplate(truck, new ConstantGenerator<>(Length.instantiateSI(15.0)),
392                     new ConstantGenerator<>(Length.instantiateSI(2.5)), speedTruck, strategicalFactory, routeGeneratorA);
393             LaneBasedGtuTemplate truckF = new LaneBasedGtuTemplate(truck, new ConstantGenerator<>(Length.instantiateSI(15.0)),
394                     new ConstantGenerator<>(Length.instantiateSI(2.5)), speedTruck, strategicalFactory, routeGeneratorF);
395             //
396             Distribution<LaneBasedGtuTemplate> gtuTypeAllCarA = new Distribution<>(streams.get("gtuClass"));
397             gtuTypeAllCarA.add(new FrequencyAndObject<>(1.0, carA));
398 
399             Distribution<LaneBasedGtuTemplate> gtuType1LaneF = new Distribution<>(streams.get("gtuClass"));
400             gtuType1LaneF.add(new FrequencyAndObject<>(1.0 - 2 * TRUCK_FRACTION, carF));
401             gtuType1LaneF.add(new FrequencyAndObject<>(2 * TRUCK_FRACTION, truckF));
402 
403             Distribution<LaneBasedGtuTemplate> gtuType2ndLaneA = new Distribution<>(streams.get("gtuClass"));
404             gtuType2ndLaneA.add(new FrequencyAndObject<>(1.0 - 2 * TRUCK_FRACTION, carA));
405             gtuType2ndLaneA.add(new FrequencyAndObject<>(2 * TRUCK_FRACTION, truckA));
406 
407             Distribution<LaneBasedGtuTemplate> gtuType3rdLaneA = new Distribution<>(streams.get("gtuClass"));
408             gtuType3rdLaneA.add(new FrequencyAndObject<>(1.0 - 3 * TRUCK_FRACTION, carA));
409             gtuType3rdLaneA.add(new FrequencyAndObject<>(3 * TRUCK_FRACTION, truckA));
410 
411             GtuColorer colorer = new LmrsSwitchableColorer(DefaultsNl.GTU_TYPE_COLORS.toMap());
412             makeGenerator(getLane(linkA, "FORWARD1"), speedA, "gen1", idGenerator, gtuTypeAllCarA, headwaysA1, colorer,
413                     roomChecker, bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
414             if (NETWORK.equals("shortWeave"))
415             {
416                 makeGenerator(getLane(linkA, "FORWARD2"), speedA, "gen2", idGenerator, gtuTypeAllCarA, headwaysA2, colorer,
417                         roomChecker, bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
418                 makeGenerator(getLane(linkA, "FORWARD3"), speedA, "gen3", idGenerator, gtuType3rdLaneA, headwaysA3, colorer,
419                         roomChecker, bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
420             }
421             else
422             {
423                 makeGenerator(getLane(linkA, "FORWARD2"), speedA, "gen2", idGenerator, gtuType2ndLaneA, headwaysA2, colorer,
424                         roomChecker, bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
425             }
426             makeGenerator(getLane(linkF, "FORWARD1"), speedF, "gen4", idGenerator, gtuType1LaneF, headwaysF, colorer,
427                     roomChecker, bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
428 
429             new SpeedSign("sign1", getLane(linkA, "FORWARD1"), Length.instantiateSI(10), this.getSimulator(),
430                     new Speed(130.0, SpeedUnit.KM_PER_HOUR), DefaultsNl.VEHICLE, Duration.ZERO,
431                     new Duration(24, DurationUnit.HOUR));
432 
433         }
434 
435         /**
436          * Get lane from link by id.
437          * @param link CrossSectionLink; link
438          * @param id String; id
439          * @return lane
440          */
441         private Lane getLane(final CrossSectionLink link, final String id)
442         {
443             return (Lane) link.getCrossSectionElement(id);
444         }
445 
446         /**
447          * @param lane Lane; the reference lane for this generator
448          * @param generationSpeed Speed; the speed of the GTU
449          * @param id String; the id of the generator itself
450          * @param idGenerator IdGenerator; the generator for the ID
451          * @param distribution Distribution&lt;LaneBasedTemplateGTUType&gt;; the type generator for the GTU
452          * @param headwayGenerator Generator&lt;Duration&gt;; the headway generator for the GTU
453          * @param gtuColorer GtuColorer; the GTU colorer for animation
454          * @param roomChecker RoomChecker; the checker to see if there is room for the GTU
455          * @param bcFactory ParameterFactory; the factory to generate parameters for the GTU
456          * @param tacticalFactory LaneBasedTacticalPlannerFactory&lt;?&gt;; the generator for the tactical planner
457          * @param simulationTime Time; simulation time
458          * @param stream StreamInterface; random numbers stream
459          * @throws SimRuntimeException in case of scheduling problems
460          * @throws ProbabilityException in case of an illegal probability distribution
461          * @throws GtuException in case the GTU is inconsistent
462          * @throws ParameterException in case a parameter for the perception is missing
463          * @throws NetworkException if the object could not be added to the network
464          */
465         private void makeGenerator(final Lane lane, final Speed generationSpeed, final String id, final IdGenerator idGenerator,
466                 final Distribution<LaneBasedGtuTemplate> distribution, final Generator<Duration> headwayGenerator,
467                 final GtuColorer gtuColorer, final RoomChecker roomChecker, final ParameterFactory bcFactory,
468                 final LaneBasedTacticalPlannerFactory<?> tacticalFactory, final Time simulationTime,
469                 final StreamInterface stream)
470                 throws SimRuntimeException, ProbabilityException, GtuException, ParameterException, NetworkException
471         {
472 
473             Set<LanePosition> initialLongitudinalPositions = new LinkedHashSet<>();
474             // TODO DIR_MINUS
475             initialLongitudinalPositions.add(new LanePosition(lane, new Length(5.0, LengthUnit.SI)));
476             LaneBasedGtuTemplateDistribution characteristicsGenerator = new LaneBasedGtuTemplateDistribution(distribution);
477             new LaneBasedGtuGenerator(id, headwayGenerator, characteristicsGenerator,
478                     GeneratorPositions.create(initialLongitudinalPositions, stream), this.network, getSimulator(), roomChecker,
479                     idGenerator);
480         }
481 
482     }
483 
484     /**
485      * <p>
486      * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
487      * <br>
488      * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
489      * </p>
490      * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
491      * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
492      * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
493      */
494     private static class HeadwayGenerator implements Generator<Duration>
495     {
496         /** the simulator. */
497         private final OtsSimulatorInterface simulator;
498 
499         /** Demand level. */
500         private final Frequency demand;
501 
502         /**
503          * @param simulator OtsSimulatorInterface; the simulator
504          * @param demand Frequency; demand
505          */
506         HeadwayGenerator(final OtsSimulatorInterface simulator, final Frequency demand)
507         {
508             this.simulator = simulator;
509             this.demand = demand;
510         }
511 
512         /** {@inheritDoc} */
513         @Override
514         public Duration draw() throws ProbabilityException, ParameterException
515         {
516             return new Duration(
517                     -Math.log(this.simulator.getModel().getStream("headwayGeneration").nextDouble()) / this.demand.si,
518                     DurationUnit.SI);
519         }
520 
521     }
522 
523 }