1 package org.opentrafficsim.road.gtu.generator.od;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Comparator;
6 import java.util.LinkedHashMap;
7 import java.util.LinkedHashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Map.Entry;
11 import java.util.Set;
12 import java.util.stream.Collectors;
13
14 import org.djunits.unit.FrequencyUnit;
15 import org.djunits.value.vdouble.scalar.Duration;
16 import org.djunits.value.vdouble.scalar.Frequency;
17 import org.djunits.value.vdouble.scalar.Length;
18 import org.djunits.value.vdouble.scalar.Time;
19 import org.djutils.exceptions.Throw;
20 import org.opentrafficsim.base.parameters.ParameterException;
21 import org.opentrafficsim.core.distributions.Generator;
22 import org.opentrafficsim.core.distributions.ProbabilityException;
23 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
24 import org.opentrafficsim.core.gtu.GTUDirectionality;
25 import org.opentrafficsim.core.gtu.GTUException;
26 import org.opentrafficsim.core.gtu.GTUType;
27 import org.opentrafficsim.core.idgenerator.IdGenerator;
28 import org.opentrafficsim.core.math.Draw;
29 import org.opentrafficsim.core.network.Link;
30 import org.opentrafficsim.core.network.LinkType;
31 import org.opentrafficsim.core.network.NetworkException;
32 import org.opentrafficsim.core.network.Node;
33 import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
34 import org.opentrafficsim.road.gtu.generator.GeneratorPositions.LaneBiases;
35 import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator;
36 import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator.RoomChecker;
37 import org.opentrafficsim.road.gtu.generator.MarkovCorrelation;
38 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristics;
39 import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGTUCharacteristicsGenerator;
40 import org.opentrafficsim.road.gtu.generator.headway.Arrivals;
41 import org.opentrafficsim.road.gtu.generator.headway.ArrivalsHeadwayGenerator;
42 import org.opentrafficsim.road.gtu.generator.headway.ArrivalsHeadwayGenerator.HeadwayDistribution;
43 import org.opentrafficsim.road.gtu.generator.headway.DemandPattern;
44 import org.opentrafficsim.road.gtu.strategical.od.Categorization;
45 import org.opentrafficsim.road.gtu.strategical.od.Category;
46 import org.opentrafficsim.road.gtu.strategical.od.ODMatrix;
47 import org.opentrafficsim.road.network.OTSRoadNetwork;
48 import org.opentrafficsim.road.network.lane.CrossSectionLink;
49 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
50 import org.opentrafficsim.road.network.lane.Lane;
51 import org.opentrafficsim.road.network.lane.object.sensor.DestinationSensor;
52 import org.opentrafficsim.road.network.lane.object.sensor.Sensor;
53
54 import nl.tudelft.simulation.dsol.SimRuntimeException;
55 import nl.tudelft.simulation.dsol.logger.SimLogger;
56 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
57 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
58 import nl.tudelft.simulation.jstats.streams.StreamInterface;
59
60
61
62
63
64
65
66
67
68
69
70
71 public final class ODApplier
72 {
73
74
75
76
77 private ODApplier()
78 {
79
80 }
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 @SuppressWarnings("checkstyle:methodlength")
125 public static Map<String, GeneratorObjects> applyOD(final OTSRoadNetwork network, final ODMatrix od,
126 final OTSSimulatorInterface simulator, final ODOptions odOptions) throws ParameterException, SimRuntimeException
127 {
128 Throw.whenNull(network, "Network may not be null.");
129 Throw.whenNull(od, "OD matrix may not be null.");
130 Throw.whenNull(simulator, "Simulator may not be null.");
131 Throw.whenNull(odOptions, "OD options may not be null.");
132 Throw.when(!simulator.getSimulatorTime().eq0(), SimRuntimeException.class,
133 "Method ODApplier.applyOD() should be invoked at simulation time 0.");
134
135
136 for (Node destination : od.getDestinations())
137 {
138 createSensorsAtDestination(destination, simulator);
139 }
140
141 final Categorization categorization = od.getCategorization();
142 final boolean laneBased = categorization.entails(Lane.class);
143 boolean markovian = od.getCategorization().entails(GTUType.class);
144
145
146 StreamInterface stream = simulator.getReplication().getStream("generation");
147 if (stream == null)
148 {
149 stream = simulator.getReplication().getStream("default");
150 if (stream == null)
151 {
152 System.out.println(
153 "Using locally created stream (not from the simulator) for vehicle generation, with seed 1.");
154 stream = new MersenneTwister(1L);
155 }
156 else
157 {
158 System.out.println("Using stream 'default' for vehicle generation.");
159 }
160 }
161
162 Map<String, GeneratorObjects> output = new LinkedHashMap<>();
163 for (Node origin : od.getOrigins())
164 {
165
166 DemandNode<Node, DemandNode<Node, DemandNode<Category, ?>>> rootNode = null;
167
168
169
170
171
172
173
174
175 Map<Lane, DemandNode<Node, DemandNode<Node, DemandNode<Category, ?>>>> originNodePerLane = new LinkedHashMap<>();
176 MarkovChain markovChain = null;
177 if (!laneBased)
178 {
179 rootNode = new DemandNode<>(origin, stream, null);
180 LinkType linkType = getLinkTypeFromNode(origin);
181 if (markovian)
182 {
183 MarkovCorrelation<GTUType, Frequency> correlation = odOptions.get(ODOptions.MARKOV, null, origin,
184 linkType);
185 if (correlation != null)
186 {
187 Throw.when(!od.getCategorization().entails(GTUType.class), IllegalArgumentException.class,
188 "Markov correlation can only be used on OD categorization entailing GTU type.");
189 markovChain = new MarkovChain(correlation);
190 }
191 }
192 }
193 for (Node destination : od.getDestinations())
194 {
195 Set<Category> categories = od.getCategories(origin, destination);
196 if (!categories.isEmpty())
197 {
198 DemandNode<Node, DemandNode<Category, ?>> destinationNode = null;
199 if (!laneBased)
200 {
201 destinationNode = new DemandNode<>(destination, stream, markovChain);
202 rootNode.addChild(destinationNode);
203 }
204 for (Category category : categories)
205 {
206 if (laneBased)
207 {
208
209 Lane lane = category.get(Lane.class);
210 rootNode = originNodePerLane.get(lane);
211 if (rootNode == null)
212 {
213 rootNode = new DemandNode<>(origin, stream, null);
214 originNodePerLane.put(lane, rootNode);
215 }
216 destinationNode = rootNode.getChild(destination);
217 if (destinationNode == null)
218 {
219 markovChain = null;
220 if (markovian)
221 {
222 MarkovCorrelation<GTUType, Frequency> correlation = odOptions.get(ODOptions.MARKOV, lane,
223 origin, lane.getParentLink().getLinkType());
224 if (correlation != null)
225 {
226 Throw.when(!od.getCategorization().entails(GTUType.class),
227 IllegalArgumentException.class,
228 "Markov correlation can only be used on OD categorization entailing GTU type.");
229 markovChain = new MarkovChain(correlation);
230 }
231 }
232 destinationNode = new DemandNode<>(destination, stream, markovChain);
233 rootNode.addChild(destinationNode);
234 }
235 }
236 DemandNode<Category, ?> categoryNode = new DemandNode<>(category, od.getDemandPattern(origin,
237 destination, category));
238 if (markovian)
239 {
240 destinationNode.addLeaf(categoryNode, category.get(GTUType.class));
241 }
242 else
243 {
244 destinationNode.addChild(categoryNode);
245 }
246 }
247 }
248 }
249
250
251 Map<DemandNode<Node, DemandNode<Node, DemandNode<Category, ?>>>, Set<DirectedLanePosition>> initialPositions =
252 new LinkedHashMap<>();
253 Map<CrossSectionLink, Double> linkWeights = null;
254 Map<CrossSectionLink, Node> viaNodes = null;
255 if (laneBased)
256 {
257 for (Lane lane : originNodePerLane.keySet())
258 {
259 DemandNode<Node, DemandNode<Node, DemandNode<Category, ?>>> demandNode = originNodePerLane.get(lane);
260 Set<DirectedLanePosition> initialPosition = new LinkedHashSet<>();
261 try
262 {
263 initialPosition.add(lane.getParentLink().getStartNode().equals(demandNode.getObject())
264 ? new DirectedLanePosition(lane, Length.ZERO, GTUDirectionality.DIR_PLUS)
265 : new DirectedLanePosition(lane, lane.getLength(), GTUDirectionality.DIR_MINUS));
266 }
267 catch (GTUException ge)
268 {
269 throw new RuntimeException(ge);
270 }
271 initialPositions.put(demandNode, initialPosition);
272 }
273 }
274 else
275 {
276 Set<DirectedLanePosition> positionSet = new LinkedHashSet<>();
277 for (Link link : origin.getLinks())
278 {
279 if (link.getLinkType().isConnector())
280 {
281 if (link.getStartNode().equals(origin))
282 {
283 Node connectedNode = link.getEndNode();
284
285 int served = 0;
286 for (Link connectedLink : connectedNode.getLinks())
287 {
288 if (connectedLink instanceof CrossSectionLink && !connectedLink.getLinkType().isConnector())
289 {
290 served++;
291 }
292 }
293 for (Link connectedLink : connectedNode.getLinks())
294 {
295 if (connectedLink instanceof CrossSectionLink)
296 {
297 if (link instanceof CrossSectionLink./../org/opentrafficsim/road/network/lane/CrossSectionLink.html#CrossSectionLink">CrossSectionLink && ((CrossSectionLink) link)
298 .getDemandWeight() != null)
299 {
300 if (linkWeights == null)
301 {
302 linkWeights = new LinkedHashMap<>();
303 viaNodes = new LinkedHashMap<>();
304 }
305
306 linkWeights.put(((CrossSectionLinkrg/opentrafficsim/road/network/lane/CrossSectionLink.html#CrossSectionLink">CrossSectionLink) connectedLink), ((CrossSectionLink) link)
307 .getDemandWeight() / served);
308 viaNodes.put((CrossSectionLink) connectedLink, connectedNode);
309 }
310 setDirectedLanePosition((CrossSectionLink) connectedLink, connectedNode, positionSet);
311 }
312 }
313 }
314 }
315 else if (link instanceof CrossSectionLink)
316 {
317 setDirectedLanePosition((CrossSectionLink) link, origin, positionSet);
318 }
319 }
320 initialPositions.put(rootNode, positionSet);
321 }
322
323
324 initialPositions = sortByValue(initialPositions);
325 Map<Node, Integer> originGeneratorCounts = new LinkedHashMap<>();
326 for (DemandNode<Node, DemandNode<Node, DemandNode<Category, ?>>> root : initialPositions.keySet())
327 {
328 Set<DirectedLanePosition> initialPosition = initialPositions.get(root);
329
330 Node o = root.getObject();
331 String id = o.getId();
332 if (laneBased)
333 {
334 Integer count = originGeneratorCounts.get(o);
335 if (count == null)
336 {
337 count = 0;
338 }
339 count++;
340 id += count;
341 originGeneratorCounts.put(o, count);
342 }
343
344 Lane lane;
345 LinkType linkType;
346 if (laneBased)
347 {
348 lane = initialPosition.iterator().next().getLane();
349 linkType = lane.getParentLink().getLinkType();
350 }
351 else
352 {
353 lane = null;
354 linkType = getLinkTypeFromNode(o);
355 }
356 HeadwayDistribution randomization = odOptions.get(ODOptions.HEADWAY_DIST, lane, o, linkType);
357 ArrivalsHeadwayGeneratorvalsHeadwayGenerator.html#ArrivalsHeadwayGenerator">ArrivalsHeadwayGenerator headwayGenerator = new ArrivalsHeadwayGenerator(root, simulator, stream,
358 randomization);
359 GTUCharacteristicsGeneratorODWrapper characteristicsGenerator = new GTUCharacteristicsGeneratorODWrapper(
360 root, simulator, odOptions.get(ODOptions.GTU_TYPE, lane, o, linkType), stream);
361 RoomChecker roomChecker = odOptions.get(ODOptions.ROOM_CHECKER, lane, o, linkType);
362 IdGenerator idGenerator = odOptions.get(ODOptions.GTU_ID, lane, o, linkType);
363 LaneBiases biases = odOptions.get(ODOptions.getLaneBiasOption(network), lane, o, linkType);
364
365 try
366 {
367 LaneBasedGTUGeneratorneBasedGTUGenerator.html#LaneBasedGTUGenerator">LaneBasedGTUGenerator generator = new LaneBasedGTUGenerator(id, headwayGenerator,
368 characteristicsGenerator, GeneratorPositions.create(initialPosition, stream, biases, linkWeights,
369 viaNodes), network, simulator, roomChecker, idGenerator);
370 generator.setNoLaneChangeDistance(odOptions.get(ODOptions.NO_LC_DIST, lane, o, linkType));
371 generator.setInstantaneousLaneChange(odOptions.get(ODOptions.INSTANT_LC, lane, o, linkType));
372 generator.setErrorHandler(odOptions.get(ODOptions.ERROR_HANDLER, lane, o, linkType));
373 output.put(id, new GeneratorObjects(generator, headwayGenerator, characteristicsGenerator));
374 }
375 catch (SimRuntimeException exception)
376 {
377
378 simulator.getLogger().always().error(exception);
379 throw new RuntimeException(exception);
380 }
381 catch (ProbabilityException exception)
382 {
383
384 simulator.getLogger().always().error(exception);
385 throw new RuntimeException(exception);
386 }
387 }
388 }
389 return output;
390 }
391
392
393
394
395
396
397 private static void createSensorsAtDestination(final Node destination, final OTSSimulatorInterface simulator)
398 {
399 for (Link link : destination.getLinks())
400 {
401 if (link.getLinkType().isConnector() && !link.getStartNode().equals(destination))
402 {
403 createSensorsAtDestinationNode(link.getStartNode(), simulator);
404 }
405 else
406 {
407 createSensorsAtDestinationNode(destination, simulator);
408 }
409 }
410 }
411
412
413
414
415
416
417 private static void createSensorsAtDestinationNode(final Node destination, final OTSSimulatorInterface simulator)
418 {
419 for (Link link : destination.getLinks())
420 {
421 if (link instanceof CrossSectionLink)
422 {
423 for (Lane lane : ((CrossSectionLink) link).getLanes())
424 {
425 try
426 {
427
428 boolean destinationSensorExists = false;
429 for (Sensor sensor : lane.getSensors())
430 {
431 if (sensor instanceof DestinationSensor)
432 {
433 destinationSensorExists = true;
434 }
435 }
436 if (!destinationSensorExists)
437 {
438 if (link.getEndNode().equals(destination))
439 {
440 new DestinationSensor(lane, lane.getLength(), GTUDirectionality.DIR_PLUS, simulator);
441 }
442 else if (link.getStartNode().equals(destination))
443 {
444 new DestinationSensor(lane, Length.ZERO, GTUDirectionality.DIR_MINUS, simulator);
445 }
446 }
447 }
448 catch (NetworkException exception)
449 {
450
451 simulator.getLogger().always().error(exception);
452 throw new RuntimeException(exception);
453 }
454 }
455 }
456 }
457 }
458
459
460
461
462
463
464 private static LinkType getLinkTypeFromNode(final Node node)
465 {
466 return getLinkTypeFromNode0(node, false);
467 }
468
469
470
471
472
473
474
475 private static LinkType getLinkTypeFromNode0(final Node node, final boolean ignoreConnectors)
476 {
477 LinkType linkType = null;
478 for (Link link : node.getLinks())
479 {
480 LinkType next = link.getLinkType();
481 if (!ignoreConnectors && next.isConnector())
482 {
483 Node otherNode = link.getStartNode().equals(node) ? link.getEndNode() : link.getStartNode();
484 next = getLinkTypeFromNode0(otherNode, true);
485 }
486 if (next != null && !next.isConnector())
487 {
488 if (linkType == null)
489 {
490 linkType = next;
491 }
492 else
493 {
494 linkType = linkType.commonAncestor(next);
495 if (linkType == null)
496 {
497
498 return null;
499 }
500 }
501 }
502 }
503 return linkType;
504 }
505
506
507
508
509
510
511
512
513 private static <K, V extends Set<DirectedLanePosition>> Map<K, V> sortByValue(final Map<K, V> map)
514 {
515 return map.entrySet().stream().sorted(new Comparator<Map.Entry<K, V>>()
516 {
517 @Override
518 public int compare(final Entry<K, V> o1, final Entry<K, V> o2)
519 {
520 DirectedLanePosition lanePos1 = o1.getValue().iterator().next();
521 String linkId1 = lanePos1.getLane().getParentLink().getId();
522 DirectedLanePosition lanePos2 = o2.getValue().iterator().next();
523 String linkId2 = lanePos2.getLane().getParentLink().getId();
524 int c = linkId1.compareToIgnoreCase(linkId2);
525 if (c == 0)
526 {
527 Length pos1 = lanePos1.getGtuDirection().isPlus() ? Length.ZERO : lanePos1.getLane().getLength();
528 Length lat1 = lanePos1.getLane().getLateralCenterPosition(pos1);
529 Length pos2 = lanePos2.getGtuDirection().isPlus() ? Length.ZERO : lanePos2.getLane().getLength();
530 Length lat2 = lanePos2.getLane().getLateralCenterPosition(pos2);
531 return lat1.compareTo(lat2);
532 }
533 return c;
534 }
535 }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
536 }
537
538
539
540
541
542
543
544
545 private static void setDirectedLanePosition(final CrossSectionLink link, final Node node,
546 final Set<DirectedLanePosition> positionSet)
547 {
548 for (Lane lane : link.getLanes())
549 {
550
551 if (!lane.getParentLink().getStartNode().equals(node))
552 {
553 return;
554
555 }
556 try
557 {
558 positionSet.add(lane.getParentLink().getStartNode().equals(node) ? new DirectedLanePosition(lane,
559 Length.ZERO, GTUDirectionality.DIR_PLUS) : new DirectedLanePosition(lane, lane.getLength(),
560 GTUDirectionality.DIR_MINUS));
561 }
562 catch (GTUException ge)
563 {
564 link.getSimulator().getLogger().always().error(ge);
565 throw new RuntimeException(ge);
566 }
567 }
568 }
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592 private static class DemandNode<T, K extends DemandNode<?, ?>> implements Arrivals
593 {
594
595
596 private final T object;
597
598
599 private final StreamInterface stream;
600
601
602 private final List<K> children = new ArrayList<>();
603
604
605 private final DemandPattern demandPattern;
606
607
608 private final List<GTUType> gtuTypes = new ArrayList<>();
609
610
611 private final List<Integer> gtuTypeCounts = new ArrayList<>();
612
613
614 private final Map<K, GTUType> gtuTypesPerChild = new LinkedHashMap<>();
615
616
617 private final MarkovChain markov;
618
619
620
621
622
623
624
625 DemandNode(final T object, final StreamInterface stream, final MarkovChain markov)
626 {
627 this.object = object;
628 this.stream = stream;
629 this.demandPattern = null;
630 this.markov = markov;
631 }
632
633
634
635
636
637
638 DemandNode(final T object, final DemandPattern demandPattern)
639 {
640 this.object = object;
641 this.stream = null;
642 this.demandPattern = demandPattern;
643 this.markov = null;
644 }
645
646
647
648
649
650 public void addChild(final K child)
651 {
652 this.children.add(child);
653 }
654
655
656
657
658
659
660 public void addLeaf(final K child, final GTUType gtuType)
661 {
662 Throw.when(this.gtuTypes == null, IllegalStateException.class,
663 "Adding leaf with GTUType in not possible on a non-Markov node.");
664 addChild(child);
665 this.gtuTypesPerChild.put(child, gtuType);
666 if (!this.gtuTypes.contains(gtuType))
667 {
668 this.gtuTypes.add(gtuType);
669 this.gtuTypeCounts.add(1);
670 }
671 else
672 {
673 int index = this.gtuTypes.indexOf(gtuType);
674 this.gtuTypeCounts.set(index, this.gtuTypeCounts.get(index) + 1);
675 }
676 }
677
678
679
680
681
682
683 public K draw(final Time time)
684 {
685 Throw.when(this.children.isEmpty(), RuntimeException.class, "Calling draw on a leaf node in the demand tree.");
686 Map<K, Double> weightMap = new LinkedHashMap<>();
687 if (this.markov == null)
688 {
689
690 for (K child : this.children)
691 {
692 double f = child.getFrequency(time, true).si;
693 weightMap.put(child, f);
694 }
695 }
696 else
697 {
698
699 GTUType[] gtuTypeArray = new GTUType[this.gtuTypes.size()];
700 gtuTypeArray = this.gtuTypes.toArray(gtuTypeArray);
701 Frequency[] steadyState = new Frequency[this.gtuTypes.size()];
702 Arrays.fill(steadyState, Frequency.ZERO);
703 Map<K, Frequency> frequencies = new LinkedHashMap<>();
704 for (K child : this.children)
705 {
706 GTUType gtuType = this.gtuTypesPerChild.get(child);
707 int index = this.gtuTypes.indexOf(gtuType);
708 Frequency f = child.getFrequency(time, true);
709 frequencies.put(child, f);
710 steadyState[index] = steadyState[index].plus(f);
711 }
712 GTUType nextGtuType = this.markov.draw(gtuTypeArray, steadyState, this.stream);
713
714 for (K child : this.children)
715 {
716 if (this.gtuTypesPerChild.get(child).equals(nextGtuType))
717 {
718 double f = frequencies.get(child).si;
719 weightMap.put(child, f);
720 }
721 }
722 }
723 return Draw.drawWeighted(weightMap, this.stream);
724 }
725
726
727
728
729
730 public T getObject()
731 {
732 return this.object;
733 }
734
735
736
737
738
739
740 public K getChild(final Object obj)
741 {
742 for (K child : this.children)
743 {
744 if (child.getObject().equals(obj))
745 {
746 return child;
747 }
748 }
749 return null;
750 }
751
752
753 @Override
754 public Frequency getFrequency(final Time time, final boolean sliceStart)
755 {
756 if (this.demandPattern != null)
757 {
758 return this.demandPattern.getFrequency(time, sliceStart);
759 }
760 Frequency f = new Frequency(0.0, FrequencyUnit.PER_HOUR);
761 for (K child : this.children)
762 {
763 f = f.plus(child.getFrequency(time, sliceStart));
764 }
765 return f;
766 }
767
768
769 @Override
770 public Time nextTimeSlice(final Time time)
771 {
772 if (this.demandPattern != null)
773 {
774 return this.demandPattern.nextTimeSlice(time);
775 }
776 Time out = null;
777 for (K child : this.children)
778 {
779 Time childSlice = child.nextTimeSlice(time);
780 out = out == null || (childSlice != null && childSlice.lt(out)) ? childSlice : out;
781 }
782 return out;
783 }
784
785
786 @Override
787 public String toString()
788 {
789 return "DemandNode [object=" + this.object + ", stream=" + this.stream + ", children=" + this.children
790 + ", demandPattern=" + this.demandPattern + ", gtuTypes=" + this.gtuTypes + ", gtuTypeCounts="
791 + this.gtuTypeCounts + ", gtuTypesPerChild=" + this.gtuTypesPerChild + ", markov=" + this.markov + "]";
792 }
793
794 }
795
796
797
798
799
800 private static class MarkovChain
801 {
802
803 private final MarkovCorrelation<GTUType, Frequency> markov;
804
805
806 private GTUType previousGtuType = null;
807
808
809
810
811
812 MarkovChain(final MarkovCorrelation<GTUType, Frequency> markov)
813 {
814 this.markov = markov;
815 }
816
817
818
819
820
821
822
823
824 public GTUType draw(final GTUType[] gtuTypes, final Frequency[] intensities, final StreamInterface stream)
825 {
826 this.previousGtuType = this.markov.drawState(this.previousGtuType, gtuTypes, intensities, stream);
827 return this.previousGtuType;
828 }
829 }
830
831
832
833
834
835
836
837
838
839
840
841
842
843 private static class GTUCharacteristicsGeneratorODWrapper implements LaneBasedGTUCharacteristicsGenerator
844 {
845
846
847 private final DemandNode<Node, DemandNode<Node, DemandNode<Category, ?>>> root;
848
849
850 private final DEVSSimulatorInterface.TimeDoubleUnit simulator;
851
852
853 private final GTUCharacteristicsGeneratorOD characteristicsGenerator;
854
855
856 private final StreamInterface randomStream;
857
858
859
860
861
862
863
864 GTUCharacteristicsGeneratorODWrapper(final DemandNode<Node, DemandNode<Node, DemandNode<Category, ?>>> root,
865 final DEVSSimulatorInterface.TimeDoubleUnit simulator,
866 final GTUCharacteristicsGeneratorOD characteristicsGenerator, final StreamInterface randomStream)
867 {
868 this.root = root;
869 this.simulator = simulator;
870 this.characteristicsGenerator = characteristicsGenerator;
871 this.randomStream = randomStream;
872 }
873
874
875 @Override
876 public LaneBasedGTUCharacteristics draw() throws ProbabilityException, ParameterException, GTUException
877 {
878
879 Time time = this.simulator.getSimulatorTime();
880 Node origin = this.root.getObject();
881 DemandNode<Node, DemandNode<Category, ?>> destinationNode = this.root.draw(time);
882 Node destination = destinationNode.getObject();
883 Category category = destinationNode.draw(time).getObject();
884
885
886 return this.characteristicsGenerator.draw(origin, destination, category, this.randomStream);
887 }
888
889
890 @Override
891 public String toString()
892 {
893 return "GTUCharacteristicsGeneratorODWrapper [root=" + this.root + ", simulator=" + this.simulator
894 + ", characteristicsGenerator=" + this.characteristicsGenerator + ", randomStream=" + this.randomStream
895 + "]";
896 }
897
898 }
899
900
901
902
903
904
905
906
907
908
909
910
911
912 public static class GeneratorObjects
913 {
914
915
916 private final LaneBasedGTUGenerator generator;
917
918
919 private final Generator<Duration> headwayGenerator;
920
921
922 private final LaneBasedGTUCharacteristicsGenerator characteristicsGenerator;
923
924
925
926
927
928
929 public GeneratorObjects(final LaneBasedGTUGenerator generator, final Generator<Duration> headwayGenerator,
930 final LaneBasedGTUCharacteristicsGenerator characteristicsGenerator)
931 {
932 this.generator = generator;
933 this.headwayGenerator = headwayGenerator;
934 this.characteristicsGenerator = characteristicsGenerator;
935 }
936
937
938
939
940
941 public LaneBasedGTUGenerator getGenerator()
942 {
943 return this.generator;
944 }
945
946
947
948
949
950 public Generator<Duration> getHeadwayGenerator()
951 {
952 return this.headwayGenerator;
953 }
954
955
956
957
958
959 public LaneBasedGTUCharacteristicsGenerator getCharachteristicsGenerator()
960 {
961 return this.characteristicsGenerator;
962 }
963
964 }
965
966 }