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.djutils.exceptions.Try;
27 import org.opentrafficsim.animation.GraphLaneUtil;
28 import org.opentrafficsim.animation.gtu.colorer.IncentiveGtuColorer;
29 import org.opentrafficsim.animation.gtu.colorer.SynchronizationGtuColorer;
30 import org.opentrafficsim.base.OtsRuntimeException;
31 import org.opentrafficsim.base.parameters.ParameterException;
32 import org.opentrafficsim.base.parameters.ParameterTypes;
33 import org.opentrafficsim.core.definitions.DefaultsNl;
34 import org.opentrafficsim.core.distributions.ConstantSupplier;
35 import org.opentrafficsim.core.distributions.FrequencyAndObject;
36 import org.opentrafficsim.core.distributions.ObjectDistribution;
37 import org.opentrafficsim.core.dsol.OtsAnimator;
38 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
39 import org.opentrafficsim.core.gtu.Gtu;
40 import org.opentrafficsim.core.gtu.GtuException;
41 import org.opentrafficsim.core.gtu.GtuType;
42 import org.opentrafficsim.core.idgenerator.IdSupplier;
43 import org.opentrafficsim.core.network.Link;
44 import org.opentrafficsim.core.network.NetworkException;
45 import org.opentrafficsim.core.network.Node;
46 import org.opentrafficsim.core.network.route.ProbabilisticRouteGenerator;
47 import org.opentrafficsim.core.network.route.Route;
48 import org.opentrafficsim.core.parameters.ParameterFactory;
49 import org.opentrafficsim.core.parameters.ParameterFactoryByType;
50 import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
51 import org.opentrafficsim.demo.ShortMerge.ShortMergeModel;
52 import org.opentrafficsim.draw.colorer.Colorer;
53 import org.opentrafficsim.draw.colorer.trajectory.SynchronizationTrajectoryColorer;
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.kpi.sampling.data.ExtendedDataString;
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.generator.headway.HeadwayGenerator;
66 import org.opentrafficsim.road.gtu.lane.LaneBookkeeping;
67 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
68 import org.opentrafficsim.road.gtu.lane.tactical.Synchronizable;
69 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveCourtesy;
70 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.Lmrs;
71 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory;
72 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory.Setting;
73 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
74 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
75 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
76 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating;
77 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
78 import org.opentrafficsim.road.network.factory.xml.OtsXmlModel;
79 import org.opentrafficsim.road.network.lane.CrossSectionLink;
80 import org.opentrafficsim.road.network.lane.Lane;
81 import org.opentrafficsim.road.network.lane.LanePosition;
82 import org.opentrafficsim.road.network.lane.object.SpeedSign;
83 import org.opentrafficsim.road.network.sampling.GtuDataRoad;
84 import org.opentrafficsim.road.network.sampling.LaneDataRoad;
85 import org.opentrafficsim.road.network.sampling.RoadSampler;
86 import org.opentrafficsim.swing.graphs.OtsPlotScheduler;
87 import org.opentrafficsim.swing.graphs.SwingTrajectoryPlot;
88 import org.opentrafficsim.swing.gui.AnimationToggles;
89 import org.opentrafficsim.swing.gui.OtsAnimationPanel;
90 import org.opentrafficsim.swing.gui.OtsSimulationApplication;
91
92 import nl.tudelft.simulation.dsol.SimRuntimeException;
93 import nl.tudelft.simulation.jstats.distributions.DistNormal;
94 import nl.tudelft.simulation.jstats.distributions.DistUniform;
95 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
96 import nl.tudelft.simulation.jstats.streams.StreamInterface;
97 import nl.tudelft.simulation.language.DsolException;
98
99
100
101
102
103
104
105
106
107
108 public class ShortMerge extends OtsSimulationApplication<ShortMergeModel>
109 {
110
111 private static final long serialVersionUID = 20170407L;
112
113
114 static final String NETWORK = "shortMerge";
115
116
117 static final double TRUCK_FRACTION = 0.15;
118
119
120 static final double LEFT_FRACTION = 0.3;
121
122
123 static final Frequency MAIN_DEMAND = new Frequency(1000, FrequencyUnit.PER_HOUR);
124
125
126 static final Frequency RAMP_DEMAND = new Frequency(500, FrequencyUnit.PER_HOUR);
127
128
129 static final Synchronization SYNCHRONIZATION = Synchronization.ALIGN_GAP;
130
131
132 static final Cooperation COOPERATION = Cooperation.PASSIVE_MOVING;
133
134
135 static final boolean ADDITIONAL_INCENTIVES = true;
136
137
138 public static final Time SIMTIME = Time.ofSI(3600);
139
140
141
142
143
144
145
146 public ShortMerge(final String title, final OtsAnimationPanel panel, final ShortMergeModel model)
147 {
148 super(model, panel, Map.of(DefaultsNl.TRUCK, GtuMarker.SQUARE));
149 }
150
151 @Override
152 protected void setAnimationToggles()
153 {
154 AnimationToggles.setTextAnimationTogglesStandard(getAnimationPanel());
155 getAnimationPanel().getAnimationPanel().toggleClass(Link.class);
156 getAnimationPanel().getAnimationPanel().toggleClass(Node.class);
157 getAnimationPanel().getAnimationPanel().showClass(SpeedSign.class);
158 }
159
160 @Override
161 protected void addTabs()
162 {
163 GraphPath<LaneDataRoad> path;
164 try
165 {
166 Lane start = ((CrossSectionLink) getModel().getNetwork().getLink("AB").get()).getLanes().get(1);
167 path = GraphLaneUtil.createPath("Right lane", start);
168 }
169 catch (NetworkException exception)
170 {
171 throw new OtsRuntimeException("Could not create a path as a lane has no set speed limit.", exception);
172 }
173 ExtendedDataSync<GtuDataRoad> syncData = new ExtendedDataSync<GtuDataRoad>();
174 RoadSampler sampler = new RoadSampler(Set.of(syncData), Collections.emptySet(), getModel().getNetwork());
175 GraphPath.initRecording(sampler, path);
176 PlotScheduler scheduler = new OtsPlotScheduler(getModel().getSimulator());
177 Duration updateInterval = Duration.ofSI(10.0);
178 SwingTrajectoryPlot plot = new SwingTrajectoryPlot(
179 new TrajectoryPlot("Trajectory right lane", updateInterval, scheduler, sampler.getSamplerData(), path), true);
180 plot.addColorer(new SynchronizationTrajectoryColorer(syncData), false);
181 getAnimationPanel().getTabbedPane().addTab(getAnimationPanel().getTabbedPane().getTabCount(), "Trajectories",
182 plot.getContentPane());
183 }
184
185
186
187
188
189 public static void main(final String[] args)
190 {
191 demo(true);
192 }
193
194
195
196
197
198 public static void demo(final boolean exitOnClose)
199 {
200 try
201 {
202 OtsAnimator simulator = new OtsAnimator("ShortMerge");
203 final ShortMergeModel otsModel = new ShortMergeModel(simulator);
204 List<Colorer<? super Gtu>> colorers = new ArrayList<>(DEFAULT_GTU_COLORERS);
205 colorers.add(new SynchronizationGtuColorer());
206 colorers.add(new IncentiveGtuColorer(IncentiveCourtesy.class, "Courtesy incentive"));
207 OtsAnimationPanel animationPanel = new OtsAnimationPanel(otsModel.getNetwork().getExtent(), simulator, otsModel,
208 colorers, otsModel.getNetwork());
209 ShortMerge app = new ShortMerge("ShortMerge", animationPanel, otsModel);
210 app.setExitOnClose(exitOnClose);
211 animationPanel.enableSimulationControlButtons();
212 }
213 catch (SimRuntimeException | RemoteException | IndexOutOfBoundsException | DsolException exception)
214 {
215 exception.printStackTrace();
216 }
217 }
218
219
220
221
222
223
224
225
226
227
228
229 public static class ShortMergeModel extends OtsXmlModel
230 {
231
232
233
234
235 public ShortMergeModel(final OtsSimulatorInterface simulator)
236 {
237 super(simulator, "/resources/lmrs/" + NETWORK + ".xml");
238 }
239
240 @Override
241 public void constructModel() throws SimRuntimeException
242 {
243 super.constructModel();
244 Try.execute(() -> addGenerator(), OtsRuntimeException.class, "Unable to add generator to network.");
245 }
246
247
248
249
250
251
252
253
254 private void addGenerator() throws ParameterException, GtuException, NetworkException, SimRuntimeException
255 {
256
257 Random seedGenerator = new Random(1L);
258 Map<String, StreamInterface> streams = new LinkedHashMap<>();
259 StreamInterface stream = new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1);
260 streams.put("headwayGeneration", stream);
261 streams.put("gtuClass", new MersenneTwister(Math.abs(seedGenerator.nextLong()) + 1));
262 getStreamInformation().addStream("headwayGeneration", stream);
263 getStreamInformation().addStream("gtuClass", streams.get("gtuClass"));
264
265 TtcRoomChecker roomChecker = new TtcRoomChecker(new Duration(10.0, DurationUnit.SI));
266 IdSupplier idGenerator = new IdSupplier("");
267
268 LmrsFactory<Lmrs> tacticalFactory = new LmrsFactory<Lmrs>(Lmrs::new).setStream(stream)
269 .set(Setting.SYNCHRONIZATION, SYNCHRONIZATION).set(Setting.COOPERATION, COOPERATION);
270 if (ADDITIONAL_INCENTIVES)
271 {
272 tacticalFactory.set(Setting.INCENTIVE_COURTESY, true);
273 }
274
275 GtuType car = DefaultsNl.CAR;
276 GtuType truck = DefaultsNl.TRUCK;
277 Route routeAE =
278 getNetwork().getShortestRouteBetween(car, getNetwork().getNode("A").get(), getNetwork().getNode("E").get());
279 Route routeAG = !NETWORK.equals("shortWeave") ? null : getNetwork().getShortestRouteBetween(car,
280 getNetwork().getNode("A").get(), getNetwork().getNode("G").get());
281 Route routeFE =
282 getNetwork().getShortestRouteBetween(car, getNetwork().getNode("F").get(), getNetwork().getNode("E").get());
283 Route routeFG = !NETWORK.equals("shortWeave") ? null : getNetwork().getShortestRouteBetween(car,
284 getNetwork().getNode("F").get(), getNetwork().getNode("G").get());
285
286 double leftFraction = NETWORK.equals("shortWeave") ? LEFT_FRACTION : 0.0;
287 List<FrequencyAndObject<Route>> routesA = new ArrayList<>();
288 routesA.add(new FrequencyAndObject<>(1.0 - leftFraction, routeAE));
289 routesA.add(new FrequencyAndObject<>(leftFraction, routeAG));
290 List<FrequencyAndObject<Route>> routesF = new ArrayList<>();
291 routesF.add(new FrequencyAndObject<>(1.0 - leftFraction, routeFE));
292 routesF.add(new FrequencyAndObject<>(leftFraction, routeFG));
293 Supplier<Route> routeGeneratorA = new ProbabilisticRouteGenerator(routesA, stream);
294 Supplier<Route> routeGeneratorF = new ProbabilisticRouteGenerator(routesF, stream);
295
296 Speed speedA = new Speed(120.0, SpeedUnit.KM_PER_HOUR);
297 Speed speedF = new Speed(20.0, SpeedUnit.KM_PER_HOUR);
298
299 CrossSectionLink linkA = (CrossSectionLink) getNetwork().getLink("AB").get();
300 CrossSectionLink linkF = (CrossSectionLink) getNetwork().getLink("FF2").get();
301
302 ParameterFactoryByType bcFactory = new ParameterFactoryByType();
303 bcFactory.addParameter(car, ParameterTypes.FSPEED, new DistNormal(stream, 123.7 / 120, 12.0 / 120));
304 bcFactory.addParameter(car, LmrsParameters.SOCIO, new DistNormal(stream, 0.5, 0.1));
305 bcFactory.addParameter(truck, ParameterTypes.A, new Acceleration(0.8, AccelerationUnit.SI));
306 bcFactory.addParameter(truck, LmrsParameters.SOCIO, new DistNormal(stream, 0.5, 0.1));
307 bcFactory.addParameter(Tailgating.RHO, Tailgating.RHO.getDefaultValue());
308
309 Supplier<Duration> headwaysA1 = new HeadwayGenerator(MAIN_DEMAND, stream);
310 Supplier<Duration> headwaysA2 = new HeadwayGenerator(MAIN_DEMAND, stream);
311 Supplier<Duration> headwaysA3 = new HeadwayGenerator(MAIN_DEMAND, stream);
312 Supplier<Duration> headwaysF = new HeadwayGenerator(RAMP_DEMAND, stream);
313
314
315 ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedCar =
316 new ContinuousDistDoubleScalar.Rel<>(new DistUniform(stream, 160, 200), SpeedUnit.KM_PER_HOUR);
317 ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedTruck =
318 new ContinuousDistDoubleScalar.Rel<>(new DistUniform(stream, 80, 95), SpeedUnit.KM_PER_HOUR);
319
320 LaneBasedStrategicalRoutePlannerFactory strategicalFactory =
321 new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory, bcFactory);
322
323 LaneBasedGtuTemplate carA = new LaneBasedGtuTemplate(car, new ConstantSupplier<>(Length.ofSI(4.0)),
324 new ConstantSupplier<>(Length.ofSI(2.0)), speedCar, strategicalFactory, routeGeneratorA);
325 LaneBasedGtuTemplate carF = new LaneBasedGtuTemplate(car, new ConstantSupplier<>(Length.ofSI(4.0)),
326 new ConstantSupplier<>(Length.ofSI(2.0)), speedCar, strategicalFactory, routeGeneratorF);
327 LaneBasedGtuTemplate truckA = new LaneBasedGtuTemplate(truck, new ConstantSupplier<>(Length.ofSI(15.0)),
328 new ConstantSupplier<>(Length.ofSI(2.5)), speedTruck, strategicalFactory, routeGeneratorA);
329 LaneBasedGtuTemplate truckF = new LaneBasedGtuTemplate(truck, new ConstantSupplier<>(Length.ofSI(15.0)),
330 new ConstantSupplier<>(Length.ofSI(2.5)), speedTruck, strategicalFactory, routeGeneratorF);
331
332 ObjectDistribution<LaneBasedGtuTemplate> gtuTypeAllCarA = new ObjectDistribution<>(streams.get("gtuClass"));
333 gtuTypeAllCarA.add(new FrequencyAndObject<>(1.0, carA));
334
335 ObjectDistribution<LaneBasedGtuTemplate> gtuType1LaneF = new ObjectDistribution<>(streams.get("gtuClass"));
336 gtuType1LaneF.add(new FrequencyAndObject<>(1.0 - 2 * TRUCK_FRACTION, carF));
337 gtuType1LaneF.add(new FrequencyAndObject<>(2 * TRUCK_FRACTION, truckF));
338
339 ObjectDistribution<LaneBasedGtuTemplate> gtuType2ndLaneA = new ObjectDistribution<>(streams.get("gtuClass"));
340 gtuType2ndLaneA.add(new FrequencyAndObject<>(1.0 - 2 * TRUCK_FRACTION, carA));
341 gtuType2ndLaneA.add(new FrequencyAndObject<>(2 * TRUCK_FRACTION, truckA));
342
343 ObjectDistribution<LaneBasedGtuTemplate> gtuType3rdLaneA = new ObjectDistribution<>(streams.get("gtuClass"));
344 gtuType3rdLaneA.add(new FrequencyAndObject<>(1.0 - 3 * TRUCK_FRACTION, carA));
345 gtuType3rdLaneA.add(new FrequencyAndObject<>(3 * TRUCK_FRACTION, truckA));
346
347 makeGenerator(getLane(linkA, "FORWARD1"), speedA, "gen1", idGenerator, gtuTypeAllCarA, headwaysA1, roomChecker,
348 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
349 if (NETWORK.equals("shortWeave"))
350 {
351 makeGenerator(getLane(linkA, "FORWARD2"), speedA, "gen2", idGenerator, gtuTypeAllCarA, headwaysA2, roomChecker,
352 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
353 makeGenerator(getLane(linkA, "FORWARD3"), speedA, "gen3", idGenerator, gtuType3rdLaneA, headwaysA3, roomChecker,
354 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
355 }
356 else
357 {
358 makeGenerator(getLane(linkA, "FORWARD2"), speedA, "gen2", idGenerator, gtuType2ndLaneA, headwaysA2, roomChecker,
359 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
360 }
361 makeGenerator(getLane(linkF, "FORWARD1"), speedF, "gen4", idGenerator, gtuType1LaneF, headwaysF, roomChecker,
362 bcFactory, tacticalFactory, SIMTIME, streams.get("gtuClass"));
363
364 new SpeedSign("sign1", getLane(linkA, "FORWARD1"), Length.ofSI(10), new Speed(130.0, SpeedUnit.KM_PER_HOUR),
365 DefaultsNl.VEHICLE, Duration.ZERO, new Duration(24, DurationUnit.HOUR));
366
367 }
368
369
370
371
372
373
374
375 private Lane getLane(final CrossSectionLink link, final String id)
376 {
377 return (Lane) link.getCrossSectionElement(id).orElseThrow();
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397 private void makeGenerator(final Lane lane, final Speed generationSpeed, final String id, final IdSupplier idSupplier,
398 final ObjectDistribution<LaneBasedGtuTemplate> distribution, final Supplier<Duration> headwaySupplier,
399 final RoomChecker roomChecker, final ParameterFactory bcFactory,
400 final LaneBasedTacticalPlannerFactory<?> tacticalFactory, final Time simulationTime,
401 final StreamInterface stream) throws SimRuntimeException, GtuException, ParameterException, NetworkException
402 {
403
404 Set<LanePosition> initialLongitudinalPositions = new LinkedHashSet<>();
405 initialLongitudinalPositions.add(new LanePosition(lane, new Length(5.0, LengthUnit.SI)));
406 LaneBasedGtuTemplateDistribution characteristicsGenerator = new LaneBasedGtuTemplateDistribution(distribution);
407 LaneBasedGtuGenerator generator = new LaneBasedGtuGenerator(id, headwaySupplier, characteristicsGenerator,
408 GeneratorPositions.create(initialLongitudinalPositions, stream), getNetwork(), getSimulator(), roomChecker,
409 idSupplier);
410 generator.setNoLaneChangeDistance(Length.ofSI(100.0));
411 generator.setBookkeeping(LaneBookkeeping.START);
412 }
413
414 }
415
416
417
418
419
420 public static class ExtendedDataSync<G extends GtuDataRoad> extends ExtendedDataString<G>
421 {
422
423
424
425
426 public ExtendedDataSync()
427 {
428 super("sync", "Synchronization status");
429 }
430
431 @Override
432 public Optional<String> getValue(final GtuDataRoad gtu)
433 {
434 if (gtu.getGtu().getTacticalPlanner() instanceof Synchronizable sync)
435 {
436 return Optional.ofNullable(sync.getSynchronizationState().toString());
437 }
438 return Optional.of("N/A");
439 }
440
441 }
442
443 }