averbraeck / opentrafficsim

Open Source Multi-Level Traffic Simulator
BSD 3-Clause "New" or "Revised" License
29 stars 11 forks source link

Simplifying LaneBasedGtuCharacteristicsGenerator inheritance structure #48

Closed WJSchakel closed 1 year ago

WJSchakel commented 1 year ago

The LaneBasedGtuGenerator is a general purpose GTU generator. One of its major components is a LaneBasedGtuCharacteristicsGenerator. It has 3 implementations:

  1. LaneBasedTemplateGtuType, defining (distributed) properties for a GTUs of one GTU type. Additional to the non-lane-based features, this adds a LaneBasedStrategicalPlannerFactory and Generator<Route>. Origin and destination are always null, the vehicle model is always VehicleModel.MINMAX.
  2. LaneBasedTemplateGtuTypeDistribution, has multiple LaneBasedTemplateGtuType with fixed and pre-defined probabilities.
  3. GtuCharacteristicsGeneratorODWrapper (an innertype in OdApplier). This class houses a root DemandNode from which an origin Node, a destination Node, and a Category are drawn. The Category may include such things as the Lane, the GtuType and the Route. Next, the class has a GtuCharacteristicsGeneratorOd.

There are two implementation for GtuCharacteristicsGeneratorOd. The first is part of the ramp-metering demo. The second one is DefaultGtuCharacteristicsGeneratorOd. This class uses:

  1. Generator<GtuType> which may be null and currently is in all applications. (The GTU type comes from the demand.)
  2. Map<GtuType, TemplateGtuType>, which are set in the OdParser.
  3. RouteGeneratorOd which may be null and currently is in all applications. (Route comes from demand, or model determines it.) This class is used in other places, and derives a Route based on Node origin, Node destination and a GtuType.
  4. StrategicalPlannerFactorySupplierOd which has two anonymous implementations. A default implementation under the static lmrs() method, which ignores the origin Node, destination Node, and the Category. The other implementation is part of the OdParser and also ignores the origin Node and destination Node. It uses the Category to get a factory as defined in XML, if the category entails a GTU type.

Eventually either of these anonymous implementations uses a LaneBasedStrategicalPlannerFactory to create a strategical planner based on a Route, origin Node and destination Node, which may however all be null. Its only subtype is AbstractLaneBasedStrategicalPlannerFactory, housing a LaneBasedTacticalPlannerFactory and ParameterFactory. It implements desired speed and desired headway peeking. One further subtype is LaneBasedStrategicalRoutePlannerFactory which also houses a RouteGeneratorOd, which may be null. It generates LaneBasedStrategicalRoutePlanners, which may or may not have a RouteGeneratorOd. It has a super class AbstractLaneBasedStrategicalPlanner which only wraps a GTU.

The conclusion is that this is all way too complicated/convoluted. Routes can be specified in many places, and it is impossible to keep track of these places. Much input is currently ignored. Some classes have only single implementations. This whole structure provides no suitable tools to create GTU generation from injection files (issue #44). The "OD" nature of many classes is unnecessary. It is good that methods may provide route/origin/destination, but these need not come from an OD. Hence, the classes should not depend on an OD, or classes only suitable to be used by the OdApplier.

WJSchakel commented 1 year ago

There are 3 ways in which a user would want to defined the routes:

Route definition Template OD Injection file
Pre-defined Fixed/ProbabalisticRouteGenerator in LaneBasedTemplateGtuType DefaultGtuCharacteristicsGeneratorOd.draw(... Category) yes
With some procedure Generator<Route> in LaneBasedTemplateGtuType STRATEGICALPLANNER.ROUTE.NONE|SHORTEST in LaneBasedStrategicalRoutePlannerFactory yes
Strategical planner RouteGeneratorOd in LaneBasedStrategicalRoutePlanner from LaneBasedStrategicalRoutePlannerFactory RouteGeneratorOd in LaneBasedStrategicalRoutePlanner from LaneBasedStrategicalRoutePlannerFactory yes

This means the following can be dropped:

Note that if there is no route defined anywhere, but a destination is known, LaneBasedStrategicalRoutePlanner will supply a shortest-route.

WJSchakel commented 1 year ago

The following changes were made:

Rather than supplying different factories, one factory can itself do this job. This occurs anonymously in OdParser (note the use of gtuTypeFactoryMap and defaultFactory:

LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> factoryByGtuType =
        new LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner>()
        {
            /** {@inheritDoc} */
            @Override
            public LaneBasedStrategicalPlanner create(final LaneBasedGtu gtu, final Route route,
                    final Node origin, final Node destination) throws GtuException
            {
                LaneBasedStrategicalPlannerFactory<?> strategicalPlannerFactory =
                        gtuTypeFactoryMap.get(gtu.getType());
                if (strategicalPlannerFactory != null)
                {
                    // a model factory for this GTU type is specified
                    return strategicalPlannerFactory.create(gtu, route, origin, destination);
                }
                if (defaultFactory != null)
                {
                    // a default model factory is specified
                    return defaultFactory.create(gtu, route, origin, destination);
                }
                return defaultLmrsFactory.create(gtu, route, origin, destination);
            }
        };

Although LaneBasedGtuCharacteristicsGenerator and LaneBasedGtuCharacteristicsGeneratorOd are similar, they could not be removed. The LaneBasedGtuGenerator does not have any OD information, and hence can only call a draw() method. Any characteristics generator that does have OD information, must combine the two by bridging them with whatever form of the OD information (e.g. an OD matrix or injection file). For example OdApplier bridges the gap anonymously as (note how characteristicsGenerator wraps a characteristicsGeneratorOd from OdOptions):

LaneBasedGtuCharacteristicsGeneratorOd characteristicsGeneratorOd =
        odOptions.get(OdOptions.GTU_TYPE, lane, o, linkType);
LaneBasedGtuCharacteristicsGenerator characteristicsGenerator = new LaneBasedGtuCharacteristicsGenerator()
{
    /** {@inheritDoc} */
    @Override
    public LaneBasedGtuCharacteristics draw() throws ProbabilityException, ParameterException, GtuException
    {
        Time time = simulator.getSimulatorAbsTime();
        Node origin = root.getObject();
        DemandNode<Node, DemandNode<Category, ?>> destinationNode = root.draw(time);
        Node destination = destinationNode.getObject();
        Category category = destinationNode.draw(time).getObject();
        return characteristicsGeneratorOd.draw(origin, destination, category, stream);
    }
};