1 package ahfe;
2
3 import java.awt.geom.Rectangle2D;
4 import java.awt.geom.Rectangle2D.Double;
5 import java.io.BufferedWriter;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.OutputStreamWriter;
10 import java.rmi.RemoteException;
11 import java.util.ArrayList;
12 import java.util.zip.ZipEntry;
13 import java.util.zip.ZipOutputStream;
14
15 import javax.naming.NamingException;
16 import javax.swing.SwingUtilities;
17
18 import org.djunits.unit.FrequencyUnit;
19 import org.djunits.value.vdouble.scalar.Duration;
20 import org.djunits.value.vdouble.scalar.Frequency;
21 import org.djunits.value.vdouble.scalar.Length;
22 import org.djunits.value.vdouble.scalar.Time;
23 import org.opentrafficsim.base.modelproperties.Property;
24 import org.opentrafficsim.base.modelproperties.PropertyException;
25 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
26 import org.opentrafficsim.core.dsol.OTSModelInterface;
27 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
28 import org.opentrafficsim.core.gtu.AbstractGTU;
29 import org.opentrafficsim.core.network.OTSNetwork;
30 import org.opentrafficsim.kpi.interfaces.LaneDataInterface;
31 import org.opentrafficsim.kpi.sampling.KpiGtuDirectionality;
32 import org.opentrafficsim.kpi.sampling.KpiLaneDirection;
33 import org.opentrafficsim.kpi.sampling.Sampler;
34 import org.opentrafficsim.kpi.sampling.SpaceTimeRegion;
35 import org.opentrafficsim.road.animation.AnimationToggles;
36 import org.opentrafficsim.road.network.factory.xml.XmlNetworkLaneParser;
37 import org.opentrafficsim.road.network.lane.CrossSectionLink;
38 import org.opentrafficsim.road.network.sampling.GtuData;
39 import org.opentrafficsim.road.network.sampling.LinkData;
40 import org.opentrafficsim.road.network.sampling.RoadSampler;
41 import org.opentrafficsim.road.network.sampling.data.TimeToCollision;
42 import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
43 import org.opentrafficsim.simulationengine.OTSSimulationException;
44
45 import nl.tudelft.simulation.dsol.SimRuntimeException;
46 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
47 import nl.tudelft.simulation.event.EventProducer;
48 import nl.tudelft.simulation.language.Throw;
49 import nl.tudelft.simulation.language.io.URLResource;
50
51
52
53
54
55
56
57
58
59
60
61
62 public class AHFEAnimation extends AbstractWrappableAnimation
63 {
64
65
66 static final Time WARMUP = Time.createSI(360);
67
68
69 static final Time SIMEND = Time.createSI(360 + 3600);
70
71
72 private static Length ignoreStart = Length.createSI(2900);
73
74
75 private static Length ignoreEnd = Length.createSI(1000);
76
77
78 private static final long serialVersionUID = 20170228L;
79
80
81 private final Integer replication;
82
83
84 private final String anticipationStrategy;
85
86
87 private final Duration reactionTime;
88
89
90 private final Duration anticipationTime;
91
92
93 private final double truckFraction;
94
95
96 private final double distanceError;
97
98
99 private final double speedError;
100
101
102 private final double accelerationError;
103
104
105 private final Frequency leftDemand;
106
107
108 private final Frequency rightDemand;
109
110
111 private final double leftFraction;
112
113
114 Sampler<GtuData> sampler;
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 @SuppressWarnings("checkstyle:parameternumber")
130 public AHFEAnimation(final Integer replication, final String anticipationStrategy, final Duration reactionTime,
131 final Duration anticipationTime, final double truckFraction, final double distanceError, final double speedError,
132 final double accelerationError, final Frequency leftDemand, final Frequency rightDemand, final double leftFraction)
133 {
134 super();
135 this.replication = replication;
136 this.anticipationStrategy = anticipationStrategy;
137 this.reactionTime = reactionTime;
138 this.anticipationTime = anticipationTime;
139 this.truckFraction = truckFraction;
140 this.distanceError = distanceError;
141 this.speedError = speedError;
142 this.accelerationError = accelerationError;
143 this.leftDemand = leftDemand;
144 this.rightDemand = rightDemand;
145 this.leftFraction = leftFraction;
146 }
147
148
149
150
151 public Integer getReplication()
152 {
153 return this.replication;
154 }
155
156
157
158
159 public String getAnticipationStrategy()
160 {
161 return this.anticipationStrategy;
162 }
163
164
165
166
167 public Duration getReactionTime()
168 {
169 return this.reactionTime;
170 }
171
172
173
174
175 public Duration getAnticipationTime()
176 {
177 return this.anticipationTime;
178 }
179
180
181
182
183 public double getTruckFraction()
184 {
185 return this.truckFraction;
186 }
187
188
189
190
191 public double getDistanceError()
192 {
193 return this.distanceError;
194 }
195
196
197
198
199 public double getSpeedError()
200 {
201 return this.speedError;
202 }
203
204
205
206
207 public double getAccelerationError()
208 {
209 return this.accelerationError;
210 }
211
212
213
214
215 public Frequency getLeftDemand()
216 {
217 return this.leftDemand;
218 }
219
220
221
222
223 public Frequency getRightDemand()
224 {
225 return this.rightDemand;
226 }
227
228
229
230
231 public double getLeftFraction()
232 {
233 return this.leftFraction;
234 }
235
236
237
238
239
240
241 public static void main(final String[] args) throws SimRuntimeException
242 {
243 AbstractGTU.ALIGNED = false;
244 long t1 = System.currentTimeMillis();
245 boolean autorun = false;
246 int replication = 1;
247 String anticipationStrategy = "none";
248 Duration reactionTime = Duration.createSI(0.0);
249 Duration anticipationTime = Duration.ZERO;
250 double truckFraction = 0.05;
251 double distanceError = 0.0;
252 double speedError = 0.0;
253 double accelerationError = 0.0;
254 Frequency leftDemand = new Frequency(3500.0, FrequencyUnit.PER_HOUR);
255 Frequency rightDemand = new Frequency(3200.0, FrequencyUnit.PER_HOUR);
256 double leftFraction = 0.55;
257 String scenario = "test";
258
259 for (String arg : args)
260 {
261 int equalsPos = arg.indexOf("=");
262 if (equalsPos >= 0)
263 {
264
265 String key = arg.substring(0, equalsPos);
266 String value = arg.substring(equalsPos + 1);
267 if ("autorun".equalsIgnoreCase(key))
268 {
269 if ("true".equalsIgnoreCase(value))
270 {
271 autorun = true;
272 }
273 else if ("false".equalsIgnoreCase(value))
274 {
275 autorun = false;
276 }
277 else
278 {
279 System.err.println("bad autorun value " + value + " (ignored)");
280 }
281 }
282 else if ("replication".equalsIgnoreCase(key))
283 {
284 try
285 {
286 replication = Integer.parseInt(value);
287 }
288 catch (NumberFormatException nfe)
289 {
290 System.err.println("Ignoring unparsable replication number \"" + value + "\"");
291 }
292 }
293 else if ("anticipation".equalsIgnoreCase(key))
294 {
295 if (value.equalsIgnoreCase("none") || value.equalsIgnoreCase("constant_speed")
296 || value.equalsIgnoreCase("constant_acceleration"))
297 {
298 anticipationStrategy = value;
299 }
300 else
301 {
302 System.err.println("Ignoring unparsable anticipation \"" + value + "\"");
303 }
304 }
305 else if ("reactiontime".equalsIgnoreCase(key))
306 {
307 try
308 {
309 reactionTime = Duration.createSI(java.lang.Double.parseDouble(value));
310 }
311 catch (NumberFormatException nfe)
312 {
313 System.err.println("Ignoring unparsable reaction time \"" + value + "\"");
314 }
315 }
316 else if ("anticipationtime".equalsIgnoreCase(key))
317 {
318 try
319 {
320 anticipationTime = Duration.createSI(java.lang.Double.parseDouble(value));
321 }
322 catch (NumberFormatException nfe)
323 {
324 System.err.println("Ignoring unparsable anticipation time \"" + value + "\"");
325 }
326 }
327 else if ("truckfraction".equalsIgnoreCase(key))
328 {
329 try
330 {
331 truckFraction = java.lang.Double.parseDouble(value);
332 Throw.when(truckFraction < 0.0 || truckFraction > 1.0, IllegalArgumentException.class,
333 "Truck fraction must be between 0 and 1.");
334 }
335 catch (NumberFormatException nfe)
336 {
337 System.err.println("Ignoring unparsable truck fraction \"" + value + "\"");
338 }
339 }
340 else if ("distanceerror".equalsIgnoreCase(key))
341 {
342 try
343 {
344 distanceError = java.lang.Double.parseDouble(value);
345 }
346 catch (NumberFormatException nfe)
347 {
348 System.err.println("Ignoring unparsable distance error \"" + value + "\"");
349 }
350 }
351 else if ("speederror".equalsIgnoreCase(key))
352 {
353 try
354 {
355 speedError = java.lang.Double.parseDouble(value);
356 }
357 catch (NumberFormatException nfe)
358 {
359 System.err.println("Ignoring unparsable speed error \"" + value + "\"");
360 }
361 }
362 else if ("accelerationerror".equalsIgnoreCase(key))
363 {
364 try
365 {
366 accelerationError = java.lang.Double.parseDouble(value);
367 }
368 catch (NumberFormatException nfe)
369 {
370 System.err.println("Ignoring unparsable acceleration error \"" + value + "\"");
371 }
372 }
373 else if ("leftdemand".equalsIgnoreCase(key))
374 {
375 try
376 {
377 leftDemand = new Frequency(java.lang.Double.parseDouble(value), FrequencyUnit.PER_HOUR);
378 }
379 catch (NumberFormatException nfe)
380 {
381 System.err.println("Ignoring unparsable left demand \"" + value + "\"");
382 }
383 }
384 else if ("rightdemand".equalsIgnoreCase(key))
385 {
386 try
387 {
388 rightDemand = new Frequency(java.lang.Double.parseDouble(value), FrequencyUnit.PER_HOUR);
389 }
390 catch (NumberFormatException nfe)
391 {
392 System.err.println("Ignoring unparsable right demand \"" + value + "\"");
393 }
394 }
395 else if ("leftfraction".equalsIgnoreCase(key))
396 {
397 try
398 {
399 leftFraction = java.lang.Double.parseDouble(value);
400 }
401 catch (NumberFormatException nfe)
402 {
403 System.err.println("Ignoring unparsable left fraction \"" + value + "\"");
404 }
405 }
406 else if ("scenario".equalsIgnoreCase(key))
407 {
408 scenario = value;
409 }
410 else
411 {
412 System.out.println("Ignoring unknown setting " + arg);
413 }
414 }
415 else
416 {
417
418 System.err.println("Ignoring argument " + arg);
419 }
420 }
421 final boolean finalAutoRun = autorun;
422 final int finalReplication = replication;
423 final String finalAnticipationStrategy = anticipationStrategy;
424 final Duration finalReactionTime = reactionTime;
425 final Duration finalAnticipationTime = anticipationTime;
426 final double finalTruckFraction = truckFraction;
427 final double finalDistanceError = distanceError;
428 final double finalSpeedError = speedError;
429 final double finalAccelerationError = accelerationError;
430 final Frequency finalLeftDemand = leftDemand;
431 final Frequency finalRightDemand = rightDemand;
432 final double finalLeftFraction = leftFraction;
433 final String finalScenario = scenario;
434 SwingUtilities.invokeLater(new Runnable()
435 {
436 @Override
437 public void run()
438 {
439 try
440 {
441 AHFEAnimation model = new AHFEAnimation(finalReplication, finalAnticipationStrategy, finalReactionTime,
442 finalAnticipationTime, finalTruckFraction, finalDistanceError, finalSpeedError,
443 finalAccelerationError, finalLeftDemand, finalRightDemand, finalLeftFraction);
444 System.out.println("Setting up replication " + finalReplication);
445 model.setNextReplication(finalReplication);
446
447 model.buildAnimator(Time.ZERO, Duration.ZERO, Duration.createSI(SIMEND.si), new ArrayList<Property<?>>(),
448 null, true);
449 if (finalAutoRun)
450 {
451 int lastReportedTime = -1;
452 int reportTimeClick = 60;
453 while (true)
454 {
455 int currentTime = (int) model.getSimulator().getSimulatorTime().getTime().si;
456 if (currentTime >= lastReportedTime + reportTimeClick)
457 {
458 lastReportedTime = currentTime / reportTimeClick * reportTimeClick;
459 System.out.println("time is " + model.getSimulator().getSimulatorTime().getTime());
460 }
461 try
462 {
463 model.getSimulator().step();
464 }
465 catch (SimRuntimeException sre)
466 {
467 if (sre.getCause() != null && sre.getCause().getCause() != null
468 && sre.getCause().getCause().getMessage().equals(
469 "Model has calcalated a negative infinite or negative max value acceleration."))
470 {
471 System.err.println("Collision detected.");
472 String file = finalScenario + ".csv.zip";
473 FileOutputStream fos = null;
474 ZipOutputStream zos = null;
475 OutputStreamWriter osw = null;
476 BufferedWriter bw = null;
477 try
478 {
479 fos = new FileOutputStream(file);
480 zos = new ZipOutputStream(fos);
481 zos.putNextEntry(new ZipEntry(finalScenario + ".csv"));
482 osw = new OutputStreamWriter(zos);
483 bw = new BufferedWriter(osw);
484 bw.write("Collision");
485 bw.write(model.getSimulator().getSimulatorTime().getTime().toString());
486 }
487 catch (IOException exception2)
488 {
489 throw new RuntimeException("Could not write to file.", exception2);
490 }
491
492 finally
493 {
494 try
495 {
496 if (bw != null)
497 {
498 bw.close();
499 }
500 if (osw != null)
501 {
502 osw.close();
503 }
504 if (zos != null)
505 {
506 zos.close();
507 }
508 if (fos != null)
509 {
510 fos.close();
511 }
512 }
513 catch (IOException ex)
514 {
515 ex.printStackTrace();
516 }
517 }
518 }
519 else
520 {
521 System.out.println(
522 "Simulation ends; time is " + model.getSimulator().getSimulatorTime().getTime());
523 if (model.sampler != null)
524 {
525 model.sampler.writeToFile(finalScenario + ".csv");
526 }
527 }
528 long t2 = System.currentTimeMillis();
529 System.out.println("Run took " + (t2 - t1) / 1000 + "s.");
530 System.exit(0);
531 break;
532 }
533 }
534
535 }
536 }
537 catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException
538 | RemoteException exception)
539 {
540 exception.printStackTrace();
541 }
542 }
543 });
544 }
545
546
547 private SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator;
548
549
550 @Override
551 public final String shortName()
552 {
553 return "AFFE Simulation";
554 }
555
556
557 @Override
558 public final String description()
559 {
560 return "Simulation for AHFE congress";
561 }
562
563
564 @Override
565 protected final OTSModelInterface makeModel() throws OTSSimulationException
566 {
567 return new AHFEModel();
568 }
569
570
571 @Override
572 protected final void addAnimationToggles()
573 {
574 AnimationToggles.setTextAnimationTogglesStandard(this);
575 }
576
577
578 @Override
579 protected final Double makeAnimationRectangle()
580 {
581 return new Rectangle2D.Double(-50, -100, 8050, 150);
582 }
583
584
585
586
587 class AHFEModel extends EventProducer implements OTSModelInterface
588 {
589
590
591 private static final long serialVersionUID = 20170228L;
592
593
594 private OTSNetwork network;
595
596
597 @SuppressWarnings("synthetic-access")
598 @Override
599 public void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
600 throws SimRuntimeException, RemoteException
601 {
602 AHFEAnimation.this.simulator = theSimulator;
603
604 AHFEAnimation.this.sampler = new RoadSampler((OTSDEVSSimulatorInterface) theSimulator);
605 AHFEAnimation.this.sampler.registerExtendedDataType(new TimeToCollision());
606 try
607 {
608 InputStream stream = URLResource.getResourceAsStream("/AHFE/Network.xml");
609 XmlNetworkLaneParser nlp = new XmlNetworkLaneParser((OTSDEVSSimulatorInterface) theSimulator);
610 this.network = new OTSNetwork("AHFE");
611 nlp.build(stream, this.network, true);
612
613
614 LinkData linkData = new LinkData((CrossSectionLink) this.network.getLink("LEFTIN"));
615 registerLinkToSampler(linkData, ignoreStart, linkData.getLength());
616 linkData = new LinkData((CrossSectionLink) this.network.getLink("RIGHTIN"));
617 registerLinkToSampler(linkData, ignoreStart, linkData.getLength());
618 linkData = new LinkData((CrossSectionLink) this.network.getLink("CONVERGE"));
619 registerLinkToSampler(linkData, Length.ZERO, linkData.getLength());
620 linkData = new LinkData((CrossSectionLink) this.network.getLink("WEAVING"));
621 registerLinkToSampler(linkData, Length.ZERO, linkData.getLength());
622 linkData = new LinkData((CrossSectionLink) this.network.getLink("END"));
623 registerLinkToSampler(linkData, Length.ZERO, linkData.getLength().minus(ignoreEnd));
624
625
626 AHFEUtil.createDemand(this.network, AHFEAnimation.this.getColorer(), (OTSDEVSSimulatorInterface) theSimulator,
627 getReplication(), getAnticipationStrategy(), getReactionTime(), getAnticipationTime(),
628 getTruckFraction(), SIMEND, getLeftDemand(), getRightDemand(), getLeftFraction(), getDistanceError(),
629 getSpeedError(), getAccelerationError());
630
631 }
632 catch (Exception exception)
633 {
634 exception.printStackTrace();
635 }
636 }
637
638
639
640
641
642
643
644 private void registerLinkToSampler(final LinkData linkData, final Length startDistance, final Length endDistance)
645 {
646 for (LaneDataInterface laneData : linkData.getLaneDatas())
647 {
648 Length start = laneData.getLength().multiplyBy(startDistance.si / linkData.getLength().si);
649 Length end = laneData.getLength().multiplyBy(endDistance.si / linkData.getLength().si);
650 AHFEAnimation.this.sampler.registerSpaceTimeRegion(new SpaceTimeRegion(
651 new KpiLaneDirection(laneData, KpiGtuDirectionality.DIR_PLUS), start, end, WARMUP, SIMEND));
652 }
653 }
654
655
656 @SuppressWarnings("synthetic-access")
657 @Override
658 public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
659 {
660 return AHFEAnimation.this.simulator;
661 }
662
663
664 @Override
665 public OTSNetwork getNetwork()
666 {
667 return this.network;
668 }
669
670 }
671
672
673
674
675
676 public final SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
677 {
678 return this.simulator;
679 }
680
681 }