View Javadoc
1   package org.opentrafficsim.demo;
2   
3   import java.rmi.RemoteException;
4   import java.util.ArrayList;
5   import java.util.Collections;
6   import java.util.LinkedHashMap;
7   import java.util.LinkedHashSet;
8   import java.util.List;
9   import java.util.Map;
10  import java.util.Optional;
11  import java.util.Random;
12  import java.util.Set;
13  import java.util.function.Supplier;
14  
15  import org.djunits.unit.AccelerationUnit;
16  import org.djunits.unit.DurationUnit;
17  import org.djunits.unit.FrequencyUnit;
18  import org.djunits.unit.LengthUnit;
19  import org.djunits.unit.SpeedUnit;
20  import org.djunits.value.vdouble.scalar.Acceleration;
21  import org.djunits.value.vdouble.scalar.Duration;
22  import org.djunits.value.vdouble.scalar.Frequency;
23  import org.djunits.value.vdouble.scalar.Length;
24  import org.djunits.value.vdouble.scalar.Speed;
25  import org.djunits.value.vdouble.scalar.Time;
26  import org.opentrafficsim.animation.colorer.Colorer;
27  import org.opentrafficsim.animation.colorer.trajectory.SynchronizationTrajectoryColorer;
28  import org.opentrafficsim.animation.data.gtu.IncentiveGtuColorer;
29  import org.opentrafficsim.animation.data.gtu.SynchronizationGtuColorer;
30  import org.opentrafficsim.animation.data.util.GraphLaneUtil;
31  import org.opentrafficsim.animation.graphs.GraphPath;
32  import org.opentrafficsim.animation.graphs.PlotScheduler;
33  import org.opentrafficsim.animation.graphs.TrajectoryPlot;
34  import org.opentrafficsim.base.OtsRuntimeException;
35  import org.opentrafficsim.base.parameters.ParameterException;
36  import org.opentrafficsim.base.parameters.ParameterTypes;
37  import org.opentrafficsim.core.definitions.DefaultsNl;
38  import org.opentrafficsim.core.distributions.ConstantSupplier;
39  import org.opentrafficsim.core.distributions.FrequencyAndObject;
40  import org.opentrafficsim.core.distributions.ObjectDistribution;
41  import org.opentrafficsim.core.dsol.OtsAnimator;
42  import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
43  import org.opentrafficsim.core.gtu.Gtu;
44  import org.opentrafficsim.core.gtu.GtuType;
45  import org.opentrafficsim.core.idgenerator.IdSupplier;
46  import org.opentrafficsim.core.network.Network;
47  import org.opentrafficsim.core.network.NetworkException;
48  import org.opentrafficsim.core.network.route.ProbabilisticRouteGenerator;
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.demo.ShortMerge.ShortMergeModel;
54  import org.opentrafficsim.kpi.sampling.data.ExtendedDataString;
55  import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
56  import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator;
57  import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator.RoomChecker;
58  import org.opentrafficsim.road.gtu.generator.TtcRoomChecker;
59  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuTemplate;
60  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuTemplateDistribution;
61  import org.opentrafficsim.road.gtu.generator.headway.HeadwayGenerator;
62  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
63  import org.opentrafficsim.road.gtu.tactical.LaneBasedTacticalPlannerFactory;
64  import org.opentrafficsim.road.gtu.tactical.Synchronizable;
65  import org.opentrafficsim.road.gtu.tactical.lmrs.IncentiveCourtesy;
66  import org.opentrafficsim.road.gtu.tactical.lmrs.Lmrs;
67  import org.opentrafficsim.road.gtu.tactical.lmrs.LmrsFactory;
68  import org.opentrafficsim.road.gtu.tactical.lmrs.LmrsFactory.Setting;
69  import org.opentrafficsim.road.gtu.tactical.util.lmrs.Cooperation;
70  import org.opentrafficsim.road.gtu.tactical.util.lmrs.LmrsParameters;
71  import org.opentrafficsim.road.gtu.tactical.util.lmrs.Synchronization;
72  import org.opentrafficsim.road.gtu.tactical.util.lmrs.Tailgating;
73  import org.opentrafficsim.road.network.CrossSectionLink;
74  import org.opentrafficsim.road.network.Lane;
75  import org.opentrafficsim.road.network.LanePosition;
76  import org.opentrafficsim.road.network.RoadNetwork;
77  import org.opentrafficsim.road.network.factory.xml.OtsXmlModel;
78  import org.opentrafficsim.road.network.sampling.GtuDataRoad;
79  import org.opentrafficsim.road.network.sampling.LaneDataRoad;
80  import org.opentrafficsim.road.network.sampling.RoadSampler;
81  import org.opentrafficsim.swing.graphs.OtsPlotScheduler;
82  import org.opentrafficsim.swing.graphs.SwingTrajectoryPlot;
83  import org.opentrafficsim.swing.gui.AnimationToggles;
84  import org.opentrafficsim.swing.gui.OtsSimulationApplication;
85  import org.opentrafficsim.swing.gui.OtsSimulationPanel;
86  import org.opentrafficsim.swing.gui.OtsSimulationPanelDecorator;
87  
88  import nl.tudelft.simulation.dsol.SimRuntimeException;
89  import nl.tudelft.simulation.jstats.distributions.DistNormal;
90  import nl.tudelft.simulation.jstats.distributions.DistUniform;
91  import nl.tudelft.simulation.jstats.streams.MersenneTwister;
92  import nl.tudelft.simulation.jstats.streams.StreamInterface;
93  import nl.tudelft.simulation.language.DsolException;
94  
95  /**
96   * <p>
97   * Copyright (c) 2013-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
98   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
99   * </p>
100  * @author Alexander Verbraeck
101  * @author Peter Knoppers
102  * @author Wouter Schakel
103  */
104 public class ShortMerge extends OtsSimulationApplication<ShortMergeModel>
105 {
106     /** Serialization version UID. */
107     private static final long serialVersionUID = 20170407L;
108 
109     /** Network. */
110     static final String NETWORK = "shortMerge";
111 
112     /** Truck fraction. */
113     static final double TRUCK_FRACTION = 0.15;
114 
115     /** Left traffic fraction. */
116     static final double LEFT_FRACTION = 0.3;
117 
118     /** Main demand per lane. */
119     static final Frequency MAIN_DEMAND = new Frequency(1000, FrequencyUnit.PER_HOUR);
120 
121     /** Ramp demand. */
122     static final Frequency RAMP_DEMAND = new Frequency(500, FrequencyUnit.PER_HOUR);
123 
124     /** Synchronization. */
125     static final Synchronization SYNCHRONIZATION = Synchronization.ALIGN_GAP;
126 
127     /** Cooperation. */
128     static final Cooperation COOPERATION = Cooperation.PASSIVE_MOVING;
129 
130     /** Use additional incentives. */
131     static final boolean ADDITIONAL_INCENTIVES = true;
132 
133     /** Simulation time. */
134     public static final Time SIMTIME = Time.ofSI(3600);
135 
136     /**
137      * Create a ShortMerge Swing application.
138      * @param title the title of the Frame
139      * @param panel the tabbed panel to display
140      * @param model the model
141      */
142     public ShortMerge(final String title, final OtsSimulationPanel panel, final ShortMergeModel model)
143     {
144         super(model, panel);
145     }
146 
147     /**
148      * Adds tabs. The default does nothing.
149      * @param animationPanel animation panel
150      * @param network network
151      */
152     private static void addTabs(final OtsSimulationPanel animationPanel, final Network network)
153     {
154         GraphPath<LaneDataRoad> path;
155         try
156         {
157             Lane start = ((CrossSectionLink) network.getLink("AB").get()).getLanes().get(1);
158             path = GraphLaneUtil.createPath("Right lane", start);
159         }
160         catch (NetworkException exception)
161         {
162             throw new OtsRuntimeException("Could not create a path as a lane has no set speed limit.", exception);
163         }
164         ExtendedDataSync<GtuDataRoad> syncData = new ExtendedDataSync<GtuDataRoad>();
165         RoadSampler sampler = new RoadSampler(Set.of(syncData), Collections.emptySet(), (RoadNetwork) network);
166         GraphPath.initRecording(sampler, path);
167         PlotScheduler scheduler = new OtsPlotScheduler(network.getSimulator());
168         Duration updateInterval = Duration.ofSI(10.0);
169         SwingTrajectoryPlot plot = new SwingTrajectoryPlot(
170                 new TrajectoryPlot("Trajectory right lane", updateInterval, scheduler, sampler.getSamplerData(), path), true);
171         plot.addColorer(new SynchronizationTrajectoryColorer(syncData), false);
172         animationPanel.getTabbedPane().addTab(animationPanel.getTabbedPane().getTabCount(), "trajectories",
173                 plot.getContentPane());
174     }
175 
176     /**
177      * Main program.
178      * @param args the command line arguments (not used)
179      */
180     public static void main(final String[] args)
181     {
182         demo(true);
183     }
184 
185     /**
186      * Start the demo.
187      * @param exitOnClose when running stand-alone: true; when running as part of a demo: false
188      */
189     public static void demo(final boolean exitOnClose)
190     {
191         try
192         {
193             OtsAnimator simulator = new OtsAnimator("ShortMerge");
194             final ShortMergeModel otsModel = new ShortMergeModel(simulator);
195             OtsSimulationPanel simulationPanel = new OtsSimulationPanel(otsModel.getNetwork(), new OtsSimulationPanelDecorator()
196             {
197                 @Override
198                 public void setAnimationToggles(final OtsSimulationPanel simulationPanel)
199                 {
200                     AnimationToggles.setIconAnimationTogglesStandard(simulationPanel);
201                 }
202 
203                 @Override
204                 public void addTabs(final OtsSimulationPanel simulationPanel, final Network network)
205                 {
206                     ShortMerge.addTabs(simulationPanel, network);
207                 }
208 
209                 @Override
210                 public List<Colorer<? super Gtu>> getGtuColorers()
211                 {
212                     List<Colorer<? super Gtu>> colorers = new ArrayList<>(DEFAULT_GTU_COLORERS);
213                     colorers.add(new SynchronizationGtuColorer());
214                     colorers.add(new IncentiveGtuColorer(IncentiveCourtesy.class, "Courtesy incentive"));
215                     return colorers;
216                 }
217             });
218             ShortMerge app = new ShortMerge("ShortMerge", simulationPanel, otsModel);
219             app.setExitOnClose(exitOnClose);
220             simulationPanel.enableSimulationControlButtons();
221         }
222         catch (SimRuntimeException | RemoteException | IndexOutOfBoundsException | DsolException exception)
223         {
224             exception.printStackTrace();
225         }
226     }
227 
228     /**
229      * Short merge model.
230      */
231     public static class ShortMergeModel extends OtsXmlModel
232     {
233         /**
234          * Constructor.
235          * @param simulator the simulator
236          */
237         public ShortMergeModel(final OtsSimulatorInterface simulator)
238         {
239             super(simulator, "/resources/lmrs/" + NETWORK + ".xml");
240         }
241 
242         @Override
243         public void constructModel() throws SimRuntimeException
244         {
245             super.constructModel();
246             try
247             {
248                 addGenerator();
249             }
250             catch (ParameterException | NetworkException | SimRuntimeException exception)
251             {
252                 throw new OtsRuntimeException("Unable to create generator.");
253             }
254         }
255 
256         /**
257          * Create generators.
258          * @throws ParameterException on parameter exception
259          * @throws NetworkException if not does not exist
260          * @throws SimRuntimeException in case of sim run time exception
261          */
262         private void addGenerator() throws ParameterException, NetworkException, SimRuntimeException
263         {
264 
265             Random seedGenerator = new Random(1L);
266             Map<String, StreamInterface> streams = new LinkedHashMap<>();
267             StreamInterface stream = new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1);
268             streams.put("headwayGeneration", stream);
269             streams.put("gtuClass", new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1));
270             getStreamInformation().addStream("headwayGeneration", stream);
271             getStreamInformation().addStream("gtuClass", streams.get("gtuClass"));
272 
273             TtcRoomChecker roomChecker = new TtcRoomChecker(new Duration(10.0, DurationUnit.SI));
274             IdSupplier idGenerator = new IdSupplier("");
275 
276             LmrsFactory<Lmrs> tacticalFactory = new LmrsFactory<Lmrs>(Lmrs::new).setStream(stream)
277                     .set(Setting.SYNCHRONIZATION, SYNCHRONIZATION).set(Setting.COOPERATION, COOPERATION);
278             if (ADDITIONAL_INCENTIVES)
279             {
280                 tacticalFactory.set(Setting.INCENTIVE_COURTESY, true);
281             }
282 
283             GtuType car = DefaultsNl.CAR;
284             GtuType truck = DefaultsNl.TRUCK;
285             Route routeAE =
286                     getNetwork().getShortestRouteBetween(car, getNetwork().getNode("A").get(), getNetwork().getNode("E").get());
287             Route routeAG = !NETWORK.equals("shortWeave") ? null : getNetwork().getShortestRouteBetween(car,
288                     getNetwork().getNode("A").get(), getNetwork().getNode("G").get());
289             Route routeFE =
290                     getNetwork().getShortestRouteBetween(car, getNetwork().getNode("F").get(), getNetwork().getNode("E").get());
291             Route routeFG = !NETWORK.equals("shortWeave") ? null : getNetwork().getShortestRouteBetween(car,
292                     getNetwork().getNode("F").get(), getNetwork().getNode("G").get());
293 
294             double leftFraction = NETWORK.equals("shortWeave") ? LEFT_FRACTION : 0.0;
295             List<FrequencyAndObject<Route>> routesA = new ArrayList<>();
296             routesA.add(new FrequencyAndObject<>(1.0 - leftFraction, routeAE));
297             routesA.add(new FrequencyAndObject<>(leftFraction, routeAG));
298             List<FrequencyAndObject<Route>> routesF = new ArrayList<>();
299             routesF.add(new FrequencyAndObject<>(1.0 - leftFraction, routeFE));
300             routesF.add(new FrequencyAndObject<>(leftFraction, routeFG));
301             Supplier<Route> routeGeneratorA = new ProbabilisticRouteGenerator(routesA, stream);
302             Supplier<Route> routeGeneratorF = new ProbabilisticRouteGenerator(routesF, stream);
303 
304             Speed speedA = new Speed(120.0, SpeedUnit.KM_PER_HOUR);
305             Speed speedF = new Speed(20.0, SpeedUnit.KM_PER_HOUR);
306 
307             CrossSectionLink linkA = (CrossSectionLink) getNetwork().getLink("AB").get();
308             CrossSectionLink linkF = (CrossSectionLink) getNetwork().getLink("FF2").get();
309 
310             ParameterFactoryByType bcFactory = new ParameterFactoryByType();
311             bcFactory.addParameter(car, ParameterTypes.FSPEED, new DistNormal(stream, 123.7 / 120, 12.0 / 120));
312             bcFactory.addParameter(car, LmrsParameters.SOCIO, new DistNormal(stream, 0.5, 0.1));
313             bcFactory.addParameter(truck, ParameterTypes.FSPEED_GTU, new DistNormal(stream, 85.0 / 80.0, 2.5 / 80.0));
314             bcFactory.addParameter(truck, ParameterTypes.A, new Acceleration(0.8, AccelerationUnit.SI));
315             bcFactory.addParameter(truck, LmrsParameters.SOCIO, new DistNormal(stream, 0.5, 0.1));
316             bcFactory.addParameter(Tailgating.RHO, Tailgating.RHO.getDefaultValue());
317 
318             Supplier<Duration> headwaysA1 = new HeadwayGenerator(MAIN_DEMAND, stream);
319             Supplier<Duration> headwaysA2 = new HeadwayGenerator(MAIN_DEMAND, stream);
320             Supplier<Duration> headwaysA3 = new HeadwayGenerator(MAIN_DEMAND, stream);
321             Supplier<Duration> headwaysF = new HeadwayGenerator(RAMP_DEMAND, stream);
322 
323             // speed generators
324             ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedCar =
325                     new ContinuousDistDoubleScalar.Rel<>(new DistUniform(stream, 160, 200), SpeedUnit.KM_PER_HOUR);
326             ConstantSupplier<Speed> speedTruck = new ConstantSupplier<>(new Speed(95.0, SpeedUnit.KM_PER_HOUR));
327             // strategical planner factory
328             LaneBasedStrategicalRoutePlannerFactory strategicalFactory =
329                     new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory, bcFactory);
330             // vehicle templates, with routes
331             LaneBasedGtuTemplate carA = new LaneBasedGtuTemplate(car, new ConstantSupplier<>(Length.ofSI(4.0)),
332                     new ConstantSupplier<>(Length.ofSI(2.0)), speedCar, strategicalFactory, routeGeneratorA);
333             LaneBasedGtuTemplate carF = new LaneBasedGtuTemplate(car, new ConstantSupplier<>(Length.ofSI(4.0)),
334                     new ConstantSupplier<>(Length.ofSI(2.0)), speedCar, strategicalFactory, routeGeneratorF);
335             LaneBasedGtuTemplate truckA = new LaneBasedGtuTemplate(truck, new ConstantSupplier<>(Length.ofSI(15.0)),
336                     new ConstantSupplier<>(Length.ofSI(2.5)), speedTruck, strategicalFactory, routeGeneratorA);
337             LaneBasedGtuTemplate truckF = new LaneBasedGtuTemplate(truck, new ConstantSupplier<>(Length.ofSI(15.0)),
338                     new ConstantSupplier<>(Length.ofSI(2.5)), speedTruck, strategicalFactory, routeGeneratorF);
339             //
340             ObjectDistribution<LaneBasedGtuTemplate> gtuTypeAllCarA = new ObjectDistribution<>(streams.get("gtuClass"));
341             gtuTypeAllCarA.add(new FrequencyAndObject<>(1.0, carA));
342 
343             ObjectDistribution<LaneBasedGtuTemplate> gtuType1LaneF = new ObjectDistribution<>(streams.get("gtuClass"));
344             gtuType1LaneF.add(new FrequencyAndObject<>(1.0 - 2 * TRUCK_FRACTION, carF));
345             gtuType1LaneF.add(new FrequencyAndObject<>(2 * TRUCK_FRACTION, truckF));
346 
347             ObjectDistribution<LaneBasedGtuTemplate> gtuType2ndLaneA = new ObjectDistribution<>(streams.get("gtuClass"));
348             gtuType2ndLaneA.add(new FrequencyAndObject<>(1.0 - 2 * TRUCK_FRACTION, carA));
349             gtuType2ndLaneA.add(new FrequencyAndObject<>(2 * TRUCK_FRACTION, truckA));
350 
351             ObjectDistribution<LaneBasedGtuTemplate> gtuType3rdLaneA = new ObjectDistribution<>(streams.get("gtuClass"));
352             gtuType3rdLaneA.add(new FrequencyAndObject<>(1.0 - 3 * TRUCK_FRACTION, carA));
353             gtuType3rdLaneA.add(new FrequencyAndObject<>(3 * TRUCK_FRACTION, truckA));
354 
355             makeGenerator(getLane(linkA, "FORWARD1"), speedA, "gen1", idGenerator, gtuTypeAllCarA, headwaysA1, roomChecker,
356                     bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
357             if (NETWORK.equals("shortWeave"))
358             {
359                 makeGenerator(getLane(linkA, "FORWARD2"), speedA, "gen2", idGenerator, gtuTypeAllCarA, headwaysA2, roomChecker,
360                         bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
361                 makeGenerator(getLane(linkA, "FORWARD3"), speedA, "gen3", idGenerator, gtuType3rdLaneA, headwaysA3, roomChecker,
362                         bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
363             }
364             else
365             {
366                 makeGenerator(getLane(linkA, "FORWARD2"), speedA, "gen2", idGenerator, gtuType2ndLaneA, headwaysA2, roomChecker,
367                         bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
368             }
369             makeGenerator(getLane(linkF, "FORWARD1"), speedF, "gen4", idGenerator, gtuType1LaneF, headwaysF, roomChecker,
370                     bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
371 
372         }
373 
374         /**
375          * Get lane from link by id.
376          * @param link link
377          * @param id id
378          * @return lane
379          */
380         private Lane getLane(final CrossSectionLink link, final String id)
381         {
382             return (Lane) link.getCrossSectionElement(id).orElseThrow();
383         }
384 
385         /**
386          * @param lane the reference lane for this generator
387          * @param generationSpeed the speed of the GTU
388          * @param id the id of the supplier itself
389          * @param idSupplier the supplier for the ID
390          * @param distribution the type generator for the GTU
391          * @param headwaySupplier the headway generator for the GTU
392          * @param roomChecker the checker to see if there is room for the GTU
393          * @param bcFactory the factory to generate parameters for the GTU
394          * @param tacticalFactory the generator for the tactical planner
395          * @param simulationTime simulation time
396          * @param stream random numbers stream
397          * @throws SimRuntimeException in case of scheduling problems
398          * @throws NetworkException if the object could not be added to the network
399          */
400         private void makeGenerator(final Lane lane, final Speed generationSpeed, final String id, final IdSupplier idSupplier,
401                 final ObjectDistribution<LaneBasedGtuTemplate> distribution, final Supplier<Duration> headwaySupplier,
402                 final RoomChecker roomChecker, final ParameterFactory bcFactory,
403                 final LaneBasedTacticalPlannerFactory<?> tacticalFactory, final Time simulationTime,
404                 final StreamInterface stream) throws SimRuntimeException, NetworkException
405         {
406 
407             Set<LanePosition> initialLongitudinalPositions = new LinkedHashSet<>();
408             initialLongitudinalPositions.add(new LanePosition(lane, new Length(5.0, LengthUnit.SI)));
409             LaneBasedGtuTemplateDistribution characteristicsGenerator = new LaneBasedGtuTemplateDistribution(distribution);
410             LaneBasedGtuGenerator generator = new LaneBasedGtuGenerator(id, headwaySupplier, characteristicsGenerator,
411                     GeneratorPositions.create(initialLongitudinalPositions, stream), getNetwork(), getSimulator(), roomChecker,
412                     idSupplier);
413             generator.setNoLaneChangeDistance(Length.ofSI(100.0));
414         }
415 
416     }
417 
418     /**
419      * Extended data of synchronization phase.
420      * @param <G> GTU data type
421      */
422     public static class ExtendedDataSync<G extends GtuDataRoad> extends ExtendedDataString<G>
423     {
424 
425         /**
426          * Constructor.
427          */
428         public ExtendedDataSync()
429         {
430             super("sync", "Synchronization status");
431         }
432 
433         @Override
434         public Optional<String> getValue(final GtuDataRoad gtu)
435         {
436             if (gtu.getGtu().getTacticalPlanner() instanceof Synchronizable sync)
437             {
438                 return Optional.ofNullable(sync.getSynchronizationState().toString());
439             }
440             return Optional.of("N/A");
441         }
442 
443     }
444 
445 }