1 package org.opentrafficsim.demo;
2
3 import java.rmi.RemoteException;
4 import java.util.ArrayList;
5 import java.util.LinkedHashSet;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Set;
9 import java.util.SortedMap;
10 import java.util.TreeMap;
11
12 import javax.naming.NamingException;
13
14 import org.djunits.unit.DurationUnit;
15 import org.djunits.unit.LengthUnit;
16 import org.djunits.unit.SpeedUnit;
17 import org.djunits.unit.util.UNITS;
18 import org.djunits.value.vdouble.scalar.Direction;
19 import org.djunits.value.vdouble.scalar.Duration;
20 import org.djunits.value.vdouble.scalar.Length;
21 import org.djunits.value.vdouble.scalar.Speed;
22 import org.djunits.value.vdouble.scalar.base.DoubleScalar;
23 import org.djutils.draw.line.PolyLine2d;
24 import org.djutils.draw.line.Polygon2d;
25 import org.djutils.draw.point.OrientedPoint2d;
26 import org.djutils.draw.point.Point2d;
27 import org.djutils.event.Event;
28 import org.djutils.event.EventListener;
29 import org.djutils.event.EventType;
30 import org.opentrafficsim.base.parameters.ParameterException;
31 import org.opentrafficsim.core.definitions.DefaultsNl;
32 import org.opentrafficsim.core.distributions.Distribution;
33 import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
34 import org.opentrafficsim.core.distributions.Generator;
35 import org.opentrafficsim.core.distributions.ProbabilityException;
36 import org.opentrafficsim.core.dsol.AbstractOtsModel;
37 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
38 import org.opentrafficsim.core.geometry.ContinuousLine;
39 import org.opentrafficsim.core.geometry.ContinuousStraight;
40 import org.opentrafficsim.core.geometry.FractionalLengthData;
41 import org.opentrafficsim.core.geometry.OtsGeometryException;
42 import org.opentrafficsim.core.geometry.OtsLine2d;
43 import org.opentrafficsim.core.gtu.Gtu;
44 import org.opentrafficsim.core.gtu.GtuException;
45 import org.opentrafficsim.core.gtu.GtuType;
46 import org.opentrafficsim.core.idgenerator.IdGenerator;
47 import org.opentrafficsim.core.network.Network;
48 import org.opentrafficsim.core.network.NetworkException;
49 import org.opentrafficsim.core.network.Node;
50 import org.opentrafficsim.core.network.route.FixedRouteGenerator;
51 import org.opentrafficsim.core.network.route.ProbabilisticRouteGenerator;
52 import org.opentrafficsim.core.network.route.Route;
53 import org.opentrafficsim.core.parameters.ParameterFactory;
54 import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
55 import org.opentrafficsim.road.definitions.DefaultsRoadNl;
56 import org.opentrafficsim.road.gtu.generator.CfRoomChecker;
57 import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
58 import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator;
59 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuTemplate;
60 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuTemplateDistribution;
61 import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlusFactory;
62 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLmrsPerceptionFactory;
63 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory;
64 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
65 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
66 import org.opentrafficsim.road.network.RoadNetwork;
67 import org.opentrafficsim.road.network.factory.LaneFactory;
68 import org.opentrafficsim.road.network.lane.CrossSectionLink;
69 import org.opentrafficsim.road.network.lane.CrossSectionSlice;
70 import org.opentrafficsim.road.network.lane.Lane;
71 import org.opentrafficsim.road.network.lane.LaneGeometryUtil;
72 import org.opentrafficsim.road.network.lane.LanePosition;
73 import org.opentrafficsim.road.network.lane.LaneType;
74 import org.opentrafficsim.road.network.lane.object.detector.SinkDetector;
75
76 import nl.tudelft.simulation.dsol.SimRuntimeException;
77 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDouble;
78 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterException;
79 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterMap;
80 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterSelectionMap;
81 import nl.tudelft.simulation.jstats.distributions.DistContinuous;
82 import nl.tudelft.simulation.jstats.distributions.DistErlang;
83 import nl.tudelft.simulation.jstats.distributions.DistUniform;
84 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
85 import nl.tudelft.simulation.jstats.streams.StreamInterface;
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public class NetworksModel extends AbstractOtsModel implements EventListener, UNITS
107 {
108
109 private static final long serialVersionUID = 20140815L;
110
111
112 private final RoadNetwork network = new RoadNetwork("network", getSimulator());
113
114
115 private LaneBasedStrategicalPlannerFactory<?> strategicalPlannerFactoryCars = null;
116
117
118 private LaneBasedStrategicalPlannerFactory<?> strategicalPlannerFactoryTrucks = null;
119
120
121 private double carProbability;
122
123
124 private Length minimumDistance = new Length(0, METER);
125
126
127 private Length maximumDistance = new Length(5000, METER);
128
129
130 private StreamInterface stream = new MersenneTwister(12345);
131
132
133 private Generator<Route> routeGeneratorMain;
134
135
136 private Generator<Route> routeGeneratorRamp;
137
138
139 private Speed speedLimit = new Speed(60, KM_PER_HOUR);
140
141
142 private List<List<Lane>> paths = new ArrayList<>();
143
144
145 private IdGenerator idGenerator = new IdGenerator("");
146
147
148 private DistContinuous headwayGenerator;
149
150
151
152
153 public NetworksModel(final OtsSimulatorInterface simulator)
154 {
155 super(simulator);
156 createInputParameters();
157 }
158
159
160
161
162 private void createInputParameters()
163 {
164 InputParameterHelper.makeInputParameterMapCarTruck(this.inputParameterMap, 1.0);
165 try
166 {
167 InputParameterMap genericMap = (InputParameterMap) this.inputParameterMap.get("generic");
168
169 genericMap.add(new InputParameterDouble("flow", "Flow per input lane", "Traffic flow per input lane", 500d, 0d,
170 3000d, true, true, "%.0f veh/h", 1.5));
171
172 SortedMap<String, String> networks = new TreeMap<>();
173 networks.put("Merge 1 plus 1 into 1", "M111");
174 networks.put("Merge 2 plus 1 into 2", "M212");
175 networks.put("Merge 2 plus 2 into 4", "M224");
176 networks.put("Split 1 into 1 plus 1", "S111");
177 networks.put("Split 2 into 1 plus 2", "S212");
178 networks.put("Split 4 into 2 plus 2", "S422");
179 InputParameterSelectionMap<String, String> paramSelect = new InputParameterSelectionMap<String, String>("network",
180 "Network to run simulation for", "Network to run simulaton for", networks, "M111", 2.0);
181 genericMap.add(paramSelect);
182 }
183 catch (InputParameterException exception)
184 {
185 exception.printStackTrace();
186 }
187
188 }
189
190
191 @Override
192 @SuppressWarnings("checkstyle:methodlength")
193 public final void constructModel() throws SimRuntimeException
194 {
195 this.network.addListener(this, Network.GTU_ADD_EVENT);
196 this.network.addListener(this, Network.GTU_REMOVE_EVENT);
197 try
198 {
199 GtuType car = DefaultsNl.CAR;
200 this.carProbability = (double) getInputParameter("generic.carProbability");
201
202 ParameterFactory params = new InputParameterHelper(getInputParameterMap());
203 this.strategicalPlannerFactoryCars = new LaneBasedStrategicalRoutePlannerFactory(
204 new LmrsFactory(new IdmPlusFactory(this.stream), new DefaultLmrsPerceptionFactory()), params);
205 this.strategicalPlannerFactoryTrucks = new LaneBasedStrategicalRoutePlannerFactory(
206 new LmrsFactory(new IdmPlusFactory(this.stream), new DefaultLmrsPerceptionFactory()), params);
207
208 Point2d pFrom2a = new Point2d(0, -50);
209 Point2d pFrom2b = new Point2d(490, -0.5);
210 Direction onrampDirection = Direction.instantiateSI(pFrom2a.directionTo(pFrom2b));
211 Node from = new Node(this.network, "From", new Point2d(0, 0), Direction.ZERO);
212 Node end = new Node(this.network, "End", new Point2d(2000, 0), Direction.ZERO);
213 Node from2a = new Node(this.network, "From2a", pFrom2a, onrampDirection);
214 Node from2b = new Node(this.network, "From2b", pFrom2b, onrampDirection);
215 Node firstVia = new Node(this.network, "Via1", new Point2d(500, 0), Direction.ZERO);
216 Point2d pEnd2a = new Point2d(1020, -0.5);
217 Point2d pEnd2b = new Point2d(2000, -50);
218 Direction offrampDirection = Direction.instantiateSI(pEnd2a.directionTo(pEnd2b));
219 Node end2a = new Node(this.network, "End2a", pEnd2a, offrampDirection);
220 Node end2b = new Node(this.network, "End2b", pEnd2b, offrampDirection);
221 Node secondVia = new Node(this.network, "Via2", new Point2d(1000, 0), Direction.ZERO);
222
223 String networkType = getInputParameter("generic.network").toString();
224 boolean merge = networkType.startsWith("M");
225 int lanesOnMain = Integer.parseInt("" + networkType.charAt(merge ? 1 : 3));
226 int lanesOnBranch = Integer.parseInt("" + networkType.charAt(2));
227 int lanesOnCommon = lanesOnMain + lanesOnBranch;
228 int lanesOnCommonCompressed = Integer.parseInt("" + networkType.charAt(merge ? 3 : 1));
229
230 double contP = (double) getInputParameter("generic.flow");
231 Duration averageHeadway = new Duration(3600.0 / contP, SECOND);
232 Duration minimumHeadway = new Duration(3, SECOND);
233 this.headwayGenerator =
234 new DistErlang(new MersenneTwister(1234), DoubleScalar.minus(averageHeadway, minimumHeadway).getSI(), 4);
235
236 LaneType laneType = DefaultsRoadNl.TWO_WAY_LANE;
237 Lane[] rampLanes = null;
238 if (merge)
239 {
240 rampLanes = LaneFactory.makeMultiLane(this.network, "From2a to From2b", from2a, from2b, null, lanesOnBranch, 0,
241 lanesOnCommon - lanesOnBranch, laneType, this.speedLimit, this.simulator, DefaultsNl.VEHICLE);
242 LaneFactory.makeMultiLaneBezier(this.network, "From2b to FirstVia", from2a, from2b, firstVia, secondVia,
243 lanesOnBranch, lanesOnCommon - lanesOnBranch, lanesOnCommon - lanesOnBranch, laneType, this.speedLimit,
244 this.simulator, DefaultsNl.VEHICLE);
245 }
246 else
247 {
248 LaneFactory.makeMultiLaneBezier(this.network, "SecondVia to end2a", firstVia, secondVia, end2a, end2b,
249 lanesOnBranch, lanesOnCommon - lanesOnBranch, lanesOnCommon - lanesOnBranch, laneType, this.speedLimit,
250 this.simulator, DefaultsNl.VEHICLE);
251 setupSink(LaneFactory.makeMultiLane(this.network, "end2a to end2b", end2a, end2b, null, lanesOnBranch,
252 lanesOnCommon - lanesOnBranch, 0, laneType, this.speedLimit, this.simulator, DefaultsNl.VEHICLE),
253 laneType);
254 }
255
256 Lane[] startLanes = LaneFactory.makeMultiLane(this.network, "From to FirstVia", from, firstVia, null,
257 merge ? lanesOnMain : lanesOnCommonCompressed, laneType, this.speedLimit, this.simulator,
258 DefaultsNl.VEHICLE);
259 Lane[] common = LaneFactory.makeMultiLane(this.network, "FirstVia to SecondVia", firstVia, secondVia, null,
260 lanesOnCommon, laneType, this.speedLimit, this.simulator, DefaultsNl.VEHICLE);
261 setupSink(LaneFactory.makeMultiLane(this.network, "SecondVia to end", secondVia, end, null,
262 merge ? lanesOnCommonCompressed : lanesOnMain, laneType, this.speedLimit, this.simulator,
263 DefaultsNl.VEHICLE), laneType);
264
265 if (merge)
266 {
267
268 ArrayList<Node> mainRouteNodes = new ArrayList<>();
269 mainRouteNodes.add(from);
270 mainRouteNodes.add(firstVia);
271 mainRouteNodes.add(secondVia);
272 mainRouteNodes.add(end);
273 Route mainRoute = new Route("main", car, mainRouteNodes);
274 this.routeGeneratorMain = new FixedRouteGenerator(mainRoute);
275
276 ArrayList<Node> rampRouteNodes = new ArrayList<>();
277 rampRouteNodes.add(from2a);
278 rampRouteNodes.add(from2b);
279 rampRouteNodes.add(firstVia);
280 rampRouteNodes.add(secondVia);
281 rampRouteNodes.add(end);
282 Route rampRoute = new Route("ramp", car, rampRouteNodes);
283 this.routeGeneratorRamp = new FixedRouteGenerator(rampRoute);
284 }
285 else
286 {
287
288 List<FrequencyAndObject<Route>> routeProbabilities = new ArrayList<>();
289
290 ArrayList<Node> mainRouteNodes = new ArrayList<>();
291 mainRouteNodes.add(from);
292 mainRouteNodes.add(firstVia);
293 mainRouteNodes.add(secondVia);
294 mainRouteNodes.add(end);
295 Route mainRoute = new Route("main", car, mainRouteNodes);
296 routeProbabilities.add(new FrequencyAndObject<>(lanesOnMain, mainRoute));
297
298 ArrayList<Node> sideRouteNodes = new ArrayList<>();
299 sideRouteNodes.add(from);
300 sideRouteNodes.add(firstVia);
301 sideRouteNodes.add(secondVia);
302 sideRouteNodes.add(end2a);
303 sideRouteNodes.add(end2b);
304 Route sideRoute = new Route("side", car, sideRouteNodes);
305 routeProbabilities.add(new FrequencyAndObject<>(lanesOnBranch, sideRoute));
306 try
307 {
308 this.routeGeneratorMain = new ProbabilisticRouteGenerator(routeProbabilities, new MersenneTwister(1234));
309 }
310 catch (ProbabilityException exception)
311 {
312 exception.printStackTrace();
313 }
314 }
315
316 if (merge)
317 {
318 setupGenerator(rampLanes);
319 }
320 setupGenerator(startLanes);
321
322 for (int index = 0; index < lanesOnCommon; index++)
323 {
324 this.paths.add(new ArrayList<Lane>());
325 Lane lane = common[index];
326
327 while (lane.prevLanes(car).size() > 0)
328 {
329 if (lane.prevLanes(car).size() > 1)
330 {
331 throw new NetworkException("This network should not have lane merge points");
332 }
333 lane = lane.prevLanes(car).iterator().next();
334 }
335
336 while (true)
337 {
338 this.paths.get(index).add(lane);
339 int branching = lane.nextLanes(car).size();
340 if (branching == 0)
341 {
342 break;
343 }
344 if (branching > 1)
345 {
346 throw new NetworkException("This network should not have lane split points");
347 }
348 lane = lane.nextLanes(car).iterator().next();
349 }
350 }
351 }
352 catch (SimRuntimeException | NetworkException | OtsGeometryException | InputParameterException | GtuException
353 | ParameterException | NamingException | ProbabilityException exception)
354 {
355 exception.printStackTrace();
356 }
357 }
358
359
360
361
362
363
364
365
366
367
368
369 private Lane[] setupGenerator(final Lane[] lanes)
370 throws SimRuntimeException, GtuException, ProbabilityException, ParameterException, NetworkException
371 {
372 for (Lane lane : lanes)
373 {
374 makeGenerator(lane);
375 }
376 return lanes;
377 }
378
379
380
381
382
383
384
385
386
387
388
389 private LaneBasedGtuGenerator makeGenerator(final Lane lane)
390 throws GtuException, SimRuntimeException, ProbabilityException, ParameterException, NetworkException
391 {
392 Distribution<LaneBasedGtuTemplate> distribution = new Distribution<>(this.stream);
393 Length initialPosition = new Length(16, METER);
394 Set<LanePosition> initialPositions = new LinkedHashSet<>(1);
395 initialPositions.add(new LanePosition(lane, initialPosition));
396
397 LaneBasedGtuTemplate template = makeTemplate(this.stream, lane,
398 new ContinuousDistDoubleScalar.Rel<Length, LengthUnit>(new DistUniform(this.stream, 3, 6), METER),
399 new ContinuousDistDoubleScalar.Rel<Length, LengthUnit>(new DistUniform(this.stream, 1.6, 2.0), METER),
400 new ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit>(new DistUniform(this.stream, 140, 180), KM_PER_HOUR),
401 initialPositions, this.strategicalPlannerFactoryCars);
402
403 distribution.add(new FrequencyAndObject<>(this.carProbability, template));
404 template = makeTemplate(this.stream, lane,
405 new ContinuousDistDoubleScalar.Rel<Length, LengthUnit>(new DistUniform(this.stream, 8, 14), METER),
406 new ContinuousDistDoubleScalar.Rel<Length, LengthUnit>(new DistUniform(this.stream, 2.0, 2.5), METER),
407 new ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit>(new DistUniform(this.stream, 100, 140), KM_PER_HOUR),
408 initialPositions, this.strategicalPlannerFactoryTrucks);
409
410 distribution.add(new FrequencyAndObject<>(1.0 - this.carProbability, template));
411 LaneBasedGtuTemplateDistribution templateDistribution = new LaneBasedGtuTemplateDistribution(distribution);
412 LaneBasedGtuGenerator.RoomChecker roomChecker = new CfRoomChecker();
413 return new LaneBasedGtuGenerator(lane.getId(), new Generator<Duration>()
414 {
415 @SuppressWarnings("synthetic-access")
416 @Override
417 public Duration draw()
418 {
419 return new Duration(NetworksModel.this.headwayGenerator.draw(), DurationUnit.SI);
420 }
421 }, templateDistribution, GeneratorPositions.create(initialPositions, this.stream), this.network, this.simulator,
422 roomChecker, this.idGenerator);
423 }
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438 LaneBasedGtuTemplate makeTemplate(final StreamInterface randStream, final Lane lane,
439 final ContinuousDistDoubleScalar.Rel<Length, LengthUnit> lengthDistribution,
440 final ContinuousDistDoubleScalar.Rel<Length, LengthUnit> widthDistribution,
441 final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> maximumSpeedDistribution,
442 final Set<LanePosition> initialPositions, final LaneBasedStrategicalPlannerFactory<?> strategicalPlannerFactory)
443 throws GtuException
444 {
445 return new LaneBasedGtuTemplate(DefaultsNl.CAR, new Generator<Length>()
446 {
447 @Override
448 public Length draw()
449 {
450 return lengthDistribution.draw();
451 }
452 }, new Generator<Length>()
453 {
454 @Override
455 public Length draw()
456 {
457 return widthDistribution.draw();
458 }
459 }, new Generator<Speed>()
460 {
461 @Override
462 public Speed draw()
463 {
464 return maximumSpeedDistribution.draw();
465 }
466 }, strategicalPlannerFactory,
467 lane.getLink().getStartNode().getId().equals("From") ? this.routeGeneratorMain : this.routeGeneratorRamp);
468
469 }
470
471
472
473
474
475
476
477
478
479 private Lane[] setupSink(final Lane[] lanes, final LaneType laneType) throws NetworkException, OtsGeometryException
480 {
481 CrossSectionLink link = lanes[0].getLink();
482 Node to = (Node) link.getEndNode();
483 Node from = (Node) link.getStartNode();
484 double endLinkLength = 50;
485 double endX = to.getPoint().x + (endLinkLength / link.getLength().getSI()) * (to.getPoint().x - from.getPoint().x);
486 double endY = to.getPoint().y + (endLinkLength / link.getLength().getSI()) * (to.getPoint().y - from.getPoint().y);
487 Node end = new Node(this.network, link.getId() + "END", new Point2d(endX, endY),
488 Direction.instantiateSI(Math.atan2(to.getPoint().y - from.getPoint().y, to.getPoint().x - from.getPoint().x)));
489 double dir = Math.atan2(to.getPoint().y - from.getPoint().y, to.getPoint().x - from.getPoint().x);
490 OrientedPoint2d startPoint = new OrientedPoint2d(to.getPoint().x, to.getPoint().y, dir);
491 ContinuousLine designLine = new ContinuousStraight(startPoint, endLinkLength);
492 CrossSectionLink endLink = LaneFactory.makeLink(this.network, link.getId() + "endLink", to, end, null, this.simulator);
493 for (Lane lane : lanes)
494 {
495 double offset = lane.getLateralCenterPosition(1.0).si;
496 double width = lane.getWidth(1.0).si;
497 PolyLine2d centerLine = designLine.flattenOffset(FractionalLengthData.of(0.0, offset), null);
498 PolyLine2d leftEdge = designLine.flattenOffset(FractionalLengthData.of(0.0, offset + .5 * width), null);
499 PolyLine2d rightEdge = designLine.flattenOffset(FractionalLengthData.of(0.0, offset - .5 * width), null);
500 Polygon2d contour = LaneGeometryUtil.getContour(leftEdge, rightEdge);
501 List<CrossSectionSlice> crossSections =
502 LaneGeometryUtil.getSlices(designLine, Length.instantiateSI(offset), Length.instantiateSI(width));
503
504
505 Lane sinkLane = new Lane(endLink, lane.getId() + "." + "sinkLane", new OtsLine2d(centerLine), contour,
506 crossSections, laneType, Map.of(DefaultsNl.VEHICLE, this.speedLimit));
507 new SinkDetector(sinkLane, new Length(10.0, METER), this.simulator, DefaultsRoadNl.ROAD_USERS);
508 }
509 return lanes;
510 }
511
512
513 private Set<Gtu> knownGTUs = new LinkedHashSet<>();
514
515
516 @Override
517 public void notify(final Event event) throws RemoteException
518 {
519 EventType eventType = event.getType();
520 if (Network.GTU_ADD_EVENT.equals(eventType))
521 {
522 System.out.println("A GTU was created (id " + (String) event.getContent() + ")");
523 this.knownGTUs.add(this.network.getGTU((String) event.getContent()));
524 }
525 else if (Network.GTU_REMOVE_EVENT.equals(eventType))
526 {
527 System.out.println("A GTU was removed (id " + ((String) event.getContent()) + ")");
528 this.knownGTUs.remove(this.network.getGTU((String) event.getContent()));
529 }
530 }
531
532
533 @Override
534 public RoadNetwork getNetwork()
535 {
536 return this.network;
537 }
538
539
540
541
542
543 public final List<Lane> getPath(final int index)
544 {
545 return this.paths.get(index);
546 }
547
548
549
550
551
552 public final int pathCount()
553 {
554 return this.paths.size();
555 }
556
557
558
559
560 public final Length getMinimumDistance()
561 {
562 return this.minimumDistance;
563 }
564
565
566
567
568 public final Length getMaximumDistance()
569 {
570 return this.maximumDistance;
571 }
572
573 }