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