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