1 package org.opentrafficsim.demo;
2
3 import java.io.BufferedWriter;
4 import java.io.IOException;
5 import java.rmi.RemoteException;
6 import java.util.ArrayList;
7 import java.util.LinkedHashMap;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import org.djunits.unit.FrequencyUnit;
13 import org.djunits.unit.SpeedUnit;
14 import org.djunits.unit.TimeUnit;
15 import org.djunits.value.storage.StorageType;
16 import org.djunits.value.vdouble.scalar.Acceleration;
17 import org.djunits.value.vdouble.scalar.Direction;
18 import org.djunits.value.vdouble.scalar.Duration;
19 import org.djunits.value.vdouble.scalar.Length;
20 import org.djunits.value.vdouble.scalar.Speed;
21 import org.djunits.value.vdouble.scalar.Time;
22 import org.djunits.value.vdouble.vector.FrequencyVector;
23 import org.djunits.value.vdouble.vector.TimeVector;
24 import org.djunits.value.vdouble.vector.base.DoubleVector;
25 import org.djutils.cli.CliUtil;
26 import org.djutils.data.csv.CsvData;
27 import org.djutils.data.serialization.TextSerializationException;
28 import org.djutils.event.Event;
29 import org.djutils.exceptions.Throw;
30 import org.djutils.exceptions.Try;
31 import org.djutils.io.CompressedFileWriter;
32 import org.opentrafficsim.base.parameters.ParameterException;
33 import org.opentrafficsim.base.parameters.ParameterSet;
34 import org.opentrafficsim.base.parameters.ParameterTypeDuration;
35 import org.opentrafficsim.base.parameters.ParameterTypes;
36 import org.opentrafficsim.base.parameters.Parameters;
37 import org.opentrafficsim.base.parameters.constraint.NumericConstraint;
38 import org.opentrafficsim.core.animation.gtu.colorer.AccelerationGtuColorer;
39 import org.opentrafficsim.core.animation.gtu.colorer.GtuColorer;
40 import org.opentrafficsim.core.animation.gtu.colorer.IdGtuColorer;
41 import org.opentrafficsim.core.animation.gtu.colorer.SpeedGtuColorer;
42 import org.opentrafficsim.core.animation.gtu.colorer.SwitchableGtuColorer;
43 import org.opentrafficsim.core.definitions.Defaults;
44 import org.opentrafficsim.core.definitions.DefaultsNl;
45 import org.opentrafficsim.core.definitions.Definitions;
46 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
47 import org.opentrafficsim.core.geometry.DirectedPoint;
48 import org.opentrafficsim.core.geometry.OtsPoint3d;
49 import org.opentrafficsim.core.gtu.Gtu;
50 import org.opentrafficsim.core.gtu.GtuCharacteristics;
51 import org.opentrafficsim.core.gtu.GtuException;
52 import org.opentrafficsim.core.gtu.GtuType;
53 import org.opentrafficsim.core.gtu.perception.DirectEgoPerception;
54 import org.opentrafficsim.core.gtu.perception.EgoPerception;
55 import org.opentrafficsim.core.gtu.perception.Perception;
56 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
57 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
58 import org.opentrafficsim.core.network.LateralDirectionality;
59 import org.opentrafficsim.core.network.LinkType;
60 import org.opentrafficsim.core.network.NetworkException;
61 import org.opentrafficsim.core.network.Node;
62 import org.opentrafficsim.core.network.Network;
63 import org.opentrafficsim.core.network.route.Route;
64 import org.opentrafficsim.core.parameters.ParameterFactoryByType;
65 import org.opentrafficsim.road.definitions.DefaultsRoadNl;
66 import org.opentrafficsim.road.gtu.colorer.GtuTypeColorer;
67 import org.opentrafficsim.road.gtu.generator.GeneratorPositions.LaneBias;
68 import org.opentrafficsim.road.gtu.generator.GeneratorPositions.LaneBiases;
69 import org.opentrafficsim.road.gtu.generator.characteristics.DefaultLaneBasedGtuCharacteristicsGeneratorOd;
70 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuCharacteristics;
71 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuCharacteristicsGeneratorOd;
72 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
73 import org.opentrafficsim.road.gtu.lane.VehicleModel;
74 import org.opentrafficsim.road.gtu.lane.perception.CategoricalLanePerception;
75 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
76 import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
77 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
78 import org.opentrafficsim.road.gtu.lane.perception.categories.AnticipationTrafficPerception;
79 import org.opentrafficsim.road.gtu.lane.perception.categories.DirectInfrastructurePerception;
80 import org.opentrafficsim.road.gtu.lane.perception.categories.DirectIntersectionPerception;
81 import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
82 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.DirectNeighborsPerception;
83 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType;
84 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsPerception;
85 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGtu;
86 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneChange;
87 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneOperationalPlanBuilder;
88 import org.opentrafficsim.road.gtu.lane.plan.operational.SimpleOperationalPlan;
89 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlanner;
90 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
91 import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIdm;
92 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
93 import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlus;
94 import org.opentrafficsim.road.gtu.lane.tactical.following.IdmPlusFactory;
95 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AbstractIncentivesTacticalPlanner;
96 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationIncentive;
97 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLmrsPerceptionFactory;
98 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory;
99 import org.opentrafficsim.road.gtu.lane.tactical.util.CarFollowingUtil;
100 import org.opentrafficsim.road.gtu.lane.tactical.util.TrafficLightUtil;
101 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
102 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
103 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Incentive;
104 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
105 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsUtil;
106 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
107 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlannerFactory;
108 import org.opentrafficsim.road.network.RoadNetwork;
109 import org.opentrafficsim.road.network.control.rampmetering.CycleTimeLightController;
110 import org.opentrafficsim.road.network.control.rampmetering.RampMetering;
111 import org.opentrafficsim.road.network.control.rampmetering.RampMeteringLightController;
112 import org.opentrafficsim.road.network.control.rampmetering.RampMeteringSwitch;
113 import org.opentrafficsim.road.network.control.rampmetering.RwsSwitch;
114 import org.opentrafficsim.road.network.factory.LaneFactory;
115 import org.opentrafficsim.road.network.lane.Lane;
116 import org.opentrafficsim.road.network.lane.LaneType;
117 import org.opentrafficsim.road.network.lane.Stripe;
118 import org.opentrafficsim.road.network.lane.Stripe.Type;
119 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
120 import org.opentrafficsim.road.network.lane.object.detector.LoopDetector;
121 import org.opentrafficsim.road.network.lane.object.detector.SinkDetector;
122 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
123 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
124 import org.opentrafficsim.road.network.speed.SpeedLimitProspect;
125 import org.opentrafficsim.road.od.Categorization;
126 import org.opentrafficsim.road.od.Category;
127 import org.opentrafficsim.road.od.Interpolation;
128 import org.opentrafficsim.road.od.OdApplier;
129 import org.opentrafficsim.road.od.OdMatrix;
130 import org.opentrafficsim.road.od.OdOptions;
131 import org.opentrafficsim.swing.script.AbstractSimulationScript;
132
133 import nl.tudelft.simulation.jstats.distributions.DistNormal;
134 import nl.tudelft.simulation.jstats.streams.StreamInterface;
135 import picocli.CommandLine.Option;
136
137
138
139
140
141
142
143
144
145
146 public class RampMeteringDemo extends AbstractSimulationScript
147 {
148
149
150 private static final String CONTROLLED_CAR_ID = "controlledCar";
151
152
153 private ParameterFactoryByType parameterFactory = new ParameterFactoryByType();
154
155
156 @Option(names = {"-r", "--rampMetering"}, description = "Ramp metering on or off", defaultValue = "true")
157 private boolean rampMetering;
158
159
160 @Option(names = "--output", description = "Generate output.", negatable = true, defaultValue = "false")
161 private boolean output;
162
163
164 @Option(names = "--acceptedGap", description = "Accepted gap.", defaultValue = "0.5s")
165 private Duration acceptedGap;
166
167
168 private FrequencyVector mainDemand;
169
170
171 @Option(names = "--mainDemand", description = "Main demand in veh/h.", defaultValue = "2000,3000,3900,3900,3000")
172 private String mainDemandString;
173
174
175 private FrequencyVector rampDemand;
176
177
178 @Option(names = "--rampDemand", description = "Ramp demand in veh/h.", defaultValue = "500,500,500,500,500")
179 private String rampDemandString;
180
181
182 private TimeVector demandTime;
183
184
185 @Option(names = "--demandTime", description = "Demand time in min.", defaultValue = "0,10,40,50,70")
186 private String demandTimeString;
187
188
189 @Option(names = "--scenario", description = "Scenario name.", defaultValue = "test")
190 private String scenario;
191
192
193 private Map<String, Double> gtusInSimulation = new LinkedHashMap<>();
194
195
196 private double totalTravelTime = 0.0;
197
198
199 private double totalTravelTimeDelay = 0.0;
200
201
202 private Definitions definitions = new Definitions();
203
204
205
206
207 protected RampMeteringDemo()
208 {
209 super("Ramp metering 1", "Ramp metering 2");
210 }
211
212
213
214
215
216 public static void main(final String[] args) throws Exception
217 {
218 RampMeteringDemo demo = new RampMeteringDemo();
219 CliUtil.changeOptionDefault(demo, "simulationTime", "4200s");
220 CliUtil.execute(demo, args);
221 demo.mainDemand =
222 DoubleVector.instantiate(arrayFromString(demo.mainDemandString), FrequencyUnit.PER_HOUR, StorageType.DENSE);
223 demo.rampDemand =
224 DoubleVector.instantiate(arrayFromString(demo.rampDemandString), FrequencyUnit.PER_HOUR, StorageType.DENSE);
225 demo.demandTime =
226 DoubleVector.instantiate(arrayFromString(demo.demandTimeString), TimeUnit.BASE_MINUTE, StorageType.DENSE);
227 demo.start();
228 }
229
230
231
232
233
234
235 private static double[] arrayFromString(final String str)
236 {
237 int n = 0;
238 for (String part : str.split(","))
239 {
240 n++;
241 }
242 double[] out = new double[n];
243 int i = 0;
244 for (String part : str.split(","))
245 {
246 out[i] = Double.valueOf(part);
247 i++;
248 }
249 return out;
250 }
251
252
253 @Override
254 protected RoadNetwork setupSimulation(final OtsSimulatorInterface sim) throws Exception
255 {
256 RoadNetwork network = new RoadNetwork("RampMetering", sim);
257 if (this.output)
258 {
259 network.addListener(this, Network.GTU_ADD_EVENT);
260 network.addListener(this, Network.GTU_REMOVE_EVENT);
261 }
262 GtuType car = DefaultsNl.CAR;
263 GtuType.registerTemplateSupplier(car, Defaults.NL);
264 GtuType controlledCar = new GtuType(CONTROLLED_CAR_ID, car);
265 this.definitions.add(GtuType.class, car);
266 this.definitions.add(GtuType.class, controlledCar);
267
268 GtuColorer[] colorers =
269 new GtuColorer[] {new IdGtuColorer(), new SpeedGtuColorer(new Speed(150, SpeedUnit.KM_PER_HOUR)),
270 new AccelerationGtuColorer(Acceleration.instantiateSI(-6.0), Acceleration.instantiateSI(2)),
271 new GtuTypeColorer().add(car).add(controlledCar)};
272 SwitchableGtuColorer colorer = new SwitchableGtuColorer(0, colorers);
273 setGtuColorer(colorer);
274
275
276 StreamInterface stream = sim.getModel().getStream("generation");
277 this.parameterFactory.addParameter(ParameterTypes.FSPEED, new DistNormal(stream, 123.7 / 120.0, 12.0 / 1200));
278
279 Node nodeA = new Node(network, "A", new OtsPoint3d(0, 0), Direction.ZERO);
280 Node nodeB = new Node(network, "B", new OtsPoint3d(3000, 0), Direction.ZERO);
281 Node nodeC = new Node(network, "C", new OtsPoint3d(3250, 0), Direction.ZERO);
282 Node nodeD = new Node(network, "D", new OtsPoint3d(6000, 0), Direction.ZERO);
283 Node nodeE = new Node(network, "E", new OtsPoint3d(2000, -25), Direction.ZERO);
284 Node nodeF = new Node(network, "F", new OtsPoint3d(2750, 0.0), Direction.ZERO);
285
286 LinkType freeway = DefaultsNl.FREEWAY;
287 LaneKeepingPolicy policy = LaneKeepingPolicy.KEEPRIGHT;
288 Length laneWidth = Length.instantiateSI(3.6);
289 LaneType freewayLane = DefaultsRoadNl.FREEWAY;
290 Speed speedLimit = new Speed(120, SpeedUnit.KM_PER_HOUR);
291 Speed rampSpeedLimit = new Speed(70, SpeedUnit.KM_PER_HOUR);
292 List<Lane> lanesAB = new LaneFactory(network, nodeA, nodeB, freeway, sim, policy, DefaultsNl.VEHICLE)
293 .leftToRight(1.0, laneWidth, freewayLane, speedLimit).addLanes(Type.DASHED).getLanes();
294 List<Stripe> stripes = new ArrayList<>();
295 List<Lane> lanesBC = new LaneFactory(network, nodeB, nodeC, freeway, sim, policy, DefaultsNl.VEHICLE)
296 .leftToRight(1.0, laneWidth, freewayLane, speedLimit).addLanes(stripes, Type.DASHED, Type.BLOCK).getLanes();
297 stripes.get(2).addPermeability(car, LateralDirectionality.LEFT);
298 List<Lane> lanesCD = new LaneFactory(network, nodeC, nodeD, freeway, sim, policy, DefaultsNl.VEHICLE)
299 .leftToRight(1.0, laneWidth, freewayLane, speedLimit).addLanes(Type.DASHED).getLanes();
300 List<Lane> lanesEF = new LaneFactory(network, nodeE, nodeF, freeway, sim, policy, DefaultsNl.VEHICLE)
301 .setOffsetEnd(laneWidth.times(1.5).neg()).leftToRight(0.5, laneWidth, freewayLane, rampSpeedLimit).addLanes()
302 .getLanes();
303 List<Lane> lanesFB = new LaneFactory(network, nodeF, nodeB, freeway, sim, policy, DefaultsNl.VEHICLE)
304 .setOffsetStart(laneWidth.times(1.5).neg()).setOffsetEnd(laneWidth.times(1.5).neg())
305 .leftToRight(0.5, laneWidth, freewayLane, speedLimit).addLanes().getLanes();
306 for (Lane lane : lanesCD)
307 {
308 new SinkDetector(lane, lane.getLength().minus(Length.instantiateSI(50)), sim, DefaultsRoadNl.ROAD_USERS);
309 }
310
311 Duration agg = Duration.instantiateSI(60.0);
312
313 Length detectorLength = Length.ZERO;
314 LoopDetector det1 = new LoopDetector("1", lanesAB.get(0), Length.instantiateSI(2900), detectorLength,
315 DefaultsRoadNl.LOOP_DETECTOR, sim, agg, LoopDetector.MEAN_SPEED, LoopDetector.OCCUPANCY);
316 LoopDetector det2 = new LoopDetector("2", lanesAB.get(1), Length.instantiateSI(2900), detectorLength,
317 DefaultsRoadNl.LOOP_DETECTOR, sim, agg, LoopDetector.MEAN_SPEED, LoopDetector.OCCUPANCY);
318 LoopDetector det3 = new LoopDetector("3", lanesCD.get(0), Length.instantiateSI(100), detectorLength,
319 DefaultsRoadNl.LOOP_DETECTOR, sim, agg, LoopDetector.MEAN_SPEED, LoopDetector.OCCUPANCY);
320 LoopDetector det4 = new LoopDetector("4", lanesCD.get(1), Length.instantiateSI(100), detectorLength,
321 DefaultsRoadNl.LOOP_DETECTOR, sim, agg, LoopDetector.MEAN_SPEED, LoopDetector.OCCUPANCY);
322 List<LoopDetector> detectors12 = new ArrayList<>();
323 detectors12.add(det1);
324 detectors12.add(det2);
325 List<LoopDetector> detectors34 = new ArrayList<>();
326 detectors34.add(det3);
327 detectors34.add(det4);
328 if (this.rampMetering)
329 {
330
331 TrafficLight light = new TrafficLight("light", lanesEF.get(0), lanesEF.get(0).getLength(), sim);
332 List<TrafficLight> lightList = new ArrayList<>();
333 lightList.add(light);
334
335 RampMeteringSwitch rampSwitch = new RwsSwitch(detectors12);
336 RampMeteringLightController rampLightController =
337 new CycleTimeLightController(sim, lightList, DefaultsRoadNl.LOOP_DETECTOR);
338 new RampMetering(sim, rampSwitch, rampLightController);
339 }
340
341
342 List<Node> origins = new ArrayList<>();
343 origins.add(nodeA);
344 origins.add(nodeE);
345 List<Node> destinations = new ArrayList<>();
346 destinations.add(nodeD);
347 Categorization categorization = new Categorization("cat", GtuType.class);
348 Interpolation globalInterpolation = Interpolation.LINEAR;
349 OdMatrix od = new OdMatrix("rampMetering", origins, destinations, categorization, this.demandTime, globalInterpolation);
350
351
352 Category carCatRamp = new Category(categorization, car);
353 Category controlledCarCat = new Category(categorization, controlledCar);
354
355 od.putDemandVector(nodeA, nodeD, carCatRamp, this.mainDemand, 0.6);
356 od.putDemandVector(nodeA, nodeD, controlledCarCat, this.mainDemand, 0.4);
357
358
359 od.putDemandVector(nodeE, nodeD, carCatRamp, this.rampDemand, 0.6);
360 od.putDemandVector(nodeE, nodeD, controlledCarCat, this.rampDemand, 0.4);
361 OdOptions odOptions = new OdOptions();
362 DefaultLaneBasedGtuCharacteristicsGeneratorOd.Factory factory =
363 new DefaultLaneBasedGtuCharacteristicsGeneratorOd.Factory(new LaneBasedStrategicalRoutePlannerFactory(
364 new LmrsFactory(new IdmPlusFactory(stream), new DefaultLmrsPerceptionFactory())));
365 odOptions.set(OdOptions.GTU_TYPE, new ControlledStrategicalPlannerGenerator(factory.create()));
366 odOptions.set(OdOptions.INSTANT_LC, true);
367 odOptions.set(OdOptions.LANE_BIAS, new LaneBiases().addBias(car, LaneBias.WEAK_LEFT));
368 odOptions.set(OdOptions.NO_LC_DIST, Length.instantiateSI(300));
369 OdApplier.applyOd(network, od, odOptions, DefaultsRoadNl.ROAD_USERS);
370
371 return network;
372 }
373
374
375
376
377
378 final ParameterFactoryByType getParameterFactory()
379 {
380 return this.parameterFactory;
381 }
382
383
384 @Override
385 public void notify(final Event event) throws RemoteException
386 {
387 if (event.getType().equals(Network.GTU_ADD_EVENT))
388 {
389 this.gtusInSimulation.put((String) event.getContent(), getSimulator().getSimulatorTime().si);
390 }
391 else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
392 {
393 measureTravelTime((String) event.getContent());
394 }
395 else
396 {
397 super.notify(event);
398 }
399 }
400
401
402
403
404
405 private void measureTravelTime(final String id)
406 {
407 double tt = getSimulator().getSimulatorTime().si - this.gtusInSimulation.get(id);
408 double x = getNetwork().getGTU(id).getOdometer().si;
409
410 double ttd = tt - (x / (120 / 3.6));
411 this.totalTravelTime += tt;
412 this.totalTravelTimeDelay += ttd;
413 this.gtusInSimulation.remove(id);
414 }
415
416
417 @Override
418 protected void onSimulationEnd()
419 {
420 if (this.output)
421 {
422
423 String file = String.format("%s_%02d_detectors.csv", this.scenario, getSeed());
424 try
425 {
426 CsvData.writeData(file, file + ".header", LoopDetector.asTablePeriodicData(getNetwork()));
427 }
428 catch (IOException | TextSerializationException exception)
429 {
430 throw new RuntimeException(exception);
431 }
432
433
434 for (Gtu gtu : getNetwork().getGTUs())
435 {
436 measureTravelTime(gtu.getId());
437 }
438 Throw.when(!this.gtusInSimulation.isEmpty(), RuntimeException.class,
439 "GTUs remain in simulation that are not measured.");
440 file = String.format("%s_%02d_time.txt", this.scenario, getSeed());
441 BufferedWriter bw = null;
442 try
443 {
444 bw = CompressedFileWriter.create(file, false);
445 bw.write(String.format("Total travel time: %.3fs", this.totalTravelTime));
446 bw.newLine();
447 bw.write(String.format("Total travel time delay: %.3fs", this.totalTravelTimeDelay));
448 bw.close();
449 }
450 catch (IOException exception)
451 {
452 throw new RuntimeException(exception);
453 }
454 finally
455 {
456 try
457 {
458 if (bw != null)
459 {
460 bw.close();
461 }
462 }
463 catch (IOException ex)
464 {
465 throw new RuntimeException(ex);
466 }
467 }
468 }
469 }
470
471
472
473
474
475 private class ControlledStrategicalPlannerGenerator implements LaneBasedGtuCharacteristicsGeneratorOd
476 {
477
478
479 private final DefaultLaneBasedGtuCharacteristicsGeneratorOd defaultGenerator;
480
481
482 private LaneBasedStrategicalPlannerFactory<?> controlledPlannerFactory;
483
484
485
486
487
488 ControlledStrategicalPlannerGenerator(final DefaultLaneBasedGtuCharacteristicsGeneratorOd defaultGenerator)
489 {
490 this.defaultGenerator = defaultGenerator;
491
492 LaneBasedTacticalPlannerFactory<?> tacticalPlannerFactory =
493 new LaneBasedTacticalPlannerFactory<LaneBasedTacticalPlanner>()
494 {
495 @Override
496 public Parameters getParameters() throws ParameterException
497 {
498 ParameterSet set = new ParameterSet();
499 set.setDefaultParameter(ParameterTypes.PERCEPTION);
500 set.setDefaultParameter(ParameterTypes.LOOKBACK);
501 set.setDefaultParameter(ParameterTypes.LOOKAHEAD);
502 set.setDefaultParameter(ParameterTypes.S0);
503 set.setDefaultParameter(ParameterTypes.TMIN);
504 set.setDefaultParameter(ParameterTypes.TMAX);
505 set.setDefaultParameter(ParameterTypes.DT);
506 set.setDefaultParameter(ParameterTypes.VCONG);
507 set.setDefaultParameter(ParameterTypes.T0);
508 set.setDefaultParameter(TrafficLightUtil.B_YELLOW);
509 set.setDefaultParameters(LmrsParameters.class);
510 set.setDefaultParameters(AbstractIdm.class);
511 return set;
512 }
513
514 @SuppressWarnings("synthetic-access")
515 @Override
516 public LaneBasedTacticalPlanner create(final LaneBasedGtu gtu) throws GtuException
517 {
518
519 ParameterSet settings = new ParameterSet();
520 try
521 {
522
523 settings.setParameter(SyncAndAccept.SYNCTIME, Duration.instantiateSI(1.0));
524 settings.setParameter(SyncAndAccept.COOPTIME, Duration.instantiateSI(2.0));
525
526 settings.setParameter(AbstractIdm.DELTA, 1.0);
527 settings.setParameter(ParameterTypes.S0, Length.instantiateSI(3.0));
528 settings.setParameter(ParameterTypes.A, Acceleration.instantiateSI(2.0));
529 settings.setParameter(ParameterTypes.B, Acceleration.instantiateSI(2.0));
530 settings.setParameter(ParameterTypes.T, RampMeteringDemo.this.acceptedGap);
531 settings.setParameter(ParameterTypes.FSPEED, 1.0);
532 settings.setParameter(ParameterTypes.B0, Acceleration.instantiateSI(0.5));
533 settings.setParameter(ParameterTypes.VCONG, new Speed(60, SpeedUnit.KM_PER_HOUR));
534 }
535 catch (ParameterException exception)
536 {
537 throw new GtuException(exception);
538 }
539 return new ControlledTacticalPlanner(gtu, new SyncAndAccept(gtu, new IdmPlus(), settings));
540 }
541 };
542
543 this.controlledPlannerFactory = new LaneBasedStrategicalRoutePlannerFactory(tacticalPlannerFactory,
544 RampMeteringDemo.this.getParameterFactory());
545 }
546
547
548 @Override
549 public LaneBasedGtuCharacteristics draw(final Node origin, final Node destination, final Category category,
550 final StreamInterface randomStream) throws GtuException
551 {
552 GtuType gtuType = category.get(GtuType.class);
553
554 if (gtuType.equals(RampMeteringDemo.this.definitions.get(GtuType.class, CONTROLLED_CAR_ID)))
555 {
556 Route route = null;
557 VehicleModel vehicleModel = VehicleModel.MINMAX;
558 GtuCharacteristics gtuCharacteristics =
559 GtuType.defaultCharacteristics(gtuType, origin.getNetwork(), randomStream);
560 return new LaneBasedGtuCharacteristics(gtuCharacteristics, this.controlledPlannerFactory, route, origin,
561 destination, vehicleModel);
562 }
563
564 return this.defaultGenerator.draw(origin, destination, category, randomStream);
565 }
566
567 }
568
569
570 private static class ControlledTacticalPlanner extends AbstractIncentivesTacticalPlanner
571 {
572
573 private static final long serialVersionUID = 20190731L;
574
575
576 private AutomaticLaneChangeSystem laneChangeSystem;
577
578
579 private final LaneChange laneChange;
580
581
582 private Map<Class<? extends Incentive>, Desire> dummyMap = new LinkedHashMap<>();
583
584
585
586
587
588
589 ControlledTacticalPlanner(final LaneBasedGtu gtu, final AutomaticLaneChangeSystem laneChangeSystem)
590 {
591 super(new IdmPlus(), gtu, generatePerception(gtu));
592 setDefaultIncentives();
593 this.laneChangeSystem = laneChangeSystem;
594 this.laneChange = Try.assign(() -> new LaneChange(gtu), "Parameter LCDUR is required.", GtuException.class);
595 }
596
597
598
599
600
601
602 private static LanePerception generatePerception(final LaneBasedGtu gtu)
603 {
604 CategoricalLanePerception perception = new CategoricalLanePerception(gtu);
605 perception.addPerceptionCategory(new DirectEgoPerception<LaneBasedGtu, Perception<LaneBasedGtu>>(perception));
606 perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
607
608 perception.addPerceptionCategory(new DirectNeighborsPerception(perception, HeadwayGtuType.WRAP));
609 perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
610 perception.addPerceptionCategory(new DirectIntersectionPerception(perception, HeadwayGtuType.WRAP));
611 return perception;
612 }
613
614
615 @Override
616 public OperationalPlan generateOperationalPlan(final Time startTime, final DirectedPoint locationAtStartTime)
617 throws OperationalPlanException, GtuException, NetworkException, ParameterException
618 {
619
620 Speed speed = getPerception().getPerceptionCategory(EgoPerception.class).getSpeed();
621 SpeedLimitProspect slp = getPerception().getPerceptionCategory(InfrastructurePerception.class)
622 .getSpeedLimitProspect(RelativeLane.CURRENT);
623 SpeedLimitInfo sli = slp.getSpeedLimitInfo(Length.ZERO);
624
625
626 Desire desire = LmrsUtil.getLaneChangeDesire(getGtu().getParameters(), getPerception(), getCarFollowingModel(),
627 getMandatoryIncentives(), getVoluntaryIncentives(), this.dummyMap);
628
629
630 getGtu().getParameters().setParameter(LmrsParameters.DLEFT, desire.getLeft());
631 getGtu().getParameters().setParameter(LmrsParameters.DRIGHT, desire.getRight());
632
633
634 Acceleration a = getGtu().getCarFollowingAcceleration();
635
636
637 Acceleration aCoop = Cooperation.PASSIVE.cooperate(getPerception(), getGtu().getParameters(), sli,
638 getCarFollowingModel(), LateralDirectionality.LEFT, desire);
639 a = Acceleration.min(a, aCoop);
640 aCoop = Cooperation.PASSIVE.cooperate(getPerception(), getGtu().getParameters(), sli, getCarFollowingModel(),
641 LateralDirectionality.RIGHT, desire);
642 a = Acceleration.min(a, aCoop);
643
644
645 SimpleOperationalPlan simplePlan =
646 new SimpleOperationalPlan(a, getGtu().getParameters().getParameter(ParameterTypes.DT));
647 for (AccelerationIncentive incentive : getAccelerationIncentives())
648 {
649 incentive.accelerate(simplePlan, RelativeLane.CURRENT, Length.ZERO, getGtu(), getPerception(),
650 getCarFollowingModel(), speed, getGtu().getParameters(), sli);
651 }
652
653
654 if (!this.laneChange.isChangingLane())
655 {
656 double dFree = getGtu().getParameters().getParameter(LmrsParameters.DFREE);
657 if (this.laneChangeSystem.initiatedLaneChange().isNone())
658 {
659 if (desire.leftIsLargerOrEqual() && desire.getLeft() > dFree)
660 {
661 this.laneChangeSystem.initiateLaneChange(LateralDirectionality.LEFT);
662 }
663 else if (desire.getRight() > dFree)
664 {
665 this.laneChangeSystem.initiateLaneChange(LateralDirectionality.RIGHT);
666 }
667 }
668 else
669 {
670 if ((this.laneChangeSystem.initiatedLaneChange().isLeft() && desire.getLeft() < dFree)
671 || (this.laneChangeSystem.initiatedLaneChange().isRight() && desire.getRight() < dFree))
672 {
673 this.laneChangeSystem.initiateLaneChange(LateralDirectionality.NONE);
674 }
675 }
676 }
677 simplePlan = this.laneChangeSystem.operate(simplePlan, getGtu().getParameters());
678 simplePlan.setTurnIndicator(getGtu());
679
680
681 return LaneOperationalPlanBuilder.buildPlanFromSimplePlan(getGtu(), startTime, simplePlan, this.laneChange);
682 }
683 }
684
685
686 private interface AutomaticLaneChangeSystem
687 {
688
689
690
691
692
693
694
695
696
697 SimpleOperationalPlan operate(SimpleOperationalPlan simplePlan, Parameters parameters)
698 throws OperationalPlanException, ParameterException;
699
700
701
702
703
704
705 LateralDirectionality initiatedLaneChange();
706
707
708
709
710
711 void initiateLaneChange(LateralDirectionality dir);
712
713 }
714
715
716 private static class SyncAndAccept implements AutomaticLaneChangeSystem
717 {
718
719 public static final ParameterTypeDuration SYNCTIME = new ParameterTypeDuration("tSync",
720 "Time after which synchronization starts.", Duration.instantiateSI(1.0), NumericConstraint.POSITIVE);
721
722
723 public static final ParameterTypeDuration COOPTIME = new ParameterTypeDuration("tCoop",
724 "Time after which cooperation starts (indicator).", Duration.instantiateSI(2.0), NumericConstraint.POSITIVE);
725
726
727 private final LaneBasedGtu gtu;
728
729
730 private final CarFollowingModel carFollowingModel;
731
732
733 private final Parameters settings;
734
735
736 private LateralDirectionality direction = LateralDirectionality.NONE;
737
738
739 private Time initiationTime;
740
741
742
743
744
745
746
747 SyncAndAccept(final LaneBasedGtu gtu, final CarFollowingModel carFollowingModel, final Parameters settings)
748 {
749 this.gtu = gtu;
750 this.carFollowingModel = carFollowingModel;
751 this.settings = settings;
752 }
753
754
755 @Override
756 public SimpleOperationalPlan operate(final SimpleOperationalPlan simplePlan, final Parameters parameters)
757 throws OperationalPlanException, ParameterException
758 {
759
760 if (this.direction.isNone())
761 {
762 return simplePlan;
763 }
764
765
766 InfrastructurePerception infra =
767 this.gtu.getTacticalPlanner().getPerception().getPerceptionCategory(InfrastructurePerception.class);
768 SpeedLimitInfo sli = infra.getSpeedLimitProspect(RelativeLane.CURRENT).getSpeedLimitInfo(Length.ZERO);
769 NeighborsPerception neighbors =
770 this.gtu.getTacticalPlanner().getPerception().getPerceptionCategory(NeighborsPerception.class);
771 if (infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, this.direction).gt0()
772 && !neighbors.isGtuAlongside(this.direction)
773 && acceptGap(neighbors.getFirstFollowers(this.direction), sli, false)
774 && acceptGap(neighbors.getFirstLeaders(this.direction), sli, true))
775 {
776
777 SimpleOperationalPlan plan =
778 new SimpleOperationalPlan(simplePlan.getAcceleration(), simplePlan.getDuration(), this.direction);
779 this.direction = LateralDirectionality.NONE;
780 this.initiationTime = null;
781 return plan;
782 }
783
784
785 Duration since = this.gtu.getSimulator().getSimulatorAbsTime().minus(this.initiationTime);
786 if (since.gt(this.settings.getParameter(SYNCTIME))
787 || this.gtu.getSpeed().lt(this.settings.getParameter(ParameterTypes.VCONG)))
788 {
789 PerceptionCollectable<HeadwayGtu, LaneBasedGtu> leaders =
790 neighbors.getLeaders(new RelativeLane(this.direction, 1));
791 if (!leaders.isEmpty())
792 {
793 HeadwayGtu leader = leaders.first();
794 Acceleration a = CarFollowingUtil.followSingleLeader(this.carFollowingModel, this.settings,
795 this.gtu.getSpeed(), sli, leader);
796 a = Acceleration.max(a, this.settings.getParameter(ParameterTypes.B).neg());
797 simplePlan.minimizeAcceleration(a);
798 }
799 }
800
801
802 if (since.gt(this.settings.getParameter(COOPTIME))
803 || this.gtu.getSpeed().lt(this.settings.getParameter(ParameterTypes.VCONG)))
804 {
805 if (this.direction.isLeft())
806 {
807 simplePlan.setIndicatorIntentLeft();
808 }
809 else
810 {
811 simplePlan.setIndicatorIntentRight();
812 }
813 }
814
815
816 return simplePlan;
817 }
818
819
820
821
822
823
824
825
826
827 private boolean acceptGap(final Set<HeadwayGtu> neighbors, final SpeedLimitInfo sli, final boolean leaders)
828 throws ParameterException
829 {
830 for (HeadwayGtu neighbor : neighbors)
831 {
832 Acceleration a = CarFollowingUtil.followSingleLeader(this.carFollowingModel, this.settings,
833 leaders ? this.gtu.getSpeed() : neighbor.getSpeed(), sli, neighbor.getDistance(),
834 leaders ? neighbor.getSpeed() : this.gtu.getSpeed());
835 if (a.lt(this.settings.getParameter(ParameterTypes.B).neg()))
836 {
837 return false;
838 }
839 }
840 return true;
841 }
842
843
844 @Override
845 public LateralDirectionality initiatedLaneChange()
846 {
847 return this.direction;
848 }
849
850
851 @Override
852 public void initiateLaneChange(final LateralDirectionality dir)
853 {
854 this.direction = dir;
855 if (!dir.isNone())
856 {
857 this.initiationTime = this.gtu.getSimulator().getSimulatorAbsTime();
858 }
859 else
860 {
861 this.initiationTime = null;
862 }
863 }
864 }
865
866 }