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.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   * 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.createSI(360);
65  
66      /** Simulation time, including warm-up time. */
67      static final Time SIMEND = Time.createSI(360 + 3600);
68  
69      /** Distance to not consider at start of the network. */
70      private static Length ignoreStart = Length.createSI(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.createSI(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.createSI(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.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                 // 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.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                                     // 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                 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                 // Space-time regions for sampler
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                 // Generator
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          * Register a link to the sampler, so data is sampled there.
528          * @param linkData LinkData; link data
529          * @param startDistance Length; start distance on link
530          * @param endDistance Length; end distance on link
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         /** {@inheritDoc} */
544         @Override
545         public OTSRoadNetwork getNetwork()
546         {
547             return this.network;
548         }
549 
550         /**
551          * @return replication.
552          */
553         public Integer getReplication()
554         {
555             return this.replication;
556         }
557 
558         /**
559          * @return anticipationStrategy.
560          */
561         public String getAnticipationStrategy()
562         {
563             return this.anticipationStrategy;
564         }
565 
566         /**
567          * @return reactionTime.
568          */
569         public Duration getReactionTime()
570         {
571             return this.reactionTime;
572         }
573 
574         /**
575          * @return anticipationTime.
576          */
577         public Duration getAnticipationTime()
578         {
579             return this.anticipationTime;
580         }
581 
582         /**
583          * @return truckFraction.
584          */
585         public double getTruckFraction()
586         {
587             return this.truckFraction;
588         }
589 
590         /**
591          * @return distanceError.
592          */
593         public double getDistanceError()
594         {
595             return this.distanceError;
596         }
597 
598         /**
599          * @return speedError.
600          */
601         public double getSpeedError()
602         {
603             return this.speedError;
604         }
605 
606         /**
607          * @return accelerationError.
608          */
609         public double getAccelerationError()
610         {
611             return this.accelerationError;
612         }
613 
614         /**
615          * @return leftDemand.
616          */
617         public Frequency getLeftDemand()
618         {
619             return this.leftDemand;
620         }
621 
622         /**
623          * @return rightDemand.
624          */
625         public Frequency getRightDemand()
626         {
627             return this.rightDemand;
628         }
629 
630         /**
631          * @return leftFraction.
632          */
633         public double getLeftFraction()
634         {
635             return this.leftFraction;
636         }
637 
638         /**
639          * @return sampler
640          */
641         public final Sampler<GtuData> getSampler()
642         {
643             return this.sampler;
644         }
645 
646     }
647 
648 }