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