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