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.io.Serializable;
11  import java.net.URL;
12  import java.rmi.RemoteException;
13  import java.util.zip.ZipEntry;
14  import java.util.zip.ZipOutputStream;
15  
16  import javax.naming.NamingException;
17  import javax.swing.SwingUtilities;
18  
19  import org.djunits.unit.FrequencyUnit;
20  import org.djunits.value.vdouble.scalar.Duration;
21  import org.djunits.value.vdouble.scalar.Frequency;
22  import org.djunits.value.vdouble.scalar.Length;
23  import org.djunits.value.vdouble.scalar.Time;
24  import org.djutils.exceptions.Throw;
25  import org.djutils.io.URLResource;
26  import org.opentrafficsim.ahfe.AHFEAnimation.AHFEModel;
27  import org.opentrafficsim.core.animation.gtu.colorer.DefaultSwitchableGTUColorer;
28  import org.opentrafficsim.core.dsol.AbstractOTSModel;
29  import org.opentrafficsim.core.dsol.OTSAnimator;
30  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
31  import org.opentrafficsim.core.gtu.AbstractGTU;
32  import org.opentrafficsim.draw.core.OTSDrawingException;
33  import org.opentrafficsim.kpi.interfaces.LaneDataInterface;
34  import org.opentrafficsim.kpi.sampling.KpiGtuDirectionality;
35  import org.opentrafficsim.kpi.sampling.KpiLaneDirection;
36  import org.opentrafficsim.kpi.sampling.Sampler;
37  import org.opentrafficsim.kpi.sampling.SpaceTimeRegion;
38  import org.opentrafficsim.road.network.OTSRoadNetwork;
39  import org.opentrafficsim.road.network.factory.xml.parser.XmlNetworkLaneParser;
40  import org.opentrafficsim.road.network.lane.CrossSectionLink;
41  import org.opentrafficsim.road.network.sampling.GtuData;
42  import org.opentrafficsim.road.network.sampling.LinkData;
43  import org.opentrafficsim.road.network.sampling.RoadSampler;
44  import org.opentrafficsim.road.network.sampling.data.TimeToCollision;
45  import org.opentrafficsim.swing.gui.OTSAnimationPanel;
46  import org.opentrafficsim.swing.gui.OTSSimulationApplication;
47  
48  import nl.tudelft.simulation.dsol.SimRuntimeException;
49  import nl.tudelft.simulation.language.DSOLException;
50  
51  /**
52   * Simulation for AHFE congress.
53   * <p>
54   * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
55   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
56   * <p>
57   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Feb 28, 2017 <br>
58   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
59   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
60   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
61   */
62  public class AHFEAnimation extends OTSSimulationApplication<AHFEModel>
63  {
64  
65      /** Warm-up time. */
66      static final Time WARMUP = Time.instantiateSI(360);
67  
68      /** Simulation time, including warm-up time. */
69      static final Time SIMEND = Time.instantiateSI(360 + 3600);
70  
71      /** Distance to not consider at start of the network. */
72      private static Length ignoreStart = Length.instantiateSI(2900); // Not 100m on pre-link, so 3000 total
73  
74      /** Distance to not consider at end of the network. */
75      private static Length ignoreEnd = Length.instantiateSI(1000);
76  
77      /** */
78      private static final long serialVersionUID = 20170228L;
79  
80      /**
81       * @param title String; the title of the Frame
82       * @param panel OTSAnimationPanel; the tabbed panel to display
83       * @param model AHFEModel; the model
84       * @throws OTSDrawingException on animation error
85       */
86      public AHFEAnimation(final String title, final OTSAnimationPanel panel, final AHFEModel model) throws OTSDrawingException
87      {
88          super(model, panel);
89      }
90  
91      /**
92       * Main program.
93       * @param args String[]; the command line arguments
94       * @throws SimRuntimeException should never happen
95       */
96      @SuppressWarnings("checkstyle:methodlength")
97      public static void main(final String[] args) throws SimRuntimeException
98      {
99          AbstractGTU.ALIGNED = false;
100         long t1 = System.currentTimeMillis();
101         boolean autorun = false;
102         int replication = 1;
103         String anticipationStrategy = "none";
104         Duration reactionTime = Duration.instantiateSI(0.0);
105         Duration anticipationTime = Duration.ZERO;
106         double truckFraction = 0.05;
107         double distanceError = 0.0; // 0.05;
108         double speedError = 0.0; // 0.01;
109         double accelerationError = 0.0; // 0.10;
110         Frequency leftDemand = new Frequency(3500.0, FrequencyUnit.PER_HOUR);
111         Frequency rightDemand = new Frequency(3200.0, FrequencyUnit.PER_HOUR);
112         double leftFraction = 0.55;
113         String scenario = "test";
114 
115         for (String arg : args)
116         {
117             int equalsPos = arg.indexOf("=");
118             if (equalsPos >= 0)
119             {
120                 // set something
121                 String key = arg.substring(0, equalsPos);
122                 String value = arg.substring(equalsPos + 1);
123                 if ("autorun".equalsIgnoreCase(key))
124                 {
125                     if ("true".equalsIgnoreCase(value))
126                     {
127                         autorun = true;
128                     }
129                     else if ("false".equalsIgnoreCase(value))
130                     {
131                         autorun = false;
132                     }
133                     else
134                     {
135                         System.err.println("bad autorun value " + value + " (ignored)");
136                     }
137                 }
138                 else if ("replication".equalsIgnoreCase(key))
139                 {
140                     try
141                     {
142                         replication = Integer.parseInt(value);
143                     }
144                     catch (NumberFormatException nfe)
145                     {
146                         System.err.println("Ignoring unparsable replication number \"" + value + "\"");
147                     }
148                 }
149                 else if ("anticipation".equalsIgnoreCase(key))
150                 {
151                     if (value.equalsIgnoreCase("none") || value.equalsIgnoreCase("constant_speed")
152                             || value.equalsIgnoreCase("constant_acceleration"))
153                     {
154                         anticipationStrategy = value;
155                     }
156                     else
157                     {
158                         System.err.println("Ignoring unparsable anticipation \"" + value + "\"");
159                     }
160                 }
161                 else if ("reactiontime".equalsIgnoreCase(key))
162                 {
163                     try
164                     {
165                         reactionTime = Duration.instantiateSI(java.lang.Double.parseDouble(value));
166                     }
167                     catch (NumberFormatException nfe)
168                     {
169                         System.err.println("Ignoring unparsable reaction time \"" + value + "\"");
170                     }
171                 }
172                 else if ("anticipationtime".equalsIgnoreCase(key))
173                 {
174                     try
175                     {
176                         anticipationTime = Duration.instantiateSI(java.lang.Double.parseDouble(value));
177                     }
178                     catch (NumberFormatException nfe)
179                     {
180                         System.err.println("Ignoring unparsable anticipation time \"" + value + "\"");
181                     }
182                 }
183                 else if ("truckfraction".equalsIgnoreCase(key))
184                 {
185                     try
186                     {
187                         truckFraction = java.lang.Double.parseDouble(value);
188                         Throw.when(truckFraction < 0.0 || truckFraction > 1.0, IllegalArgumentException.class,
189                                 "Truck fraction must be between 0 and 1.");
190                     }
191                     catch (NumberFormatException nfe)
192                     {
193                         System.err.println("Ignoring unparsable truck fraction \"" + value + "\"");
194                     }
195                 }
196                 else if ("distanceerror".equalsIgnoreCase(key))
197                 {
198                     try
199                     {
200                         distanceError = java.lang.Double.parseDouble(value);
201                     }
202                     catch (NumberFormatException nfe)
203                     {
204                         System.err.println("Ignoring unparsable distance error \"" + value + "\"");
205                     }
206                 }
207                 else if ("speederror".equalsIgnoreCase(key))
208                 {
209                     try
210                     {
211                         speedError = java.lang.Double.parseDouble(value);
212                     }
213                     catch (NumberFormatException nfe)
214                     {
215                         System.err.println("Ignoring unparsable speed error \"" + value + "\"");
216                     }
217                 }
218                 else if ("accelerationerror".equalsIgnoreCase(key))
219                 {
220                     try
221                     {
222                         accelerationError = java.lang.Double.parseDouble(value);
223                     }
224                     catch (NumberFormatException nfe)
225                     {
226                         System.err.println("Ignoring unparsable acceleration error \"" + value + "\"");
227                     }
228                 }
229                 else if ("leftdemand".equalsIgnoreCase(key))
230                 {
231                     try
232                     {
233                         leftDemand = new Frequency(java.lang.Double.parseDouble(value), FrequencyUnit.PER_HOUR);
234                     }
235                     catch (NumberFormatException nfe)
236                     {
237                         System.err.println("Ignoring unparsable left demand \"" + value + "\"");
238                     }
239                 }
240                 else if ("rightdemand".equalsIgnoreCase(key))
241                 {
242                     try
243                     {
244                         rightDemand = new Frequency(java.lang.Double.parseDouble(value), FrequencyUnit.PER_HOUR);
245                     }
246                     catch (NumberFormatException nfe)
247                     {
248                         System.err.println("Ignoring unparsable right demand \"" + value + "\"");
249                     }
250                 }
251                 else if ("leftfraction".equalsIgnoreCase(key))
252                 {
253                     try
254                     {
255                         leftFraction = java.lang.Double.parseDouble(value);
256                     }
257                     catch (NumberFormatException nfe)
258                     {
259                         System.err.println("Ignoring unparsable left fraction \"" + value + "\"");
260                     }
261                 }
262                 else if ("scenario".equalsIgnoreCase(key))
263                 {
264                     scenario = value;
265                 }
266                 else
267                 {
268                     System.out.println("Ignoring unknown setting " + arg);
269                 }
270             }
271             else
272             {
273                 // not a flag
274                 System.err.println("Ignoring argument " + arg);
275             }
276         }
277         final boolean finalAutoRun = autorun;
278         final int finalReplication = replication;
279         final String finalAnticipationStrategy = anticipationStrategy;
280         final Duration finalReactionTime = reactionTime;
281         final Duration finalAnticipationTime = anticipationTime;
282         final double finalTruckFraction = truckFraction;
283         final double finalDistanceError = distanceError;
284         final double finalSpeedError = speedError;
285         final double finalAccelerationError = accelerationError;
286         final Frequency finalLeftDemand = leftDemand;
287         final Frequency finalRightDemand = rightDemand;
288         final double finalLeftFraction = leftFraction;
289         final String finalScenario = scenario;
290         SwingUtilities.invokeLater(new Runnable()
291         {
292             @Override
293             public void run()
294             {
295                 try
296                 {
297                     OTSAnimator simulator = new OTSAnimator("AHFEAnimation");
298                     final AHFEModel ahfeModel = new AHFEModel(simulator, finalReplication, finalAnticipationStrategy,
299                             finalReactionTime, finalAnticipationTime, finalTruckFraction, finalDistanceError, finalSpeedError,
300                             finalAccelerationError, finalLeftDemand, finalRightDemand, finalLeftFraction);
301                     System.out.println("Setting up replication " + finalReplication);
302                     simulator.initialize(Time.ZERO, Duration.ZERO, Duration.instantiateSI(SIMEND.si), ahfeModel, finalReplication);
303                     OTSAnimationPanel animationPanel = new OTSAnimationPanel(ahfeModel.getNetwork().getExtent(),
304                             new Dimension(800, 600), simulator, ahfeModel, DEFAULT_COLORER, ahfeModel.getNetwork());
305                     new AHFEAnimation("AHFE", animationPanel, ahfeModel);
306                     if (finalAutoRun)
307                     {
308                         int lastReportedTime = -1;
309                         int reportTimeClick = 60;
310                         while (true)
311                         {
312                             int currentTime = (int) simulator.getSimulatorTime().si;
313                             if (currentTime >= lastReportedTime + reportTimeClick)
314                             {
315                                 lastReportedTime = currentTime / reportTimeClick * reportTimeClick;
316                                 System.out.println("time is " + simulator.getSimulatorTime());
317                             }
318                             try
319                             {
320                                 simulator.step();
321                             }
322                             catch (SimRuntimeException sre)
323                             {
324                                 if (sre.getCause() != null && sre.getCause().getCause() != null
325                                         && sre.getCause().getCause().getMessage().equals(
326                                                 "Model has calcalated a negative infinite or negative max value acceleration."))
327                                 {
328                                     System.err.println("Collision detected.");
329                                     String file = finalScenario + ".csv.zip";
330                                     FileOutputStream fos = null;
331                                     ZipOutputStream zos = null;
332                                     OutputStreamWriter osw = null;
333                                     BufferedWriter bw = null;
334                                     try
335                                     {
336                                         fos = new FileOutputStream(file);
337                                         zos = new ZipOutputStream(fos);
338                                         zos.putNextEntry(new ZipEntry(finalScenario + ".csv"));
339                                         osw = new OutputStreamWriter(zos);
340                                         bw = new BufferedWriter(osw);
341                                         bw.write("Collision");
342                                         bw.write(simulator.getSimulatorTime().toString());
343                                     }
344                                     catch (IOException exception2)
345                                     {
346                                         throw new RuntimeException("Could not write to file.", exception2);
347                                     }
348                                     // close file on fail
349                                     finally
350                                     {
351                                         try
352                                         {
353                                             if (bw != null)
354                                             {
355                                                 bw.close();
356                                             }
357                                             if (osw != null)
358                                             {
359                                                 osw.close();
360                                             }
361                                             if (zos != null)
362                                             {
363                                                 zos.close();
364                                             }
365                                             if (fos != null)
366                                             {
367                                                 fos.close();
368                                             }
369                                         }
370                                         catch (IOException ex)
371                                         {
372                                             ex.printStackTrace();
373                                         }
374                                     }
375                                 }
376                                 else
377                                 {
378                                     System.out.println("Simulation ends; time is " + simulator.getSimulatorTime());
379                                     if (ahfeModel.getSampler() != null)
380                                     {
381                                         ahfeModel.getSampler().getSamplerData().writeToFile(finalScenario + ".csv");
382                                     }
383                                 }
384                                 long t2 = System.currentTimeMillis();
385                                 System.out.println("Run took " + (t2 - t1) / 1000 + "s.");
386                                 System.exit(0);
387                                 break;
388                             }
389                         }
390 
391                     }
392                 }
393                 catch (SimRuntimeException | NamingException | RemoteException | OTSDrawingException | DSOLException exception)
394                 {
395                     exception.printStackTrace();
396                 }
397             }
398         });
399     }
400 
401     /** {@inheritDoc} */
402     @Override
403     protected final Double makeAnimationRectangle()
404     {
405         return new Rectangle2D.Double(-50, -100, 8050, 150);
406     }
407 
408     /**
409      * The AHFE simulation model.
410      */
411     static class AHFEModel extends AbstractOTSModel
412     {
413         /** */
414         private static final long serialVersionUID = 20170228L;
415 
416         /** The network. */
417         private OTSRoadNetwork network;
418 
419         /** Replication. */
420         private final Integer replication;
421 
422         /** Anticipation strategy. */
423         private final String anticipationStrategy;
424 
425         /** Reaction time. */
426         private final Duration reactionTime;
427 
428         /** Future anticipation time. */
429         private final Duration anticipationTime;
430 
431         /** Truck fraction. */
432         private final double truckFraction;
433 
434         /** Distance error. */
435         private final double distanceError;
436 
437         /** Speed error. */
438         private final double speedError;
439 
440         /** Acceleration error. */
441         private final double accelerationError;
442 
443         /** Left demand. */
444         private final Frequency leftDemand;
445 
446         /** Right demand. */
447         private final Frequency rightDemand;
448 
449         /** Left fraction, per road. */
450         private final double leftFraction;
451 
452         /** Sampler. */
453         private Sampler<GtuData> sampler;
454 
455         /**
456          * @param simulator OTSSimulatorInterface; the simulator
457          * @param replication Integer; replication
458          * @param anticipationStrategy String; anticipation strategy
459          * @param reactionTime Duration; reaction time
460          * @param anticipationTime Duration; anticipation time
461          * @param truckFraction double; truck fraction
462          * @param distanceError double; distance error
463          * @param speedError double; speed error
464          * @param accelerationError double; acceleration error
465          * @param leftFraction double; left demand
466          * @param rightDemand Frequency; right demand
467          * @param leftDemand Frequency; left fraction, per road
468          */
469         @SuppressWarnings("checkstyle:parameternumber")
470         AHFEModel(final OTSSimulatorInterface simulator, final Integer replication, final String anticipationStrategy,
471                 final Duration reactionTime, final Duration anticipationTime, final double truckFraction,
472                 final double distanceError, final double speedError, final double accelerationError, final Frequency leftDemand,
473                 final Frequency rightDemand, final double leftFraction)
474         {
475             super(simulator);
476             this.replication = replication;
477             this.anticipationStrategy = anticipationStrategy;
478             this.reactionTime = reactionTime;
479             this.anticipationTime = anticipationTime;
480             this.truckFraction = truckFraction;
481             this.distanceError = distanceError;
482             this.speedError = speedError;
483             this.accelerationError = accelerationError;
484             this.leftDemand = leftDemand;
485             this.rightDemand = rightDemand;
486             this.leftFraction = leftFraction;
487         }
488 
489         /** {@inheritDoc} */
490         @SuppressWarnings("synthetic-access")
491         @Override
492         public void constructModel() throws SimRuntimeException
493         {
494             this.sampler = RoadSampler.build(this.network).registerExtendedDataType(new TimeToCollision()).create();
495             try
496             {
497                 URL xmlURL = URLResource.getResource("/AHFE/Network.xml");
498                 this.network = new OTSRoadNetwork("AHFE", true, getSimulator());
499                 XmlNetworkLaneParser.build(xmlURL, this.network, false);
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().times(startDistance.si / linkData.getLength().si);
537                 Length end = laneData.getLength().times(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         /** {@inheritDoc} */
647         @Override
648         public Serializable getSourceId()
649         {
650             return "AHFEAnimation.Model";
651         }
652 
653     }
654 
655 }