1 package org.opentrafficsim.demo;
2
3 import java.io.BufferedWriter;
4 import java.io.IOException;
5 import java.rmi.RemoteException;
6 import java.util.ArrayList;
7 import java.util.LinkedHashMap;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import org.djunits.unit.FrequencyUnit;
13 import org.djunits.unit.SpeedUnit;
14 import org.djunits.unit.TimeUnit;
15 import org.djunits.value.storage.StorageType;
16 import org.djunits.value.vdouble.scalar.Acceleration;
17 import org.djunits.value.vdouble.scalar.Direction;
18 import org.djunits.value.vdouble.scalar.Duration;
19 import org.djunits.value.vdouble.scalar.Length;
20 import org.djunits.value.vdouble.scalar.Speed;
21 import org.djunits.value.vdouble.scalar.Time;
22 import org.djunits.value.vdouble.vector.FrequencyVector;
23 import org.djunits.value.vdouble.vector.TimeVector;
24 import org.djunits.value.vdouble.vector.base.DoubleVector;
25 import org.djutils.cli.CliUtil;
26 import org.djutils.exceptions.Throw;
27 import org.djutils.exceptions.Try;
28 import org.opentrafficsim.base.CompressedFileWriter;
29 import org.opentrafficsim.base.parameters.ParameterException;
30 import org.opentrafficsim.base.parameters.ParameterSet;
31 import org.opentrafficsim.base.parameters.ParameterTypeDuration;
32 import org.opentrafficsim.base.parameters.ParameterTypes;
33 import org.opentrafficsim.base.parameters.Parameters;
34 import org.opentrafficsim.base.parameters.constraint.NumericConstraint;
35 import org.opentrafficsim.core.animation.gtu.colorer.AccelerationGTUColorer;
36 import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
37 import org.opentrafficsim.core.animation.gtu.colorer.IDGTUColorer;
38 import org.opentrafficsim.core.animation.gtu.colorer.SpeedGTUColorer;
39 import org.opentrafficsim.core.animation.gtu.colorer.SwitchableGTUColorer;
40 import org.opentrafficsim.core.compatibility.Compatible;
41 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
42 import org.opentrafficsim.core.geometry.OTSPoint3D;
43 import org.opentrafficsim.core.gtu.GTU;
44 import org.opentrafficsim.core.gtu.GTUCharacteristics;
45 import org.opentrafficsim.core.gtu.GTUDirectionality;
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.road.gtu.colorer.GTUTypeColorer;
61 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristics;
62 import org.opentrafficsim.road.gtu.generator.od.DefaultGTUCharacteristicsGeneratorOD;
63 import org.opentrafficsim.road.gtu.generator.od.GTUCharacteristicsGeneratorOD;
64 import org.opentrafficsim.road.gtu.generator.od.ODApplier;
65 import org.opentrafficsim.road.gtu.generator.od.ODOptions;
66 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
67 import org.opentrafficsim.road.gtu.lane.VehicleModel;
68 import org.opentrafficsim.road.gtu.lane.perception.CategoricalLanePerception;
69 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
70 import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
71 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
72 import org.opentrafficsim.road.gtu.lane.perception.categories.AnticipationTrafficPerception;
73 import org.opentrafficsim.road.gtu.lane.perception.categories.DirectInfrastructurePerception;
74 import org.opentrafficsim.road.gtu.lane.perception.categories.DirectIntersectionPerception;
75 import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
76 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.DirectNeighborsPerception;
77 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType;
78 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsPerception;
79 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
80 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneChange;
81 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneOperationalPlanBuilder;
82 import org.opentrafficsim.road.gtu.lane.plan.operational.SimpleOperationalPlan;
83 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlanner;
84 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlannerFactory;
85 import org.opentrafficsim.road.gtu.lane.tactical.following.AbstractIDM;
86 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
87 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlus;
88 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AbstractIncentivesTacticalPlanner;
89 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.AccelerationIncentive;
90 import org.opentrafficsim.road.gtu.lane.tactical.util.CarFollowingUtil;
91 import org.opentrafficsim.road.gtu.lane.tactical.util.TrafficLightUtil;
92 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Cooperation;
93 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
94 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Incentive;
95 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
96 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsUtil;
97 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
98 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
99 import org.opentrafficsim.road.gtu.strategical.od.Categorization;
100 import org.opentrafficsim.road.gtu.strategical.od.Category;
101 import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
102 import org.opentrafficsim.road.gtu.strategical.od.ODMatrix;
103 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
104 import org.opentrafficsim.road.network.OTSRoadNetwork;
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.LaneType;
113 import org.opentrafficsim.road.network.lane.OTSRoadNode;
114 import org.opentrafficsim.road.network.lane.Stripe.Permeable;
115 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
116 import org.opentrafficsim.road.network.lane.object.sensor.Detector;
117 import org.opentrafficsim.road.network.lane.object.sensor.Detector.CompressionMethod;
118 import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
119 import org.opentrafficsim.road.network.lane.object.trafficlight.SimpleTrafficLight;
120 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
121 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
122 import org.opentrafficsim.road.network.speed.SpeedLimitProspect;
123 import org.opentrafficsim.swing.script.AbstractSimulationScript;
124
125 import nl.tudelft.simulation.dsol.logger.SimLogger;
126 import nl.tudelft.simulation.event.EventInterface;
127 import nl.tudelft.simulation.jstats.distributions.DistNormal;
128 import nl.tudelft.simulation.jstats.streams.StreamInterface;
129 import nl.tudelft.simulation.language.d3.DirectedPoint;
130 import picocli.CommandLine.Option;
131
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.", defaultValue = "0.5s")
161 private Duration acceptedGap;
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
199
200 protected RampMeteringDemo()
201 {
202 super("Ramp metering 1", "Ramp metering 2");
203 }
204
205
206
207
208
209 public static void main(final String[] args) throws Exception
210 {
211 RampMeteringDemoo.html#RampMeteringDemo">RampMeteringDemo demo = new RampMeteringDemo();
212 CliUtil.changeOptionDefault(demo, "simulationTime", "4200s");
213 CliUtil.execute(demo, args);
214 demo.mainDemand =
215 DoubleVector.instantiate(arrayFromString(demo.mainDemandString), FrequencyUnit.PER_HOUR, StorageType.DENSE);
216 demo.rampDemand =
217 DoubleVector.instantiate(arrayFromString(demo.rampDemandString), FrequencyUnit.PER_HOUR, StorageType.DENSE);
218 demo.demandTime =
219 DoubleVector.instantiate(arrayFromString(demo.demandTimeString), TimeUnit.BASE_MINUTE, StorageType.DENSE);
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 OTSRoadNetwork setupSimulation(final OTSSimulatorInterface sim) throws Exception
248 {
249 SimLogger.setSimulator(sim);
250
251 OTSRoadNetwork network = new OTSRoadNetwork("RampMetering", true);
252 if (this.output)
253 {
254 network.addListener(this, Network.GTU_ADD_EVENT);
255 network.addListener(this, Network.GTU_REMOVE_EVENT);
256 }
257 GTUType car = network.getGtuType(GTUType.DEFAULTS.CAR);
258 GTUType controlledCar = new GTUType(CONTROLLED_CAR_ID, car);
259
260 GTUColorer[] colorers =
261 new GTUColorer[] {new IDGTUColorer(), new SpeedGTUColorer(new Speed(150, SpeedUnit.KM_PER_HOUR)),
262 new AccelerationGTUColorer(Acceleration.instantiateSI(-6.0), Acceleration.instantiateSI(2)),
263 new GTUTypeColorer().add(car).add(controlledCar)};
264 SwitchableGTUColorer colorer = new SwitchableGTUColorer(0, colorers);
265 setGtuColorer(colorer);
266
267
268 StreamInterface stream = sim.getReplication().getStream("generation");
269 this.parameterFactory.addParameter(ParameterTypes.FSPEED, new DistNormal(stream, 123.7 / 120.0, 12.0 / 1200));
270
271 OTSRoadNode nodeA = new OTSRoadNode(network, "A", new OTSPoint3D(0, 0), Direction.ZERO);
272 OTSRoadNode nodeB = new OTSRoadNode(network, "B", new OTSPoint3D(3000, 0), Direction.ZERO);
273 OTSRoadNode nodeC = new OTSRoadNode(network, "C", new OTSPoint3D(3250, 0), Direction.ZERO);
274 OTSRoadNode nodeD = new OTSRoadNode(network, "D", new OTSPoint3D(6000, 0), Direction.ZERO);
275 OTSRoadNode nodeE = new OTSRoadNode(network, "E", new OTSPoint3D(2000, -25), Direction.ZERO);
276 OTSRoadNode nodeF = new OTSRoadNode(network, "F", new OTSPoint3D(2750, 0.0), Direction.ZERO);
277
278 LinkType freeway = network.getLinkType(LinkType.DEFAULTS.FREEWAY);
279 LaneKeepingPolicy policy = LaneKeepingPolicy.KEEPRIGHT;
280 Length laneWidth = Length.instantiateSI(3.6);
281 LaneType freewayLane = network.getLaneType(LaneType.DEFAULTS.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)
285 .leftToRight(1.0, laneWidth, freewayLane, speedLimit).addLanes(Permeable.BOTH).getLanes();
286 List<Lane> lanesBC = new LaneFactory(network, nodeB, nodeC, freeway, sim, policy)
287 .leftToRight(1.0, laneWidth, freewayLane, speedLimit).addLanes(Permeable.BOTH, Permeable.LEFT).getLanes();
288 List<Lane> lanesCD = new LaneFactory(network, nodeC, nodeD, freeway, sim, policy)
289 .leftToRight(1.0, laneWidth, freewayLane, speedLimit).addLanes(Permeable.BOTH).getLanes();
290 List<Lane> lanesEF =
291 new LaneFactory(network, nodeE, nodeF, freeway, sim, policy).setOffsetEnd(laneWidth.times(1.5).neg())
292 .leftToRight(0.5, laneWidth, freewayLane, rampSpeedLimit).addLanes().getLanes();
293 List<Lane> lanesFB = new LaneFactory(network, nodeF, nodeB, freeway, sim, policy)
294 .setOffsetStart(laneWidth.times(1.5).neg()).setOffsetEnd(laneWidth.times(1.5).neg())
295 .leftToRight(0.5, laneWidth, freewayLane, speedLimit).addLanes().getLanes();
296 for (Lane lane : lanesCD)
297 {
298 new SinkSensor(lane, lane.getLength().minus(Length.instantiateSI(50)), GTUDirectionality.DIR_PLUS, sim);
299 }
300
301 Duration agg = Duration.instantiateSI(60.0);
302
303 Length detectorLength = Length.ZERO;
304 Detector det1 = new Detector("1", lanesAB.get(0), Length.instantiateSI(2900), detectorLength, sim, agg,
305 Detector.MEAN_SPEED, Detector.OCCUPANCY);
306 Detector det2 = new Detector("2", lanesAB.get(1), Length.instantiateSI(2900), detectorLength, sim, agg,
307 Detector.MEAN_SPEED, Detector.OCCUPANCY);
308 Detector det3 = new Detector("3", lanesCD.get(0), Length.instantiateSI(100), detectorLength, sim, agg,
309 Detector.MEAN_SPEED, Detector.OCCUPANCY);
310 Detector det4 = new Detector("4", lanesCD.get(1), Length.instantiateSI(100), detectorLength, sim, agg,
311 Detector.MEAN_SPEED, Detector.OCCUPANCY);
312 List<Detector> detectors12 = new ArrayList<>();
313 detectors12.add(det1);
314 detectors12.add(det2);
315 List<Detector> detectors34 = new ArrayList<>();
316 detectors34.add(det3);
317 detectors34.add(det4);
318 if (this.rampMetering)
319 {
320
321 TrafficLight light = new SimpleTrafficLight("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, Compatible.EVERYTHING);
328 new RampMetering(sim, rampSwitch, rampLightController);
329 }
330
331
332 List<OTSRoadNode> origins = new ArrayList<>();
333 origins.add(nodeA);
334 origins.add(nodeE);
335 List<OTSRoadNode> 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 odOptions.set(ODOptions.GTU_TYPE, new ControlledStrategicalPlannerGenerator()).set(ODOptions.INSTANT_LC, true);
353 ODApplier.applyOD(network, od, sim, odOptions);
354
355 return network;
356 }
357
358
359
360
361
362 final ParameterFactoryByType getParameterFactory()
363 {
364 return this.parameterFactory;
365 }
366
367
368 @Override
369 public void notify(final EventInterface event) throws RemoteException
370 {
371 if (event.getType().equals(Network.GTU_ADD_EVENT))
372 {
373 this.gtusInSimulation.put((String) event.getContent(), getSimulator().getSimulatorTime().si);
374 }
375 else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
376 {
377 measureTravelTime((String) event.getContent());
378 }
379 else
380 {
381 super.notify(event);
382 }
383 }
384
385
386
387
388
389 private void measureTravelTime(final String id)
390 {
391 double tt = getSimulator().getSimulatorTime().si - this.gtusInSimulation.get(id);
392 double x = getNetwork().getGTU(id).getOdometer().si;
393
394 double ttd = tt - (x / (120 / 3.6));
395 this.totalTravelTime += tt;
396 this.totalTravelTimeDelay += ttd;
397 this.gtusInSimulation.remove(id);
398 }
399
400
401 @Override
402 protected void onSimulationEnd()
403 {
404 if (this.output)
405 {
406
407 String file = String.format("%s_%02d_detectors.txt", this.scenario, getSeed());
408 Detector.writeToFile(getNetwork(), file, true, "%.3f", CompressionMethod.NONE);
409
410
411 for (GTU gtu : getNetwork().getGTUs())
412 {
413 measureTravelTime(gtu.getId());
414 }
415 Throw.when(!this.gtusInSimulation.isEmpty(), RuntimeException.class,
416 "GTUs remain in simulation that are not measured.");
417 file = String.format("%s_%02d_time.txt", this.scenario, getSeed());
418 BufferedWriter bw = CompressedFileWriter.create(file, false);
419 try
420 {
421 bw.write(String.format("Total travel time: %.3fs", this.totalTravelTime));
422 bw.newLine();
423 bw.write(String.format("Total travel time delay: %.3fs", this.totalTravelTimeDelay));
424 bw.close();
425 }
426 catch (IOException exception)
427 {
428 throw new RuntimeException(exception);
429 }
430 finally
431 {
432 try
433 {
434 if (bw != null)
435 {
436 bw.close();
437 }
438 }
439 catch (IOException ex)
440 {
441 throw new RuntimeException(ex);
442 }
443 }
444 }
445 }
446
447
448
449
450
451 private class ControlledStrategicalPlannerGenerator implements GTUCharacteristicsGeneratorOD
452 {
453
454
455 private DefaultGTUCharacteristicsGeneratorOD defaultGenerator = new DefaultGTUCharacteristicsGeneratorOD();
456
457
458 private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> controlledPlannerFactory;
459
460
461 ControlledStrategicalPlannerGenerator()
462 {
463
464 LaneBasedTacticalPlannerFactory<?> tacticalPlannerFactory =
465 new LaneBasedTacticalPlannerFactory<LaneBasedTacticalPlanner>()
466 {
467 @Override
468 public Parameters getParameters() throws ParameterException
469 {
470 ParameterSet set = new ParameterSet();
471 set.setDefaultParameter(ParameterTypes.PERCEPTION);
472 set.setDefaultParameter(ParameterTypes.LOOKBACK);
473 set.setDefaultParameter(ParameterTypes.LOOKAHEAD);
474 set.setDefaultParameter(ParameterTypes.S0);
475 set.setDefaultParameter(ParameterTypes.TMIN);
476 set.setDefaultParameter(ParameterTypes.TMAX);
477 set.setDefaultParameter(ParameterTypes.DT);
478 set.setDefaultParameter(ParameterTypes.VCONG);
479 set.setDefaultParameter(ParameterTypes.T0);
480 set.setDefaultParameter(TrafficLightUtil.B_YELLOW);
481 set.setDefaultParameters(LmrsParameters.class);
482 set.setDefaultParameters(AbstractIDM.class);
483 return set;
484 }
485
486 @SuppressWarnings("synthetic-access")
487 @Override
488 public LaneBasedTacticalPlanner create(final LaneBasedGTU gtu) throws GTUException
489 {
490
491 ParameterSet settings = new ParameterSet();
492 try
493 {
494
495 settings.setParameter(SyncAndAccept.SYNCTIME, Duration.instantiateSI(1.0));
496 settings.setParameter(SyncAndAccept.COOPTIME, Duration.instantiateSI(2.0));
497
498 settings.setParameter(AbstractIDM.DELTA, 1.0);
499 settings.setParameter(ParameterTypes.S0, Length.instantiateSI(3.0));
500 settings.setParameter(ParameterTypes.A, Acceleration.instantiateSI(2.0));
501 settings.setParameter(ParameterTypes.B, Acceleration.instantiateSI(2.0));
502 settings.setParameter(ParameterTypes.T, RampMeteringDemo.this.acceptedGap);
503 settings.setParameter(ParameterTypes.FSPEED, 1.0);
504 settings.setParameter(ParameterTypes.B0, Acceleration.instantiateSI(0.5));
505 settings.setParameter(ParameterTypes.VCONG, new Speed(60, SpeedUnit.KM_PER_HOUR));
506 }
507 catch (ParameterException exception)
508 {
509 throw new GTUException(exception);
510 }
511 return new ControlledTacticalPlanner(gtu, new SyncAndAccept(gtu, new IDMPlus(), settings));
512 }
513 };
514
515 this.controlledPlannerFactory = new LaneBasedStrategicalRoutePlannerFactory(tacticalPlannerFactory,
516 RampMeteringDemo.this.getParameterFactory());
517 }
518
519
520 @Override
521 public LaneBasedGTUCharacteristics draw(final Node origin, final Node destination, final Category category,
522 final StreamInterface randomStream) throws GTUException
523 {
524 GTUType gtuType = category.get(GTUType.class);
525
526 if (gtuType.equals(getNetwork().getGtuType(CONTROLLED_CAR_ID)))
527 {
528 Route route = null;
529 VehicleModel vehicleModel = VehicleModel.MINMAX;
530 GTUCharacteristics gtuCharacteristics =
531 GTUType.defaultCharacteristics(gtuType, origin.getNetwork(), randomStream);
532 return new LaneBasedGTUCharacteristics(gtuCharacteristics, this.controlledPlannerFactory, route, origin,
533 destination, vehicleModel);
534 }
535
536 return this.defaultGenerator.draw(origin, destination, category, randomStream);
537 }
538
539 }
540
541
542 private static class ControlledTacticalPlanner extends AbstractIncentivesTacticalPlanner
543 {
544
545 private static final long serialVersionUID = 20190731L;
546
547
548 private AutomaticLaneChangeSystem laneChangeSystem;
549
550
551 private final LaneChange laneChange;
552
553
554 private Map<Class<? extends Incentive>, Desire> dummyMap = new LinkedHashMap<>();
555
556
557
558
559
560
561 ControlledTacticalPlanner(final LaneBasedGTU gtu, final AutomaticLaneChangeSystem laneChangeSystem)
562 {
563 super(new IDMPlus(), gtu, generatePerception(gtu));
564 setDefaultIncentives();
565 this.laneChangeSystem = laneChangeSystem;
566 this.laneChange = Try.assign(() -> new LaneChange(gtu), "Parameter LCDUR is required.", GTUException.class);
567 }
568
569
570
571
572
573
574 private static LanePerception generatePerception(final LaneBasedGTU gtu)
575 {
576 CategoricalLanePerception perception = new CategoricalLanePerception(gtu);
577 perception.addPerceptionCategory(new DirectEgoPerception<LaneBasedGTU, Perception<LaneBasedGTU>>(perception));
578 perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
579
580 perception.addPerceptionCategory(new DirectNeighborsPerception(perception, HeadwayGtuType.WRAP));
581 perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
582 perception.addPerceptionCategory(new DirectIntersectionPerception(perception, HeadwayGtuType.WRAP));
583 return perception;
584 }
585
586
587 @Override
588 public OperationalPlan generateOperationalPlan(final Time startTime, final DirectedPoint locationAtStartTime)
589 throws OperationalPlanException, GTUException, NetworkException, ParameterException
590 {
591
592 Speed speed = getPerception().getPerceptionCategory(EgoPerception.class).getSpeed();
593 SpeedLimitProspect slp = getPerception().getPerceptionCategory(InfrastructurePerception.class)
594 .getSpeedLimitProspect(RelativeLane.CURRENT);
595 SpeedLimitInfo sli = slp.getSpeedLimitInfo(Length.ZERO);
596
597
598 Desire desire = LmrsUtil.getLaneChangeDesire(getGtu().getParameters(), getPerception(), getCarFollowingModel(),
599 getMandatoryIncentives(), getVoluntaryIncentives(), this.dummyMap);
600
601
602 getGtu().getParameters().setParameter(LmrsParameters.DLEFT, desire.getLeft());
603 getGtu().getParameters().setParameter(LmrsParameters.DRIGHT, desire.getRight());
604
605
606 Acceleration a = getGtu().getCarFollowingAcceleration();
607
608
609 Acceleration aCoop = Cooperation.PASSIVE.cooperate(getPerception(), getGtu().getParameters(), sli,
610 getCarFollowingModel(), LateralDirectionality.LEFT, desire);
611 a = Acceleration.min(a, aCoop);
612 aCoop = Cooperation.PASSIVE.cooperate(getPerception(), getGtu().getParameters(), sli, getCarFollowingModel(),
613 LateralDirectionality.RIGHT, desire);
614 a = Acceleration.min(a, aCoop);
615
616
617 SimpleOperationalPlan simplePlan =
618 new SimpleOperationalPlan(a, getGtu().getParameters().getParameter(ParameterTypes.DT));
619 for (AccelerationIncentive incentive : getAccelerationIncentives())
620 {
621 incentive.accelerate(simplePlan, RelativeLane.CURRENT, Length.ZERO, getGtu(), getPerception(),
622 getCarFollowingModel(), speed, getGtu().getParameters(), sli);
623 }
624
625
626 if (!this.laneChange.isChangingLane())
627 {
628 double dFree = getGtu().getParameters().getParameter(LmrsParameters.DFREE);
629 if (this.laneChangeSystem.initiatedLaneChange().isNone())
630 {
631 if (desire.leftIsLargerOrEqual() && desire.getLeft() > dFree)
632 {
633 this.laneChangeSystem.initiateLaneChange(LateralDirectionality.LEFT);
634 }
635 else if (desire.getRight() > dFree)
636 {
637 this.laneChangeSystem.initiateLaneChange(LateralDirectionality.RIGHT);
638 }
639 }
640 else
641 {
642 if ((this.laneChangeSystem.initiatedLaneChange().isLeft() && desire.getLeft() < dFree)
643 || (this.laneChangeSystem.initiatedLaneChange().isRight() && desire.getRight() < dFree))
644 {
645 this.laneChangeSystem.initiateLaneChange(LateralDirectionality.NONE);
646 }
647 }
648 }
649 simplePlan = this.laneChangeSystem.operate(simplePlan, getGtu().getParameters());
650 simplePlan.setTurnIndicator(getGtu());
651
652
653 return LaneOperationalPlanBuilder.buildPlanFromSimplePlan(getGtu(), startTime, simplePlan, this.laneChange);
654 }
655 }
656
657
658 private interface AutomaticLaneChangeSystem
659 {
660
661
662
663
664
665
666
667
668
669 SimpleOperationalPlan operate(SimpleOperationalPlan simplePlan, Parameters parameters)
670 throws OperationalPlanException, ParameterException;
671
672
673
674
675
676
677 LateralDirectionality initiatedLaneChange();
678
679
680
681
682
683 void initiateLaneChange(LateralDirectionality dir);
684
685 }
686
687
688 private static class SyncAndAccept implements AutomaticLaneChangeSystem
689 {
690
691 public static final ParameterTypeDuration SYNCTIME = new ParameterTypeDuration("tSync",
692 "Time after which synchronization starts.", Duration.instantiateSI(1.0), NumericConstraint.POSITIVE);
693
694
695 public static final ParameterTypeDuration COOPTIME = new ParameterTypeDuration("tCoop",
696 "Time after which cooperation starts (indicator).", Duration.instantiateSI(2.0), NumericConstraint.POSITIVE);
697
698
699 private final LaneBasedGTU gtu;
700
701
702 private final CarFollowingModel carFollowingModel;
703
704
705 private final Parameters settings;
706
707
708 private LateralDirectionality direction = LateralDirectionality.NONE;
709
710
711 private Time initiationTime;
712
713
714
715
716
717
718
719 SyncAndAccept(final LaneBasedGTU gtu, final CarFollowingModel carFollowingModel, final Parameters settings)
720 {
721 this.gtu = gtu;
722 this.carFollowingModel = carFollowingModel;
723 this.settings = settings;
724 }
725
726
727 @Override
728 public SimpleOperationalPlan operate(final SimpleOperationalPlan simplePlan, final Parameters parameters)
729 throws OperationalPlanException, ParameterException
730 {
731
732 if (this.direction.isNone())
733 {
734 return simplePlan;
735 }
736
737
738 InfrastructurePerception infra =
739 this.gtu.getTacticalPlanner().getPerception().getPerceptionCategory(InfrastructurePerception.class);
740 SpeedLimitInfo sli = infra.getSpeedLimitProspect(RelativeLane.CURRENT).getSpeedLimitInfo(Length.ZERO);
741 NeighborsPerception neighbors =
742 this.gtu.getTacticalPlanner().getPerception().getPerceptionCategory(NeighborsPerception.class);
743 if (infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, this.direction).gt0()
744 && !neighbors.isGtuAlongside(this.direction)
745 && acceptGap(neighbors.getFirstFollowers(this.direction), sli, false)
746 && acceptGap(neighbors.getFirstLeaders(this.direction), sli, true))
747 {
748
749 SimpleOperationalPlan plan =
750 new SimpleOperationalPlan(simplePlan.getAcceleration(), simplePlan.getDuration(), this.direction);
751 this.direction = LateralDirectionality.NONE;
752 this.initiationTime = null;
753 return plan;
754 }
755
756
757 Duration since = this.gtu.getSimulator().getSimulatorTime().minus(this.initiationTime);
758 if (since.gt(this.settings.getParameter(SYNCTIME))
759 || this.gtu.getSpeed().lt(this.settings.getParameter(ParameterTypes.VCONG)))
760 {
761 PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders =
762 neighbors.getLeaders(new RelativeLane(this.direction, 1));
763 if (!leaders.isEmpty())
764 {
765 HeadwayGTU leader = leaders.first();
766 Acceleration a = CarFollowingUtil.followSingleLeader(this.carFollowingModel, this.settings,
767 this.gtu.getSpeed(), sli, leader);
768 a = Acceleration.max(a, this.settings.getParameter(ParameterTypes.B).neg());
769 simplePlan.minimizeAcceleration(a);
770 }
771 }
772
773
774 if (since.gt(this.settings.getParameter(COOPTIME))
775 || this.gtu.getSpeed().lt(this.settings.getParameter(ParameterTypes.VCONG)))
776 {
777 if (this.direction.isLeft())
778 {
779 simplePlan.setIndicatorIntentLeft();
780 }
781 else
782 {
783 simplePlan.setIndicatorIntentRight();
784 }
785 }
786
787
788 return simplePlan;
789 }
790
791
792
793
794
795
796
797
798
799 private boolean acceptGap(final Set<HeadwayGTU> neighbors, final SpeedLimitInfo sli, final boolean leaders)
800 throws ParameterException
801 {
802 for (HeadwayGTU neighbor : neighbors)
803 {
804 Acceleration a = CarFollowingUtil.followSingleLeader(this.carFollowingModel, this.settings,
805 leaders ? this.gtu.getSpeed() : neighbor.getSpeed(), sli, neighbor.getDistance(),
806 leaders ? neighbor.getSpeed() : this.gtu.getSpeed());
807 if (a.lt(this.settings.getParameter(ParameterTypes.B).neg()))
808 {
809 return false;
810 }
811 }
812 return true;
813 }
814
815
816 @Override
817 public LateralDirectionality initiatedLaneChange()
818 {
819 return this.direction;
820 }
821
822
823 @Override
824 public void initiateLaneChange(final LateralDirectionality dir)
825 {
826 this.direction = dir;
827 if (!dir.isNone())
828 {
829 this.initiationTime = this.gtu.getSimulator().getSimulatorTime();
830 }
831 else
832 {
833 this.initiationTime = null;
834 }
835 }
836 }
837
838 }