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.animation.GTUColorer;
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.LinkData;
39  import org.opentrafficsim.road.network.sampling.RoadSampler;
40  import org.opentrafficsim.road.network.sampling.data.TimeToCollision;
41  import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
42  import org.opentrafficsim.simulationengine.OTSSimulationException;
43  
44  import nl.tudelft.simulation.dsol.SimRuntimeException;
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-2017 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 AHFESimulation 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 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 AHFESimulation(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         long t1 = System.currentTimeMillis();
243         boolean autorun = false;
244         int replication = 1;
245         String anticipationStrategy = "none";
246         Duration reactionTime = Duration.createSI(0.0);
247         Duration anticipationTime = Duration.ZERO;
248         double truckFraction = 0.05;
249         double distanceError = 0.0; // 0.05;
250         double speedError = 0.0; // 0.01;
251         double accelerationError = 0.0; // 0.10;
252         Frequency leftDemand = new Frequency(3500.0, FrequencyUnit.PER_HOUR);
253         Frequency rightDemand = new Frequency(3200.0, FrequencyUnit.PER_HOUR);
254         double leftFraction = 0.55;
255         String scenario = "test";
256 
257         for (String arg : args)
258         {
259             int equalsPos = arg.indexOf("=");
260             if (equalsPos >= 0)
261             {
262                 // set something
263                 String key = arg.substring(0, equalsPos);
264                 String value = arg.substring(equalsPos + 1);
265                 if ("autorun".equalsIgnoreCase(key))
266                 {
267                     if ("true".equalsIgnoreCase(value))
268                     {
269                         autorun = true;
270                     }
271                     else if ("false".equalsIgnoreCase(value))
272                     {
273                         autorun = false;
274                     }
275                     else
276                     {
277                         System.err.println("bad autorun value " + value + " (ignored)");
278                     }
279                 }
280                 else if ("replication".equalsIgnoreCase(key))
281                 {
282                     try
283                     {
284                         replication = Integer.parseInt(value);
285                     }
286                     catch (NumberFormatException nfe)
287                     {
288                         System.err.println("Ignoring unparsable replication number \"" + value + "\"");
289                     }
290                 }
291                 else if ("anticipation".equalsIgnoreCase(key))
292                 {
293                     if (value.equalsIgnoreCase("none") || value.equalsIgnoreCase("constant_speed")
294                             || value.equalsIgnoreCase("constant_acceleration"))
295                     {
296                         anticipationStrategy = value;
297                     }
298                     else
299                     {
300                         System.err.println("Ignoring unparsable anticipation \"" + value + "\"");
301                     }
302                 }
303                 else if ("reactiontime".equalsIgnoreCase(key))
304                 {
305                     try
306                     {
307                         reactionTime = Duration.createSI(java.lang.Double.parseDouble(value));
308                     }
309                     catch (NumberFormatException nfe)
310                     {
311                         System.err.println("Ignoring unparsable reaction time \"" + value + "\"");
312                     }
313                 }
314                 else if ("anticipationtime".equalsIgnoreCase(key))
315                 {
316                     try
317                     {
318                         anticipationTime = Duration.createSI(java.lang.Double.parseDouble(value));
319                     }
320                     catch (NumberFormatException nfe)
321                     {
322                         System.err.println("Ignoring unparsable anticipation time \"" + value + "\"");
323                     }
324                 }
325                 else if ("truckfraction".equalsIgnoreCase(key))
326                 {
327                     try
328                     {
329                         truckFraction = java.lang.Double.parseDouble(value);
330                         Throw.when(truckFraction < 0.0 || truckFraction > 1.0, IllegalArgumentException.class,
331                                 "Truck fraction must be between 0 and 1.");
332                     }
333                     catch (NumberFormatException nfe)
334                     {
335                         System.err.println("Ignoring unparsable truck fraction \"" + value + "\"");
336                     }
337                 }
338                 else if ("distanceerror".equalsIgnoreCase(key))
339                 {
340                     try
341                     {
342                         distanceError = java.lang.Double.parseDouble(value);
343                     }
344                     catch (NumberFormatException nfe)
345                     {
346                         System.err.println("Ignoring unparsable distance error \"" + value + "\"");
347                     }
348                 }
349                 else if ("speederror".equalsIgnoreCase(key))
350                 {
351                     try
352                     {
353                         speedError = java.lang.Double.parseDouble(value);
354                     }
355                     catch (NumberFormatException nfe)
356                     {
357                         System.err.println("Ignoring unparsable speed error \"" + value + "\"");
358                     }
359                 }
360                 else if ("accelerationerror".equalsIgnoreCase(key))
361                 {
362                     try
363                     {
364                         accelerationError = java.lang.Double.parseDouble(value);
365                     }
366                     catch (NumberFormatException nfe)
367                     {
368                         System.err.println("Ignoring unparsable acceleration error \"" + value + "\"");
369                     }
370                 }
371                 else if ("leftdemand".equalsIgnoreCase(key))
372                 {
373                     try
374                     {
375                         leftDemand = new Frequency(java.lang.Double.parseDouble(value), FrequencyUnit.PER_HOUR);
376                     }
377                     catch (NumberFormatException nfe)
378                     {
379                         System.err.println("Ignoring unparsable left demand \"" + value + "\"");
380                     }
381                 }
382                 else if ("rightdemand".equalsIgnoreCase(key))
383                 {
384                     try
385                     {
386                         rightDemand = new Frequency(java.lang.Double.parseDouble(value), FrequencyUnit.PER_HOUR);
387                     }
388                     catch (NumberFormatException nfe)
389                     {
390                         System.err.println("Ignoring unparsable right demand \"" + value + "\"");
391                     }
392                 }
393                 else if ("leftfraction".equalsIgnoreCase(key))
394                 {
395                     try
396                     {
397                         leftFraction = java.lang.Double.parseDouble(value);
398                     }
399                     catch (NumberFormatException nfe)
400                     {
401                         System.err.println("Ignoring unparsable left fraction \"" + value + "\"");
402                     }
403                 }
404                 else if ("scenario".equalsIgnoreCase(key))
405                 {
406                     scenario = value;
407                 }
408                 else
409                 {
410                     System.out.println("Ignoring unknown setting " + arg);
411                 }
412             }
413             else
414             {
415                 // not a flag
416                 System.err.println("Ignoring argument " + arg);
417             }
418         }
419         final boolean finalAutoRun = autorun;
420         final int finalReplication = replication;
421         final String finalAnticipationStrategy = anticipationStrategy;
422         final Duration finalReactionTime = reactionTime;
423         final Duration finalAnticipationTime = anticipationTime;
424         final double finalTruckFraction = truckFraction;
425         final double finalDistanceError = distanceError;
426         final double finalSpeedError = speedError;
427         final double finalAccelerationError = accelerationError;
428         final Frequency finalLeftDemand = leftDemand;
429         final Frequency finalRightDemand = rightDemand;
430         final double finalLeftFraction = leftFraction;
431         final String finalScenario = scenario;
432         SwingUtilities.invokeLater(new Runnable()
433         {
434             @Override
435             public void run()
436             {
437                 try
438                 {
439                     AHFESimulation model = new AHFESimulation(finalReplication, finalAnticipationStrategy, finalReactionTime,
440                             finalAnticipationTime, finalTruckFraction, finalDistanceError, finalSpeedError,
441                             finalAccelerationError, finalLeftDemand, finalRightDemand, finalLeftFraction);
442                     System.out.println("Setting up replication " + finalReplication);
443                     model.setNextReplication(finalReplication);
444                     // 1 hour simulation run for testing
445                     model.buildAnimator(Time.ZERO, Duration.ZERO, Duration.createSI(SIMEND.si), new ArrayList<Property<?>>(),
446                             null, true);
447                     if (finalAutoRun)
448                     {
449                         int lastReportedTime = -1;
450                         int reportTimeClick = 60;
451                         while (true)
452                         {
453                             int currentTime = (int) model.getSimulator().getSimulatorTime().getTime().si;
454                             if (currentTime >= lastReportedTime + reportTimeClick)
455                             {
456                                 lastReportedTime = currentTime / reportTimeClick * reportTimeClick;
457                                 System.out.println("time is " + model.getSimulator().getSimulatorTime().getTime());
458                             }
459                             try
460                             {
461                                 model.getSimulator().step();
462                             }
463                             catch (SimRuntimeException sre)
464                             {
465                                 if (sre.getCause() != null && sre.getCause().getCause() != null
466                                         && sre.getCause().getCause().getMessage().equals(
467                                                 "Model has calcalated a negative infinite or negative max value acceleration."))
468                                 {
469                                     System.err.println("Collision detected.");
470                                     String file = finalScenario + ".csv.zip";
471                                     FileOutputStream fos = null;
472                                     ZipOutputStream zos = null;
473                                     OutputStreamWriter osw = null;
474                                     BufferedWriter bw = null;
475                                     try
476                                     {
477                                         fos = new FileOutputStream(file);
478                                         zos = new ZipOutputStream(fos);
479                                         zos.putNextEntry(new ZipEntry(finalScenario + ".csv"));
480                                         osw = new OutputStreamWriter(zos);
481                                         bw = new BufferedWriter(osw);
482                                         bw.write("Collision");
483                                         bw.write(model.getSimulator().getSimulatorTime().getTime().toString());
484                                     }
485                                     catch (IOException exception2)
486                                     {
487                                         throw new RuntimeException("Could not write to file.", exception2);
488                                     }
489                                     // close file on fail
490                                     finally
491                                     {
492                                         try
493                                         {
494                                             if (bw != null)
495                                             {
496                                                 bw.close();
497                                             }
498                                             if (osw != null)
499                                             {
500                                                 osw.close();
501                                             }
502                                             if (zos != null)
503                                             {
504                                                 zos.close();
505                                             }
506                                             if (fos != null)
507                                             {
508                                                 fos.close();
509                                             }
510                                         }
511                                         catch (IOException ex)
512                                         {
513                                             ex.printStackTrace();
514                                         }
515                                     }
516                                 }
517                                 else
518                                 {
519                                     System.out.println(
520                                             "Simulation ends; time is " + model.getSimulator().getSimulatorTime().getTime());
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
536                         | RemoteException exception)
537                 {
538                     exception.printStackTrace();
539                 }
540             }
541         });
542     }
543 
544     /** The simulator. */
545     private SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator;
546 
547     /** {@inheritDoc} */
548     @Override
549     public final String shortName()
550     {
551         return "AFFE Simulation";
552     }
553 
554     /** {@inheritDoc} */
555     @Override
556     public final String description()
557     {
558         return "Simulation for AHFE congress";
559     }
560 
561     /** {@inheritDoc} */
562     @Override
563     protected final OTSModelInterface makeModel(final GTUColorer colorer) throws OTSSimulationException
564     {
565         return new AHFEModel(colorer);
566     }
567 
568     /** {@inheritDoc} */
569     @Override
570     protected final void addAnimationToggles()
571     {
572         AnimationToggles.setTextAnimationTogglesStandard(this);
573     }
574 
575     /** {@inheritDoc} */
576     @Override
577     protected final Double makeAnimationRectangle()
578     {
579         return new Rectangle2D.Double(-50, -100, 8050, 150);
580     }
581 
582     /**
583      * The AHFE simulation model.
584      */
585     class AHFEModel extends EventProducer implements OTSModelInterface
586     {
587 
588         /** */
589         private static final long serialVersionUID = 20170228L;
590 
591         /** The network. */
592         private OTSNetwork network;
593 
594         /** Colorer. */
595         private final GTUColorer colorer;
596 
597         /**
598          * @param colorer colorer
599          */
600         AHFEModel(final GTUColorer colorer)
601         {
602             this.colorer = colorer;
603         }
604 
605         /** {@inheritDoc} */
606         @SuppressWarnings("synthetic-access")
607         @Override
608         public void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
609                 throws SimRuntimeException, RemoteException
610         {
611             AHFESimulation.this.simulator = theSimulator;
612 
613             AHFESimulation.this.sampler = new RoadSampler((OTSDEVSSimulatorInterface) theSimulator);
614             AHFESimulation.this.sampler.registerExtendedDataType(new TimeToCollision());
615             try
616             {
617                 InputStream stream = URLResource.getResourceAsStream("/AHFE/Network.xml");
618                 XmlNetworkLaneParser nlp = new XmlNetworkLaneParser((OTSDEVSSimulatorInterface) theSimulator);
619                 this.network = new OTSNetwork("AHFE");
620                 nlp.build(stream, this.network);
621 
622                 // Space-time regions for sampler
623                 LinkData linkData = new LinkData((CrossSectionLink) this.network.getLink("LEFTIN"));
624                 registerLinkToSampler(linkData, ignoreStart, linkData.getLength());
625                 linkData = new LinkData((CrossSectionLink) this.network.getLink("RIGHTIN"));
626                 registerLinkToSampler(linkData, ignoreStart, linkData.getLength());
627                 linkData = new LinkData((CrossSectionLink) this.network.getLink("CONVERGE"));
628                 registerLinkToSampler(linkData, Length.ZERO, linkData.getLength());
629                 linkData = new LinkData((CrossSectionLink) this.network.getLink("WEAVING"));
630                 registerLinkToSampler(linkData, Length.ZERO, linkData.getLength());
631                 linkData = new LinkData((CrossSectionLink) this.network.getLink("END"));
632                 registerLinkToSampler(linkData, Length.ZERO, linkData.getLength().minus(ignoreEnd));
633 
634                 // Generator
635                 AHFEUtil.createDemand(this.network, this.colorer, (OTSDEVSSimulatorInterface) theSimulator, getReplication(),
636                         getAnticipationStrategy(), getReactionTime(), getAnticipationTime(), getTruckFraction(), SIMEND,
637                         getLeftDemand(), getRightDemand(), getLeftFraction(), getDistanceError(), getSpeedError(),
638                         getAccelerationError());
639 
640             }
641             catch (Exception exception)
642             {
643                 exception.printStackTrace();
644             }
645         }
646 
647         /**
648          * Register a link to the sampler, so data is sampled there.
649          * @param linkData link data
650          * @param startDistance start distance on link
651          * @param endDistance end distance on link
652          */
653         private void registerLinkToSampler(final LinkData linkData, final Length startDistance, final Length endDistance)
654         {
655             for (LaneDataInterface laneData : linkData.getLaneDatas())
656             {
657                 Length start = laneData.getLength().multiplyBy(startDistance.si / linkData.getLength().si);
658                 Length end = laneData.getLength().multiplyBy(endDistance.si / linkData.getLength().si);
659                 AHFESimulation.this.sampler.registerSpaceTimeRegion(new SpaceTimeRegion(
660                         new KpiLaneDirection(laneData, KpiGtuDirectionality.DIR_PLUS), start, end, WARMUP, SIMEND));
661             }
662         }
663 
664         /** {@inheritDoc} */
665         @SuppressWarnings("synthetic-access")
666         @Override
667         public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
668         {
669             return AHFESimulation.this.simulator;
670         }
671 
672         /** {@inheritDoc} */
673         @Override
674         public OTSNetwork getNetwork()
675         {
676             return this.network;
677         }
678 
679     }
680 
681     /**
682      * Retrieve the simulator.
683      * @return SimulatorInterface&lt;Time, Duration, OTSSimTimeDouble&gt;; the simulator.
684      */
685     public final SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
686     {
687         return this.simulator;
688     }
689 
690 }