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