package strategies; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.naming.NamingException; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JLabel; import javax.swing.JSlider; import javax.swing.SwingConstants; import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.djunits.unit.DirectionUnit; import org.djunits.unit.SpeedUnit; import org.djunits.value.vdouble.scalar.Acceleration; import org.djunits.value.vdouble.scalar.Direction; import org.djunits.value.vdouble.scalar.Duration; import org.djunits.value.vdouble.scalar.Length; import org.djunits.value.vdouble.scalar.Speed; import org.djutils.cli.CliException; import org.djutils.cli.CliUtil; import org.djutils.event.EventInterface; import org.djutils.event.EventListenerInterface; import org.djutils.exceptions.Try; import org.opentrafficsim.base.parameters.ParameterException; import org.opentrafficsim.base.parameters.ParameterSet; import org.opentrafficsim.base.parameters.ParameterTypes; import org.opentrafficsim.base.parameters.Parameters; import org.opentrafficsim.core.animation.gtu.colorer.AccelerationGTUColorer; import org.opentrafficsim.core.animation.gtu.colorer.SpeedGTUColorer; import org.opentrafficsim.core.animation.gtu.colorer.SwitchableGTUColorer; import org.opentrafficsim.core.dsol.OTSSimulatorInterface; import org.opentrafficsim.core.geometry.OTSGeometryException; import org.opentrafficsim.core.geometry.OTSLine3D; import org.opentrafficsim.core.geometry.OTSPoint3D; import org.opentrafficsim.core.gtu.GTU; import org.opentrafficsim.core.gtu.GTUCharacteristics; import org.opentrafficsim.core.gtu.GTUDirectionality; import org.opentrafficsim.core.gtu.GTUException; import org.opentrafficsim.core.gtu.GTUType; import org.opentrafficsim.core.gtu.perception.DirectEgoPerception; import org.opentrafficsim.core.network.Link; import org.opentrafficsim.core.network.LinkType; import org.opentrafficsim.core.network.NetworkException; import org.opentrafficsim.core.parameters.ParameterFactoryByType; import org.opentrafficsim.road.gtu.colorer.DesiredHeadwayColorer; import org.opentrafficsim.road.gtu.colorer.FixedColor; import org.opentrafficsim.road.gtu.colorer.IncentiveColorer; import org.opentrafficsim.road.gtu.colorer.SocialPressureColorer; import org.opentrafficsim.road.gtu.lane.LaneBasedGTU; import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU; import org.opentrafficsim.road.gtu.lane.perception.CategoricalLanePerception; import org.opentrafficsim.road.gtu.lane.perception.LanePerception; import org.opentrafficsim.road.gtu.lane.perception.PerceptionFactory; import org.opentrafficsim.road.gtu.lane.perception.categories.AnticipationTrafficPerception; import org.opentrafficsim.road.gtu.lane.perception.categories.DirectInfrastructurePerception; import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.DirectNeighborsPerception; import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType; import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM; 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.AccelerationIncentive; import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveKeep; import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveRoute; import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSocioSpeed; import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveSpeedWithCourtesy; import org.opentrafficsim.road.gtu.lane.tactical.lmrs.IncentiveStayRight; import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory; import org.opentrafficsim.road.gtu.lane.tactical.lmrs.SocioDesiredSpeed; import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation; import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance; import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters; import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.MandatoryIncentive; import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization; import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating; import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive; import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner; import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory; import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory; import org.opentrafficsim.road.network.OTSRoadNetwork; import org.opentrafficsim.road.network.factory.LaneFactory; 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.OTSRoadNode; import org.opentrafficsim.road.network.lane.Stripe.Permeable; import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy; import org.opentrafficsim.swing.gui.OTSAnimationPanel; import org.opentrafficsim.swing.gui.OTSAnimationPanel.DemoPanelPosition; import org.opentrafficsim.swing.script.AbstractSimulationScript; import nl.tudelft.simulation.dsol.SimRuntimeException; import nl.tudelft.simulation.jstats.distributions.DistNormal; import nl.tudelft.simulation.jstats.streams.MersenneTwister; import nl.tudelft.simulation.jstats.streams.StreamInterface; import picocli.CommandLine.Option; /** * Demo of lane change strategies. *

* Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License. *

* @version $Revision$, $LastChangedDate$, by $Author$, initial version 4 jun. 2018
* @author Wouter Schakel */ public class StrategiesDemo extends AbstractSimulationScript { /** Factories. */ private final Map> factories = new LinkedHashMap<>(); /** GTU id number. */ private int gtuIdNum = 0; /** Number of GTUs. */ private int gtuNum = 60; /** Random stream. */ private final StreamInterface stream = new MersenneTwister(1L); /** Queue of cumulative odometers. */ private final List queue = new ArrayList<>(); /** Lane change listener. */ private KmplcListener kmplcListener; /** Truck fraction. */ private double truckFraction = 0.1; /** Next GTU type. */ private GTUType nextGtuType; /** Truck length. */ private Length truckLength; /** Truck mid. */ private Length truckMid; /** Car length. */ @Option(names = "--length", description = "Length", defaultValue = "2m") private Length carLength; /** Car mid. */ private Length carMid; /** * Constructor. */ protected StrategiesDemo() { super("Strategies demo", "Demo of driving strategies in LMRS."); setGtuColorer(SwitchableGTUColorer.builder().addColorer(new FixedColor(Color.BLUE, "Blue")).addColorer( new SpeedGTUColorer(new Speed(150, SpeedUnit.KM_PER_HOUR))).addColorer(new AccelerationGTUColorer(Acceleration .instantiateSI(-6.0), Acceleration.instantiateSI(2))).addActiveColorer(new SocialPressureColorer()).addColorer( new DesiredHeadwayColorer(Duration.instantiateSI(0.5), Duration.instantiateSI(1.6))).addColorer( new IncentiveColorer(IncentiveSocioSpeed.class)).build()); try { CliUtil.changeOptionDefault(this, "simulationTime", "3600000s"); } catch (NoSuchFieldException | IllegalStateException | IllegalArgumentException | CliException exception) { throw new RuntimeException(exception); } } /** * Main method. * @param args String[]; arguments */ public static void main(final String[] args) { StrategiesDemo demo = new StrategiesDemo(); CliUtil.execute(demo, args); try { demo.start(); } catch (Exception ex) { ex.printStackTrace(); } } /** {@inheritDoc} */ @Override protected void setupDemo(final OTSAnimationPanel animation, final OTSRoadNetwork network) { // demo panel animation.createDemoPanel(DemoPanelPosition.RIGHT); animation.getDemoPanel().setBorder(new EmptyBorder(10, 10, 10, 10)); animation.getDemoPanel().setLayout(new BoxLayout(animation.getDemoPanel(), BoxLayout.Y_AXIS)); animation.getDemoPanel().setPreferredSize(new Dimension(300, 300)); // text JLabel textLabel = new JLabel("

" + "Adjust the sliders below to change the ego-speed sensitivity and socio-speed sensitivity of the drivers, " + "and observe how traffic is affected. Detailed instructions are in the attached read-me." + ""); textLabel.setAlignmentX(Component.CENTER_ALIGNMENT); animation.getDemoPanel().add(textLabel); // spacer animation.getDemoPanel().add(Box.createVerticalStrut(20)); // number of vehicles JLabel gtuLabel = new JLabel("Number of vehicles"); gtuLabel.setHorizontalAlignment(SwingConstants.CENTER); gtuLabel.setPreferredSize(new Dimension(200, 0)); gtuLabel.setAlignmentX(Component.CENTER_ALIGNMENT); animation.getDemoPanel().add(gtuLabel); JSlider gtuSlider = new JSlider(0, 120, this.gtuNum); gtuSlider.setMinorTickSpacing(10); gtuSlider.setMajorTickSpacing(30); gtuSlider.setPaintTicks(true); gtuSlider.setPaintLabels(true); gtuSlider.setToolTipText("Number of vehicles"); gtuSlider.addChangeListener(new ChangeListener() { @SuppressWarnings("synthetic-access") @Override public void stateChanged(final ChangeEvent e) { StrategiesDemo.this.gtuNum = ((JSlider) e.getSource()).getValue(); if (!StrategiesDemo.this.getSimulator().isStartingOrRunning()) { // StrategiesDemo.this.checkVehicleNumber(); animation.getDemoPanel().getParent().repaint(); } } }); animation.getDemoPanel().add(gtuSlider); // spacer animation.getDemoPanel().add(Box.createVerticalStrut(20)); // ego JLabel egoLabel = new JLabel("Ego-speed sensitivity-1 [km/h]"); egoLabel.setHorizontalAlignment(SwingConstants.CENTER); egoLabel.setPreferredSize(new Dimension(200, 0)); egoLabel.setAlignmentX(Component.CENTER_ALIGNMENT); animation.getDemoPanel().add(egoLabel); int egoSteps = 70; JSlider egoSlider = new JSlider(0, egoSteps, egoSteps / 2); egoSlider.setMinorTickSpacing(2); egoSlider.setMajorTickSpacing(egoSteps / 5); egoSlider.setPaintTicks(true); egoSlider.setPaintLabels(true); Hashtable egoTable = new Hashtable<>(); for (int i = 0; i <= egoSteps; i += egoSteps / 5) { egoTable.put(i, new JLabel(String.format("%d", i))); } egoSlider.setLabelTable(egoTable); egoSlider.setToolTipText("Ego-speed sensitivity as 1/vgain"); egoSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(final ChangeEvent e) { double v = Math.max(((JSlider) e.getSource()).getValue(), 0.01); Speed vGain = new Speed(v, SpeedUnit.KM_PER_HOUR); for (GTU gtu : getNetwork().getGTUs()) { if (gtu.getGTUType().isOfType(GTUType.DEFAULTS.CAR)) { Try.execute(() -> gtu.getParameters().setParameter(LmrsParameters.VGAIN, vGain), "Exception while setting vGain"); } } } }); animation.getDemoPanel().add(egoSlider); // spacer animation.getDemoPanel().add(Box.createVerticalStrut(20)); // socio JLabel socioLabel = new JLabel("Socio-speed sensitivity [-]"); socioLabel.setAlignmentX(Component.CENTER_ALIGNMENT); animation.getDemoPanel().add(socioLabel); int socioSteps = 20; JSlider socioSlider = new JSlider(0, socioSteps, socioSteps / 2); socioSlider.setMinorTickSpacing(1); socioSlider.setMajorTickSpacing(socioSteps / 5); socioSlider.setPaintTicks(true); socioSlider.setPaintLabels(true); Hashtable socioTable = new Hashtable<>(); for (int i = 0; i <= socioSteps; i += socioSteps / 5) { double val = (double) i / socioSteps; socioTable.put(i, new JLabel(String.format("%.2f", val))); } socioSlider.setLabelTable(socioTable); socioSlider.setToolTipText("Socio-speed sensitivity between 0 and 1"); socioSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(final ChangeEvent e) { JSlider slider = (JSlider) e.getSource(); double sigma = ((double) slider.getValue()) / slider.getMaximum(); for (GTU gtu : getNetwork().getGTUs()) { if (gtu.getGTUType().isOfType(GTUType.DEFAULTS.CAR)) { Try.execute(() -> gtu.getParameters().setParameter(LmrsParameters.SOCIO, sigma), "Exception while setting vGain"); } } } }); animation.getDemoPanel().add(socioSlider); // spacer animation.getDemoPanel().add(Box.createVerticalStrut(20)); // km/lc JLabel kmplcLabel = new JLabel("Km between lane changes (last 0): -"); this.kmplcListener = new KmplcListener(kmplcLabel, network); for (GTU gtu : network.getGTUs()) { Try.execute(() -> gtu.addListener(this.kmplcListener, LaneBasedGTU.LANE_CHANGE_EVENT), "Exception while adding lane change listener"); } kmplcLabel.setHorizontalAlignment(SwingConstants.LEFT); kmplcLabel.setAlignmentX(Component.CENTER_ALIGNMENT); animation.getDemoPanel().add(kmplcLabel); } /** * Create or destroy vehicles. */ @SuppressWarnings("unused") private void checkVehicleNumber() { while (getNetwork().getGTUs().size() > this.gtuNum) { int i = StrategiesDemo.this.stream.nextInt(0, getNetwork().getGTUs().size()); Iterator it = getNetwork().getGTUs().iterator(); GTU gtu = it.next(); for (int j = 0; j < i; j++) { gtu = it.next(); } gtu.destroy(); this.queue.clear(); } // if: add one vehicle per cycle, so we limit the disturbance if (getNetwork().getGTUs().size() < this.gtuNum) { Lane lane = null; Length pos = null; Speed initialSpeed = null; Length gap = Length.ZERO; for (Link link : getNetwork().getLinkMap().values()) { for (Lane l : ((CrossSectionLink) link).getLanes()) { if (l.numberOfGtus() == 0) { lane = l; pos = lane.getLength().times(0.5); gap = Length.POSITIVE_INFINITY; initialSpeed = Speed.ZERO; } for (int i = 0; i < l.numberOfGtus(); i++) { LaneBasedGTU gtu1 = l.getGtu(i); Length up = Try.assign(() -> gtu1.position(l, gtu1.getFront()), ""); LaneBasedGTU gtu2; Length down; if (i < l.numberOfGtus() - 1) { gtu2 = l.getGtu(i + 1); down = Try.assign(() -> gtu2.position(l, gtu2.getRear()), ""); } else { Lane nextLane = l.nextLanes(getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE)).keySet().iterator() .next(); if (nextLane.numberOfGtus() == 0) { continue; } gtu2 = nextLane.getGtu(0); down = l.getLength().plus(Try.assign(() -> gtu2.position(nextLane, gtu2.getRear()), "")); } Length tentativeGap = down.minus(up).minus(this.nextGtuType.isOfType(getNetwork().getGtuType( GTUType.DEFAULTS.TRUCK)) ? this.truckLength : this.carLength); if (tentativeGap.gt(gap)) { // check reasonable gap (0.3s) Speed maxSpeed = Speed.max(gtu1.getSpeed(), gtu2.getSpeed()); if (maxSpeed.eq0() || tentativeGap.divide(maxSpeed).si * .5 > .3) { gap = tentativeGap; initialSpeed = Speed.interpolate(gtu1.getSpeed(), gtu2.getSpeed(), 0.5); pos = up.plus(tentativeGap.times(0.5)).minus(this.nextGtuType.isOfType(getNetwork().getGtuType( GTUType.DEFAULTS.TRUCK)) ? this.truckMid : this.carMid); if (pos.gt(l.getLength())) { pos = pos.minus(l.getLength()); lane = l.nextLanes(getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE)).keySet().iterator() .next(); } else { lane = l; } } } } } } if (lane != null) { try { createGtu(lane, pos, this.nextGtuType, initialSpeed, getNetwork()); } catch (NamingException | GTUException | NetworkException | SimRuntimeException | OTSGeometryException exception) { throw new RuntimeException(exception); } this.nextGtuType = this.stream.nextDouble() < this.truckFraction ? getNetwork().getGtuType( GTUType.DEFAULTS.TRUCK) : getNetwork().getGtuType(GTUType.DEFAULTS.CAR); this.queue.clear(); } } Try.execute(() -> getSimulator().scheduleEventRel(Duration.instantiateSI(0.5), this, this, "checkVehicleNumber", new Object[] {}), ""); } /** Lane change listener. */ private class KmplcListener implements EventListenerInterface { /** Label to show statistic. */ private final JLabel label; /** Network. */ private final OTSRoadNetwork network; /** * Constructor. * @param label JLabel; label * @param network OTSRoadNetwork; network */ @SuppressWarnings("synthetic-access") KmplcListener(final JLabel label, final OTSRoadNetwork network) { this.label = label; this.network = network; StrategiesDemo.this.queue.add(0.0); } /** {@inheritDoc} */ @SuppressWarnings("synthetic-access") @Override public void notify(final EventInterface event) throws RemoteException { if (event.getType().equals(LaneBasedGTU.LANE_CHANGE_EVENT)) { double cumul = 0.0; for (GTU gtu : this.network.getGTUs()) { cumul += gtu.getOdometer().si; } cumul /= 1000; StrategiesDemo.this.queue.add(cumul); while (StrategiesDemo.this.queue.size() > 51) { StrategiesDemo.this.queue.remove(0); } double val = (StrategiesDemo.this.queue.get(StrategiesDemo.this.queue.size() - 1) - StrategiesDemo.this.queue .get(0)) / (StrategiesDemo.this.queue.size() - 1.0); this.label.setText(String.format("Lane change rate (last %d): %.1f km/lc", StrategiesDemo.this.queue.size() - 1, val)); } } } /** {@inheritDoc} */ @Override protected OTSRoadNetwork setupSimulation(final OTSSimulatorInterface sim) throws Exception { OTSRoadNetwork network = new OTSRoadNetwork("Strategies demo", true, getSimulator()); GTUCharacteristics truck = GTUType.defaultCharacteristics(network.getGtuType(GTUType.DEFAULTS.TRUCK), network, this.stream); GTUCharacteristics car = GTUType.defaultCharacteristics(network.getGtuType(GTUType.DEFAULTS.CAR), network, this.stream); this.truckLength = truck.getLength(); this.truckMid = truck.getLength().times(0.5).minus(truck.getFront()); this.carLength = car.getLength(); this.carMid = car.getLength().times(0.5).minus(car.getFront()); double radius = 150; Speed speedLimit = new Speed(120.0, SpeedUnit.KM_PER_HOUR); OTSRoadNode nodeA = new OTSRoadNode(network, "A", new OTSPoint3D(-radius, 0, 0), new Direction(270, DirectionUnit.EAST_DEGREE)); OTSRoadNode nodeB = new OTSRoadNode(network, "B", new OTSPoint3D(radius, 0, 0), new Direction(90, DirectionUnit.EAST_DEGREE)); OTSPoint3D[] coordsHalf1 = new OTSPoint3D[127]; for (int i = 0; i < coordsHalf1.length; i++) { double angle = Math.PI * (i) / (coordsHalf1.length - 1); coordsHalf1[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0); } List lanes1 = new LaneFactory(network, nodeB, nodeA, network.getLinkType(LinkType.DEFAULTS.FREEWAY), sim, LaneKeepingPolicy.KEEPLEFT, new OTSLine3D(coordsHalf1)).leftToRight(0.0, Length.instantiateSI(3.5), network .getLaneType(LaneType.DEFAULTS.FREEWAY), speedLimit).addLanes(Permeable.BOTH).getLanes(); OTSPoint3D[] coordsHalf2 = new OTSPoint3D[127]; for (int i = 0; i < coordsHalf2.length; i++) { double angle = Math.PI + Math.PI * (i) / (coordsHalf2.length - 1); coordsHalf2[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle), 0); } List lanes2 = new LaneFactory(network, nodeA, nodeB, network.getLinkType(LinkType.DEFAULTS.FREEWAY), sim, LaneKeepingPolicy.KEEPLEFT, new OTSLine3D(coordsHalf2)).leftToRight(0.0, Length.instantiateSI(3.5), network .getLaneType(LaneType.DEFAULTS.FREEWAY), speedLimit).addLanes(Permeable.BOTH).getLanes(); // Strategical factories PerceptionFactory perceptionFactory = new LmrsStrategiesPerceptionFactory(); // random parameters ParameterFactoryByType parameterFactory = new ParameterFactoryByType(); parameterFactory.addParameter(Tailgating.RHO, 0.0); parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.CAR), LmrsParameters.SOCIO, 0.5); parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), LmrsParameters.SOCIO, 1.0); parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.CAR), LmrsParameters.VGAIN, new Speed(35.0, SpeedUnit.KM_PER_HOUR)); parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), LmrsParameters.VGAIN, new Speed(50.0, SpeedUnit.KM_PER_HOUR)); parameterFactory.addParameter(ParameterTypes.TMAX, Duration.instantiateSI(1.6)); parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.CAR), ParameterTypes.FSPEED, new DistNormal( this.stream, 123.7 / 120.0, 12.0 / 120.0)); parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), ParameterTypes.A, Acceleration.instantiateSI( 0.4)); parameterFactory.addParameter(network.getGtuType(GTUType.DEFAULTS.TRUCK), ParameterTypes.FSPEED, 1.0); for (GTUType gtuType : new GTUType[] {network.getGtuType(GTUType.DEFAULTS.CAR), network.getGtuType( GTUType.DEFAULTS.TRUCK)}) { // incentives Set mandatoryIncentives = new LinkedHashSet<>(); Set voluntaryIncentives = new LinkedHashSet<>(); Set accelerationIncentives = new LinkedHashSet<>(); mandatoryIncentives.add(new IncentiveRoute()); voluntaryIncentives.add(new IncentiveSpeedWithCourtesy()); voluntaryIncentives.add(new IncentiveKeep()); voluntaryIncentives.add(new IncentiveSocioSpeed()); if (gtuType.equals(network.getGtuType(GTUType.DEFAULTS.TRUCK))) { voluntaryIncentives.add(new IncentiveStayRight()); } // car-following factory CarFollowingModelFactory cfFactory = // trucks don't change their desired speed gtuType.equals(network.getGtuType(GTUType.DEFAULTS.CAR)) ? new SocioIDMFactory() : new IDMPlusFactory( this.stream); // tailgating Tailgating tlgt = Tailgating.PRESSURE; // strategical and tactical factory LaneBasedStrategicalPlannerFactory laneBasedStrategicalPlannerFactory = new LaneBasedStrategicalRoutePlannerFactory(new LMRSFactory(cfFactory, perceptionFactory, Synchronization.PASSIVE, Cooperation.PASSIVE, GapAcceptance.INFORMED, tlgt, mandatoryIncentives, voluntaryIncentives, accelerationIncentives), parameterFactory); this.factories.put(gtuType, laneBasedStrategicalPlannerFactory); } for (int i = 0; i < lanes1.size(); i++) { Length pos = Length.instantiateSI(10.0); Length gap = lanes1.get(i).getLength().plus(lanes2.get(i).getLength()).divide(this.gtuNum / 2); for (int j = 0; j < 2; j++) { Lane lane = j == 0 ? lanes1.get(i) : lanes2.get(i); while (true) { GTUType gtuType; if (i == 0) { gtuType = network.getGtuType(GTUType.DEFAULTS.CAR); } else { gtuType = this.stream.nextDouble() < 2 * this.truckFraction ? network.getGtuType(GTUType.DEFAULTS.TRUCK) : network.getGtuType(GTUType.DEFAULTS.CAR); } Speed initialSpeed = Speed.ZERO; createGtu(lane, pos, gtuType, initialSpeed, network); pos = pos.plus(gap); if (pos.si > lane.getLength().si) { pos = pos.minus(lane.getLength()); break; } } } } this.nextGtuType = this.stream.nextDouble() < this.truckFraction ? network.getGtuType(GTUType.DEFAULTS.TRUCK) : network .getGtuType(GTUType.DEFAULTS.CAR); sim.scheduleEventNow(this, this, "checkVehicleNumber", new Object[] {}); return network; } /** * Creates a GTU. * @param lane Lane; lane * @param pos Length; position * @param gtuType GTUType; GTU type * @param initialSpeed Speed; initial speed * @param net OTSRoadNetwork; network * @throws NamingException on exception * @throws GTUException on exception * @throws NetworkException on exception * @throws SimRuntimeException on exception * @throws OTSGeometryException on exception */ public void createGtu(final Lane lane, final Length pos, final GTUType gtuType, final Speed initialSpeed, final OTSRoadNetwork net) throws NamingException, GTUException, NetworkException, SimRuntimeException, OTSGeometryException { GTUCharacteristics gtuCharacteristics = Try.assign(() -> GTUType.defaultCharacteristics(gtuType, net, this.stream), "Exception while applying default GTU characteristics."); LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.gtuIdNum), gtuType, gtuCharacteristics.getLength(), gtuCharacteristics.getWidth(), gtuCharacteristics.getMaximumSpeed(), gtuCharacteristics.getFront(), getSimulator(), net); gtu.setMaximumAcceleration(gtuCharacteristics.getMaximumAcceleration()); gtu.setMaximumDeceleration(gtuCharacteristics.getMaximumDeceleration()); gtu.setNoLaneChangeDistance(Length.instantiateSI(50)); gtu.setInstantaneousLaneChange(true); // strategical planner LaneBasedStrategicalPlanner strategicalPlanner = this.factories.get(gtuType).create(gtu, null, null, null); // init Set initialPositions = new LinkedHashSet<>(1); initialPositions.add(new DirectedLanePosition(lane, pos, GTUDirectionality.DIR_PLUS)); if (pos.plus(gtu.getFront().getDx()).gt(lane.getLength())) { Lane nextLane = lane.nextLanes(gtuType).keySet().iterator().next(); Length nextPos = pos.minus(lane.getLength()); initialPositions.add(new DirectedLanePosition(nextLane, nextPos, GTUDirectionality.DIR_PLUS)); } if (pos.plus(gtu.getRear().getDx()).lt0()) { Lane prevLane = lane.prevLanes(gtuType).keySet().iterator().next(); Length prevPos = prevLane.getLength().plus(pos.plus(gtu.getRear().getDx())); initialPositions.add(new DirectedLanePosition(prevLane, prevPos, GTUDirectionality.DIR_PLUS)); } gtu.init(strategicalPlanner, initialPositions, initialSpeed); if (this.kmplcListener != null) { Try.execute(() -> gtu.addListener(this.kmplcListener, LaneBasedGTU.LANE_CHANGE_EVENT), "Exception while adding lane change listener"); } } /** IDM factory with socio speed. */ class SocioIDMFactory implements CarFollowingModelFactory { /** {@inheritDoc} */ @Override public Parameters getParameters() throws ParameterException { ParameterSet parameters = new ParameterSet(); parameters.setDefaultParameters(AbstractIDM.class); return parameters; } /** {@inheritDoc} */ @Override public IDMPlus generateCarFollowingModel() { return new IDMPlus(AbstractIDM.HEADWAY, new SocioDesiredSpeed(AbstractIDM.DESIRED_SPEED)); } } /** Perception factory. */ class LmrsStrategiesPerceptionFactory implements PerceptionFactory { /** {@inheritDoc} */ @Override public LanePerception generatePerception(final LaneBasedGTU gtu) { LanePerception perception = new CategoricalLanePerception(gtu); perception.addPerceptionCategory(new DirectEgoPerception<>(perception)); perception.addPerceptionCategory(new DirectInfrastructurePerception(perception)); perception.addPerceptionCategory(new DirectNeighborsPerception(perception, HeadwayGtuType.WRAP)); perception.addPerceptionCategory(new AnticipationTrafficPerception(perception)); return perception; } /** {@inheritDoc} */ @Override public Parameters getParameters() throws ParameterException { return new ParameterSet().setDefaultParameter(ParameterTypes.LOOKAHEAD).setDefaultParameter( ParameterTypes.LOOKBACKOLD).setDefaultParameter(ParameterTypes.PERCEPTION).setDefaultParameter( ParameterTypes.LOOKBACK); } } }