View Javadoc
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.OutputStreamWriter;
10  import java.net.URL;
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.parser.XmlNetworkLaneParser;
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   * Simulation for AHFE congress.
51   * <p>
52   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
53   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
54   * <p>
55   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Feb 28, 2017 <br>
56   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
57   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
58   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
59   */
60  public class AHFEAnimation extends OTSSimulationApplication<AHFEModel>
61  {
62  
63      /** Warm-up time. */
64      static final Time WARMUP = Time.instantiateSI(360);
65  
66      /** Simulation time, including warm-up time. */
67      static final Time SIMEND = Time.instantiateSI(360 + 3600);
68  
69      /** Distance to not consider at start of the network. */
70      private static Length ignoreStart = Length.instantiateSI(2900); // Not 100m on pre-link, so 3000 total
71  
72      /** Distance to not consider at end of the network. */
73      private static Length ignoreEnd = Length.instantiateSI(1000);
74  
75      /** */
76      private static final long serialVersionUID = 20170228L;
77  
78      /**
79       * @param title String; the title of the Frame
80       * @param panel OTSAnimationPanel; the tabbed panel to display
81       * @param model AHFEModel; the model
82       * @throws OTSDrawingException on animation error
83       */
84      public AHFEAnimation(final String title, final OTSAnimationPanel panel, final AHFEModel model) throws OTSDrawingException
85      {
86          super(model, panel);
87      }
88  
89      /**
90       * Main program.
91       * @param args String[]; the command line arguments
92       * @throws SimRuntimeException should never happen
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.instantiateSI(0.0);
103         Duration anticipationTime = Duration.ZERO;
104         double truckFraction = 0.05;
105         double distanceError = 0.0; // 0.05;
106         double speedError = 0.0; // 0.01;
107         double accelerationError = 0.0; // 0.10;
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                 // set something
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.instantiateSI(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.instantiateSI(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                 // not a flag
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.instantiateSI(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                                     // close file on fail
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     /** {@inheritDoc} */
400     @Override
401     protected final Double makeAnimationRectangle()
402     {
403         return new Rectangle2D.Double(-50, -100, 8050, 150);
404     }
405 
406     /**
407      * The AHFE simulation model.
408      */
409     static class AHFEModel extends AbstractOTSModel
410     {
411         /** */
412         private static final long serialVersionUID = 20170228L;
413 
414         /** The network. */
415         private OTSRoadNetwork network;
416 
417         /** Replication. */
418         private final Integer replication;
419 
420         /** Anticipation strategy. */
421         private final String anticipationStrategy;
422 
423         /** Reaction time. */
424         private final Duration reactionTime;
425 
426         /** Future anticipation time. */
427         private final Duration anticipationTime;
428 
429         /** Truck fraction. */
430         private final double truckFraction;
431 
432         /** Distance error. */
433         private final double distanceError;
434 
435         /** Speed error. */
436         private final double speedError;
437 
438         /** Acceleration error. */
439         private final double accelerationError;
440 
441         /** Left demand. */
442         private final Frequency leftDemand;
443 
444         /** Right demand. */
445         private final Frequency rightDemand;
446 
447         /** Left fraction, per road. */
448         private final double leftFraction;
449 
450         /** Sampler. */
451         private Sampler<GtuData> sampler;
452 
453         /**
454          * @param simulator OTSSimulatorInterface; the simulator
455          * @param replication Integer; replication
456          * @param anticipationStrategy String; anticipation strategy
457          * @param reactionTime Duration; reaction time
458          * @param anticipationTime Duration; anticipation time
459          * @param truckFraction double; truck fraction
460          * @param distanceError double; distance error
461          * @param speedError double; speed error
462          * @param accelerationError double; acceleration error
463          * @param leftFraction double; left demand
464          * @param rightDemand Frequency; right demand
465          * @param leftDemand Frequency; left fraction, per road
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         /** {@inheritDoc} */
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                 URL xmlURL = URLResource.getResource("/AHFE/Network.xml");
497                 this.network = new OTSRoadNetwork("AHFE", true);
498                 XmlNetworkLaneParser.build(xmlURL, this.network, getSimulator());
499 
500                 // Space-time regions for sampler
501                 LinkData linkData = new LinkData((CrossSectionLink) this.network.getLink("LEFTIN"));
502                 registerLinkToSampler(linkData, ignoreStart, linkData.getLength());
503                 linkData = new LinkData((CrossSectionLink) this.network.getLink("RIGHTIN"));
504                 registerLinkToSampler(linkData, ignoreStart, linkData.getLength());
505                 linkData = new LinkData((CrossSectionLink) this.network.getLink("CONVERGE"));
506                 registerLinkToSampler(linkData, Length.ZERO, linkData.getLength());
507                 linkData = new LinkData((CrossSectionLink) this.network.getLink("WEAVING"));
508                 registerLinkToSampler(linkData, Length.ZERO, linkData.getLength());
509                 linkData = new LinkData((CrossSectionLink) this.network.getLink("END"));
510                 registerLinkToSampler(linkData, Length.ZERO, linkData.getLength().minus(ignoreEnd));
511 
512                 // Generator
513                 AHFEUtil.createDemand(this.network, new DefaultSwitchableGTUColorer(), this.simulator, getReplication(),
514                         getAnticipationStrategy(), getReactionTime(), getAnticipationTime(), getTruckFraction(), SIMEND,
515                         getLeftDemand(), getRightDemand(), getLeftFraction(), getDistanceError(), getSpeedError(),
516                         getAccelerationError());
517 
518             }
519             catch (Exception exception)
520             {
521                 exception.printStackTrace();
522             }
523         }
524 
525         /**
526          * Register a link to the sampler, so data is sampled there.
527          * @param linkData LinkData; link data
528          * @param startDistance Length; start distance on link
529          * @param endDistance Length; end distance on link
530          */
531         private void registerLinkToSampler(final LinkData linkData, final Length startDistance, final Length endDistance)
532         {
533             for (LaneDataInterface laneData : linkData.getLaneDatas())
534             {
535                 Length start = laneData.getLength().times(startDistance.si / linkData.getLength().si);
536                 Length end = laneData.getLength().times(endDistance.si / linkData.getLength().si);
537                 this.sampler.registerSpaceTimeRegion(new SpaceTimeRegion(
538                         new KpiLaneDirection(laneData, KpiGtuDirectionality.DIR_PLUS), start, end, WARMUP, SIMEND));
539             }
540         }
541 
542         /** {@inheritDoc} */
543         @Override
544         public OTSRoadNetwork getNetwork()
545         {
546             return this.network;
547         }
548 
549         /**
550          * @return replication.
551          */
552         public Integer getReplication()
553         {
554             return this.replication;
555         }
556 
557         /**
558          * @return anticipationStrategy.
559          */
560         public String getAnticipationStrategy()
561         {
562             return this.anticipationStrategy;
563         }
564 
565         /**
566          * @return reactionTime.
567          */
568         public Duration getReactionTime()
569         {
570             return this.reactionTime;
571         }
572 
573         /**
574          * @return anticipationTime.
575          */
576         public Duration getAnticipationTime()
577         {
578             return this.anticipationTime;
579         }
580 
581         /**
582          * @return truckFraction.
583          */
584         public double getTruckFraction()
585         {
586             return this.truckFraction;
587         }
588 
589         /**
590          * @return distanceError.
591          */
592         public double getDistanceError()
593         {
594             return this.distanceError;
595         }
596 
597         /**
598          * @return speedError.
599          */
600         public double getSpeedError()
601         {
602             return this.speedError;
603         }
604 
605         /**
606          * @return accelerationError.
607          */
608         public double getAccelerationError()
609         {
610             return this.accelerationError;
611         }
612 
613         /**
614          * @return leftDemand.
615          */
616         public Frequency getLeftDemand()
617         {
618             return this.leftDemand;
619         }
620 
621         /**
622          * @return rightDemand.
623          */
624         public Frequency getRightDemand()
625         {
626             return this.rightDemand;
627         }
628 
629         /**
630          * @return leftFraction.
631          */
632         public double getLeftFraction()
633         {
634             return this.leftFraction;
635         }
636 
637         /**
638          * @return sampler
639          */
640         public final Sampler<GtuData> getSampler()
641         {
642             return this.sampler;
643         }
644 
645     }
646 
647 }