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")).addColorer(
241 new SynchronizationColorer()).addColorer(new DistractionColorer(DefaultDistraction.ANSWERING_CELL_PHONE,
242 DefaultDistraction.CONVERSING, DefaultDistraction.MANIPULATING_AUDIO_CONTROLS,
243 DefaultDistraction.EXTERNAL_DISTRACTION)).addColorer(new SpeedGTUColorer(new Speed(150, SpeedUnit.KM_PER_HOUR)))
244 .addColorer(new AccelerationGTUColorer(Acceleration.instantiateSI(-6.0), Acceleration.instantiateSI(2))).addColorer(
245 new DesiredHeadwayColorer(Duration.instantiateSI(0.56), Duration.instantiateSI(2.4))).addColorer(
246 new TaskSaturationColorer()).build());
247 try
248 {
249 CliUtil.changeOptionDefault(this, "warmupTime", "300s");
250 CliUtil.changeOptionDefault(this, "simulationTime", "3900s");
251 CliUtil.changeOptionDefault(IdmOptions.class, "aTruck", "0.8m/s^2");
252 }
253 catch (NoSuchFieldException | IllegalStateException | IllegalArgumentException | CliException exception)
254 {
255 exception.printStackTrace();
256 }
257 }
258
259
260
261
262
263 public static void main(final String... args)
264 {
265 try
266 {
267 SdmSimulationimulation.html#SdmSimulation">SdmSimulation sim = new SdmSimulation();
268 CliUtil.execute(sim, args);
269 sim.start();
270 }
271 catch (Exception ex)
272 {
273 ex.printStackTrace();
274 }
275 }
276
277
278 @Override
279 public void check() throws Exception
280 {
281 super.check();
282 Throw.when(this.truckFraction < 0.0 || this.truckFraction > 1.0, IllegalArgumentException.class,
283 "Truck fraction %f is below 0.0 or above 1.0.");
284 }
285
286
287 @Override
288 protected OTSRoadNetwork setupSimulation(final OTSSimulatorInterface sim) throws Exception
289 {
290
291 sim.getReplication().setHistoryManager(new HistoryManagerDEVS(sim, AdaptationSituationalAwareness.TR_MAX
292 .getDefaultValue(), Duration.instantiateSI(10.0)));
293
294
295 this.network = new OTSRoadNetwork("SDM", true, getSimulator());
296 OTSPoint3D pointA = new OTSPoint3D(0.0, 0.0);
297 OTSPoint3D pointB = new OTSPoint3D(0.0, -20.0);
298 OTSPoint3D pointC = new OTSPoint3D(1600.0, -20.0);
299 OTSPoint3D pointD = new OTSPoint3D(2000.0, 0.0);
300 OTSPoint3D pointE = new OTSPoint3D(2500.0, 0.0);
301 OTSPoint3D pointF = new OTSPoint3D(3500.0, 0.0);
302 OTSRoadNode nodeA = new OTSRoadNode(this.network, "A", pointA, Direction.ZERO);
303 OTSRoadNode nodeB = new OTSRoadNode(this.network, "B", pointB, Direction.ZERO);
304 OTSRoadNode nodeC = new OTSRoadNode(this.network, "C", pointC, Direction.ZERO);
305 OTSRoadNode nodeD = new OTSRoadNode(this.network, "D", pointD, Direction.ZERO);
306 OTSRoadNode nodeE = new OTSRoadNode(this.network, "E", pointE, Direction.ZERO);
307 OTSRoadNode nodeF = new OTSRoadNode(this.network, "F", pointF, Direction.ZERO);
308 LinkType type = this.network.getLinkType(LinkType.DEFAULTS.FREEWAY);
309 LaneKeepingPolicy policy = LaneKeepingPolicy.KEEPRIGHT;
310 Length laneWidth = Length.instantiateSI(3.5);
311 LaneType laneType = this.network.getLaneType(LaneType.DEFAULTS.FREEWAY);
312 Speed speedLimit = new Speed(120.0, SpeedUnit.KM_PER_HOUR);
313 List<Lane> allLanes = new ArrayList<>();
314 allLanes.addAll(new LaneFactory(this.network, nodeA, nodeD, type, sim, policy).leftToRight(2.0, laneWidth, laneType,
315 speedLimit).addLanes(Permeable.BOTH).getLanes());
316 allLanes.addAll(new LaneFactory(this.network, nodeB, nodeC, type, sim, policy).leftToRight(0.0, laneWidth, laneType,
317 speedLimit).addLanes(Permeable.BOTH).getLanes());
318 allLanes.addAll(new LaneFactory(this.network, nodeC, nodeD, type, sim, policy).leftToRight(0.0, laneWidth, laneType,
319 speedLimit).addLanes(Permeable.BOTH).getLanes());
320 allLanes.addAll(new LaneFactory(this.network, nodeD, nodeE, type, sim, policy).leftToRight(2.0, laneWidth, laneType,
321 speedLimit).addLanes(Permeable.BOTH, Permeable.BOTH, Permeable.BOTH).getLanes());
322 List<Lane> lanesEF = new LaneFactory(this.network, nodeE, nodeF, type, sim, policy).leftToRight(1.0, laneWidth,
323 laneType, speedLimit).addLanes(Permeable.BOTH, Permeable.BOTH).getLanes();
324 allLanes.addAll(lanesEF);
325 for (Lane lane : lanesEF)
326 {
327 new SinkSensor(lane, lane.getLength().minus(Length.instantiateSI(50)), Compatible.EVERYTHING, sim);
328 }
329
330
331 List<OTSNode> origins = new ArrayList<>();
332 origins.add(nodeA);
333 origins.add(nodeB);
334 List<OTSNode> destinations = new ArrayList<>();
335 destinations.add(nodeF);
336 double wut = sim.getReplication().getTreatment().getWarmupPeriod().si;
337 double rl = sim.getReplication().getTreatment().getRunLength().si;
338 TimeVector timeVector = DoubleVector.instantiate(new double[] {0.0, wut, wut + (rl - wut) * 0.5, rl}, TimeUnit.DEFAULT,
339 StorageType.DENSE);
340 Interpolation interpolation = Interpolation.LINEAR;
341 Categorization categorization = new Categorization("GTU categorization", GTUType.class);
342 ODMatrix odMatrix = new ODMatrix("OD", origins, destinations, categorization, timeVector, interpolation);
343 Category carCategory = new Category(categorization, this.network.getGtuType(GTUType.DEFAULTS.CAR));
344 Category truCategory = new Category(categorization, this.network.getGtuType(GTUType.DEFAULTS.TRUCK));
345 double f1 = this.truckFraction;
346 double f2 = 1.0 - f1;
347 double left2 = this.demandLeft.getInUnit(FrequencyUnit.PER_HOUR);
348 double right2 = this.demandRight.getInUnit(FrequencyUnit.PER_HOUR);
349 double startDemandFactor = this.startDemandFctor;
350 double left1 = left2 * startDemandFactor;
351 double right1 = right2 * startDemandFactor;
352 odMatrix.putDemandVector(nodeA, nodeF, carCategory, freq(new double[] {f2 * left1, f2 * left1, f2 * left2, 0.0}));
353 odMatrix.putDemandVector(nodeA, nodeF, truCategory, freq(new double[] {f1 * left1, f1 * left1, f1 * left2, 0.0}));
354 odMatrix.putDemandVector(nodeB, nodeF, carCategory, freq(new double[] {f2 * right1, f2 * right1, f2 * right2, 0.0}));
355 odMatrix.putDemandVector(nodeB, nodeF, truCategory, freq(new double[] {f1 * right1, f1 * right1, f1 * right2, 0.0}));
356 ODOptions odOptions = new ODOptions().set(ODOptions.NO_LC_DIST, Length.instantiateSI(200)).set(ODOptions.GTU_TYPE,
357 new DefaultGTUCharacteristicsGeneratorOD(new SdmStrategicalPlannerFactory(this.network, sim.getReplication()
358 .getStream("generation"), this)));
359 ODApplier.applyOD(this.network, odMatrix, odOptions);
360
361
362 DistractionFactory distFactory = new DistractionFactory(sim.getReplication().getStream("default"));
363 for (String distraction : this.distractions)
364 {
365 DefaultDistraction dist = DefaultDistraction.values()[Integer.parseInt(distraction) - 1];
366 distFactory.addDistraction(dist, getTaskSupplier(dist, sim.getReplication().getStream("default")));
367 }
368 new StochasticDistractionModel(this.multitasking, distFactory.build(), sim, this.network);
369
370
371 if (this.output)
372 {
373 this.sampler = RoadSampler.build(this.network).registerExtendedDataType(this.ttc).create();
374 Time start = new Time(0.05, TimeUnit.BASE_HOUR);
375 Time end = new Time(1.05, TimeUnit.BASE_HOUR);
376 for (Lane lane : allLanes)
377 {
378 KpiLaneDirection kpiLane = new KpiLaneDirection(new LaneData(lane), KpiGtuDirectionality.DIR_PLUS);
379 SpaceTimeRegion region = new SpaceTimeRegion(kpiLane, Length.ZERO, lane.getLength(), start, end);
380 this.regions.add(region);
381 this.sampler.registerSpaceTimeRegion(region);
382 }
383 }
384
385
386 return this.network;
387 }
388
389
390 @Override
391 protected void addTabs(final OTSSimulatorInterface sim, final OTSSimulationApplication<?> animation)
392 {
393 if (!this.output || !this.plots)
394 {
395 return;
396 }
397 try
398 {
399 TablePanel charts = new TablePanel(2, 2);
400 GraphPath<KpiLaneDirection> path1 = GraphLaneUtil.createPath("Left road, left lane", new LaneDirection(
401 (Lane) ((CrossSectionLink) this.network.getLink("AD")).getCrossSectionElement("Lane 1"),
402 GTUDirectionality.DIR_PLUS));
403 GraphPath<KpiLaneDirection> path2 = GraphLaneUtil.createPath("Left road, right lane", new LaneDirection(
404 (Lane) ((CrossSectionLink) this.network.getLink("AD")).getCrossSectionElement("Lane 2"),
405 GTUDirectionality.DIR_PLUS));
406 GraphPath<KpiLaneDirection> path3 = GraphLaneUtil.createPath("Right road, left lane", new LaneDirection(
407 (Lane) ((CrossSectionLink) this.network.getLink("BC")).getCrossSectionElement("Lane 1"),
408 GTUDirectionality.DIR_PLUS));
409 GraphPath<KpiLaneDirection> path4 = GraphLaneUtil.createPath("Right road, right lane", new LaneDirection(
410 (Lane) ((CrossSectionLink) this.network.getLink("BC")).getCrossSectionElement("Lane 2"),
411 GTUDirectionality.DIR_PLUS));
412 GraphPath.initRecording(this.sampler, path1);
413 GraphPath.initRecording(this.sampler, path2);
414 GraphPath.initRecording(this.sampler, path3);
415 GraphPath.initRecording(this.sampler, path4);
416 SwingPlot plot = null;
417 plot = new SwingContourPlot(new ContourPlotSpeed("Left road, left lane", sim, new ContourDataSource<>(this.sampler
418 .getSamplerData(), path1)));
419 charts.setCell(plot.getContentPane(), 0, 0);
420 plot = new SwingContourPlot(new ContourPlotSpeed("Left road, right lane", sim, new ContourDataSource<>(this.sampler
421 .getSamplerData(), path2)));
422 charts.setCell(plot.getContentPane(), 1, 0);
423 plot = new SwingContourPlot(new ContourPlotSpeed("Right road, left lane", sim, new ContourDataSource<>(this.sampler
424 .getSamplerData(), path3)));
425 charts.setCell(plot.getContentPane(), 0, 1);
426 plot = new SwingContourPlot(new ContourPlotSpeed("Right road, right lane", sim, new ContourDataSource<>(this.sampler
427 .getSamplerData(), path4)));
428 charts.setCell(plot.getContentPane(), 1, 1);
429 animation.getAnimationPanel().getTabbedPane().addTab(animation.getAnimationPanel().getTabbedPane().getTabCount(),
430 "statistics ", charts);
431 }
432 catch (NetworkException exception)
433 {
434 throw new RuntimeException(exception);
435 }
436 }
437
438
439
440
441
442
443
444 private FrequencyVector freq(final double[] array) throws ValueRuntimeException
445 {
446 return DoubleVector.instantiate(array, FrequencyUnit.PER_HOUR, StorageType.DENSE);
447 }
448
449
450
451
452
453
454
455 private TaskSupplier getTaskSupplier(final DefaultDistraction distraction, final StreamInterface stream)
456 {
457 switch (distraction)
458 {
459 case TALKING_CELL_PHONE:
460 {
461 return new TaskSupplier()
462 {
463
464 @SuppressWarnings("synthetic-access")
465 @Override
466 public Task getTask(final LaneBasedGTU gtu)
467 {
468 return new ExponentialTask(distraction.getId(), SdmSimulation.this.phoneInit,
469 SdmSimulation.this.phoneFinal, SdmSimulation.this.phoneTau, gtu.getSimulator());
470 }
471 };
472 }
473 case CONVERSING:
474 {
475 return new TaskSupplier.Constant(distraction.getId(), SdmSimulation.this.conversing);
476 }
477 case MANIPULATING_AUDIO_CONTROLS:
478 {
479 return new TaskSupplier.Constant(distraction.getId(), SdmSimulation.this.audio);
480 }
481 case EXTERNAL_DISTRACTION:
482 {
483 return new TaskSupplier.Constant(distraction.getId(), SdmSimulation.this.externalBase
484 + SdmSimulation.this.externalVar * stream.nextDouble());
485 }
486 default:
487 throw new IllegalArgumentException("Distraction " + distraction + " is not recognized.");
488 }
489 }
490
491
492 @Override
493 protected void onSimulationEnd()
494 {
495 if (this.output)
496 {
497 Length preDetectorPosition = Length.instantiateSI(400.0);
498 Length postDetectorPosition = Length.instantiateSI(100.0);
499 double tts = 0.0;
500 List<Float> ttcList = new ArrayList<>();
501 List<Float> decList = new ArrayList<>();
502 int[] counts = new int[60];
503 int[] speedCounts = new int[60];
504 double[] speedSum = new double[60];
505 for (SpaceTimeRegion region : this.regions)
506 {
507 TrajectoryGroup<?> trajectoryGroup = this.sampler.getSamplerData().getTrajectoryGroup(region.getLaneDirection())
508 .getTrajectoryGroup(region.getStartPosition(), region.getEndPosition(), region.getStartTime(), region
509 .getEndTime());
510 for (Trajectory<?> trajectory : trajectoryGroup)
511 {
512 try
513 {
514 tts += trajectory.getTotalDuration().si;
515 for (FloatDuration ttcVal : trajectory.getExtendedData(this.ttc))
516 {
517 if (!Float.isNaN(ttcVal.si) && ttcVal.si < 20)
518 {
519 ttcList.add(ttcVal.si);
520 }
521 }
522 for (float decVal : trajectory.getA())
523 {
524 if (decVal < -2.0)
525 {
526 decList.add(decVal);
527 }
528 }
529 if (region.getLaneDirection().getLaneData().getLinkData().getId().equals("DE") && trajectory.size() > 1
530 && trajectory.getX(0) < preDetectorPosition.si && trajectory.getX(trajectory.size()
531 - 1) > preDetectorPosition.si)
532 {
533 double t = trajectory.getTimeAtPosition(postDetectorPosition).si - region.getStartTime().si;
534 double v = trajectory.getSpeedAtPosition(postDetectorPosition).si;
535 speedCounts[(int) (t / 60.0)]++;
536 speedSum[(int) (t / 60.0)] += v;
537 }
538 if (region.getLaneDirection().getLaneData().getLinkData().getId().equals("EF") && trajectory.size() > 1
539 && trajectory.getX(0) < postDetectorPosition.si && trajectory.getX(trajectory.size()
540 - 1) > postDetectorPosition.si)
541 {
542 double t = trajectory.getTimeAtPosition(postDetectorPosition).si - region.getStartTime().si;
543 counts[(int) (t / 60.0)]++;
544 }
545 }
546 catch (SamplingException exception)
547 {
548 throw new RuntimeException(
549 "Unexpected exception: TimeToCollission not available or index out of bounds.", exception);
550 }
551 }
552 }
553 double qMax = 0;
554 for (int i = 0; i < counts.length - 4; i++)
555 {
556 int q = 0;
557 for (int j = i; j < i + 5; j++)
558 {
559 q += counts[j];
560 }
561 qMax = qMax > q ? qMax : q;
562 }
563 qMax *= 12;
564 int n = 0;
565 int countSum = 0;
566 for (int i = 0; i < counts.length; i++)
567 {
568 double v = speedSum[i] / speedCounts[i];
569 if (v < 80 / 3.6)
570 {
571 countSum += counts[i];
572 n++;
573 }
574 }
575 double qSat = n == 0 ? Double.NaN : 60.0 * countSum / n;
576 BufferedWriter bw;
577 try
578 {
579 bw = new BufferedWriter(new OutputStreamWriter(Writer.createOutputStream(this.outputFile,
580 CompressionType.ZIP)));
581 bw.write(String.format("total time spent [s]: %.0f", tts));
582 bw.newLine();
583 bw.write(String.format("maximum flow [veh/h]: %.3f", qMax));
584 bw.newLine();
585 bw.write(String.format("saturation flow [veh/h]: %.3f", qSat));
586 bw.newLine();
587 bw.write(String.format("time to collision [s]: %s", ttcList));
588 bw.newLine();
589 bw.write(String.format("strong decelerations [m/s^2]: %s", decList));
590 bw.close();
591 }
592 catch (IOException exception)
593 {
594 throw new RuntimeException(exception);
595 }
596 }
597 }
598
599
600
601
602 public IdmOptions getIdmOptions()
603 {
604 return this.idmOptions;
605 }
606
607
608
609
610 public Duration getDt()
611 {
612 return this.dt;
613 }
614
615
616
617
618 public double getSaMin()
619 {
620 return this.saMin;
621 }
622
623
624
625
626 public double getSaMax()
627 {
628 return this.saMax;
629 }
630
631
632
633
634 public double getTc()
635 {
636 return this.tc;
637 }
638
639
640
641
642 public double getTsCrit()
643 {
644 return this.tsCrit;
645 }
646
647
648
649
650 public double getTsMax()
651 {
652 return this.tsMax;
653 }
654
655
656
657
658 public Duration getTrMax()
659 {
660 return this.trMax;
661 }
662
663
664
665
666 public double getBetaT()
667 {
668 return this.betaT;
669 }
670
671 }