Package org.movsim.simulator.vehicles.lanechange

Source Code of org.movsim.simulator.vehicles.lanechange.MOBIL

/*
* Copyright (C) 2010, 2011, 2012 by Arne Kesting, Martin Treiber, Ralph Germ, Martin Budden
* <movsim.org@gmail.com>
* -----------------------------------------------------------------------------------------
*
* This file is part of
*
* MovSim - the multi-model open-source vehicular-traffic simulator.
*
* MovSim is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MovSim is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MovSim. If not, see <http://www.gnu.org/licenses/>
* or <http://www.movsim.org>.
*
* -----------------------------------------------------------------------------------------
*/
package org.movsim.simulator.vehicles.lanechange;

import org.movsim.autogen.ModelParameterMOBIL;
import org.movsim.simulator.roadnetwork.LaneSegment;
import org.movsim.simulator.roadnetwork.Lanes;
import org.movsim.simulator.roadnetwork.RoadSegment;
import org.movsim.simulator.vehicles.Vehicle;
import org.movsim.simulator.vehicles.longitudinalmodel.acceleration.LongitudinalModelBase.ModelName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

/**
* The Class MOBIL.
*
* <p>
* Paper for reference:
* </p>
* <p>
* <a href="http://pubsindex.trb.org/view.aspx?id=801029"> M. Treiber, A. Kesting, D. Helbing, General Lanes-Changing
* Model MOBIL for Car-Following Models. Transportation Research Record, Volume 1999, Pages 86-94 (2007).</a>
* </p>
*/

// TODO needs refactoring and better documentation
public class MOBIL {

    /** The Constant LOG. */
    private static final Logger LOG = LoggerFactory.getLogger(MOBIL.class);


    private ModelParameterMOBIL param;

    /**
     * Instantiates a new MOBIL.
     *
     * @param vehicle
     *            the vehicle
     * @param modelParameterMOBIL
     *            the lane change MOBIL data
     */
    public MOBIL(Vehicle vehicle, ModelParameterMOBIL modelParameterMOBIL) {
        Preconditions.checkNotNull(modelParameterMOBIL);
        this.param = modelParameterMOBIL;

        if (vehicle != null && modelParameterMOBIL.getSafeDeceleration() > vehicle.getMaxDeceleration()) {
            // MOBIL bSafe parameter should be typically chosen well below the physical maximum deceleration
            LOG.error("not consistent modeling input data: MOBIL's bSafe must be <= vehicle's maximum deceleration."
                    + " Otherwise crashes could occur! Restrict bSafe to maximum deceleration={}",
                    vehicle.getMaxDeceleration());
            throw new IllegalStateException("Inconsistent input configuration: MOBIL max. deceleration="
                    + modelParameterMOBIL.getSafeDeceleration() + " is larger than vehicle's max. deceleration="
                    + vehicle.getMaxDeceleration());
        }
    }

    public boolean safetyCheckAcceleration(double acc) {
        return acc <= -param.getSafeDeceleration();
    }

    public double calcAccelerationBalance(Vehicle me, int direction, RoadSegment roadSegment) {

        // set prospectiveBalance to large negative to indicate no lane change when not safe
        double prospectiveBalance = -Double.MAX_VALUE;
        final int currentLane = me.lane();
        final int newLane = currentLane + direction;
        assert newLane >= Lanes.MOST_INNER_LANE && newLane <= roadSegment.laneCount();
        final LaneSegment newLaneSegment = roadSegment.laneSegment(newLane);
        if (newLaneSegment.type() == Lanes.Type.ENTRANCE) {
            // never change lane into an entrance lane
            return prospectiveBalance;
        }

        final Vehicle newFront = newLaneSegment.frontVehicle(me);
        if (newFront != null) {
            if (newFront.inProcessOfLaneChange()) {
                return prospectiveBalance;
            }
            final double gapFront = me.getNetDistance(newFront);
            if (gapFront < param.getMinimumGap()) {
                return prospectiveBalance;
            }
        }
        final Vehicle newBack = newLaneSegment.rearVehicle(me);
        if (newBack != null) {
            if (newBack.inProcessOfLaneChange()) {
                return prospectiveBalance;
            }
            final double gapRear = newBack.getNetDistance(me);
            if (gapRear < param.getMinimumGap()) {
                return prospectiveBalance;
            }
        }
        final LaneSegment currentLaneSegment = roadSegment.laneSegment(currentLane);
        final Vehicle oldFront = currentLaneSegment.frontVehicle(me);
        if (oldFront != null) {
            if (oldFront.inProcessOfLaneChange()) {
                return prospectiveBalance;
            }
        }

        // new situation: newBack with me as leader and following left lane cases
        // TO_LEFT --> just the actual situation
        // TO_RIGHT --> consideration of left-lane (with me's leader) has no effect
        // temporarily add the current vehicle to the new lane to calculate the new accelerations
        me.setLane(newLane);
        final int index = newLaneSegment.addVehicleTemp(me);
        final double newBackNewAcc = newBack == null ? 0 : newBack.calcAccModel(newLaneSegment, null);
        final double meNewAcc = me.calcAccModel(newLaneSegment, null);
        newLaneSegment.removeVehicle(index);
        me.setLane(currentLane);

        if (safetyCheckAcceleration(newBackNewAcc)) {
            return prospectiveBalance;
        }

        // check now incentive criterion
        // consider three vehicles: me, oldBack, newBack

        // old situation for me
        final double meOldAcc = me.calcAccModel(currentLaneSegment, null);

        // old situation for old back
        // in old situation same left lane as me
        final Vehicle oldBack = currentLaneSegment.rearVehicle(me);
        final double oldBackOldAcc = (oldBack != null) ? oldBack.calcAccModel(currentLaneSegment, null) : 0.0;

        // old situation for new back: just provides the actual left-lane situation
        final double newBackOldAcc = (newBack != null) ? newBack.calcAccModel(newLaneSegment, null) : 0.0;

        // new situation for new back:
        final double oldBackNewAcc;
        if (oldBack == null) {
            oldBackNewAcc = 0.0;
        } else {
            // cannot temporarily remove the current vehicle from the current lane, since we are in a loop
            // that iterates over the vehicles in the current lane. So calculate oldBackNewAcc based on just
            // the front vehicle.
            if (currentLaneSegment.frontVehicle(me) != null) { // TODO remove quickhack for avoiding nullpointer
                oldBackNewAcc = oldBack.getLongitudinalModel().calcAcc(oldBack, currentLaneSegment.frontVehicle(me));
            } else {
                oldBackNewAcc = 0.0;
            }

            // currentLaneSegment.removeVehicle(me);
            // oldBackNewAcc = oldBack.calcAccModel(currentLaneSegment, null);
            // currentLaneSegment.addVehicle(me);
        }

        // MOBIL trade-off for driver and neighborhood
        final double oldBackDiffAcc = oldBackNewAcc - oldBackOldAcc;
        final double newBackDiffAcc = newBackNewAcc - newBackOldAcc;
        final double meDiffAcc = meNewAcc - meOldAcc;

        final int changeTo = newLaneSegment.lane() - currentLaneSegment.lane();

        // hack for CCS
        if (me.getLongitudinalModel().modelName() == ModelName.CCS) {
            double biasForced = 10000;
            double biasNormal = 0.02;
            double bias;
            final int laneCount = roadSegment.laneCount();

            if (roadSegment.laneSegment(currentLane).type() == Lanes.Type.ENTRANCE) {
                double factor = (currentLane > 0.5 * (laneCount - 1)) ? (laneCount - currentLane) : (currentLane + 1);
                // System.out.println("currentLane: " + currentLane + " factor*biasForced=" + factor * biasForced);
                return biasForced * factor;
            }

            // assume increasing lane index from right to left
            bias = +2 * biasNormal / (laneCount - 1) * (currentLane - (0.5 * (laneCount - 1)));

            prospectiveBalance = meDiffAcc + param.getPoliteness() * (oldBackDiffAcc + newBackDiffAcc)
                    - param.getThresholdAcceleration() - bias * direction;

            // ###########################################################
            // new hack: bias considering BOTH the plus and the minus lane

            // Parameter considering BOTH the plus and the minus lane
            double vc = 0.5; // maximum speed for the method to be effective
            double biasmax = 50; // maximum bias
            double fracCoop = 0.8; // fraction of cooperative runners/vehicles
            double b = 10; // normal deceleration (=b in acc models)
            double dt = 0.2; // !! get elsewhere!!

            // local variables need for both (1) and (2)

            int lanePlus = currentLane + direction;
            int laneMinus = currentLane - direction;
            if ((Math.min(lanePlus, laneMinus) < Lanes.MOST_INNER_LANE) || (Math.max(lanePlus, laneMinus) > laneCount)) {
                return prospectiveBalance;
            }

            final LaneSegment laneSegmentPlus = roadSegment.laneSegment(lanePlus);
            final LaneSegment laneSegmentMinus = roadSegment.laneSegment(laneMinus);
            final Vehicle frontPlus = laneSegmentPlus.frontVehicle(me);
            final Vehicle rearPlus = laneSegmentPlus.rearVehicle(me);
            final Vehicle frontMinus = laneSegmentMinus.frontVehicle(me);
            final Vehicle rearMinus = laneSegmentMinus.rearVehicle(me);
            if ((frontPlus == null) || (frontMinus == null) || (rearPlus == null) || (rearMinus == null)) {
                return prospectiveBalance;
            }

            double vPlus = Math.min(frontPlus.getSpeed(), rearPlus.getSpeed());
            double vMinus = Math.min(frontMinus.getSpeed(), rearMinus.getSpeed());
            double vAdj = Math.min(vPlus, vMinus);

            // (1) cooperative braking of runners/vehicles
            // to make space for agents on congested adjacent lane(s)

            int vehPerCoopVeh = (int) (1. / (fracCoop + 1e-6));
            double accCoop = 0;
            if (me.getId() % vehPerCoopVeh == 0) {
                accCoop = -b * Math.max(0., (vc - vAdj) / vc)
                        * (Math.min(1., Math.max(0, ((me.getSpeed() - vc) / vc))));
                accCoop = Math.max(-b, accCoop + me.getAcc());
                me.setSpeed(me.getSpeed() + dt * accCoop);
            }

            // (2) anticipatory lane changes of runners adjacent of congested lanes
            // to the free lane on the other side (if applicable)

            int isEffective = ((vPlus - me.getSpeed()) * (me.getSpeed() - vMinus) > 0) ? 1 : 0;
            double abiasBoth = isEffective * ((vPlus - vMinus > 0) ? 1 : -1) * biasmax * Math.max(0., (vc - vAdj) / vc);
            prospectiveBalance += abiasBoth;
            // System.out.println("currentLane=" + currentLane + " direction=" + direction + " vPlus=" + vPlus
            // + " vMinus=" + vMinus + " v=" + me.getSpeed());
            // System.out.println("abiasBoth=" + abiasBoth);

            // ###########################################################

            return prospectiveBalance; // quick hack ends here
        }

        // MOBIL's incentive formula

        final int biasSign = (changeTo == Lanes.TO_LEFT) ? 1 : -1;

        prospectiveBalance = meDiffAcc + param.getPoliteness() * (oldBackDiffAcc + newBackDiffAcc)
                - param.getThresholdAcceleration() - biasSign * param.getRightBiasAcceleration();

        return prospectiveBalance;
    }

    public ModelParameterMOBIL getParameter() {
        // remark: returned object is not immutable
        return param;
    }

}
TOP

Related Classes of org.movsim.simulator.vehicles.lanechange.MOBIL

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.