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