ODApplierExample.java

package org.opentrafficsim.road.gtu.generator.od;

import java.awt.Color;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.naming.NamingException;
import javax.swing.SwingUtilities;

import org.djunits.unit.DurationUnit;
import org.djunits.unit.FrequencyUnit;
import org.djunits.unit.SpeedUnit;
import org.djunits.unit.TimeUnit;
import org.djunits.value.StorageType;
import org.djunits.value.ValueException;
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.djunits.value.vdouble.scalar.Time;
import org.djunits.value.vdouble.vector.FrequencyVector;
import org.djunits.value.vdouble.vector.TimeVector;
import org.opentrafficsim.base.modelproperties.Property;
import org.opentrafficsim.base.modelproperties.PropertyException;
import org.opentrafficsim.base.parameters.ParameterException;
import org.opentrafficsim.core.dsol.OTSModelInterface;
import org.opentrafficsim.core.geometry.OTSGeometryException;
import org.opentrafficsim.core.geometry.OTSLine3D;
import org.opentrafficsim.core.geometry.OTSPoint3D;
import org.opentrafficsim.core.gtu.GTUDirectionality;
import org.opentrafficsim.core.gtu.GTUException;
import org.opentrafficsim.core.gtu.GTUType;
import org.opentrafficsim.core.gtu.animation.GTUColorer;
import org.opentrafficsim.core.network.LinkType;
import org.opentrafficsim.core.network.NetworkException;
import org.opentrafficsim.core.network.Node;
import org.opentrafficsim.core.network.OTSNetwork;
import org.opentrafficsim.core.network.OTSNode;
import org.opentrafficsim.core.network.animation.LinkAnimation;
import org.opentrafficsim.core.network.animation.NodeAnimation;
import org.opentrafficsim.road.animation.AnimationToggles;
import org.opentrafficsim.road.gtu.animation.LmrsSwitchableColorer;
import org.opentrafficsim.road.gtu.generator.CFBARoomChecker;
import org.opentrafficsim.road.gtu.generator.GTUGeneratorAnimation;
import org.opentrafficsim.road.gtu.generator.GeneratorPositions.LaneBias;
import org.opentrafficsim.road.gtu.generator.GeneratorPositions.LaneBiases;
import org.opentrafficsim.road.gtu.generator.MarkovCorrelation;
import org.opentrafficsim.road.gtu.generator.Platoons;
import org.opentrafficsim.road.gtu.generator.od.ODApplier.GeneratorObjects;
import org.opentrafficsim.road.gtu.strategical.od.Categorization;
import org.opentrafficsim.road.gtu.strategical.od.Category;
import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
import org.opentrafficsim.road.gtu.strategical.od.ODMatrix;
import org.opentrafficsim.road.network.animation.LaneAnimation;
import org.opentrafficsim.road.network.animation.StripeAnimation;
import org.opentrafficsim.road.network.animation.StripeAnimation.TYPE;
import org.opentrafficsim.road.network.animation.TrafficLightAnimation;
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.LaneType;
import org.opentrafficsim.road.network.lane.Stripe;
import org.opentrafficsim.road.network.lane.Stripe.Permeable;
import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
import org.opentrafficsim.road.network.lane.object.trafficlight.SimpleTrafficLight;
import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLightColor;
import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
import org.opentrafficsim.simulationengine.OTSSimulationException;

import nl.tudelft.simulation.dsol.SimRuntimeException;
import nl.tudelft.simulation.dsol.simtime.SimTimeDoubleUnit;
import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
import nl.tudelft.simulation.jstats.streams.MersenneTwister;
import nl.tudelft.simulation.jstats.streams.StreamInterface;

/**
 * <p>
 * Copyright (c) 2013-2018 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 11 dec. 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>
 */
public class ODApplierExample extends AbstractWrappableAnimation
{

    /** Lane based or not. */
    static final boolean LANE_BASED = true;

    /** Simulation period. */
    static final Duration PERIOD = new Duration(60.0, DurationUnit.MINUTE);

    /** Demand factor. */
    static final Double DEMAND = 2.0;

    /** */
    private static final long serialVersionUID = 20171211L;

    /** Colorer. */
    private GTUColorer colorer = new LmrsSwitchableColorer();

    /**
     * @param args arguments
     */
    public static void main(final String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    ODApplierExample animation = new ODApplierExample();
                    // 1 hour simulation run for testing
                    animation.buildAnimator(Time.ZERO, Duration.ZERO, PERIOD, new ArrayList<Property<?>>(), null, true);

                }
                catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception)
                {
                    exception.printStackTrace();
                }
            }
        });
    }

    /** {@inheritDoc} */
    @Override
    public String shortName()
    {
        return "ODApplierExample";
    }

    /** {@inheritDoc} */
    @Override
    public String description()
    {
        return "Example use of the utility ODApplier.applyOD()";
    }

    /** {@inheritDoc} */
    @Override
    protected final void addAnimationToggles()
    {
        AnimationToggles.setIconAnimationTogglesStandard(this);
    }

    /** {@inheritDoc} */
    @Override
    protected OTSModelInterface makeModel() throws OTSSimulationException
    {
        return new ODApplierExampleModel();
    }

    /** {@inheritDoc} */
    @Override
    public GTUColorer getColorer()
    {
        return this.colorer;
    }

    /**
     * The simulation model.
     */
    class ODApplierExampleModel implements OTSModelInterface
    {

        /** */
        private static final long serialVersionUID = 20171211L;

        /** The network. */
        private OTSNetwork network;

        /** Simulator. */
        private DEVSSimulatorInterface.TimeDoubleUnit simulator;

        /** {@inheritDoc} */
        @Override
        public void constructModel(final SimulatorInterface<Time, Duration, SimTimeDoubleUnit> sim) throws SimRuntimeException
        {
            this.simulator = (DEVSSimulatorInterface.TimeDoubleUnit) sim;
            Map<String, StreamInterface> streams = new HashMap<>();
            streams.put("generation", new MersenneTwister(1L));
            this.simulator.getReplication().setStreams(streams);

            this.network = new OTSNetwork("ODApplierExample");
            try
            {
                // Network
                OTSPoint3D pointA = new OTSPoint3D(-100, 50, 0);
                OTSPoint3D pointA1 = new OTSPoint3D(50, 50, 0);
                OTSPoint3D pointA2 = new OTSPoint3D(0, 0, 0);
                OTSPoint3D pointA3 = new OTSPoint3D(0, -100, 0);
                OTSPoint3D pointB = new OTSPoint3D(1000, 0, 0);
                OTSNode nodeA = new OTSNode(this.network, "A", pointA);
                OTSNode nodeA1 = new OTSNode(this.network, "A1", pointA1);
                OTSNode nodeA2 = new OTSNode(this.network, "A2", pointA2);
                OTSNode nodeA3 = new OTSNode(this.network, "A3", pointA3);
                OTSNode nodeB = new OTSNode(this.network, "B", pointB);
                CrossSectionLink linkAA1 = new CrossSectionLink(this.network, "AA1", nodeA, nodeA1, LinkType.CONNECTOR,
                        new OTSLine3D(pointA, pointA1), this.simulator, LaneKeepingPolicy.KEEP_RIGHT);
                CrossSectionLink linkAA2 = new CrossSectionLink(this.network, "AA2", nodeA, nodeA2, LinkType.CONNECTOR,
                        new OTSLine3D(pointA, pointA2), this.simulator, LaneKeepingPolicy.KEEP_RIGHT);
                CrossSectionLink linkAA3 = new CrossSectionLink(this.network, "AA3", nodeA, nodeA3, LinkType.CONNECTOR,
                        new OTSLine3D(pointA, pointA3), this.simulator, LaneKeepingPolicy.KEEP_RIGHT);
                CrossSectionLink linkA1B = new CrossSectionLink(this.network, "A1B", nodeA1, nodeB, LinkType.FREEWAY,
                        new OTSLine3D(pointA1, pointB), this.simulator, LaneKeepingPolicy.KEEP_RIGHT);
                CrossSectionLink linkA2B = new CrossSectionLink(this.network, "A2B", nodeA2, nodeB, LinkType.FREEWAY,
                        new OTSLine3D(pointA2, pointB), this.simulator, LaneKeepingPolicy.KEEP_RIGHT);
                CrossSectionLink linkA3B = new CrossSectionLink(this.network, "A3B", nodeA3, nodeB, LinkType.FREEWAY,
                        new OTSLine3D(pointA3, pointB), this.simulator, LaneKeepingPolicy.KEEP_RIGHT);
                Lane lane0 = new Lane(linkA1B, "lane0", Length.createSI(0.0), Length.createSI(3.5), LaneType.HIGHWAY,
                        new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
                Lane lane1 = new Lane(linkA2B, "lane1", Length.createSI(3.5), Length.createSI(3.5), LaneType.HIGHWAY,
                        new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
                Lane lane2 = new Lane(linkA2B, "lane2", Length.createSI(0.0), Length.createSI(3.5), LaneType.HIGHWAY,
                        new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
                Lane lane3 = new Lane(linkA2B, "lane3", Length.createSI(-3.5), Length.createSI(3.5), LaneType.HIGHWAY,
                        new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
                Lane lane4 = new Lane(linkA3B, "lane4", Length.createSI(0.0), Length.createSI(3.5), LaneType.HIGHWAY,
                        new Speed(120, SpeedUnit.KM_PER_HOUR), new OvertakingConditions.LeftOnly());
                Set<GTUType> gtuTypes = new HashSet<>();
                gtuTypes.add(GTUType.VEHICLE);
                Stripe stripe12 = new Stripe(linkA2B, Length.createSI(1.75), Length.createSI(1.75), Length.createSI(0.2),
                        gtuTypes, Permeable.BOTH);
                Stripe stripe23 = new Stripe(linkA2B, Length.createSI(-1.75), Length.createSI(-1.75), Length.createSI(0.2),
                        gtuTypes, Permeable.BOTH);

                // animation
                new NodeAnimation(nodeA, this.simulator);
                new NodeAnimation(nodeA1, this.simulator);
                new NodeAnimation(nodeA2, this.simulator);
                new NodeAnimation(nodeA3, this.simulator);
                new NodeAnimation(nodeB, this.simulator);
                new LinkAnimation(linkAA1, this.simulator, 0.5f);
                new LinkAnimation(linkAA2, this.simulator, 0.5f);
                new LinkAnimation(linkAA3, this.simulator, 0.5f);
                new LinkAnimation(linkA1B, this.simulator, 0.5f);
                new LinkAnimation(linkA2B, this.simulator, 0.5f);
                new LinkAnimation(linkA3B, this.simulator, 0.5f);
                new LaneAnimation(lane0, this.simulator, Color.GRAY.brighter(), false);
                new LaneAnimation(lane1, this.simulator, Color.GRAY.brighter(), false);
                new LaneAnimation(lane2, this.simulator, Color.GRAY.brighter(), false);
                new LaneAnimation(lane3, this.simulator, Color.GRAY.brighter(), false);
                new LaneAnimation(lane4, this.simulator, Color.GRAY.brighter(), false);
                new StripeAnimation(stripe12, this.simulator, TYPE.DASHED);
                new StripeAnimation(stripe23, this.simulator, TYPE.DASHED);
                new SinkSensor(lane0, Length.createSI(904), this.simulator);
                new SinkSensor(lane1, Length.createSI(900), this.simulator);
                new SinkSensor(lane2, Length.createSI(900), this.simulator);
                new SinkSensor(lane3, Length.createSI(900), this.simulator);
                new SinkSensor(lane4, Length.createSI(904), this.simulator);
                // traffic light
                TrafficLight trafficLight = new SimpleTrafficLight("light1", lane1, Length.createSI(800.0), this.simulator);
                new TrafficLightAnimation(trafficLight, this.simulator);
                this.simulator.scheduleEventAbs(Time.createSI(30 * 60), this, trafficLight, "setTrafficLightColor",
                        new Object[] { TrafficLightColor.YELLOW });
                this.simulator.scheduleEventAbs(Time.createSI(30 * 60 + 6), this, trafficLight, "setTrafficLightColor",
                        new Object[] { TrafficLightColor.RED });
                this.simulator.scheduleEventAbs(Time.createSI(35 * 60), this, trafficLight, "setTrafficLightColor",
                        new Object[] { TrafficLightColor.GREEN });

                // OD
                Categorization categorization;
                if (ODApplierExample.LANE_BASED)
                {
                    categorization = new Categorization("ODExample", Lane.class, GTUType.class);
                }
                else
                {
                    categorization = new Categorization("ODExample", GTUType.class);
                }
                List<Node> origins = new ArrayList<>();
                if (ODApplierExample.LANE_BASED)
                {
                    origins.add(nodeA1);
                    origins.add(nodeA2);
                    origins.add(nodeA3);
                }
                else
                {
                    origins.add(nodeA);
                }
                List<Node> destinations = new ArrayList<>();
                destinations.add(nodeB);
                double fT = PERIOD.si / 3600;
                TimeVector timeVector = new TimeVector(new double[] { 5 * fT, 600 * fT, 610 * fT, 1800 * fT, 3000 * fT },
                        TimeUnit.BASE, StorageType.DENSE);
                ODMatrix od =
                        new ODMatrix("ODExample", origins, destinations, categorization, timeVector, Interpolation.STEPWISE);
                FrequencyVector demand = new FrequencyVector(
                        new double[] { 0 * DEMAND, 1000 * DEMAND, 3000 * DEMAND, 7000 * DEMAND, 0 * DEMAND },
                        FrequencyUnit.PER_HOUR, StorageType.DENSE);

                Category platoonCategory;
                if (ODApplierExample.LANE_BASED)
                {
                    Category category = new Category(categorization, lane1, GTUType.CAR);
                    platoonCategory = category;
                    od.putDemandVector(nodeA2, nodeB, category, demand, timeVector, Interpolation.LINEAR, .4);
                    category = new Category(categorization, lane2, GTUType.CAR);
                    od.putDemandVector(nodeA2, nodeB, category, demand, timeVector, Interpolation.LINEAR, .25);
                    category = new Category(categorization, lane2, GTUType.TRUCK);
                    od.putDemandVector(nodeA2, nodeB, category, demand, timeVector, Interpolation.LINEAR, .05);
                    category = new Category(categorization, lane3, GTUType.CAR);
                    od.putDemandVector(nodeA2, nodeB, category, demand, timeVector, Interpolation.LINEAR, .1);
                    category = new Category(categorization, lane3, GTUType.TRUCK);
                    od.putDemandVector(nodeA2, nodeB, category, demand, timeVector, Interpolation.LINEAR, .2);
                }
                else
                {
                    Category category = new Category(categorization, GTUType.CAR);
                    platoonCategory = category;
                    od.putDemandVector(nodeA, nodeB, category, demand, timeVector, Interpolation.LINEAR, .9);
                    category = new Category(categorization, GTUType.TRUCK);
                    od.putDemandVector(nodeA, nodeB, category, demand, timeVector, Interpolation.LINEAR, .1);
                }
                // options
                MarkovCorrelation<GTUType, Frequency> markov = new MarkovCorrelation<>();
                markov.addState(GTUType.TRUCK, 0.4);
                LaneBiases biases = new LaneBiases().addBias(GTUType.VEHICLE, LaneBias.bySpeed(130, 80)).addBias(GTUType.TRUCK,
                        LaneBias.TRUCK_RIGHT);
                ODOptions odOptions = new ODOptions().set(ODOptions.GTU_COLORER, getColorer())
                        .set(ODOptions.ROOM_CHECKER, new CFBARoomChecker()).set(ODOptions.MARKOV, markov)
                        .set(ODOptions.LANE_BIAS, biases).set(ODOptions.NO_LC_DIST, Length.createSI(100.0));
                Map<String, GeneratorObjects> generatedObjects = ODApplier.applyOD(this.network, od, this.simulator, odOptions);
                for (String str : generatedObjects.keySet())
                {
                    new GTUGeneratorAnimation(generatedObjects.get(str).getGenerator(), this.simulator);
                }

                // platoons
                String id = LANE_BASED ? "A21" : "A";
                Lane platoonLane = LANE_BASED ? lane1 : lane0;
                Set<DirectedLanePosition> position = new HashSet<>();
                position.add(new DirectedLanePosition(platoonLane, Length.ZERO, GTUDirectionality.DIR_PLUS));
                Platoons platoons = new Platoons(generatedObjects.get(id).getGenerator(),
                        odOptions.get(ODOptions.GTU_TYPE, null, null, null), this.simulator, streams.get("generation"),
                        position);
                platoons.addPlatoon(Time.createSI(60), Time.createSI(90));
                platoons.fixInfo(nodeA, nodeB, platoonCategory, new Speed(90, SpeedUnit.KM_PER_HOUR));
                for (double t = 62; t < 90; t += 2)
                {
                    platoons.addGtu(Time.createSI(t));
                }
                platoons.addPlatoon(Time.createSI(300), Time.createSI(330));
                for (double t = 302; t < 330; t += 2)
                {
                    platoons.addGtu(Time.createSI(t));
                }
                platoons.start();

            }
            catch (NetworkException | OTSGeometryException | NamingException | ValueException | ParameterException
                    | GTUException | RemoteException exception)
            {
                exception.printStackTrace();
            }
        }

        /** {@inheritDoc} */
        @Override
        public SimulatorInterface<Time, Duration, SimTimeDoubleUnit> getSimulator()
        {
            return this.simulator;
        }

        /** {@inheritDoc} */
        @Override
        public OTSNetwork getNetwork()
        {
            return this.network;
        }

    }

}