View Javadoc
1   package org.opentrafficsim.demo.steering;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.djunits.unit.FrequencyUnit;
7   import org.djunits.unit.MassUnit;
8   import org.djunits.unit.SpeedUnit;
9   import org.djunits.unit.TimeUnit;
10  import org.djunits.value.ValueRuntimeException;
11  import org.djunits.value.storage.StorageType;
12  import org.djunits.value.vdouble.scalar.Direction;
13  import org.djunits.value.vdouble.scalar.Length;
14  import org.djunits.value.vdouble.scalar.Mass;
15  import org.djunits.value.vdouble.scalar.Speed;
16  import org.djunits.value.vdouble.vector.FrequencyVector;
17  import org.djunits.value.vdouble.vector.TimeVector;
18  import org.djunits.value.vdouble.vector.base.DoubleVector;
19  import org.djutils.cli.CliUtil;
20  import org.opentrafficsim.base.parameters.ParameterException;
21  import org.opentrafficsim.base.parameters.ParameterSet;
22  import org.opentrafficsim.base.parameters.Parameters;
23  import org.opentrafficsim.core.compatibility.Compatible;
24  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
25  import org.opentrafficsim.core.geometry.Bezier;
26  import org.opentrafficsim.core.geometry.OTSLine3D;
27  import org.opentrafficsim.core.geometry.OTSPoint3D;
28  import org.opentrafficsim.core.gtu.GTUException;
29  import org.opentrafficsim.core.gtu.GTUType;
30  import org.opentrafficsim.core.network.LinkType;
31  import org.opentrafficsim.core.network.Node;
32  import org.opentrafficsim.core.network.OTSNode;
33  import org.opentrafficsim.core.units.distributions.ContinuousDistMass;
34  import org.opentrafficsim.road.gtu.generator.od.DefaultGTUCharacteristicsGeneratorOD;
35  import org.opentrafficsim.road.gtu.generator.od.ODApplier;
36  import org.opentrafficsim.road.gtu.generator.od.ODOptions;
37  import org.opentrafficsim.road.gtu.generator.od.StrategicalPlannerFactorySupplierOD;
38  import org.opentrafficsim.road.gtu.generator.od.StrategicalPlannerFactorySupplierOD.TacticalPlannerFactorySupplierOD;
39  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
40  import org.opentrafficsim.road.gtu.lane.VehicleModel;
41  import org.opentrafficsim.road.gtu.lane.VehicleModelFactory;
42  import org.opentrafficsim.road.gtu.lane.tactical.AbstractLaneBasedTacticalPlannerFactory;
43  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
44  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
45  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLMRSPerceptionFactory;
46  import org.opentrafficsim.road.gtu.lane.tactical.steering.SteeringLmrs;
47  import org.opentrafficsim.road.gtu.lane.tactical.util.Steering;
48  import org.opentrafficsim.road.gtu.lane.tactical.util.Steering.FeedbackTable;
49  import org.opentrafficsim.road.gtu.lane.tactical.util.Steering.FeedbackTable.FeedbackVector;
50  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
51  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.GapAcceptance;
52  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Synchronization;
53  import org.opentrafficsim.road.gtu.strategical.od.Categorization;
54  import org.opentrafficsim.road.gtu.strategical.od.Category;
55  import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
56  import org.opentrafficsim.road.gtu.strategical.od.ODMatrix;
57  import org.opentrafficsim.road.network.OTSRoadNetwork;
58  import org.opentrafficsim.road.network.lane.CrossSectionLink;
59  import org.opentrafficsim.road.network.lane.Lane;
60  import org.opentrafficsim.road.network.lane.LaneType;
61  import org.opentrafficsim.road.network.lane.OTSRoadNode;
62  import org.opentrafficsim.road.network.lane.Stripe;
63  import org.opentrafficsim.road.network.lane.Stripe.Permeable;
64  import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
65  import org.opentrafficsim.road.network.lane.object.sensor.Detector;
66  import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
67  import org.opentrafficsim.swing.script.AbstractSimulationScript;
68  
69  import nl.tudelft.simulation.jstats.distributions.DistUniform;
70  import nl.tudelft.simulation.jstats.streams.StreamInterface;
71  import picocli.CommandLine.Option;
72  
73  /**
74   * Simulation script for steering functionality.
75   * <p>
76   * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
77   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
78   * <p>
79   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 8 jan. 2019 <br>
80   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
81   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
82   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
83   */
84  public class SteeringSimulation extends AbstractSimulationScript
85  {
86  
87      /** Feedback table. */
88      static final FeedbackTable FEEDBACK_CAR;
89  
90      /** Number of lanes. */
91      @Option(names = "--numberOfLanes", description = "Number of lanes", defaultValue = "2")
92      private int numberOfLanes;
93  
94      static
95      {
96          // TODO: define tables
97          List<FeedbackVector> list = new ArrayList<>();
98          list.add(new FeedbackVector(new Speed(25.0, SpeedUnit.KM_PER_HOUR), 0.0, 0.0, 0.0, 0.0));
99          list.add(new FeedbackVector(new Speed(75.0, SpeedUnit.KM_PER_HOUR), 0.0, 0.0, 0.0, 0.0));
100         FEEDBACK_CAR = new FeedbackTable(list);
101     }
102 
103     /**
104      * Start a simulation.
105      * @param args String...; command line arguments
106      */
107     public static void main(final String... args)
108     {
109         try
110         {
111             SteeringSimulationringSimulation.html#SteeringSimulation">SteeringSimulation sim = new SteeringSimulation();
112             CliUtil.execute(sim, args);
113             sim.start();
114         }
115         catch (Exception ex)
116         {
117             ex.printStackTrace();
118         }
119     }
120 
121     /**
122      * Constructor.
123      */
124     protected SteeringSimulation()
125     {
126         super("Steering simulation", "Steering simulation");
127     }
128 
129     /**
130      * Sets up the simulation based on provided properties. Properties can be obtained with {@code getProperty()}. Setting up a
131      * simulation should at least create a network and some demand. Additionally this may setup traffic control, sampling, etc.
132      * @param sim OTSSimulatorInterface; simulator
133      * @return OTSRoadNetwork; network
134      * @throws Exception on any exception
135      */
136     @Override
137     protected OTSRoadNetwork setupSimulation(final OTSSimulatorInterface sim) throws Exception
138     {
139         OTSRoadNetwork network = new OTSRoadNetwork("Steering network", true, getSimulator());
140         Length laneWidth = Length.instantiateSI(3.5);
141         Length stripeWidth = Length.instantiateSI(0.2);
142 
143         // points
144         OTSPoint3D pointA = new OTSPoint3D(0, 0);
145         OTSPoint3D pointB = new OTSPoint3D(2000, 0);
146         OTSPoint3D pointC = new OTSPoint3D(2250, 0);
147         OTSPoint3D pointD = new OTSPoint3D(3250, 0);
148         OTSPoint3D pointE = new OTSPoint3D(1500, -30);
149 
150         // nodes
151         OTSRoadNode nodeA = new OTSRoadNode(network, "A", pointA, Direction.ZERO);
152         OTSRoadNode nodeB = new OTSRoadNode(network, "B", pointB, Direction.ZERO);
153         OTSRoadNode nodeC = new OTSRoadNode(network, "C", pointC, Direction.ZERO);
154         OTSRoadNode nodeD = new OTSRoadNode(network, "D", pointD, Direction.ZERO);
155         OTSRoadNode nodeE = new OTSRoadNode(network, "E", pointE, Direction.ZERO);
156 
157         // links
158         CrossSectionLink linkAB =
159                 new CrossSectionLink(network, "AB", nodeA, nodeB, network.getLinkType(LinkType.DEFAULTS.FREEWAY),
160                         new OTSLine3D(pointA, pointB), LaneKeepingPolicy.KEEPRIGHT);
161         CrossSectionLink linkBC =
162                 new CrossSectionLink(network, "BC", nodeB, nodeC, network.getLinkType(LinkType.DEFAULTS.FREEWAY),
163                         new OTSLine3D(pointB, pointC), LaneKeepingPolicy.KEEPRIGHT);
164         CrossSectionLink linkCD =
165                 new CrossSectionLink(network, "CD", nodeC, nodeD, network.getLinkType(LinkType.DEFAULTS.FREEWAY),
166                         new OTSLine3D(pointC, pointD), LaneKeepingPolicy.KEEPRIGHT);
167         CrossSectionLink linkEB =
168                 new CrossSectionLink(network, "EB", nodeE, nodeB, network.getLinkType(LinkType.DEFAULTS.FREEWAY),
169                         Bezier.cubic(nodeE.getLocation(), nodeB.getLocation()), LaneKeepingPolicy.KEEPRIGHT);
170 
171         // lanes and stripes
172         List<Lane> originLanes = new ArrayList<>();
173         for (int i = 0; i < this.numberOfLanes; i++)
174         {
175             for (CrossSectionLink link : new CrossSectionLink[] {linkAB, linkBC, linkCD})
176             {
177                 Lane lane = new Lane(link, "Lane " + (i + 1), laneWidth.times((0.5 + i)), laneWidth,
178                         network.getLaneType(LaneType.DEFAULTS.FREEWAY), new Speed(120, SpeedUnit.KM_PER_HOUR));
179                 Length offset = laneWidth.times(i + 1.0);
180                 Stripe stripe = new Stripe(link, offset, offset, stripeWidth);
181                 if (i < this.numberOfLanes - 1)
182                 {
183                     stripe.addPermeability(network.getGtuType(GTUType.DEFAULTS.VEHICLE), Permeable.BOTH);
184                 }
185                 // sink sensors
186                 if (lane.getParentLink().getId().equals("CD"))
187                 {
188                     new SinkSensor(lane, lane.getLength().minus(Length.instantiateSI(100.0)), Compatible.EVERYTHING, sim);
189                     // detectors 100m after on ramp
190                     new Detector(lane.getFullId(), lane, Length.instantiateSI(100.0), sim); // id equal to lane, may be
191                                                                                             // different
192                 }
193                 if (lane.getParentLink().getId().equals("AB"))
194                 {
195                     originLanes.add(lane);
196                 }
197             }
198         }
199         new Stripe(linkAB, Length.ZERO, Length.ZERO, stripeWidth);
200         Stripe stripe = new Stripe(linkBC, Length.ZERO, Length.ZERO, stripeWidth);
201         stripe.addPermeability(network.getGtuType(GTUType.DEFAULTS.VEHICLE), Permeable.LEFT);
202         new Stripe(linkCD, Length.ZERO, Length.ZERO, stripeWidth);
203         new Lane(linkBC, "Acceleration lane", laneWidth.times(-0.5), laneWidth, network.getLaneType(LaneType.DEFAULTS.FREEWAY),
204                 new Speed(120, SpeedUnit.KM_PER_HOUR));
205         new Lane(linkEB, "Onramp", laneWidth.times(-0.5), laneWidth, network.getLaneType(LaneType.DEFAULTS.FREEWAY),
206                 new Speed(120, SpeedUnit.KM_PER_HOUR));
207         new Stripe(linkEB, Length.ZERO, Length.ZERO, stripeWidth);
208         new Stripe(linkEB, laneWidth.neg(), laneWidth.neg(), stripeWidth);
209         new Stripe(linkBC, laneWidth.neg(), laneWidth.neg(), stripeWidth);
210 
211         // OD
212         List<OTSNode> origins = new ArrayList<>();
213         origins.add(nodeA);
214         origins.add(nodeE);
215         List<OTSNode> destinations = new ArrayList<>();
216         destinations.add(nodeD);
217         TimeVector timeVector = DoubleVector.instantiate(new double[] {0.0, 0.5, 1.0}, TimeUnit.BASE_HOUR, StorageType.DENSE);
218         Interpolation interpolation = Interpolation.LINEAR; // or STEPWISE
219         Categorization categorization = new Categorization("GTU type", GTUType.class);
220         Category carCategory = new Category(categorization, network.getGtuType(GTUType.DEFAULTS.CAR));
221         Category truCategory = new Category(categorization, network.getGtuType(GTUType.DEFAULTS.TRUCK));
222         ODMatrix odMatrix = new ODMatrix("Steering OD", origins, destinations, categorization, timeVector, interpolation);
223 
224         odMatrix.putDemandVector(nodeA, nodeD, carCategory, freq(new double[] {1000.0, 2000.0, 0.0}));
225         odMatrix.putDemandVector(nodeA, nodeD, truCategory, freq(new double[] {100.0, 200.0, 0.0}));
226         odMatrix.putDemandVector(nodeE, nodeD, carCategory, freq(new double[] {500.0, 1000.0, 0.0}));
227 
228         // anonymous tactical-planner-factory supplier
229         AbstractLaneBasedTacticalPlannerFactory<SteeringLmrs> car = new AbstractLaneBasedTacticalPlannerFactory<SteeringLmrs>(
230                 new IDMPlusFactory(sim.getReplication().getStream("generation")), new DefaultLMRSPerceptionFactory())
231         {
232             @Override
233             public SteeringLmrs create(final LaneBasedGTU gtu) throws GTUException
234             {
235                 return new SteeringLmrs(nextCarFollowingModel(gtu), gtu, getPerceptionFactory().generatePerception(gtu),
236                         Synchronization.PASSIVE, Cooperation.PASSIVE, GapAcceptance.INFORMED, FEEDBACK_CAR);
237             }
238 
239             @Override
240             public Parameters getParameters() throws ParameterException
241             {
242                 // TODO: add parameters if required (run and wait for ParameterException to find missing parameters)
243                 ParameterSet parameters = new ParameterSet();
244                 getCarFollowingParameters().setAllIn(parameters);
245                 parameters.setDefaultParameters(Steering.class);
246                 return parameters;
247             }
248         };
249         TacticalPlannerFactorySupplierOD tacticalPlannerFactorySupplierOD = new TacticalPlannerFactorySupplierOD()
250         {
251             @Override
252             public LaneBasedTacticalPlannerFactory<SteeringLmrs> getFactory(final Node origin, final Node destination,
253                     final Category category, final StreamInterface randomStream)
254             {
255                 GTUType gtuType = category.get(GTUType.class);
256                 if (gtuType.equals(network.getGtuType(GTUType.DEFAULTS.CAR)))
257                 {
258                     return car;
259                 }
260                 else
261                 {
262                     // TODO: other GTU types
263                     return null;
264                 }
265             };
266         };
267         // anonymous vehicle model factory
268         // TODO: supply mass and inertia values, possibly randomized, correlated?
269         ContinuousDistMass massDistCar =
270                 new ContinuousDistMass(new DistUniform(sim.getReplication().getStream("generation"), 600, 1200), MassUnit.SI);
271         ContinuousDistMass massDistTruck =
272                 new ContinuousDistMass(new DistUniform(sim.getReplication().getStream("generation"), 2000, 10000), MassUnit.SI);
273         double momentOfInertiaAboutZ = 100; // no idea...
274         VehicleModelFactory vehicleModelGenerator = new VehicleModelFactory()
275         {
276             @Override
277             public VehicleModel create(final GTUType gtuType)
278             {
279                 Mass mass =
280                         gtuType.isOfType(network.getGtuType(GTUType.DEFAULTS.CAR)) ? massDistCar.draw() : massDistTruck.draw();
281                 return new VehicleModel.MassBased(mass, momentOfInertiaAboutZ);
282             }
283         };
284         // characteristics generator using OD info and default route based strategical level
285         DefaultGTUCharacteristicsGeneratorOD characteristicsGenerator = new DefaultGTUCharacteristicsGeneratorOD.Factory()
286                 .setFactorySupplier(StrategicalPlannerFactorySupplierOD.route(tacticalPlannerFactorySupplierOD))
287                 .setVehicleModelGenerator(vehicleModelGenerator).create();
288 
289         // od options
290         ODOptions odOptions = new ODOptions().set(ODOptions.NO_LC_DIST, Length.instantiateSI(300.0)).set(ODOptions.GTU_TYPE,
291                 characteristicsGenerator);
292         ODApplier.applyOD(network, odMatrix, odOptions);
293 
294         return network;
295     }
296 
297     /**
298      * Creates a frequency vector.
299      * @param array double[]; array in veh/h
300      * @return FrequencyVector; frequency vector
301      * @throws ValueRuntimeException on problem
302      */
303     private FrequencyVector freq(final double[] array) throws ValueRuntimeException
304     {
305         return DoubleVector.instantiate(array, FrequencyUnit.PER_HOUR, StorageType.DENSE);
306     }
307 
308 }