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