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