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