1 package org.opentrafficsim.demo.sdm;
2
3 import java.awt.Color;
4 import java.io.BufferedWriter;
5 import java.io.IOException;
6 import java.io.OutputStreamWriter;
7 import java.util.ArrayList;
8 import java.util.List;
9
10 import org.djunits.unit.FrequencyUnit;
11 import org.djunits.unit.SpeedUnit;
12 import org.djunits.unit.TimeUnit;
13 import org.djunits.value.ValueRuntimeException;
14 import org.djunits.value.storage.StorageType;
15 import org.djunits.value.vdouble.scalar.Acceleration;
16 import org.djunits.value.vdouble.scalar.Direction;
17 import org.djunits.value.vdouble.scalar.Duration;
18 import org.djunits.value.vdouble.scalar.Frequency;
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.djunits.value.vfloat.scalar.FloatDuration;
26 import org.djutils.cli.CliException;
27 import org.djutils.cli.CliUtil;
28 import org.djutils.exceptions.Throw;
29 import org.opentrafficsim.base.compressedfiles.CompressionType;
30 import org.opentrafficsim.base.compressedfiles.Writer;
31 import org.opentrafficsim.core.animation.gtu.colorer.AccelerationGTUColorer;
32 import org.opentrafficsim.core.animation.gtu.colorer.SpeedGTUColorer;
33 import org.opentrafficsim.core.animation.gtu.colorer.SwitchableGTUColorer;
34 import org.opentrafficsim.core.compatibility.Compatible;
35 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
36 import org.opentrafficsim.core.geometry.OTSPoint3D;
37 import org.opentrafficsim.core.gtu.GTUDirectionality;
38 import org.opentrafficsim.core.gtu.GTUType;
39 import org.opentrafficsim.core.network.LinkType;
40 import org.opentrafficsim.core.network.NetworkException;
41 import org.opentrafficsim.core.network.OTSNode;
42 import org.opentrafficsim.core.perception.HistoryManagerDEVS;
43 import org.opentrafficsim.draw.graphs.ContourDataSource;
44 import org.opentrafficsim.draw.graphs.ContourPlotSpeed;
45 import org.opentrafficsim.draw.graphs.GraphPath;
46 import org.opentrafficsim.draw.graphs.road.GraphLaneUtil;
47 import org.opentrafficsim.kpi.sampling.KpiGtuDirectionality;
48 import org.opentrafficsim.kpi.sampling.KpiLaneDirection;
49 import org.opentrafficsim.kpi.sampling.SamplingException;
50 import org.opentrafficsim.kpi.sampling.SpaceTimeRegion;
51 import org.opentrafficsim.kpi.sampling.Trajectory;
52 import org.opentrafficsim.kpi.sampling.TrajectoryGroup;
53 import org.opentrafficsim.road.gtu.colorer.DesiredHeadwayColorer;
54 import org.opentrafficsim.road.gtu.colorer.DistractionColorer;
55 import org.opentrafficsim.road.gtu.colorer.FixedColor;
56 import org.opentrafficsim.road.gtu.colorer.SynchronizationColorer;
57 import org.opentrafficsim.road.gtu.colorer.TaskSaturationColorer;
58 import org.opentrafficsim.road.gtu.generator.od.DefaultGTUCharacteristicsGeneratorOD;
59 import org.opentrafficsim.road.gtu.generator.od.ODApplier;
60 import org.opentrafficsim.road.gtu.generator.od.ODOptions;
61 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
62 import org.opentrafficsim.road.gtu.lane.perception.mental.AdaptationSituationalAwareness;
63 import org.opentrafficsim.road.gtu.lane.perception.mental.ExponentialTask;
64 import org.opentrafficsim.road.gtu.lane.perception.mental.Task;
65 import org.opentrafficsim.road.gtu.lane.perception.mental.sdm.DefaultDistraction;
66 import org.opentrafficsim.road.gtu.lane.perception.mental.sdm.DistractionFactory;
67 import org.opentrafficsim.road.gtu.lane.perception.mental.sdm.StochasticDistractionModel;
68 import org.opentrafficsim.road.gtu.lane.perception.mental.sdm.TaskSupplier;
69 import org.opentrafficsim.road.gtu.strategical.od.Categorization;
70 import org.opentrafficsim.road.gtu.strategical.od.Category;
71 import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
72 import org.opentrafficsim.road.gtu.strategical.od.ODMatrix;
73 import org.opentrafficsim.road.network.OTSRoadNetwork;
74 import org.opentrafficsim.road.network.factory.LaneFactory;
75 import org.opentrafficsim.road.network.lane.CrossSectionLink;
76 import org.opentrafficsim.road.network.lane.Lane;
77 import org.opentrafficsim.road.network.lane.LaneDirection;
78 import org.opentrafficsim.road.network.lane.LaneType;
79 import org.opentrafficsim.road.network.lane.OTSRoadNode;
80 import org.opentrafficsim.road.network.lane.Stripe.Permeable;
81 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
82 import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
83 import org.opentrafficsim.road.network.sampling.LaneData;
84 import org.opentrafficsim.road.network.sampling.RoadSampler;
85 import org.opentrafficsim.road.network.sampling.data.TimeToCollision;
86 import org.opentrafficsim.swing.graphs.SwingContourPlot;
87 import org.opentrafficsim.swing.graphs.SwingPlot;
88 import org.opentrafficsim.swing.gui.OTSSimulationApplication;
89 import org.opentrafficsim.swing.script.AbstractSimulationScript;
90 import org.opentrafficsim.swing.script.IdmOptions;
91
92 import nl.tudelft.simulation.dsol.swing.gui.TablePanel;
93 import nl.tudelft.simulation.jstats.streams.StreamInterface;
94 import picocli.CommandLine.Mixin;
95 import picocli.CommandLine.Option;
96
97
98
99
100
101
102
103
104
105
106
107
108 public class SdmSimulation extends AbstractSimulationScript
109 {
110
111 private static final long serialVersionUID = 20200516L;
112
113
114 private OTSRoadNetwork network;
115
116
117 private RoadSampler sampler;
118
119
120 private final TimeToCollision ttc = new TimeToCollision();
121
122
123 private final List<SpaceTimeRegion> regions = new ArrayList<>();
124
125
126
127
128 @Mixin
129 private IdmOptions idmOptions;
130
131
132 @Option(names = "--outputFile", description = "Output file", defaultValue = "output.txt")
133 private String outputFile;
134
135
136 @Option(names = {"-o", "--output"}, description = "Create output", negatable = true, defaultValue = "true")
137 private boolean output;
138
139
140 @Option(names = {"-p", "--plots"}, description = "Create plots", negatable = true, defaultValue = "false")
141 private boolean plots;
142
143
144 @Option(names = "--truckFraction", description = "Fraction of trucks", defaultValue = "0.05")
145 private double truckFraction;
146
147
148 @Option(names = "--demandLeft", description = "Demand left", defaultValue = "3600/h")
149 private Frequency demandLeft;
150
151
152 @Option(names = "--demandRight", description = "Demand right", defaultValue = "3600/h")
153 private Frequency demandRight;
154
155
156 @Option(names = "--startDemandFctor", description = "Factor on demand at start", defaultValue = "0.45")
157 private double startDemandFctor;
158
159
160 @Option(names = "--multitasking", description = "Multitasking", negatable = true, defaultValue = "false")
161 private boolean multitasking;
162
163
164 @Option(names = "--distractions", split = ",",
165 description = "Distraction, 1=TALKING_CELL_PHONE,12=CONVERSING,5=MANIPULATING_AUDIO_CONTROLS,16=EXTERNAL_DISTRACTION",
166 defaultValue = "1,12,5,16")
167 private String[] distractions;
168
169
170 @Option(names = "--phoneInit", description = "Initial task demand when talking on the phone", defaultValue = "1.0")
171 private double phoneInit;
172
173
174 @Option(names = "--phoneFinal", description = "Final task demand when talking on the phone", defaultValue = "0.3")
175 private double phoneFinal;
176
177
178 @Option(names = "--phoneTau", description = "Exponential duration if task demand reduction when talking on the phone",
179 defaultValue = "10s")
180 private Duration phoneTau;
181
182
183 @Option(names = "--conversing", description = "Task demand when conversing", defaultValue = "0.3")
184 private double conversing;
185
186
187 @Option(names = "--audio", description = "Task demand when controlling audio", defaultValue = "0.3")
188 private double audio;
189
190
191 @Option(names = "--externalBase", description = "Fixed (minimum) task demand for external distraction",
192 defaultValue = "0.2")
193 private double externalBase;
194
195
196 @Option(names = "--externalVar",
197 description = "Variable task demand for external distraction (random fraction added externalBase)",
198 defaultValue = "0.3")
199 private double externalVar;
200
201
202 @Option(names = "--dt", description = "Time step", defaultValue = "0.5s")
203 private Duration dt;
204
205
206 @Option(names = "--saMin", description = "Minimum situational awareness", defaultValue = "0.5")
207 private double saMin;
208
209
210 @Option(names = "--saMax", description = "Maximum situational awareness", defaultValue = "1.0")
211 private double saMax;
212
213
214 @Option(names = "--tc", description = "Task capability", defaultValue = "1.0")
215 private double tc;
216
217
218 @Option(names = "--tsCrit", description = "Critical task saturation", defaultValue = "0.8")
219 private double tsCrit;
220
221
222 @Option(names = "--tsMax", description = "Maximum task saturation", defaultValue = "2.0")
223 private double tsMax;
224
225
226 @Option(names = "--trMax", description = "Maximum reaction time", defaultValue = "2.0s")
227 private Duration trMax;
228
229
230 @Option(names = "--betaT", description = "Maximum additional factor on headway for adaptation", defaultValue = "1.0")
231 private double betaT;
232
233
234
235
236 protected SdmSimulation()
237 {
238 super("SDM simulation", "Simulations using the Stochastic Distraction Model");
239
240 setGtuColorer(SwitchableGTUColorer.builder().addActiveColorer(new FixedColor(Color.BLUE, "Blue"))
241 .addColorer(new SynchronizationColorer())
242 .addColorer(new DistractionColorer(DefaultDistraction.ANSWERING_CELL_PHONE, DefaultDistraction.CONVERSING,
243 DefaultDistraction.MANIPULATING_AUDIO_CONTROLS, DefaultDistraction.EXTERNAL_DISTRACTION))
244 .addColorer(new SpeedGTUColorer(new Speed(150, SpeedUnit.KM_PER_HOUR)))
245 .addColorer(new AccelerationGTUColorer(Acceleration.instantiateSI(-6.0), Acceleration.instantiateSI(2)))
246 .addColorer(new DesiredHeadwayColorer(Duration.instantiateSI(0.56), Duration.instantiateSI(2.4)))
247 .addColorer(new TaskSaturationColorer()).build());
248 try
249 {
250 CliUtil.changeOptionDefault(this, "warmupTime", "300s");
251 CliUtil.changeOptionDefault(this, "simulationTime", "3900s");
252 CliUtil.changeOptionDefault(IdmOptions.class, "aTruck", "0.8m/s^2");
253 }
254 catch (NoSuchFieldException | IllegalStateException | IllegalArgumentException | CliException exception)
255 {
256 exception.printStackTrace();
257 }
258 }
259
260
261
262
263
264 public static void main(final String... args)
265 {
266 try
267 {
268 SdmSimulation sim = new SdmSimulation();
269 CliUtil.execute(sim, args);
270 sim.start();
271 }
272 catch (Exception ex)
273 {
274 ex.printStackTrace();
275 }
276 }
277
278
279 @Override
280 public void check() throws Exception
281 {
282 super.check();
283 Throw.when(this.truckFraction < 0.0 || this.truckFraction > 1.0, IllegalArgumentException.class,
284 "Truck fraction %f is below 0.0 or above 1.0.");
285 }
286
287
288 @Override
289 protected OTSRoadNetwork setupSimulation(final OTSSimulatorInterface sim) throws Exception
290 {
291
292 sim.getReplication().setHistoryManager(new HistoryManagerDEVS(sim,
293 AdaptationSituationalAwareness.TR_MAX.getDefaultValue(), Duration.instantiateSI(10.0)));
294
295
296 this.network = new OTSRoadNetwork("SDM", true, getSimulator());
297 OTSPoint3D pointA = new OTSPoint3D(0.0, 0.0);
298 OTSPoint3D pointB = new OTSPoint3D(0.0, -20.0);
299 OTSPoint3D pointC = new OTSPoint3D(1600.0, -20.0);
300 OTSPoint3D pointD = new OTSPoint3D(2000.0, 0.0);
301 OTSPoint3D pointE = new OTSPoint3D(2500.0, 0.0);
302 OTSPoint3D pointF = new OTSPoint3D(3500.0, 0.0);
303 OTSRoadNode nodeA = new OTSRoadNode(this.network, "A", pointA, Direction.ZERO);
304 OTSRoadNode nodeB = new OTSRoadNode(this.network, "B", pointB, Direction.ZERO);
305 OTSRoadNode nodeC = new OTSRoadNode(this.network, "C", pointC, Direction.ZERO);
306 OTSRoadNode nodeD = new OTSRoadNode(this.network, "D", pointD, Direction.ZERO);
307 OTSRoadNode nodeE = new OTSRoadNode(this.network, "E", pointE, Direction.ZERO);
308 OTSRoadNode nodeF = new OTSRoadNode(this.network, "F", pointF, Direction.ZERO);
309 LinkType type = this.network.getLinkType(LinkType.DEFAULTS.FREEWAY);
310 LaneKeepingPolicy policy = LaneKeepingPolicy.KEEPRIGHT;
311 Length laneWidth = Length.instantiateSI(3.5);
312 LaneType laneType = this.network.getLaneType(LaneType.DEFAULTS.FREEWAY);
313 Speed speedLimit = new Speed(120.0, SpeedUnit.KM_PER_HOUR);
314 List<Lane> allLanes = new ArrayList<>();
315 allLanes.addAll(new LaneFactory(this.network, nodeA, nodeD, type, sim, policy)
316 .leftToRight(2.0, laneWidth, laneType, speedLimit).addLanes(Permeable.BOTH).getLanes());
317 allLanes.addAll(new LaneFactory(this.network, nodeB, nodeC, type, sim, policy)
318 .leftToRight(0.0, laneWidth, laneType, speedLimit).addLanes(Permeable.BOTH).getLanes());
319 allLanes.addAll(new LaneFactory(this.network, nodeC, nodeD, type, sim, policy)
320 .leftToRight(0.0, laneWidth, laneType, speedLimit).addLanes(Permeable.BOTH).getLanes());
321 allLanes.addAll(
322 new LaneFactory(this.network, nodeD, nodeE, type, sim, policy).leftToRight(2.0, laneWidth, laneType, speedLimit)
323 .addLanes(Permeable.BOTH, Permeable.BOTH, Permeable.BOTH).getLanes());
324 List<Lane> lanesEF = new LaneFactory(this.network, nodeE, nodeF, type, sim, policy)
325 .leftToRight(1.0, laneWidth, laneType, speedLimit).addLanes(Permeable.BOTH, Permeable.BOTH).getLanes();
326 allLanes.addAll(lanesEF);
327 for (Lane lane : lanesEF)
328 {
329 new SinkSensor(lane, lane.getLength().minus(Length.instantiateSI(50)), Compatible.EVERYTHING, sim);
330 }
331
332
333 List<OTSNode> origins = new ArrayList<>();
334 origins.add(nodeA);
335 origins.add(nodeB);
336 List<OTSNode> destinations = new ArrayList<>();
337 destinations.add(nodeF);
338 double wut = sim.getReplication().getWarmupPeriod().si;
339 double rl = sim.getReplication().getRunLength().si;
340 TimeVector timeVector = DoubleVector.instantiate(new double[] {0.0, wut, wut + (rl - wut) * 0.5, rl}, TimeUnit.DEFAULT,
341 StorageType.DENSE);
342 Interpolation interpolation = Interpolation.LINEAR;
343 Categorization categorization = new Categorization("GTU categorization", GTUType.class);
344 ODMatrix odMatrix = new ODMatrix("OD", origins, destinations, categorization, timeVector, interpolation);
345 Category carCategory = new Category(categorization, this.network.getGtuType(GTUType.DEFAULTS.CAR));
346 Category truCategory = new Category(categorization, this.network.getGtuType(GTUType.DEFAULTS.TRUCK));
347 double f1 = this.truckFraction;
348 double f2 = 1.0 - f1;
349 double left2 = this.demandLeft.getInUnit(FrequencyUnit.PER_HOUR);
350 double right2 = this.demandRight.getInUnit(FrequencyUnit.PER_HOUR);
351 double startDemandFactor = this.startDemandFctor;
352 double left1 = left2 * startDemandFactor;
353 double right1 = right2 * startDemandFactor;
354 odMatrix.putDemandVector(nodeA, nodeF, carCategory, freq(new double[] {f2 * left1, f2 * left1, f2 * left2, 0.0}));
355 odMatrix.putDemandVector(nodeA, nodeF, truCategory, freq(new double[] {f1 * left1, f1 * left1, f1 * left2, 0.0}));
356 odMatrix.putDemandVector(nodeB, nodeF, carCategory, freq(new double[] {f2 * right1, f2 * right1, f2 * right2, 0.0}));
357 odMatrix.putDemandVector(nodeB, nodeF, truCategory, freq(new double[] {f1 * right1, f1 * right1, f1 * right2, 0.0}));
358 ODOptions odOptions = new ODOptions().set(ODOptions.NO_LC_DIST, Length.instantiateSI(200)).set(ODOptions.GTU_TYPE,
359 new DefaultGTUCharacteristicsGeneratorOD(
360 new SdmStrategicalPlannerFactory(this.network, sim.getModel().getStream("generation"), this)));
361 ODApplier.applyOD(this.network, odMatrix, odOptions);
362
363
364 DistractionFactory distFactory = new DistractionFactory(sim.getModel().getStream("default"));
365 for (String distraction : this.distractions)
366 {
367 DefaultDistraction dist = DefaultDistraction.values()[Integer.parseInt(distraction) - 1];
368 distFactory.addDistraction(dist, getTaskSupplier(dist, sim.getModel().getStream("default")));
369 }
370 new StochasticDistractionModel(this.multitasking, distFactory.build(), sim, this.network);
371
372
373 if (this.output)
374 {
375 this.sampler = RoadSampler.build(this.network).registerExtendedDataType(this.ttc).create();
376 Time start = new Time(0.05, TimeUnit.BASE_HOUR);
377 Time end = new Time(1.05, TimeUnit.BASE_HOUR);
378 for (Lane lane : allLanes)
379 {
380 KpiLaneDirection kpiLane = new KpiLaneDirection(new LaneData(lane), KpiGtuDirectionality.DIR_PLUS);
381 SpaceTimeRegion region = new SpaceTimeRegion(kpiLane, Length.ZERO, lane.getLength(), start, end);
382 this.regions.add(region);
383 this.sampler.registerSpaceTimeRegion(region);
384 }
385 }
386
387
388 return this.network;
389 }
390
391
392 @Override
393 protected void addTabs(final OTSSimulatorInterface sim, final OTSSimulationApplication<?> animation)
394 {
395 if (!this.output || !this.plots)
396 {
397 return;
398 }
399 try
400 {
401 TablePanel charts = new TablePanel(2, 2);
402 GraphPath<KpiLaneDirection> path1 = GraphLaneUtil.createPath("Left road, left lane",
403 new LaneDirection((Lane) ((CrossSectionLink) this.network.getLink("AD")).getCrossSectionElement("Lane 1"),
404 GTUDirectionality.DIR_PLUS));
405 GraphPath<KpiLaneDirection> path2 = GraphLaneUtil.createPath("Left road, right lane",
406 new LaneDirection((Lane) ((CrossSectionLink) this.network.getLink("AD")).getCrossSectionElement("Lane 2"),
407 GTUDirectionality.DIR_PLUS));
408 GraphPath<KpiLaneDirection> path3 = GraphLaneUtil.createPath("Right road, left lane",
409 new LaneDirection((Lane) ((CrossSectionLink) this.network.getLink("BC")).getCrossSectionElement("Lane 1"),
410 GTUDirectionality.DIR_PLUS));
411 GraphPath<KpiLaneDirection> path4 = GraphLaneUtil.createPath("Right road, right lane",
412 new LaneDirection((Lane) ((CrossSectionLink) this.network.getLink("BC")).getCrossSectionElement("Lane 2"),
413 GTUDirectionality.DIR_PLUS));
414 GraphPath.initRecording(this.sampler, path1);
415 GraphPath.initRecording(this.sampler, path2);
416 GraphPath.initRecording(this.sampler, path3);
417 GraphPath.initRecording(this.sampler, path4);
418 SwingPlot plot = null;
419 plot = new SwingContourPlot(new ContourPlotSpeed("Left road, left lane", sim,
420 new ContourDataSource<>(this.sampler.getSamplerData(), path1)));
421 charts.setCell(plot.getContentPane(), 0, 0);
422 plot = new SwingContourPlot(new ContourPlotSpeed("Left road, right lane", sim,
423 new ContourDataSource<>(this.sampler.getSamplerData(), path2)));
424 charts.setCell(plot.getContentPane(), 1, 0);
425 plot = new SwingContourPlot(new ContourPlotSpeed("Right road, left lane", sim,
426 new ContourDataSource<>(this.sampler.getSamplerData(), path3)));
427 charts.setCell(plot.getContentPane(), 0, 1);
428 plot = new SwingContourPlot(new ContourPlotSpeed("Right road, right lane", sim,
429 new ContourDataSource<>(this.sampler.getSamplerData(), path4)));
430 charts.setCell(plot.getContentPane(), 1, 1);
431 animation.getAnimationPanel().getTabbedPane().addTab(animation.getAnimationPanel().getTabbedPane().getTabCount(),
432 "statistics ", charts);
433 }
434 catch (NetworkException exception)
435 {
436 throw new RuntimeException(exception);
437 }
438 }
439
440
441
442
443
444
445
446 private FrequencyVector freq(final double[] array) throws ValueRuntimeException
447 {
448 return DoubleVector.instantiate(array, FrequencyUnit.PER_HOUR, StorageType.DENSE);
449 }
450
451
452
453
454
455
456
457 private TaskSupplier getTaskSupplier(final DefaultDistraction distraction, final StreamInterface stream)
458 {
459 switch (distraction)
460 {
461 case TALKING_CELL_PHONE:
462 {
463 return new TaskSupplier()
464 {
465
466 @SuppressWarnings("synthetic-access")
467 @Override
468 public Task getTask(final LaneBasedGTU gtu)
469 {
470 return new ExponentialTask(distraction.getId(), SdmSimulation.this.phoneInit,
471 SdmSimulation.this.phoneFinal, SdmSimulation.this.phoneTau, gtu.getSimulator());
472 }
473 };
474 }
475 case CONVERSING:
476 {
477 return new TaskSupplier.Constant(distraction.getId(), SdmSimulation.this.conversing);
478 }
479 case MANIPULATING_AUDIO_CONTROLS:
480 {
481 return new TaskSupplier.Constant(distraction.getId(), SdmSimulation.this.audio);
482 }
483 case EXTERNAL_DISTRACTION:
484 {
485 return new TaskSupplier.Constant(distraction.getId(),
486 SdmSimulation.this.externalBase + SdmSimulation.this.externalVar * stream.nextDouble());
487 }
488 default:
489 throw new IllegalArgumentException("Distraction " + distraction + " is not recognized.");
490 }
491 }
492
493
494 @Override
495 protected void onSimulationEnd()
496 {
497 if (this.output)
498 {
499 Length preDetectorPosition = Length.instantiateSI(400.0);
500 Length postDetectorPosition = Length.instantiateSI(100.0);
501 double tts = 0.0;
502 List<Float> ttcList = new ArrayList<>();
503 List<Float> decList = new ArrayList<>();
504 int[] counts = new int[60];
505 int[] speedCounts = new int[60];
506 double[] speedSum = new double[60];
507 for (SpaceTimeRegion region : this.regions)
508 {
509 TrajectoryGroup<?> trajectoryGroup =
510 this.sampler.getSamplerData().getTrajectoryGroup(region.getLaneDirection()).getTrajectoryGroup(
511 region.getStartPosition(), region.getEndPosition(), region.getStartTime(), region.getEndTime());
512 for (Trajectory<?> trajectory : trajectoryGroup)
513 {
514 try
515 {
516 tts += trajectory.getTotalDuration().si;
517 for (FloatDuration ttcVal : trajectory.getExtendedData(this.ttc))
518 {
519 if (!Float.isNaN(ttcVal.si) && ttcVal.si < 20)
520 {
521 ttcList.add(ttcVal.si);
522 }
523 }
524 for (float decVal : trajectory.getA())
525 {
526 if (decVal < -2.0)
527 {
528 decList.add(decVal);
529 }
530 }
531 if (region.getLaneDirection().getLaneData().getLinkData().getId().equals("DE") && trajectory.size() > 1
532 && trajectory.getX(0) < preDetectorPosition.si
533 && trajectory.getX(trajectory.size() - 1) > preDetectorPosition.si)
534 {
535 double t = trajectory.getTimeAtPosition(postDetectorPosition).si - region.getStartTime().si;
536 double v = trajectory.getSpeedAtPosition(postDetectorPosition).si;
537 speedCounts[(int) (t / 60.0)]++;
538 speedSum[(int) (t / 60.0)] += v;
539 }
540 if (region.getLaneDirection().getLaneData().getLinkData().getId().equals("EF") && trajectory.size() > 1
541 && trajectory.getX(0) < postDetectorPosition.si
542 && trajectory.getX(trajectory.size() - 1) > postDetectorPosition.si)
543 {
544 double t = trajectory.getTimeAtPosition(postDetectorPosition).si - region.getStartTime().si;
545 counts[(int) (t / 60.0)]++;
546 }
547 }
548 catch (SamplingException exception)
549 {
550 throw new RuntimeException(
551 "Unexpected exception: TimeToCollission not available or index out of bounds.", exception);
552 }
553 }
554 }
555 double qMax = 0;
556 for (int i = 0; i < counts.length - 4; i++)
557 {
558 int q = 0;
559 for (int j = i; j < i + 5; j++)
560 {
561 q += counts[j];
562 }
563 qMax = qMax > q ? qMax : q;
564 }
565 qMax *= 12;
566 int n = 0;
567 int countSum = 0;
568 for (int i = 0; i < counts.length; i++)
569 {
570 double v = speedSum[i] / speedCounts[i];
571 if (v < 80 / 3.6)
572 {
573 countSum += counts[i];
574 n++;
575 }
576 }
577 double qSat = n == 0 ? Double.NaN : 60.0 * countSum / n;
578 BufferedWriter bw;
579 try
580 {
581 bw = new BufferedWriter(
582 new OutputStreamWriter(Writer.createOutputStream(this.outputFile, CompressionType.ZIP)));
583 bw.write(String.format("total time spent [s]: %.0f", tts));
584 bw.newLine();
585 bw.write(String.format("maximum flow [veh/h]: %.3f", qMax));
586 bw.newLine();
587 bw.write(String.format("saturation flow [veh/h]: %.3f", qSat));
588 bw.newLine();
589 bw.write(String.format("time to collision [s]: %s", ttcList));
590 bw.newLine();
591 bw.write(String.format("strong decelerations [m/s^2]: %s", decList));
592 bw.close();
593 }
594 catch (IOException exception)
595 {
596 throw new RuntimeException(exception);
597 }
598 }
599 }
600
601
602
603
604 public IdmOptions getIdmOptions()
605 {
606 return this.idmOptions;
607 }
608
609
610
611
612 public Duration getDt()
613 {
614 return this.dt;
615 }
616
617
618
619
620 public double getSaMin()
621 {
622 return this.saMin;
623 }
624
625
626
627
628 public double getSaMax()
629 {
630 return this.saMax;
631 }
632
633
634
635
636 public double getTc()
637 {
638 return this.tc;
639 }
640
641
642
643
644 public double getTsCrit()
645 {
646 return this.tsCrit;
647 }
648
649
650
651
652 public double getTsMax()
653 {
654 return this.tsMax;
655 }
656
657
658
659
660 public Duration getTrMax()
661 {
662 return this.trMax;
663 }
664
665
666
667
668 public double getBetaT()
669 {
670 return this.betaT;
671 }
672
673 }