GeneratorSinkParser.java
package org.opentrafficsim.road.network.factory.xml.parser;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.djunits.unit.DurationUnit;
import org.djunits.value.vdouble.scalar.Duration;
import org.djunits.value.vdouble.scalar.Frequency;
import org.djunits.value.vdouble.scalar.Length;
import org.djunits.value.vdouble.scalar.Speed;
import org.opentrafficsim.base.parameters.ParameterException;
import org.opentrafficsim.core.distributions.Distribution;
import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
import org.opentrafficsim.core.distributions.Generator;
import org.opentrafficsim.core.distributions.ProbabilityException;
import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
import org.opentrafficsim.core.gtu.GTUDirectionality;
import org.opentrafficsim.core.gtu.GTUType;
import org.opentrafficsim.core.idgenerator.IdGenerator;
import org.opentrafficsim.core.network.NetworkException;
import org.opentrafficsim.core.network.Node;
import org.opentrafficsim.core.network.route.FixedRouteGenerator;
import org.opentrafficsim.core.network.route.ProbabilisticRouteGenerator;
import org.opentrafficsim.core.network.route.Route;
import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator;
import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator.RoomChecker;
import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUType;
import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUTypeDistribution;
import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModelFactory;
import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlus;
import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLMRSPerceptionFactory;
import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRS;
import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory;
import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
import org.opentrafficsim.road.network.OTSRoadNetwork;
import org.opentrafficsim.road.network.factory.xml.XmlParserException;
import org.opentrafficsim.road.network.factory.xml.utils.Generators;
import org.opentrafficsim.road.network.factory.xml.utils.StreamInformation;
import org.opentrafficsim.road.network.factory.xml.utils.Transformer;
import org.opentrafficsim.road.network.lane.CrossSectionLink;
import org.opentrafficsim.road.network.lane.DirectedLanePosition;
import org.opentrafficsim.road.network.lane.Lane;
import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
import org.opentrafficsim.xml.generated.GENERATOR;
import org.opentrafficsim.xml.generated.GTUTEMPLATE;
import org.opentrafficsim.xml.generated.NETWORKDEMAND;
import org.opentrafficsim.xml.generated.ROUTE;
import org.opentrafficsim.xml.generated.ROUTEMIX;
import org.opentrafficsim.xml.generated.SHORTESTROUTE;
import org.opentrafficsim.xml.generated.SHORTESTROUTEMIX;
import org.opentrafficsim.xml.generated.SINK;
import nl.tudelft.simulation.jstats.streams.MersenneTwister;
import nl.tudelft.simulation.jstats.streams.StreamInterface;
/**
* GeneratorSinkParser.java. <br>
* <br>
* Copyright (c) 2003-2018 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
* source code and binary code of this software is proprietary information of Delft University of Technology.
* @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
*/
public final class GeneratorSinkParser
{
/** */
private GeneratorSinkParser()
{
// utility class
}
/**
* Parse the ROUTE tags.
* @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
* @param demand NETWORKDEMAND; the NETWORKDEMAND tag
* @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
*/
@SuppressWarnings("checkstyle:needbraces")
static void parseRoutes(final OTSRoadNetwork otsNetwork, final NETWORKDEMAND demand) throws NetworkException
{
for (ROUTE routeTag : demand.getROUTE())
{
Route route = new Route(routeTag.getID());
GTUType gtuType = otsNetwork.getGtuType(routeTag.getGTUTYPE());
if (gtuType == null)
throw new NetworkException("GTUTYPE " + routeTag.getGTUTYPE() + " not found in ROUTE " + routeTag.getID());
for (ROUTE.NODE nodeTag : routeTag.getNODE())
{
Node node = otsNetwork.getNode(nodeTag.getID());
if (node == null)
throw new NetworkException("NODE " + nodeTag.getID() + " not found in ROUTE " + routeTag.getID());
route.addNode(node);
}
otsNetwork.addRoute(gtuType, route);
}
}
/**
* Parse the SHORTESTROUTE tags.
* @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
* @param demand NETWORKDEMAND; the NETWORKDEMAND tag
* @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
*/
@SuppressWarnings("checkstyle:needbraces")
static void parseShortestRoutes(final OTSRoadNetwork otsNetwork, final NETWORKDEMAND demand) throws NetworkException
{
for (SHORTESTROUTE shortestRouteTag : demand.getSHORTESTROUTE())
{
Route route = new Route(shortestRouteTag.getID());
GTUType gtuType = otsNetwork.getGtuType(shortestRouteTag.getGTUTYPE());
if (gtuType == null)
throw new NetworkException(
"GTUTYPE " + shortestRouteTag.getGTUTYPE() + " not found in SHORTESTROUTE " + shortestRouteTag.getID());
Node nodeFrom = otsNetwork.getNode(shortestRouteTag.getFROM().getNODE());
if (nodeFrom == null)
throw new NetworkException("FROM NODE " + shortestRouteTag.getFROM().getNODE() + " not found in SHORTESTROUTE "
+ shortestRouteTag.getID());
Node nodeTo = otsNetwork.getNode(shortestRouteTag.getTO().getNODE());
if (nodeTo == null)
throw new NetworkException("TO NODE " + shortestRouteTag.getTO().getNODE() + " not found in SHORTESTROUTE "
+ shortestRouteTag.getID());
List<Node> nodesVia = new ArrayList<>();
for (SHORTESTROUTE.VIA nodeViaTag : shortestRouteTag.getVIA())
{
Node nodeVia = otsNetwork.getNode(nodeViaTag.getNODE());
if (nodeTo == null)
throw new NetworkException(
"VIA NODE " + nodeViaTag.getNODE() + " not found in SHORTESTROUTE " + shortestRouteTag.getID());
nodesVia.add(nodeVia);
}
// TODO: distance weight and time weight
Route shortestRoute = otsNetwork.getShortestRouteBetween(gtuType, nodeFrom, nodeTo, nodesVia);
if (shortestRoute == null)
{
throw new NetworkException("Cannot find shortest route from " + nodeFrom.getId() + " to " + nodeTo.getId());
}
for (Node node : shortestRoute.getNodes())
{
route.addNode(node);
}
otsNetwork.addRoute(gtuType, route);
}
}
/**
* Parse the ROUTEMIX tags.
* @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
* @param demand NETWORKDEMAND; the NETWORKDEMAND tag
* @return id-based Map of routemix objects as FrequencyAndObject lists
* @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
*/
@SuppressWarnings("checkstyle:needbraces")
static Map<String, List<FrequencyAndObject<Route>>> parseRouteMix(final OTSRoadNetwork otsNetwork,
final NETWORKDEMAND demand) throws NetworkException
{
Map<String, List<FrequencyAndObject<Route>>> routeMixMap = new LinkedHashMap<>();
for (ROUTEMIX routeMixTag : demand.getROUTEMIX())
{
List<FrequencyAndObject<Route>> probRoutes = new ArrayList<>();
for (ROUTEMIX.ROUTE mixRoute : routeMixTag.getROUTE())
{
String routeName = mixRoute.getID();
double weight = mixRoute.getWEIGHT();
Route route = otsNetwork.getRoute(routeName);
if (route == null)
throw new NetworkException(
"Parsing ROUTEMIX " + routeMixTag.getID() + " -- ROUTE " + routeName + " not found");
probRoutes.add(new FrequencyAndObject<>(weight, route));
}
routeMixMap.put(routeMixTag.getID(), probRoutes);
}
return routeMixMap;
}
/**
* Parse the SHORTESTROUTEMIX tags.
* @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
* @param demand NETWORKDEMAND; the NETWORKDEMAND tag
* @return id-based Map of routemix objects as FrequencyAndObject lists
* @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
*/
@SuppressWarnings("checkstyle:needbraces")
static Map<String, List<FrequencyAndObject<Route>>> parseShortestRouteMix(final OTSRoadNetwork otsNetwork,
final NETWORKDEMAND demand) throws NetworkException
{
Map<String, List<FrequencyAndObject<Route>>> shortestRouteMixMap = new LinkedHashMap<>();
for (SHORTESTROUTEMIX routeMixTag : demand.getSHORTESTROUTEMIX())
{
List<FrequencyAndObject<Route>> probRoutes = new ArrayList<>();
for (SHORTESTROUTEMIX.SHORTESTROUTE mixRoute : routeMixTag.getSHORTESTROUTE())
{
String routeName = mixRoute.getID();
double weight = mixRoute.getWEIGHT();
Route route = otsNetwork.getRoute(routeName);
if (route == null)
throw new NetworkException(
"Parsing SHORTESTROUTEMIX " + routeMixTag.getID() + " -- SHORESTROUTE " + routeName + " not found");
probRoutes.add(new FrequencyAndObject<>(weight, route));
}
shortestRouteMixMap.put(routeMixTag.getID(), probRoutes);
}
return shortestRouteMixMap;
}
/**
* Parse the Generators.
* @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
* @param demand NETWORK; the NETWORK tag
* @param gtuTemplates GGTUTEMPLATE tags
* @param routeMixMap map with route mix entries
* @param shortestRouteMixMap map with shortest route mix entries
* @param streamMap map with stream information
* @return list of created GTU generators
* @throws XmlParserException when the objects cannot be inserted into the network due to inconsistencies
*/
@SuppressWarnings("checkstyle:needbraces")
public static List<LaneBasedGTUGenerator> parseGenerators(final OTSRoadNetwork otsNetwork, final NETWORKDEMAND demand,
final Map<String, GTUTEMPLATE> gtuTemplates, final Map<String, List<FrequencyAndObject<Route>>> routeMixMap,
final Map<String, List<FrequencyAndObject<Route>>> shortestRouteMixMap,
final Map<String, StreamInformation> streamMap) throws XmlParserException
{
OTSSimulatorInterface simulator = otsNetwork.getSimulator();
List<LaneBasedGTUGenerator> generators = new ArrayList<>();
try
{
for (GENERATOR generatorTag : demand.getGENERATOR())
{
if (simulator.getReplication().getStream("generation") == null)
{
simulator.getReplication().getStreams().put("generation", new MersenneTwister(1L));
}
StreamInterface stream = simulator.getReplication().getStream("generation");
Generator<Route> routeGenerator;
if (generatorTag.getROUTE() != null)
{
Route route = otsNetwork.getRoute(generatorTag.getROUTE());
if (route == null)
throw new XmlParserException("GENERATOR for LANE " + generatorTag.getLINK() + "."
+ generatorTag.getLANE() + ": Route " + generatorTag.getROUTE() + " not found");
routeGenerator = new FixedRouteGenerator(route);
}
else if (generatorTag.getROUTEMIX() != null)
{
List<FrequencyAndObject<Route>> routeMix = routeMixMap.get(generatorTag.getROUTEMIX());
if (routeMix == null)
throw new XmlParserException("GENERATOR for LANE " + generatorTag.getLINK() + "."
+ generatorTag.getLANE() + ": RouteMix " + generatorTag.getROUTEMIX() + " not found");
try
{
routeGenerator = new ProbabilisticRouteGenerator(routeMix, stream);
}
catch (ProbabilityException exception)
{
throw new RuntimeException("GENERATOR for LANE " + generatorTag.getLINK() + "." + generatorTag.getLANE()
+ "Could not generate RouteMix " + generatorTag.getROUTEMIX());
}
}
else if (generatorTag.getSHORTESTROUTE() != null)
{
Route shortestRoute = otsNetwork.getRoute(generatorTag.getSHORTESTROUTE());
if (shortestRoute == null)
throw new XmlParserException("GENERATOR for LANE " + generatorTag.getLINK() + "."
+ generatorTag.getLANE() + ": ShortestRoute " + generatorTag.getSHORTESTROUTE() + " not found");
routeGenerator = new FixedRouteGenerator(shortestRoute);
}
else if (generatorTag.getSHORTESTROUTEMIX() != null)
{
List<FrequencyAndObject<Route>> shortestRouteMix =
shortestRouteMixMap.get(generatorTag.getSHORTESTROUTEMIX());
if (shortestRouteMix == null)
throw new XmlParserException(
"GENERATOR for LANE " + generatorTag.getLINK() + "." + generatorTag.getLANE()
+ ": ShortestRouteMix " + generatorTag.getSHORTESTROUTEMIX() + " not found");
try
{
routeGenerator = new ProbabilisticRouteGenerator(shortestRouteMix, stream);
}
catch (ProbabilityException exception)
{
throw new RuntimeException("GENERATOR for LANE " + generatorTag.getLINK() + "." + generatorTag.getLANE()
+ "Could not generate ShortestRouteMix " + generatorTag.getSHORTESTROUTEMIX());
}
}
else
{
throw new XmlParserException("GENERATOR for LANE " + generatorTag.getLINK() + "." + generatorTag.getLANE()
+ ": No route information");
}
CarFollowingModelFactory<IDMPlus> idmPlusFactory = new IDMPlusFactory(streamMap.get("generation").getStream());
LaneBasedTacticalPlannerFactory<LMRS> tacticalFactory =
new LMRSFactory(idmPlusFactory, new DefaultLMRSPerceptionFactory());
LaneBasedStrategicalRoutePlannerFactory strategicalFactory =
new LaneBasedStrategicalRoutePlannerFactory(tacticalFactory);
// the distribution of GTUs
Distribution<LaneBasedTemplateGTUType> gtuTypeDistribution =
new Distribution<>(streamMap.get("generation").getStream());
if (generatorTag.getGTUTEMPLATE() != null)
{
GTUTEMPLATE templateTag = gtuTemplates.get(generatorTag.getGTUTEMPLATE());
if (templateTag == null)
throw new XmlParserException(
"GTUTEMPLATE " + generatorTag.getGTUTEMPLATE() + " in generator not defined");
GTUType gtuType = otsNetwork.getGtuType(templateTag.getGTUTYPE());
if (gtuType == null)
throw new XmlParserException("GTUTYPE " + templateTag.getGTUTYPE() + " in GTUTEMPLATE "
+ generatorTag.getGTUTEMPLATE() + " not defined");
Generator<Length> lengthGenerator = Generators.makeLengthGenerator(streamMap, templateTag.getLENGTHDIST());
Generator<Length> widthGenerator = Generators.makeLengthGenerator(streamMap, templateTag.getWIDTHDIST());
Generator<Speed> maximumSpeedGenerator =
Generators.makeSpeedGenerator(streamMap, templateTag.getMAXSPEEDDIST());
LaneBasedTemplateGTUType templateGTUType = new LaneBasedTemplateGTUType(gtuType, lengthGenerator,
widthGenerator, maximumSpeedGenerator, strategicalFactory, routeGenerator);
gtuTypeDistribution.add(new FrequencyAndObject<>(1.0, templateGTUType));
}
else if (generatorTag.getGTUTEMPLATEMIX() != null)
{
// TODO: GTUTEMPLATEMIX
throw new XmlParserException("GtuTemplateMix not implemented yet in GENERATOR");
}
else
{
throw new XmlParserException("No GTU information in GENERATOR");
}
RoomChecker roomChecker = Transformer.parseRoomChecker(generatorTag.getROOMCHECKER());
Generator<Duration> headwayGenerator =
new HeadwayGenerator(generatorTag.getFREQUENCY(), streamMap.get("generation").getStream());
CrossSectionLink link = (CrossSectionLink) otsNetwork.getLink(generatorTag.getLINK());
Lane lane = (Lane) link.getCrossSectionElement(generatorTag.getLANE());
// TODO: remove this hack for testing
Length position = Length.instantiateSI(5.0); // Transformer.parseLengthBeginEnd(generatorTag.getPOSITION(),
// lane.getLength());
GTUDirectionality direction = GTUDirectionality.valueOf(generatorTag.getDIRECTION());
Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>();
initialLongitudinalPositions.add(new DirectedLanePosition(lane, position, direction));
IdGenerator idGenerator = new IdGenerator(lane.getFullId());
LaneBasedTemplateGTUTypeDistribution characteristicsGenerator =
new LaneBasedTemplateGTUTypeDistribution(gtuTypeDistribution);
generators.add(new LaneBasedGTUGenerator(lane.getFullId(), headwayGenerator, characteristicsGenerator,
GeneratorPositions.create(initialLongitudinalPositions, stream), otsNetwork, simulator, roomChecker,
idGenerator));
}
}
catch (Exception exception)
{
throw new XmlParserException(exception);
}
return generators;
}
/**
* Parse the Sinks.
* @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
* @param demand NETWORK; the NETWORK tag
* @param simulator OTSSimulatorInterface; the simulator
* @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
*/
public static void parseSinks(final OTSRoadNetwork otsNetwork, final NETWORKDEMAND demand,
final OTSSimulatorInterface simulator) throws NetworkException
{
for (SINK sinkTag : demand.getSINK())
{
CrossSectionLink link = (CrossSectionLink) otsNetwork.getLink(sinkTag.getLINK());
Lane lane = (Lane) link.getCrossSectionElement(sinkTag.getLANE());
Length position = Transformer.parseLengthBeginEnd(sinkTag.getPOSITION(), lane.getLength());
new SinkSensor(lane, position, GTUDirectionality.valueOf(sinkTag.getDIRECTION()), simulator);
}
}
/**
* <p>
* Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* <br>
* BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
* <p>
* @version $Revision$, $LastChangedDate$, by $Author$, initial version 29 jan. 2017 <br>
* @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
* @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
*/
private static class HeadwayGenerator implements Generator<Duration>
{
/** Demand level. */
private final Frequency demand;
/** the stream information. */
private final StreamInterface stream;
/**
* @param demand Frequency; demand
* @param stream the stream to use for generation
*/
HeadwayGenerator(final Frequency demand, final StreamInterface stream)
{
this.demand = demand;
this.stream = stream;
}
/** {@inheritDoc} */
@Override
public Duration draw() throws ProbabilityException, ParameterException
{
return new Duration(-Math.log(this.stream.nextDouble()) / this.demand.si, DurationUnit.SI);
}
}
}