21 package org.matsim.core.mobsim.qsim.qnetsimengine;
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
41 import java.util.Arrays;
42 import java.util.Comparator;
43 import java.util.Random;
48 final class QNodeImpl
extends AbstractQNode {
49 private static final Logger log = LogManager.getLogger(QNodeImpl.class);
55 this.netsimEngine = netsimEngine2;
64 return new QNodeImpl( n, context, netsimEngine, turnAcceptanceLogic, qsimConfig ) ;
68 private final QLinkI[] inLinksArrayCache;
69 private final QLinkI[] tempLinks;
70 private Double[] inLinkPriorities;
72 private final Random random;
78 private boolean stopMoveNodeWhenSingleOutlinkFull;
79 private boolean atLeastOneOutgoingLaneIsJammed;
86 private static boolean capacityLeft(
double x) {
93 this.netsimEngine = netsimEngine2 ;
98 switch (nodeTransitionLogic) {
99 case emptyBufferAfterBufferRandomDistribution_nodeBlockedWhenSingleOutlinkFull:
100 case moveVehByVehRandomDistribution_nodeBlockedWhenSingleOutlinkFull:
101 case moveVehByVehDeterministicPriorities_nodeBlockedWhenSingleOutlinkFull:
102 this.stopMoveNodeWhenSingleOutlinkFull =
true;
104 case emptyBufferAfterBufferRandomDistribution_dontBlockNode:
105 case moveVehByVehRandomDistribution_dontBlockNode:
106 this.stopMoveNodeWhenSingleOutlinkFull =
false;
109 throw new UnsupportedOperationException(
"Node transition logic " + nodeTransitionLogic +
" is not implemented.");
113 this.inLinksArrayCache =
new QLinkI[nofInLinks];
114 this.tempLinks =
new QLinkI[nofInLinks];
134 for (
Link l : this.node.getInLinks().values()) {
136 this.inLinksArrayCache[i] = network.
getNetsimLinks().get(l.getId());
142 Arrays.sort(this.inLinksArrayCache,
new Comparator<NetsimLink>() {
168 public boolean doSimStep(
final double now) {
170 if (inLinkPriorities == null) {
174 inLinkPriorities =
new Double[inLinksArrayCache.length];
175 for (
int inLinkCounter=0; inLinkCounter<this.inLinksArrayCache.length; inLinkCounter++) {
177 inLinkPriorities[inLinkCounter] = 1. / linkCap;
182 this.atLeastOneOutgoingLaneIsJammed =
false;
184 double inLinksCapSum = 0.0;
186 for (
int inLinkIndex = 0; inLinkIndex < this.inLinksArrayCache.length; inLinkIndex++) {
187 QLinkI link = this.inLinksArrayCache[inLinkIndex];
189 this.tempLinks[inLinkIndex] = link;
194 if (!capacityLeft(inLinksCapSum)) {
195 this.setActive(
false);
200 switch (nodeTransitionLogic) {
201 case emptyBufferAfterBufferRandomDistribution_dontBlockNode:
202 case emptyBufferAfterBufferRandomDistribution_nodeBlockedWhenSingleOutlinkFull:
204 while (capacityLeft(inLinksCapSum)) {
205 double rndNum = random.nextDouble() * inLinksCapSum;
207 for (
int i = 0; i < this.inLinksArrayCache.length; i++) {
208 QLinkI link = this.tempLinks[i];
212 if (selCap >= rndNum) {
215 this.tempLinks[i] = null;
216 this.moveLink(link, now);
217 if (this.stopMoveNodeWhenSingleOutlinkFull && this.atLeastOneOutgoingLaneIsJammed) {
227 case moveVehByVehRandomDistribution_dontBlockNode:
228 case moveVehByVehRandomDistribution_nodeBlockedWhenSingleOutlinkFull:
230 while (capacityLeft(inLinksCapSum)) {
231 double rndNum = random.nextDouble() * inLinksCapSum;
233 for (
int i = 0; i < this.inLinksArrayCache.length; i++) {
234 QLinkI link = this.tempLinks[i];
238 if (selCap >= rndNum) {
240 if ( ! moveFirstVehicleOnLink(now, link)) {
243 this.tempLinks[i] = null;
247 if (this.stopMoveNodeWhenSingleOutlinkFull && this.atLeastOneOutgoingLaneIsJammed) {
258 case moveVehByVehDeterministicPriorities_nodeBlockedWhenSingleOutlinkFull:
260 double prioWithWhichTheLastVehWasSent = 0.;
261 while (capacityLeft(inLinksCapSum)) {
263 double minPrio = Float.MAX_VALUE;
264 int prioInLinkIndex = -1;
265 for (
int i = 0; i < this.inLinksArrayCache.length; i++) {
266 if (tempLinks[i] != null &&
272 (
float) this.inLinkPriorities[i].doubleValue() < (
float) minPrio) {
274 minPrio = this.inLinkPriorities[i];
278 QLinkI selectedLink = this.inLinksArrayCache[prioInLinkIndex];
281 if ( ! moveFirstVehicleOnLink(now, selectedLink)) {
284 this.tempLinks[prioInLinkIndex] = null;
287 prioWithWhichTheLastVehWasSent = minPrio;
288 this.inLinkPriorities[prioInLinkIndex] += 1. / selectedLink.
getLink().
getCapacity(now);
290 if (this.atLeastOneOutgoingLaneIsJammed) {
293 updatePriorities(now, prioWithWhichTheLastVehWasSent, prioInLinkIndex);
300 updatePriorities(now, prioWithWhichTheLastVehWasSent, -1);
303 throw new UnsupportedOperationException(
"Node transition logic " + nodeTransitionLogic +
" is not implemented.");
309 private void updatePriorities(
final double now,
double prioWithWhichTheLastVehWasSent,
int linkIndexToBeExcluded) {
311 for (
int linkIndex=0; linkIndex < this.inLinkPriorities.length; linkIndex++) {
313 if (linkIndex != linkIndexToBeExcluded && tempLinks[linkIndex] == null) {
316 inLinkPriorities[linkIndex] = prioWithWhichTheLastVehWasSent
320 inLinkPriorities[linkIndex] -= prioWithWhichTheLastVehWasSent;
330 private boolean moveFirstVehicleOnLink(
final double now,
QLinkI link) {
335 +
" are only implemented for the case without lanes. But link " + link.
getLink().
getId()
336 +
" in your scenario has more than one lane. " 339 +
" or adapt the implementation such that it also works for lanes.");
342 if (! lane.isNotOfferingVehicle()) {
343 QVehicle veh = lane.getFirstVehicle();
344 if (moveVehicleOverNode(veh, link, lane, now)) {
349 if (this.stopMoveNodeWhenSingleOutlinkFull && this.atLeastOneOutgoingLaneIsJammed) {
362 private void moveLink(
final QLinkI link,
final double now){
364 while (! lane.isNotOfferingVehicle()) {
365 QVehicle veh = lane.getFirstVehicle();
366 if (! moveVehicleOverNode(veh, link, lane, now )) {
368 if (this.stopMoveNodeWhenSingleOutlinkFull && this.atLeastOneOutgoingLaneIsJammed) {
389 private boolean moveVehicleOverNode(
final QVehicle veh,
QLinkI fromLink,
final QLaneI fromLane,
final double now ) {
395 moveVehicleFromInlinkToAbort( veh, fromLane, now, currentLink.
getId() ) ;
404 moveVehicleFromInlinkToOutlink(veh, currentLink.
getId(), fromLane, nextLinkId, nextQueueLane);
408 this.atLeastOneOutgoingLaneIsJammed =
true;
410 if (vehicleIsStuck(fromLane, now)) {
416 moveVehicleFromInlinkToAbort(veh, fromLane, now, currentLink.
getId());
427 moveVehicleFromInlinkToOutlink(veh, currentLink.
getId(), fromLane, nextLinkId, nextQueueLane);
438 private static int wrnCnt = 0 ;
439 private void moveVehicleFromInlinkToAbort(
final QVehicle veh,
final QLaneI fromLane,
final double now,
Id<Link> currentLinkId) {
448 ((MobsimAgent)pp).setStateToAbort(now);
450 }
else if ( wrnCnt < 1 ) {
452 log.warn(
"encountering PassengerAgent that cannot be cast into a MobsimAgent; cannot say if this is a problem" ) ;
464 double now = this.context.getSimTimer().
getTimeOfDay() ;
480 private boolean vehicleIsStuck(
final QLaneI fromLaneBuffer,
final double now) {
482 final double stuckTime = this.context.qsimConfig.
getStuckTime() ;
List< QLaneI > getOfferingQLanes()
QVehicle popFirstVehicle()
final NetsimInternalInterface netsimEngine
double getLastMovementTimeOfFirstVehicle()
static final String ONLYONCE
static Random getRandom()
emptyBufferAfterBufferRandomDistribution_dontBlockNode
void notifyMoveOverNode(Id< Link > newLinkId)
void setStateToAbort(final double now)
Map< Id< Link >, QLinkI > getNetsimLinks()
boolean isNotOfferingVehicle()
boolean isNotifyAboutStuckVehicles()
Map< Id< Link >, ? extends Link > getInLinks()
QNetwork getNetsimNetwork()
static Random getLocalInstance()
boolean isRemoveStuckVehicles()
moveVehByVehRandomDistribution_nodeBlockedWhenSingleOutlinkFull
final QSimConfigGroup qsimConfig
QLaneI getAcceptingQLane()
Collection<? extends PassengerAgent > getPassengers()
AcceptTurn isAcceptingTurn(Link currentLink, QLaneI currentLane, Id< Link > nextLinkId, QVehicle veh, QNetwork qNetwork, double now)
final void setTurnAcceptanceLogic(TurnAcceptanceLogic turnAcceptanceLogic)
emptyBufferAfterBufferRandomDistribution_nodeBlockedWhenSingleOutlinkFull
void processEvent(final Event event)
moveVehByVehDeterministicPriorities_nodeBlockedWhenSingleOutlinkFull
boolean isAcceptingFromUpstream()
final NetsimEngineContext context
MobsimDriverAgent getDriver()
TurnAcceptanceLogic turnAcceptanceLogic
moveVehByVehRandomDistribution_dontBlockNode
void arrangeNextAgentState(MobsimAgent pp)
void addFromUpstream(final QVehicle veh)
Id< Link > chooseNextLinkId()
NodeTransition getNodeTransitionLogic()
Builder(NetsimInternalInterface netsimEngine2, NetsimEngineContext context, QSimConfigGroup qsimConfig)