1 package org.opentrafficsim.road.gtu.generator;
2
3 import java.util.ArrayList;
4 import java.util.LinkedHashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import nl.tudelft.simulation.dsol.SimRuntimeException;
9
10 import org.djunits.unit.LengthUnit;
11 import org.djunits.unit.SpeedUnit;
12 import org.djunits.unit.TimeUnit;
13 import org.opentrafficsim.core.OTS_DIST;
14 import org.opentrafficsim.core.OTS_SCALAR;
15 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
16 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
17 import org.opentrafficsim.core.gtu.GTUException;
18 import org.opentrafficsim.core.gtu.GTUType;
19 import org.opentrafficsim.core.gtu.RelativePosition;
20 import org.opentrafficsim.core.gtu.animation.GTUColorer;
21 import org.opentrafficsim.core.network.NetworkException;
22 import org.opentrafficsim.core.network.route.RouteGenerator;
23 import org.opentrafficsim.road.car.LaneBasedIndividualCar;
24 import org.opentrafficsim.road.car.LaneBasedIndividualCar.LaneBasedIndividualCarBuilder;
25 import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
26 import org.opentrafficsim.road.gtu.following.GTUFollowingModel;
27 import org.opentrafficsim.road.gtu.following.HeadwayGTU;
28 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
29 import org.opentrafficsim.road.gtu.lane.changing.LaneChangeModel;
30 import org.opentrafficsim.road.network.lane.Lane;
31 import org.opentrafficsim.road.network.route.LaneBasedRouteGenerator;
32 import org.opentrafficsim.road.network.route.LaneBasedRouteNavigator;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public abstract class AbstractGTUGenerator implements OTS_SCALAR, OTS_DIST
50 {
51
52 private final String name;
53
54
55 private final GTUType gtuType;
56
57
58 private final Class<?> gtuClass;
59
60
61 private final GTUFollowingModel gtuFollowingModel;
62
63
64 private final LaneChangeModel laneChangeModel;
65
66
67 private final ContinuousDistScalar.Abs<Speed.Abs, SpeedUnit> initialSpeedDist;
68
69
70 private final ContinuousDistScalar.Rel<Time.Rel, TimeUnit> interarrivelTimeDist;
71
72
73 private long generatedGTUs = 0;
74
75
76 private final long maxGTUs;
77
78
79 private final Time.Abs startTime;
80
81
82 private final Time.Abs endTime;
83
84
85 private final Lane lane;
86
87
88 private final Length.Rel position;
89
90
91 private LaneBasedRouteGenerator routeGenerator;
92
93
94 private final GTUColorer gtuColorer;
95
96
97 private List<LaneBasedIndividualCarBuilder> carBuilderList = new ArrayList<>();
98
99
100 @SuppressWarnings("checkstyle:visibilitymodifier")
101 protected long numberGTUs = 0;
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 @SuppressWarnings("checkstyle:parameternumber")
122 public AbstractGTUGenerator(final String name, final OTSDEVSSimulatorInterface simulator, final GTUType gtuType,
123 final Class<?> gtuClass, final GTUFollowingModel gtuFollowingModel, final LaneChangeModel laneChangeModel,
124 final ContinuousDistScalar.Abs<Speed.Abs, SpeedUnit> initialSpeedDist,
125 final ContinuousDistScalar.Rel<Time.Rel, TimeUnit> interarrivelTimeDist, final long maxGTUs,
126 final Time.Abs startTime, final Time.Abs endTime, final Lane lane, final Length.Rel position,
127 final LaneBasedRouteGenerator routeGenerator, final GTUColorer gtuColorer) throws SimRuntimeException
128 {
129 super();
130 this.name = name;
131 this.gtuType = gtuType;
132 this.gtuClass = gtuClass;
133 this.gtuFollowingModel = gtuFollowingModel;
134 this.laneChangeModel = laneChangeModel;
135 this.initialSpeedDist = initialSpeedDist;
136 this.interarrivelTimeDist = interarrivelTimeDist;
137 this.maxGTUs = maxGTUs;
138 this.startTime = startTime;
139 this.endTime = endTime;
140 this.lane = lane;
141 this.position = position;
142 this.routeGenerator = routeGenerator;
143 this.gtuColorer = gtuColorer;
144
145 simulator.scheduleEventAbs(startTime, this, this, "generate", null);
146 }
147
148
149
150
151
152 protected final void generate() throws Exception
153 {
154
155 if (getSimulator().getSimulatorTime().getTime().gt(this.endTime))
156 {
157 return;
158 }
159
160
161 if (this.generatedGTUs >= this.maxGTUs)
162 {
163 return;
164 }
165
166
167 this.numberGTUs++;
168 String id = this.name + ":" + this.numberGTUs;
169
170
171 if (LaneBasedIndividualCar.class.isAssignableFrom(getGtuClass()))
172 {
173 LaneBasedIndividualCarBuilder carBuilder = new LaneBasedIndividualCarBuilder();
174 carBuilder.setId(id);
175 carBuilder.setGtuType(getGtuType());
176 carBuilder.setGTUFollowingModel(this.gtuFollowingModel);
177 carBuilder.setLaneChangeModel(this.laneChangeModel);
178 Length.Rel carLength = getLengthDist().draw();
179 carBuilder.setLength(carLength);
180 carBuilder.setWidth(getWidthDist().draw());
181 carBuilder.setMaximumVelocity(getMaximumSpeedDist().draw());
182 carBuilder.setInitialSpeed(getInitialSpeedDist().draw());
183 carBuilder.setSimulator(getSimulator());
184 Map<Lane, Length.Rel> initialLongitudinalPositions = new LinkedHashMap<>(1);
185 initialLongitudinalPositions.put(this.lane, this.position);
186 carBuilder.setInitialLongitudinalPositions(initialLongitudinalPositions);
187 carBuilder.setRouteGenerator(this.routeGenerator);
188 carBuilder.setAnimationClass(DefaultCarAnimation.class);
189 carBuilder.setGtuColorer(this.gtuColorer);
190 this.generatedGTUs++;
191
192 if (enoughSpace(carBuilder))
193 {
194 carBuilder.build();
195 }
196 else
197 {
198
199 this.carBuilderList.add(carBuilder);
200
201 if (this.carBuilderList.size() == 1)
202 {
203
204 getSimulator().scheduleEventRel(new Time.Rel(0.1, SECOND), this, this, "checkCarBuilderList", null);
205 }
206 }
207 }
208 else
209 {
210 throw new GTUException("GTU class " + getGtuClass().getName() + ": cannot instantiate, no builder.");
211 }
212
213
214 OTSSimTimeDouble nextTime = getSimulator().getSimulatorTime().plus(this.interarrivelTimeDist.draw());
215 if (nextTime.get().le(this.endTime))
216 {
217 getSimulator().scheduleEventAbs(nextTime, this, this, "generate", null);
218 }
219 }
220
221
222
223
224
225
226
227
228 protected final boolean enoughSpace(final LaneBasedIndividualCarBuilder carBuilder) throws NetworkException
229 {
230 Lane generatorLane = carBuilder.getInitialLongitudinalPositions().keySet().iterator().next();
231 double genPosSI = carBuilder.getInitialLongitudinalPositions().get(generatorLane).getSI();
232 double lengthSI = generatorLane.getLength().getSI();
233 double frontNew = (genPosSI + carBuilder.getLength().getSI()) / lengthSI;
234 double rearNew = genPosSI / lengthSI;
235
236
237 for (LaneBasedGTU gtu : generatorLane.getGtuList())
238 {
239 double frontGTU = gtu.fractionalPosition(generatorLane, gtu.getFront());
240 double rearGTU = gtu.fractionalPosition(generatorLane, gtu.getRear());
241 if ((frontNew >= rearGTU && frontNew <= frontGTU) || (rearNew >= rearGTU && rearNew <= frontGTU)
242 || (frontGTU >= rearNew && frontGTU <= frontNew) || (rearGTU >= rearNew && rearGTU <= frontNew))
243 {
244
245 return false;
246 }
247 }
248
249
250 GTUFollowingModel followingModel = carBuilder.getGtuFollowingModel();
251
252 HeadwayGTU headwayGTU =
253 headway(new Length.Rel(250.0, METER), carBuilder.getRouteGenerator().generateRouteNavigator(),
254 generatorLane);
255 Length.Rel minimumHeadway = new Length.Rel(0.0, METER);
256 if (headwayGTU.getOtherGTU() != null)
257 {
258 minimumHeadway =
259 followingModel.minimumHeadway(carBuilder.getInitialSpeed(), headwayGTU.getOtherGTU()
260 .getLongitudinalVelocity(), new Length.Rel(1.0, CENTIMETER), generatorLane.getSpeedLimit(carBuilder
261 .getGtuType()), carBuilder.getMaximumVelocity());
262 double acc =
263 followingModel
264 .computeAcceleration(carBuilder.getInitialSpeed(), carBuilder.getMaximumVelocity(),
265 headwayGTU.getOtherGTU().getLongitudinalVelocity(), minimumHeadway,
266 carBuilder.getMaximumVelocity()).getSI();
267 if (acc < 0)
268 {
269 System.err.println(getSimulator().getSimulatorTime() + ", generator headway for GTU "
270 + headwayGTU.getOtherGTU() + ", distance " + headwayGTU.getDistanceSI() + " m, max "
271 + minimumHeadway + ", has to brake with a=" + acc + " m/s^2");
272 return false;
273 }
274 }
275
276
277
278 return headwayGTU.getDistance().ge(minimumHeadway);
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294 private HeadwayGTU headwayRecursiveForwardSI(final Lane theLane, final double lanePositionSI,
295 final double cumDistanceSI, final double maxDistanceSI, final Time.Abs when,
296 final LaneBasedRouteNavigator routeNavigator) throws NetworkException
297 {
298 LaneBasedGTU otherGTU = theLane.getGtuAfter(new Length.Rel(lanePositionSI, METER), RelativePosition.REAR, when);
299 if (otherGTU != null)
300 {
301 double distanceM =
302 cumDistanceSI + otherGTU.position(theLane, otherGTU.getRear(), when).getSI() - lanePositionSI;
303 if (distanceM > 0 && distanceM <= maxDistanceSI)
304 {
305 return new HeadwayGTU(otherGTU, distanceM);
306 }
307 return new HeadwayGTU(null, Double.MAX_VALUE);
308 }
309
310
311 if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
312 {
313
314 if (theLane.nextLanes(this.gtuType).size() > 0)
315 {
316 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, Double.MAX_VALUE);
317 for (Lane nextLane : theLane.nextLanes(this.gtuType))
318 {
319
320
321
322
323 {
324 double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
325 HeadwayGTU closest =
326 headwayRecursiveForwardSI(nextLane, 0.0, traveledDistanceSI, maxDistanceSI, when,
327 routeNavigator);
328 if (closest.getDistanceSI() < maxDistanceSI
329 && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
330 {
331 foundMaxGTUDistanceSI = closest;
332 }
333 }
334 }
335 return foundMaxGTUDistanceSI;
336 }
337 }
338
339
340 return new HeadwayGTU(null, Double.MAX_VALUE);
341 }
342
343
344
345
346
347
348
349
350
351
352 private HeadwayGTU headwayGTUSIForward(final double maxDistanceSI, final LaneBasedRouteNavigator routeNavigator,
353 final Lane generatorLane) throws NetworkException
354 {
355 Time.Abs when = getSimulator().getSimulatorTime().getTime();
356 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, Double.MAX_VALUE);
357
358
359 HeadwayGTU closest =
360 headwayRecursiveForwardSI(this.lane, generatorLane.getLength().getSI(), 0.0, maxDistanceSI, when,
361 routeNavigator);
362 if (closest.getDistanceSI() < maxDistanceSI && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
363 {
364 foundMaxGTUDistanceSI = closest;
365 }
366 return foundMaxGTUDistanceSI;
367 }
368
369
370
371
372
373
374
375
376
377 public final HeadwayGTU headway(final Length.Rel maxDistance, final LaneBasedRouteNavigator routeNavigator,
378 final Lane generatorLane) throws NetworkException
379 {
380 return headwayGTUSIForward(maxDistance.getSI(), routeNavigator, generatorLane);
381 }
382
383
384
385
386
387 protected final void checkCarBuilderList() throws Exception
388 {
389 if (!this.carBuilderList.isEmpty())
390 {
391 LaneBasedIndividualCarBuilder carBuilder = this.carBuilderList.get(0);
392 if (enoughSpace(carBuilder))
393 {
394 this.carBuilderList.remove(0);
395 carBuilder.build();
396 }
397 }
398
399
400 if (!this.carBuilderList.isEmpty())
401 {
402 getSimulator().scheduleEventRel(new Time.Rel(0.1, SECOND), this, this, "checkCarBuilderList", null);
403 }
404 }
405
406
407 public abstract OTSDEVSSimulatorInterface getSimulator();
408
409
410 public abstract ContinuousDistScalar.Rel<Length.Rel, LengthUnit> getLengthDist();
411
412
413 public abstract ContinuousDistScalar.Rel<Length.Rel, LengthUnit> getWidthDist();
414
415
416 public abstract ContinuousDistScalar.Abs<Speed.Abs, SpeedUnit> getMaximumSpeedDist();
417
418
419
420
421 public final String getName()
422 {
423 return this.name;
424 }
425
426
427
428
429 public final GTUType getGtuType()
430 {
431 return this.gtuType;
432 }
433
434
435
436
437 public final Class<?> getGtuClass()
438 {
439 return this.gtuClass;
440 }
441
442
443
444
445 public final GTUFollowingModel getGtuFollowingModel()
446 {
447 return this.gtuFollowingModel;
448 }
449
450
451
452
453 public final ContinuousDistScalar.Abs<Speed.Abs, SpeedUnit> getInitialSpeedDist()
454 {
455 return this.initialSpeedDist;
456 }
457
458
459
460
461 public final ContinuousDistScalar.Rel<Time.Rel, TimeUnit> getInterarrivelTimeDist()
462 {
463 return this.interarrivelTimeDist;
464 }
465
466
467
468
469 public final long getMaxGTUs()
470 {
471 return this.maxGTUs;
472 }
473
474
475
476
477 public final Time.Abs getStartTime()
478 {
479 return this.startTime;
480 }
481
482
483
484
485 public final Time.Abs getEndTime()
486 {
487 return this.endTime;
488 }
489
490
491
492
493 public final RouteGenerator getRouteGenerator()
494 {
495 return this.routeGenerator;
496 }
497
498
499
500
501 public final void setRouteGenerator(final LaneBasedRouteGenerator routeGenerator)
502 {
503 this.routeGenerator = routeGenerator;
504 }
505
506
507
508
509 public final LaneChangeModel getLaneChangeModel()
510 {
511 return this.laneChangeModel;
512 }
513
514
515
516
517 public final GTUColorer getGtuColorer()
518 {
519 return this.gtuColorer;
520 }
521
522 }