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
97
98
99
100
101
102
103
104 public class ShortMerge extends OtsSimulationApplication<ShortMergeModel>
105 {
106
107 private static final long serialVersionUID = 20170407L;
108
109
110 static final String NETWORK = "shortMerge";
111
112
113 static final double TRUCK_FRACTION = 0.15;
114
115
116 static final double LEFT_FRACTION = 0.3;
117
118
119 static final Frequency MAIN_DEMAND = new Frequency(1000, FrequencyUnit.PER_HOUR);
120
121
122 static final Frequency RAMP_DEMAND = new Frequency(500, FrequencyUnit.PER_HOUR);
123
124
125 static final Synchronization SYNCHRONIZATION = Synchronization.ALIGN_GAP;
126
127
128 static final Cooperation COOPERATION = Cooperation.PASSIVE_MOVING;
129
130
131 static final boolean ADDITIONAL_INCENTIVES = true;
132
133
134 public static final Time SIMTIME = Time.ofSI(3600);
135
136
137
138
139
140
141
142 public ShortMerge(final String title, final OtsSimulationPanel panel, final ShortMergeModel model)
143 {
144 super(model, panel);
145 }
146
147
148
149
150
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
178
179
180 public static void main(final String[] args)
181 {
182 demo(true);
183 }
184
185
186
187
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
230
231 public static class ShortMergeModel extends OtsXmlModel
232 {
233
234
235
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
258
259
260
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
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
328 LaneBasedStrategicalRoutePlannerFactory strategicalFactory =
329 new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory, bcFactory);
330
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
376
377
378
379
380 private Lane getLane(final CrossSectionLink link, final String id)
381 {
382 return (Lane) link.getCrossSectionElement(id).orElseThrow();
383 }
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
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
420
421
422 public static class ExtendedDataSync<G extends GtuDataRoad> extends ExtendedDataString<G>
423 {
424
425
426
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 }