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