View Javadoc
1   package org.opentrafficsim.road.network.factory.xml.parser;
2   
3   import java.util.ArrayList;
4   import java.util.LinkedHashMap;
5   import java.util.LinkedHashSet;
6   import java.util.List;
7   import java.util.Map;
8   import java.util.Set;
9   
10  import org.djunits.unit.DurationUnit;
11  import org.djunits.value.vdouble.scalar.Duration;
12  import org.djunits.value.vdouble.scalar.Frequency;
13  import org.djunits.value.vdouble.scalar.Length;
14  import org.djunits.value.vdouble.scalar.Speed;
15  import org.opentrafficsim.base.parameters.ParameterException;
16  import org.opentrafficsim.core.distributions.Distribution;
17  import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
18  import org.opentrafficsim.core.distributions.Generator;
19  import org.opentrafficsim.core.distributions.ProbabilityException;
20  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
21  import org.opentrafficsim.core.gtu.GTUDirectionality;
22  import org.opentrafficsim.core.gtu.GTUType;
23  import org.opentrafficsim.core.idgenerator.IdGenerator;
24  import org.opentrafficsim.core.network.NetworkException;
25  import org.opentrafficsim.core.network.Node;
26  import org.opentrafficsim.core.network.route.FixedRouteGenerator;
27  import org.opentrafficsim.core.network.route.ProbabilisticRouteGenerator;
28  import org.opentrafficsim.core.network.route.Route;
29  import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
30  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator;
31  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator.RoomChecker;
32  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUType;
33  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUTypeDistribution;
34  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
35  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
36  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlus;
37  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
38  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLMRSPerceptionFactory;
39  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRS;
40  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory;
41  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
42  import org.opentrafficsim.road.network.OTSRoadNetwork;
43  import org.opentrafficsim.road.network.factory.xml.XmlParserException;
44  import org.opentrafficsim.road.network.factory.xml.utils.Generators;
45  import org.opentrafficsim.road.network.factory.xml.utils.StreamInformation;
46  import org.opentrafficsim.road.network.factory.xml.utils.Transformer;
47  import org.opentrafficsim.road.network.lane.CrossSectionLink;
48  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
49  import org.opentrafficsim.road.network.lane.Lane;
50  import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
51  import org.opentrafficsim.xml.generated.GENERATOR;
52  import org.opentrafficsim.xml.generated.GTUTEMPLATE;
53  import org.opentrafficsim.xml.generated.NETWORKDEMAND;
54  import org.opentrafficsim.xml.generated.ROUTE;
55  import org.opentrafficsim.xml.generated.ROUTEMIX;
56  import org.opentrafficsim.xml.generated.SHORTESTROUTE;
57  import org.opentrafficsim.xml.generated.SHORTESTROUTEMIX;
58  import org.opentrafficsim.xml.generated.SINK;
59  
60  import nl.tudelft.simulation.jstats.streams.MersenneTwister;
61  import nl.tudelft.simulation.jstats.streams.StreamInterface;
62  
63  /**
64   * GeneratorSinkParser.java. <br>
65   * <br>
66   * Copyright (c) 2003-2018 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
67   * for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
68   * source code and binary code of this software is proprietary information of Delft University of Technology.
69   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
70   */
71  public final class GeneratorSinkParser
72  {
73      /** */
74      private GeneratorSinkParser()
75      {
76          // utility class
77      }
78  
79      /**
80       * Parse the ROUTE tags.
81       * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
82       * @param demand NETWORKDEMAND; the NETWORKDEMAND tag
83       * @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
84       */
85      @SuppressWarnings("checkstyle:needbraces")
86      static void parseRoutes(final OTSRoadNetwork otsNetwork, final NETWORKDEMAND demand) throws NetworkException
87      {
88          for (ROUTE routeTag : demand.getROUTE())
89          {
90              Route route = new Route(routeTag.getID());
91              GTUType gtuType = otsNetwork.getGtuType(routeTag.getGTUTYPE());
92              if (gtuType == null)
93                  throw new NetworkException("GTUTYPE " + routeTag.getGTUTYPE() + " not found in ROUTE " + routeTag.getID());
94              for (ROUTE.NODE nodeTag : routeTag.getNODE())
95              {
96                  Node node = otsNetwork.getNode(nodeTag.getID());
97                  if (node == null)
98                      throw new NetworkException("NODE " + nodeTag.getID() + " not found in ROUTE " + routeTag.getID());
99                  route.addNode(node);
100             }
101             otsNetwork.addRoute(gtuType, route);
102         }
103     }
104 
105     /**
106      * Parse the SHORTESTROUTE tags.
107      * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
108      * @param demand NETWORKDEMAND; the NETWORKDEMAND tag
109      * @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
110      */
111     @SuppressWarnings("checkstyle:needbraces")
112     static void parseShortestRoutes(final OTSRoadNetwork otsNetwork, final NETWORKDEMAND demand) throws NetworkException
113     {
114         for (SHORTESTROUTE shortestRouteTag : demand.getSHORTESTROUTE())
115         {
116             Route route = new Route(shortestRouteTag.getID());
117             GTUType gtuType = otsNetwork.getGtuType(shortestRouteTag.getGTUTYPE());
118             if (gtuType == null)
119                 throw new NetworkException(
120                         "GTUTYPE " + shortestRouteTag.getGTUTYPE() + " not found in SHORTESTROUTE " + shortestRouteTag.getID());
121             Node nodeFrom = otsNetwork.getNode(shortestRouteTag.getFROM().getNODE());
122             if (nodeFrom == null)
123                 throw new NetworkException("FROM NODE " + shortestRouteTag.getFROM().getNODE() + " not found in SHORTESTROUTE "
124                         + shortestRouteTag.getID());
125             Node nodeTo = otsNetwork.getNode(shortestRouteTag.getTO().getNODE());
126             if (nodeTo == null)
127                 throw new NetworkException("TO NODE " + shortestRouteTag.getTO().getNODE() + " not found in SHORTESTROUTE "
128                         + shortestRouteTag.getID());
129             List<Node> nodesVia = new ArrayList<>();
130             for (SHORTESTROUTE.VIA nodeViaTag : shortestRouteTag.getVIA())
131             {
132                 Node nodeVia = otsNetwork.getNode(nodeViaTag.getNODE());
133                 if (nodeTo == null)
134                     throw new NetworkException(
135                             "VIA NODE " + nodeViaTag.getNODE() + " not found in SHORTESTROUTE " + shortestRouteTag.getID());
136                 nodesVia.add(nodeVia);
137             }
138             // TODO: distance weight and time weight
139             Route shortestRoute = otsNetwork.getShortestRouteBetween(gtuType, nodeFrom, nodeTo, nodesVia);
140             if (shortestRoute == null)
141             {
142                 throw new NetworkException("Cannot find shortest route from " + nodeFrom.getId() + " to " + nodeTo.getId());
143             }
144             for (Node node : shortestRoute.getNodes())
145             {
146                 route.addNode(node);
147             }
148             otsNetwork.addRoute(gtuType, route);
149         }
150     }
151 
152     /**
153      * Parse the ROUTEMIX tags.
154      * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
155      * @param demand NETWORKDEMAND; the NETWORKDEMAND tag
156      * @return id-based Map of routemix objects as FrequencyAndObject lists
157      * @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
158      */
159     @SuppressWarnings("checkstyle:needbraces")
160     static Map<String, List<FrequencyAndObject<Route>>> parseRouteMix(final OTSRoadNetwork otsNetwork,
161             final NETWORKDEMAND demand) throws NetworkException
162     {
163         Map<String, List<FrequencyAndObject<Route>>> routeMixMap = new LinkedHashMap<>();
164         for (ROUTEMIX routeMixTag : demand.getROUTEMIX())
165         {
166             List<FrequencyAndObject<Route>> probRoutes = new ArrayList<>();
167             for (ROUTEMIX.ROUTE mixRoute : routeMixTag.getROUTE())
168             {
169                 String routeName = mixRoute.getID();
170                 double weight = mixRoute.getWEIGHT();
171                 Route route = otsNetwork.getRoute(routeName);
172                 if (route == null)
173                     throw new NetworkException(
174                             "Parsing ROUTEMIX " + routeMixTag.getID() + " -- ROUTE " + routeName + " not found");
175                 probRoutes.add(new FrequencyAndObject<>(weight, route));
176             }
177             routeMixMap.put(routeMixTag.getID(), probRoutes);
178         }
179         return routeMixMap;
180     }
181 
182     /**
183      * Parse the SHORTESTROUTEMIX tags.
184      * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
185      * @param demand NETWORKDEMAND; the NETWORKDEMAND tag
186      * @return id-based Map of routemix objects as FrequencyAndObject lists
187      * @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
188      */
189     @SuppressWarnings("checkstyle:needbraces")
190     static Map<String, List<FrequencyAndObject<Route>>> parseShortestRouteMix(final OTSRoadNetwork otsNetwork,
191             final NETWORKDEMAND demand) throws NetworkException
192     {
193         Map<String, List<FrequencyAndObject<Route>>> shortestRouteMixMap = new LinkedHashMap<>();
194         for (SHORTESTROUTEMIX routeMixTag : demand.getSHORTESTROUTEMIX())
195         {
196             List<FrequencyAndObject<Route>> probRoutes = new ArrayList<>();
197             for (SHORTESTROUTEMIX.SHORTESTROUTE mixRoute : routeMixTag.getSHORTESTROUTE())
198             {
199                 String routeName = mixRoute.getID();
200                 double weight = mixRoute.getWEIGHT();
201                 Route route = otsNetwork.getRoute(routeName);
202                 if (route == null)
203                     throw new NetworkException(
204                             "Parsing SHORTESTROUTEMIX " + routeMixTag.getID() + " -- SHORESTROUTE " + routeName + " not found");
205                 probRoutes.add(new FrequencyAndObject<>(weight, route));
206             }
207             shortestRouteMixMap.put(routeMixTag.getID(), probRoutes);
208         }
209         return shortestRouteMixMap;
210     }
211 
212     /**
213      * Parse the Generators.
214      * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
215      * @param demand NETWORK; the NETWORK tag
216      * @param gtuTemplates GGTUTEMPLATE tags
217      * @param routeMixMap map with route mix entries
218      * @param shortestRouteMixMap map with shortest route mix entries
219      * @param streamMap map with stream information
220      * @return list of created GTU generators
221      * @throws XmlParserException when the objects cannot be inserted into the network due to inconsistencies
222      */
223     @SuppressWarnings("checkstyle:needbraces")
224     public static List<LaneBasedGTUGenerator> parseGenerators(final OTSRoadNetwork otsNetwork, final NETWORKDEMAND demand,
225             final Map<String, GTUTEMPLATE> gtuTemplates, final Map<String, List<FrequencyAndObject<Route>>> routeMixMap,
226             final Map<String, List<FrequencyAndObject<Route>>> shortestRouteMixMap,
227             final Map<String, StreamInformation> streamMap) throws XmlParserException
228     {
229         OTSSimulatorInterface simulator = otsNetwork.getSimulator();
230         List<LaneBasedGTUGenerator> generators = new ArrayList<>();
231         try
232         {
233             for (GENERATOR generatorTag : demand.getGENERATOR())
234             {
235 
236                 if (simulator.getReplication().getStream("generation") == null)
237                 {
238                     simulator.getReplication().getStreams().put("generation", new MersenneTwister(1L));
239                 }
240                 StreamInterface stream = simulator.getReplication().getStream("generation");
241 
242                 Generator<Route> routeGenerator;
243                 if (generatorTag.getROUTE() != null)
244                 {
245                     Route route = otsNetwork.getRoute(generatorTag.getROUTE());
246                     if (route == null)
247                         throw new XmlParserException("GENERATOR for LANE " + generatorTag.getLINK() + "."
248                                 + generatorTag.getLANE() + ": Route " + generatorTag.getROUTE() + " not found");
249                     routeGenerator = new FixedRouteGenerator(route);
250                 }
251 
252                 else if (generatorTag.getROUTEMIX() != null)
253                 {
254                     List<FrequencyAndObject<Route>> routeMix = routeMixMap.get(generatorTag.getROUTEMIX());
255                     if (routeMix == null)
256                         throw new XmlParserException("GENERATOR for LANE " + generatorTag.getLINK() + "."
257                                 + generatorTag.getLANE() + ": RouteMix " + generatorTag.getROUTEMIX() + " not found");
258                     try
259                     {
260                         routeGenerator = new ProbabilisticRouteGenerator(routeMix, stream);
261                     }
262                     catch (ProbabilityException exception)
263                     {
264                         throw new RuntimeException("GENERATOR for LANE " + generatorTag.getLINK() + "." + generatorTag.getLANE()
265                                 + "Could not generate RouteMix " + generatorTag.getROUTEMIX());
266                     }
267                 }
268 
269                 else if (generatorTag.getSHORTESTROUTE() != null)
270                 {
271                     Route shortestRoute = otsNetwork.getRoute(generatorTag.getSHORTESTROUTE());
272                     if (shortestRoute == null)
273                         throw new XmlParserException("GENERATOR for LANE " + generatorTag.getLINK() + "."
274                                 + generatorTag.getLANE() + ": ShortestRoute " + generatorTag.getSHORTESTROUTE() + " not found");
275                     routeGenerator = new FixedRouteGenerator(shortestRoute);
276                 }
277 
278                 else if (generatorTag.getSHORTESTROUTEMIX() != null)
279                 {
280                     List<FrequencyAndObject<Route>> shortestRouteMix =
281                             shortestRouteMixMap.get(generatorTag.getSHORTESTROUTEMIX());
282                     if (shortestRouteMix == null)
283                         throw new XmlParserException(
284                                 "GENERATOR for LANE " + generatorTag.getLINK() + "." + generatorTag.getLANE()
285                                         + ": ShortestRouteMix " + generatorTag.getSHORTESTROUTEMIX() + " not found");
286                     try
287                     {
288                         routeGenerator = new ProbabilisticRouteGenerator(shortestRouteMix, stream);
289                     }
290                     catch (ProbabilityException exception)
291                     {
292                         throw new RuntimeException("GENERATOR for LANE " + generatorTag.getLINK() + "." + generatorTag.getLANE()
293                                 + "Could not generate ShortestRouteMix " + generatorTag.getSHORTESTROUTEMIX());
294                     }
295                 }
296 
297                 else
298                 {
299                     throw new XmlParserException("GENERATOR for LANE " + generatorTag.getLINK() + "." + generatorTag.getLANE()
300                             + ": No route information");
301                 }
302 
303                 CarFollowingModelFactory<IDMPlus> idmPlusFactory = new IDMPlusFactory(streamMap.get("generation").getStream());
304                 LaneBasedTacticalPlannerFactory<LMRS> tacticalFactory =
305                         new LMRSFactory(idmPlusFactory, new DefaultLMRSPerceptionFactory());
306                 LaneBasedStrategicalRoutePlannerFactory strategicalFactory =
307                         new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory);
308 
309                 // the distribution of GTUs
310                 Distribution<LaneBasedTemplateGTUType> gtuTypeDistribution =
311                         new Distribution<>(streamMap.get("generation").getStream());
312                 if (generatorTag.getGTUTEMPLATE() != null)
313                 {
314                     GTUTEMPLATE templateTag = gtuTemplates.get(generatorTag.getGTUTEMPLATE());
315                     if (templateTag == null)
316                         throw new XmlParserException(
317                                 "GTUTEMPLATE " + generatorTag.getGTUTEMPLATE() + " in generator not defined");
318                     GTUType gtuType = otsNetwork.getGtuType(templateTag.getGTUTYPE());
319                     if (gtuType == null)
320                         throw new XmlParserException("GTUTYPE " + templateTag.getGTUTYPE() + " in GTUTEMPLATE "
321                                 + generatorTag.getGTUTEMPLATE() + " not defined");
322                     Generator<Length> lengthGenerator = Generators.makeLengthGenerator(streamMap, templateTag.getLENGTHDIST());
323                     Generator<Length> widthGenerator = Generators.makeLengthGenerator(streamMap, templateTag.getWIDTHDIST());
324                     Generator<Speed> maximumSpeedGenerator =
325                             Generators.makeSpeedGenerator(streamMap, templateTag.getMAXSPEEDDIST());
326                     LaneBasedTemplateGTUType templateGTUType = new LaneBasedTemplateGTUType(gtuType, lengthGenerator,
327                             widthGenerator, maximumSpeedGenerator, strategicalFactory, routeGenerator);
328                     gtuTypeDistribution.add(new FrequencyAndObject<>(1.0, templateGTUType));
329                 }
330                 else if (generatorTag.getGTUTEMPLATEMIX() != null)
331                 {
332                     // TODO: GTUTEMPLATEMIX
333                     throw new XmlParserException("GtuTemplateMix not implemented yet in GENERATOR");
334                 }
335                 else
336                 {
337                     throw new XmlParserException("No GTU information in GENERATOR");
338                 }
339 
340                 RoomChecker roomChecker = Transformer.parseRoomChecker(generatorTag.getROOMCHECKER());
341 
342                 Generator<Duration> headwayGenerator =
343                         new HeadwayGenerator(generatorTag.getFREQUENCY(), streamMap.get("generation").getStream());
344 
345                 CrossSectionLink link = (CrossSectionLink) otsNetwork.getLink(generatorTag.getLINK());
346                 Lane lane = (Lane) link.getCrossSectionElement(generatorTag.getLANE());
347                 // TODO: remove this hack for testing
348                 Length position = Length.instantiateSI(5.0); // Transformer.parseLengthBeginEnd(generatorTag.getPOSITION(),
349                                                         // lane.getLength());
350                 GTUDirectionality direction = GTUDirectionality.valueOf(generatorTag.getDIRECTION());
351                 Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>();
352                 initialLongitudinalPositions.add(new DirectedLanePosition(lane, position, direction));
353 
354                 IdGenerator idGenerator = new IdGenerator(lane.getFullId());
355 
356                 LaneBasedTemplateGTUTypeDistribution characteristicsGenerator =
357                         new LaneBasedTemplateGTUTypeDistribution(gtuTypeDistribution);
358                 generators.add(new LaneBasedGTUGenerator(lane.getFullId(), headwayGenerator, characteristicsGenerator,
359                         GeneratorPositions.create(initialLongitudinalPositions, stream), otsNetwork, simulator, roomChecker,
360                         idGenerator));
361             }
362         }
363         catch (Exception exception)
364         {
365             throw new XmlParserException(exception);
366         }
367         return generators;
368     }
369 
370     /**
371      * Parse the Sinks.
372      * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
373      * @param demand NETWORK; the NETWORK tag
374      * @param simulator OTSSimulatorInterface; the simulator
375      * @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
376      */
377     public static void parseSinks(final OTSRoadNetwork otsNetwork, final NETWORKDEMAND demand,
378             final OTSSimulatorInterface simulator) throws NetworkException
379     {
380         for (SINK sinkTag : demand.getSINK())
381         {
382             CrossSectionLink link = (CrossSectionLink) otsNetwork.getLink(sinkTag.getLINK());
383             Lane lane = (Lane) link.getCrossSectionElement(sinkTag.getLANE());
384             Length position = Transformer.parseLengthBeginEnd(sinkTag.getPOSITION(), lane.getLength());
385             new SinkSensor(lane, position, GTUDirectionality.valueOf(sinkTag.getDIRECTION()), simulator);
386         }
387     }
388 
389     /**
390      * <p>
391      * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
392      * <br>
393      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
394      * <p>
395      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 29 jan. 2017 <br>
396      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
397      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
398      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
399      */
400     private static class HeadwayGenerator implements Generator<Duration>
401     {
402         /** Demand level. */
403         private final Frequency demand;
404 
405         /** the stream information. */
406         private final StreamInterface stream;
407 
408         /**
409          * @param demand Frequency; demand
410          * @param stream the stream to use for generation
411          */
412         HeadwayGenerator(final Frequency demand, final StreamInterface stream)
413         {
414             this.demand = demand;
415             this.stream = stream;
416         }
417 
418         /** {@inheritDoc} */
419         @Override
420         public Duration draw() throws ProbabilityException, ParameterException
421         {
422             return new Duration(-Math.log(this.stream.nextDouble()) / this.demand.si, DurationUnit.SI);
423         }
424 
425     }
426 }