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