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