* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* $LastChangedDate$, @version $Revision$, by $Author$,
* initial version 21 nov. 2014
* @author Peter Knoppers
*/
public class CircularRoad extends AbstractWrappableAnimation implements UNITS
{
/** */
private static final long serialVersionUID = 1L;
/** The model. */
private RoadSimulationModel model;
/**
* Create a CircularRoad simulation.
* @throws PropertyException when a property is not handled
*/
public CircularRoad() throws PropertyException
{
this.properties.add(new SelectionProperty("LaneChanging", "Lane changing",
"The lane change strategies vary in politeness. "
+ "Two types are implemented:
Egoistic (looks only at personal gain).
"
+ "
Altruistic (assigns effect on new and current follower the same weight as "
+ "the personal gain).",
new String[] { "Egoistic", "Altruistic" }, 0, false, 500));
this.properties.add(new SelectionProperty("TacticalPlanner", "Tactical planner",
"The tactical planner determines if a lane change is desired and possible.",
new String[] { "IDM", "MOBIL/IDM", "DIRECTED/IDM", "LMRS", "Toledo" }, 1, false, 600));
this.properties.add(new IntegerProperty("TrackLength", "Track length", "Circumference of the track", 2000, 500, 6000,
"Track length %dm", false, 10));
this.properties.add(new ContinuousProperty("MeanDensity", "Mean density", "Number of vehicles per km", 40.0, 5.0, 45.0,
"Density %.1f veh/km", false, 11));
this.properties.add(new ContinuousProperty("DensityVariability", "Density variability",
"Variability of the number of vehicles per km", 0.0, 0.0, 1.0, "%.1f", false, 12));
List> outputProperties = new ArrayList>();
for (int lane = 1; lane <= 2; lane++)
{
String laneId = String.format("Lane %d ", lane);
outputProperties.add(new BooleanProperty(laneId + "Density", laneId + " Density", laneId + "Density contour plot",
true, false, 0));
outputProperties
.add(new BooleanProperty(laneId + "Flow", laneId + " Flow", laneId + "Flow contour plot", true, false, 1));
outputProperties.add(
new BooleanProperty(laneId + "Speed", laneId + " Speed", laneId + "Speed contour plot", true, false, 2));
outputProperties.add(new BooleanProperty(laneId + "Acceleration", laneId + " Acceleration",
laneId + "Acceleration contour plot", true, false, 3));
outputProperties.add(new BooleanProperty(laneId + "Fixed Sample Rate Trajectories", laneId + " FSR Trajectories",
laneId + "Trajectory (time/distance) diagram", true, false, 4));
outputProperties.add(new BooleanProperty(laneId + "Variable Sample Rate Trajectories", laneId + " VSR Trajectories",
laneId + "Trajectory (time/distance) diagram", true, false, 5));
}
this.properties.add(new CompoundProperty("OutputGraphs", "Output graphs", "Select the graphical output",
outputProperties, true, 1000));
}
/** {@inheritDoc} */
@Override
public final void stopTimersThreads()
{
super.stopTimersThreads();
this.model = null;
}
/**
* Main program.
* @param args String[]; the command line arguments (not used)
* @throws SimRuntimeException should never happen
*/
public static void main(final String[] args) throws SimRuntimeException
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
try
{
CircularRoad circularRoad = new CircularRoad();
List> propertyList = circularRoad.getProperties();
try
{
propertyList.add(new ProbabilityDistributionProperty("TrafficComposition", "Traffic composition",
"Mix of passenger cars and trucks", new String[] { "passenger car", "truck" },
new Double[] { 0.8, 0.2 }, false, 10));
}
catch (PropertyException exception)
{
exception.printStackTrace();
}
propertyList.add(new SelectionProperty("CarFollowingModel", "Car following model",
"The car following model determines "
+ "the acceleration that a vehicle will make taking into account "
+ "nearby vehicles, infrastructural restrictions (e.g. speed limit, "
+ "curvature of the road) capabilities of the vehicle and personality "
+ "of the driver.",
new String[] { "IDM", "IDM+" }, 1, false, 1));
propertyList.add(IDMPropertySet.makeIDMPropertySet("IDMCar", "Car",
new Acceleration(1.0, METER_PER_SECOND_2), new Acceleration(1.5, METER_PER_SECOND_2),
new Length(2.0, METER), new Duration(1.0, SECOND), 2));
propertyList.add(IDMPropertySet.makeIDMPropertySet("IDMTruck", "Truck",
new Acceleration(0.5, METER_PER_SECOND_2), new Acceleration(1.25, METER_PER_SECOND_2),
new Length(2.0, METER), new Duration(1.0, SECOND), 3));
circularRoad.buildAnimator(new Time(0.0, SECOND), new Duration(0.0, SECOND), new Duration(3600.0, SECOND),
propertyList, null, true);
}
catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception)
{
exception.printStackTrace();
}
}
});
}
/** {@inheritDoc} */
@Override
protected final OTSModelInterface makeModel(final GTUColorer colorer)
{
this.model = new RoadSimulationModel(getSavedUserModifiedProperties(), colorer);
return this.model;
}
/**
* @return the saved user properties for a next run
*/
private List> getSavedUserModifiedProperties()
{
return this.savedUserModifiedProperties;
}
/** {@inheritDoc} */
@Override
protected final void addAnimationToggles()
{
AnimationToggles.setTextAnimationTogglesStandard(this);
}
/** {@inheritDoc} */
@Override
protected final void addTabs(final SimpleSimulatorInterface simulator) throws OTSSimulationException, PropertyException
{
// Make the tab with the plots
Property> output = new CompoundProperty("", "", "", this.properties, false, 0).findByKey("OutputGraphs");
if (null == output)
{
throw new Error("Cannot find output properties");
}
ArrayList graphs = new ArrayList();
if (output instanceof CompoundProperty)
{
CompoundProperty outputProperties = (CompoundProperty) output;
for (Property> ap : outputProperties.getValue())
{
if (ap instanceof BooleanProperty)
{
BooleanProperty bp = (BooleanProperty) ap;
if (bp.getValue())
{
graphs.add(bp);
}
}
}
}
else
{
throw new Error("output properties should be compound");
}
int graphCount = graphs.size();
int columns = (int) Math.ceil(Math.sqrt(graphCount));
int rows = 0 == columns ? 0 : (int) Math.ceil(graphCount * 1.0 / columns);
TablePanel charts = new TablePanel(columns, rows);
for (int i = 0; i < graphCount; i++)
{
String graphName = graphs.get(i).getKey();
Container container = null;
LaneBasedGTUSampler graph;
int pos = graphName.indexOf(' ') + 1;
String laneNumberText = graphName.substring(pos, pos + 1);
int lane = Integer.parseInt(laneNumberText) - 1;
if (graphName.contains("Trajectories"))
{
Duration sampleInterval = graphName.contains("Variable Sample Rate") ? null : new Duration(0.2, SECOND);
TrajectoryPlot tp = new TrajectoryPlot(graphName, sampleInterval, this.model.getPath(lane), simulator);
tp.setTitle("Trajectory Graph");
tp.setExtendedState(Frame.MAXIMIZED_BOTH);
graph = tp;
container = tp.getContentPane();
}
else
{
ContourPlot cp;
if (graphName.contains("Density"))
{
cp = new DensityContourPlot(graphName, this.model.getPath(lane));
cp.setTitle("Density Contour Graph");
}
else if (graphName.contains("Speed"))
{
cp = new SpeedContourPlot(graphName, this.model.getPath(lane));
cp.setTitle("Speed Contour Graph");
}
else if (graphName.contains("Flow"))
{
cp = new FlowContourPlot(graphName, this.model.getPath(lane));
cp.setTitle("Flow Contour Graph");
}
else if (graphName.contains("Acceleration"))
{
cp = new AccelerationContourPlot(graphName, this.model.getPath(lane));
cp.setTitle("Acceleration Contour Graph");
}
else
{
throw new Error("Unhandled type of contourplot: " + graphName);
}
graph = cp;
container = cp.getContentPane();
}
// Add the container to the matrix
charts.setCell(container, i % columns, i / columns);
this.model.getPlots().add(graph);
}
addTab(getTabCount(), "statistics", charts);
}
/** {@inheritDoc} */
@Override
public final String shortName()
{
return "Circular Road simulation";
}
/** {@inheritDoc} */
@Override
public final String description()
{
return "
Circular Road simulation
" + "Vehicles are unequally distributed over a two lane ring road. "
+ "When simulation starts, all vehicles begin driving, some lane changes will occurr and some "
+ "shockwaves should develop. "
+ "Trajectories and contourplots are generated during the simulation for both lanes.";
}
}
/**
* Simulate traffic on a circular, two-lane road.
*
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* $LastChangedDate$, @version $Revision$, by $Author$,
* initial version 1 nov. 2014
* @author Peter Knoppers
*/
class RoadSimulationModel implements OTSModelInterface, UNITS
{
/** */
private static final long serialVersionUID = 20141121L;
/** The simulator. */
private OTSDEVSSimulatorInterface simulator;
/** Number of cars created. */
private int carsCreated = 0;
/** The car following model, e.g. IDM Plus for cars. */
private GTUFollowingModelOld carFollowingModelCars;
/** The car following model, e.g. IDM Plus for trucks. */
private GTUFollowingModelOld carFollowingModelTrucks;
/** The probability that the next generated GTU is a passenger car. */
private double carProbability;
/** The lane change model. */
private AbstractLaneChangeModel laneChangeModel;
/** Minimum distance. */
private Length minimumDistance = new Length(0, METER);
/** The speed limit. */
private Speed speedLimit = new Speed(100, KM_PER_HOUR);
/** The plots. */
private List plots = new ArrayList<>();
/** User settable properties. */
private List> properties = null;
/** The sequence of Lanes that all vehicles will follow. */
private List> paths = new ArrayList<>();
/** The random number generator used to decide what kind of GTU to generate. */
private Random randomGenerator = new Random(12345);
/** The GTUColorer for the generated vehicles. */
private final GTUColorer gtuColorer;
/** Strategical planner generator for cars. */
private LaneBasedStrategicalPlannerFactory strategicalPlannerGeneratorCars = null;
/** Strategical planner generator for cars. */
private LaneBasedStrategicalPlannerFactory strategicalPlannerGeneratorTrucks = null;
/** The OTSNetwork. */
private final OTSNetwork network = new OTSNetwork("network");
/**
* @param properties ArrayList<AbstractProperty<?>>; the properties
* @param gtuColorer the default and initial GTUColorer, e.g. a DefaultSwitchableTUColorer
*/
RoadSimulationModel(final List> properties, final GTUColorer gtuColorer)
{
this.properties = properties;
this.gtuColorer = gtuColorer;
}
/**
* @param index int; the rank number of the path
* @return List<Lane>; the set of lanes for the specified index
*/
public List getPath(final int index)
{
return this.paths.get(index);
}
/** {@inheritDoc} */
@Override
public void constructModel(final SimulatorInterface