1 package org.opentrafficsim.road.gtu.generator;
2
3 import java.io.Serializable;
4 import java.rmi.RemoteException;
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.LinkedHashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import javax.media.j3d.BoundingBox;
13 import javax.media.j3d.Bounds;
14 import javax.vecmath.Point3d;
15
16 import org.djunits.unit.DurationUnit;
17 import org.djunits.unit.LengthUnit;
18 import org.djunits.unit.SpeedUnit;
19 import org.djunits.value.vdouble.scalar.Acceleration;
20 import org.djunits.value.vdouble.scalar.Duration;
21 import org.djunits.value.vdouble.scalar.Length;
22 import org.djunits.value.vdouble.scalar.Speed;
23 import org.djunits.value.vdouble.scalar.Time;
24 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
25 import org.opentrafficsim.core.geometry.OTSGeometryException;
26 import org.opentrafficsim.core.gtu.GTUDirectionality;
27 import org.opentrafficsim.core.gtu.GTUException;
28 import org.opentrafficsim.core.gtu.GTUType;
29 import org.opentrafficsim.core.gtu.RelativePosition;
30 import org.opentrafficsim.core.network.Network;
31 import org.opentrafficsim.core.network.NetworkException;
32 import org.opentrafficsim.core.network.OTSNetwork;
33 import org.opentrafficsim.core.network.route.RouteGenerator;
34 import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
35 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
36 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
37 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU.LaneBasedIndividualCarBuilder;
38 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
39 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayDistance;
40 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUSimple;
41 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
42 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
43 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
44 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
45 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
46 import org.opentrafficsim.road.network.lane.Lane;
47
48 import nl.tudelft.simulation.dsol.SimRuntimeException;
49 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
50 import nl.tudelft.simulation.event.EventProducer;
51 import nl.tudelft.simulation.language.d3.DirectedPoint;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public abstract class AbstractGTUGenerator extends EventProducer implements Serializable, GTUGenerator
69 {
70
71 private static final long serialVersionUID = 20150202L;
72
73
74 private final String name;
75
76
77 private final GTUType gtuType;
78
79
80 private final Class<?> gtuClass;
81
82
83 private final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist;
84
85
86 private final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist;
87
88
89 private long generatedGTUs = 0;
90
91
92 private final long maxGTUs;
93
94
95 private final Time startTime;
96
97
98 private final Time endTime;
99
100
101 private final Lane lane;
102
103
104 private final Length position;
105
106
107 private final GTUDirectionality direction;
108
109
110 private final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory;
111
112
113 private final RouteGenerator routeGenerator;
114
115
116 private final OTSNetwork network;
117
118
119 private List<LaneBasedIndividualCarBuilder> carBuilderList = new ArrayList<>();
120
121
122 @SuppressWarnings("checkstyle:visibilitymodifier")
123 protected long numberGTUs = 0;
124
125
126 private final Bounds bounds;
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 @SuppressWarnings("checkstyle:parameternumber")
151 public AbstractGTUGenerator(final String name, final DEVSSimulatorInterface.TimeDoubleUnit simulator, final GTUType gtuType,
152 final Class<?> gtuClass, final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist,
153 final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist, final long maxGTUs,
154 final Time startTime, final Time endTime, final Lane lane, final Length position, final GTUDirectionality direction,
155 final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory,
156 final RouteGenerator routeGenerator, final OTSNetwork network) throws SimRuntimeException
157 {
158 super();
159 this.name = name;
160 this.gtuType = gtuType;
161 this.gtuClass = gtuClass;
162 this.initialSpeedDist = initialSpeedDist;
163 this.interarrivelTimeDist = interarrivelTimeDist;
164 this.maxGTUs = maxGTUs;
165 this.startTime = startTime;
166 this.endTime = endTime;
167 this.lane = lane;
168 this.position = position;
169 this.direction = direction;
170 this.strategicalPlannerFactory = strategicalPlannerFactory;
171 this.routeGenerator = routeGenerator;
172 this.network = network;
173 DirectedPoint p;
174 try
175 {
176 p = this.getLocation();
177 this.bounds = new BoundingBox(new Point3d(p.x - 1, p.y - 1, 0.0), new Point3d(p.x + 1, p.y + 1, 0.0));
178 }
179 catch (RemoteException exception)
180 {
181 throw new RuntimeException("Bounds for generator cannot be determined.");
182 }
183 simulator.scheduleEventAbs(startTime, this, this, "generate", null);
184
185
186 fireEvent(Network.GENERATOR_ADD_EVENT, name);
187 fireEvent(Network.ANIMATION_GENERATOR_ADD_EVENT, this);
188 }
189
190
191
192
193
194 protected final void generate() throws Exception
195 {
196
197 if (getSimulator().getSimulatorTime().gt(this.endTime))
198 {
199 return;
200 }
201
202
203 if (this.generatedGTUs >= this.maxGTUs)
204 {
205 return;
206 }
207
208
209 this.numberGTUs++;
210 String id = this.name + ":" + this.numberGTUs;
211
212
213 if (LaneBasedIndividualGTU.class.isAssignableFrom(getGtuClass()))
214 {
215 LaneBasedIndividualCarBuilder carBuilder = new LaneBasedIndividualCarBuilder();
216 carBuilder.setId(id);
217 carBuilder.setGtuType(getGtuType());
218 Length carLength = getLengthDist().draw();
219 carBuilder.setLength(carLength);
220 carBuilder.setFront(carLength.multiplyBy(0.75));
221 carBuilder.setWidth(getWidthDist().draw());
222 carBuilder.setMaximumSpeed(getMaximumSpeedDist().draw());
223 carBuilder.setInitialSpeed(getInitialSpeedDist().draw());
224 carBuilder.setSimulator(getSimulator());
225 Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
226 initialLongitudinalPositions.add(new DirectedLanePosition(this.lane, this.position, this.direction));
227 carBuilder.setInitialLongitudinalPositions(initialLongitudinalPositions);
228 carBuilder.setNetwork(this.network);
229 carBuilder.setMaximumAcceleration(Acceleration.createSI(3.0));
230 carBuilder.setMaximumDeceleration(Acceleration.createSI(-8.0));
231 this.generatedGTUs++;
232
233 if (enoughSpace(carBuilder))
234 {
235 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw(), null, null);
236 }
237 else
238 {
239
240 this.carBuilderList.add(carBuilder);
241
242 if (this.carBuilderList.size() == 1)
243 {
244
245 getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList",
246 null);
247 }
248 }
249 }
250 else
251 {
252 throw new GTUException("GTU class " + getGtuClass().getName() + ": cannot instantiate, no builder.");
253 }
254
255
256 Time nextTime = getSimulator().getSimulatorTime().plus(this.interarrivelTimeDist.draw());
257 if (nextTime.le(this.endTime))
258 {
259 getSimulator().scheduleEventAbs(nextTime, this, this, "generate", null);
260 }
261 }
262
263
264
265
266
267
268
269
270
271 protected final boolean enoughSpace(final LaneBasedIndividualCarBuilder carBuilder) throws NetworkException, GTUException
272 {
273 DirectedLanePosition directedLanePosition = carBuilder.getInitialLongitudinalPositions().iterator().next();
274 Lane generatorLane = directedLanePosition.getLane();
275 double genPosSI = directedLanePosition.getPosition().getSI();
276
277
278 double lengthSI = generatorLane.getLength().getSI();
279 double frontNew = (genPosSI + carBuilder.getLength().getSI()) / lengthSI;
280 double rearNew = genPosSI / lengthSI;
281
282
283 for (LaneBasedGTU gtu : generatorLane.getGtuList())
284 {
285 double frontGTU = gtu.fractionalPosition(generatorLane, gtu.getFront());
286 double rearGTU = gtu.fractionalPosition(generatorLane, gtu.getRear());
287 if ((frontNew >= rearGTU && frontNew <= frontGTU) || (rearNew >= rearGTU && rearNew <= frontGTU)
288 || (frontGTU >= rearNew && frontGTU <= frontNew) || (rearGTU >= rearNew && rearGTU <= frontNew))
289 {
290
291 return false;
292 }
293 }
294
295
296 GTUFollowingModelOld followingModel = new IDMPlusOld();
297
298
299 Headway headway = headway(new Length(250.0, LengthUnit.METER), generatorLane);
300 Length minimumHeadway = new Length(0.0, LengthUnit.METER);
301 if (headway.getObjectType().isGtu())
302 {
303 minimumHeadway = followingModel.minimumHeadway(carBuilder.getInitialSpeed(), headway.getSpeed(),
304 new Length(1.0, LengthUnit.CENTIMETER), new Length(250.0, LengthUnit.METER),
305 generatorLane.getSpeedLimit(carBuilder.getGtuType()), carBuilder.getMaximumSpeed());
306
307 double acc = followingModel.computeAcceleration(carBuilder.getInitialSpeed(), carBuilder.getMaximumSpeed(),
308 headway.getSpeed(), headway.getDistance(), carBuilder.getMaximumSpeed()).getSI();
309 if (acc < 0)
310 {
311
312
313
314 return false;
315 }
316 }
317
318
319
320 return headway.getDistance().ge(minimumHeadway);
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334
335 private Headway headwayRecursiveForwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
336 final double maxDistanceSI, final Time when) throws GTUException
337 {
338
339 LaneBasedGTU otherGTU = theLane.getGtuAhead(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
340 RelativePosition.REAR, when);
341 if (otherGTU != null)
342 {
343 double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getRear(), when).getSI() - lanePositionSI;
344 if (distanceM > 0 && distanceM <= maxDistanceSI)
345 {
346 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
347 otherGTU.getLength(), otherGTU.getWidth(), otherGTU.getSpeed(), otherGTU.getAcceleration(), null);
348 }
349 return new HeadwayDistance(Double.MAX_VALUE);
350 }
351
352
353 if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
354 {
355
356 if (theLane.nextLanes(this.gtuType).size() > 0)
357 {
358 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
359 for (Lane nextLane : theLane.nextLanes(this.gtuType).keySet())
360 {
361
362
363
364
365 {
366 double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
367 Headway closest = headwayRecursiveForwardSI(nextLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
368 if (closest.getDistance().si < maxDistanceSI
369 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
370 {
371 foundMaxGTUDistanceSI = closest;
372 }
373 }
374 }
375 return foundMaxGTUDistanceSI;
376 }
377 }
378
379
380 return new HeadwayDistance(Double.MAX_VALUE);
381 }
382
383
384
385
386
387
388
389
390
391
392
393
394
395 private Headway headwayRecursiveBackwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
396 final double maxDistanceSI, final Time when) throws GTUException
397 {
398
399 LaneBasedGTU otherGTU = theLane.getGtuBehind(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
400 RelativePosition.FRONT, when);
401 if (otherGTU != null)
402 {
403 double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getFront(), when).getSI() - lanePositionSI;
404 if (distanceM > 0 && distanceM <= maxDistanceSI)
405 {
406 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
407 otherGTU.getLength(), otherGTU.getWidth(), otherGTU.getSpeed(), otherGTU.getAcceleration(), null);
408 }
409 return new HeadwayDistance(Double.MAX_VALUE);
410 }
411
412
413 if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
414 {
415
416 if (theLane.prevLanes(this.gtuType).size() > 0)
417 {
418 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
419 for (Lane prevLane : theLane.prevLanes(this.gtuType).keySet())
420 {
421
422
423
424
425 {
426 double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
427 Headway closest = headwayRecursiveBackwardSI(prevLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
428 if (closest.getDistance().si < maxDistanceSI
429 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
430 {
431 foundMaxGTUDistanceSI = closest;
432 }
433 }
434 }
435 return foundMaxGTUDistanceSI;
436 }
437 }
438
439
440 return new HeadwayDistance(Double.MAX_VALUE);
441 }
442
443
444
445
446
447
448
449
450
451 private Headway headwayGTUSIForward(final double maxDistanceSI, final Lane generatorLane) throws GTUException
452 {
453 Time when = getSimulator().getSimulatorTime();
454 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
455
456 Headway closest;
457 if (this.direction.equals(GTUDirectionality.DIR_PLUS))
458 {
459 closest = headwayRecursiveForwardSI(this.lane, 0.0, 0.0, maxDistanceSI, when);
460 }
461 else
462 {
463 closest = headwayRecursiveBackwardSI(this.lane, generatorLane.getLength().getSI(), 0.0, maxDistanceSI, when);
464 }
465 if (closest.getDistance().si < maxDistanceSI && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
466 {
467 foundMaxGTUDistanceSI = closest;
468 }
469 return foundMaxGTUDistanceSI;
470 }
471
472
473
474
475
476
477
478
479 public final Headway headway(final Length maxDistance, final Lane generatorLane) throws GTUException
480 {
481 return headwayGTUSIForward(maxDistance.getSI(), generatorLane);
482 }
483
484
485
486
487
488 protected final void checkCarBuilderList() throws Exception
489 {
490 if (!this.carBuilderList.isEmpty())
491 {
492 LaneBasedIndividualCarBuilder carBuilder = this.carBuilderList.get(0);
493 if (enoughSpace(carBuilder))
494 {
495 this.carBuilderList.remove(0);
496 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw(), null, null);
497 }
498 }
499
500
501 if (!this.carBuilderList.isEmpty())
502 {
503 getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList", null);
504 }
505 }
506
507
508 public abstract OTSSimulatorInterface getSimulator();
509
510
511 public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getLengthDist();
512
513
514 public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getWidthDist();
515
516
517 public abstract ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getMaximumSpeedDist();
518
519
520
521
522 public final String getName()
523 {
524 return this.name;
525 }
526
527
528
529
530 public final GTUType getGtuType()
531 {
532 return this.gtuType;
533 }
534
535
536
537
538 public final Class<?> getGtuClass()
539 {
540 return this.gtuClass;
541 }
542
543
544
545
546 public final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getInitialSpeedDist()
547 {
548 return this.initialSpeedDist;
549 }
550
551
552
553
554 public final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> getInterarrivelTimeDist()
555 {
556 return this.interarrivelTimeDist;
557 }
558
559
560
561
562 public final long getMaxGTUs()
563 {
564 return this.maxGTUs;
565 }
566
567
568
569
570 public final Time getStartTime()
571 {
572 return this.startTime;
573 }
574
575
576
577
578 public final Time getEndTime()
579 {
580 return this.endTime;
581 }
582
583
584
585
586 public final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> getStrategicalPlannerFactory()
587 {
588 return this.strategicalPlannerFactory;
589 }
590
591
592 @Override
593 public DirectedPoint getLocation() throws RemoteException
594 {
595 try
596 {
597 return this.lane.getCenterLine().getLocation(this.position);
598 }
599 catch (OTSGeometryException exception)
600 {
601 return this.lane.getLocation();
602 }
603 }
604
605
606 @Override
607 public Bounds getBounds() throws RemoteException
608 {
609 return this.bounds;
610 }
611
612
613 @Override
614 public Map<DirectedPoint, Integer> getQueueLengths()
615 {
616 Map<DirectedPoint, Integer> map = new HashMap<>();
617 try
618 {
619 map.put(getLocation(), this.carBuilderList.size());
620 }
621 catch (RemoteException exception)
622 {
623 throw new RuntimeException("Locartion for generator queue cannot be determined.");
624 }
625 return map;
626 }
627
628 }