C ---------------------------------------------------------------------- INTEGER FUNCTION LINK_LINK2LINK(io,sim,net,act,veh,i) C ---------------------------------------------------------------------- C - Loops over all the links once more to move vehicles across C This is the second of the link passes where vehicles that C reached the end of their current links and did not exit C the network are moved to the next link in their path. C Limits on this movement may depend on available capacity C on the downstream link and possibly flow allocation C depending on the number of particles on the inflow links C - INCLUDED FILES: #include "dyna.inc" #include "io.inc" #include "sim.inc" #include "network.inc" #include "activity.inc" #include "vehicle.inc" C - UNMODIFIED ARGUMENTS: RECORD /Io_Data/ io RECORD /Sim_Data/ sim RECORD /Activity/ act C - MODIFIED ARGUMENTS: RECORD /Road_Network/ net RECORD /Vehicle_Data/ veh(NU_VE) INTEGER i ! link number being updated C - MODIFIED GLOBAL DATA: ! NONE C - LOCAL VARIABLES: INTEGER j,k,ii,iii INTEGER i1,il,im,kn INTEGER mk,in INTEGER nc,ncan,itmp,nb INTEGER indexl,inext,nll,ipp,nlii,nlindex INTEGER moveturn ! why is this here? REAL tma,tl INTEGER LABELNK(NU_LI) INTEGER knext,jnext REAL tend,xspd INTEGER first,last INTEGER mv INTEGER movedelaycnt(6) ! # of vehicles which were ! delayed on each movement ! entering this link. The index is used ! in the same order as the usmoveptr ! (assume a maximum of six links ! entering) INTEGER plan INTEGER phase,phptr INTEGER node INTEGER mi ! moveindex INTEGER mt ! movetype C - FUNCTIONS CALLED: INTEGER LINKMOVEINDEX C - RETURN VALUE: ! Simulation status C ---------------------------------------------------------------------- Cr - Clear delay data for current rolling horizon cell DO j = 1,net.link(i).numuslinks movedelaycnt(j) = 0 net.movement(net.link(i).usmoveptr(j)) + .delaytime(sim.delayrhind) = 0.0 net.movement(net.link(i).usmoveptr(j)).queued = 0 net.movement(net.link(i).usmoveptr(j)).moved = 0 ENDDO TEND = sim.time.minutes + sim.timestep C CHECK IF THE LINK HAS INCIDENT LINKS. **** IF (net.link(i).numuslinks.EQ.0) GOTO 9 C SET UP THE INCIDENT LINK ORDER NUMBER OF DIFFERENT LINKS **** C COMING INTO THIS LINK. **** DO k=1,6 IF (net.link(i).usmoveptr(k).GT.0) + labelnk(net.movement(net.link(i).usmoveptr(k)). + fromlink) = k ENDDO C --- Determine the number of vehicles that can move onto link i based C --- on capacity and saturation flow constraints. crcrc ncan = DENSMAX*net.link(i).xl-net.link(i).npar ! the above does not work well because ! instead of considering conditions as ! of the end of the last time step, it ! can also (depending on link-processing ! order) consider changes to link ! concentration as a result of vehicles ! moving in and out of a link during ! this time step. The result is that ! vehicles in the generation queue ! cannot enter a congested link when ! there is upstream demand. ncan = (DENSMAX-net.link(i).conc)*net.link(i).xl nc = ncan if (ncan.gt.net.link(i).seccap) nc = net.link(i).seccap IF (nc.GT.net.link(i).intoo) nc = net.link(i).intoo C --- C - Move the NC vehicles in to link i from all links with vehicles C - waiting to move in. itmp = net.link(i).intoo DO 11 nb=1,nc C - Find the vehicle with the earliest link-end-arrival time C - and capacity that allows it to move among all the vehicles C - remaining to be moved in. TMA = -100.0 k = net.link(i).into.first mk = 0 DO WHILE (k.NE.NULLP) knext = veh(k).nextveh TL = veh(k).tqwait IF (TL.EQ.0) TL = veh(k).tleft IF (TL.LT.0) THEN !CR: DYNAINT CALL DYNA_ERROR( + 'Negative Tleft for non shared veh'//CHAR(0) + ,DYNA_FATAL_ERROR + ,DYNA_LOGIC_BUG + ,DYNA_VEH_TLEFT) cr TL = 0.D0 ENDIF IF (TL.GT.TMA + .AND. + net.movement(veh(k).mvindex).capacity- + net.movement(veh(k).mvindex).moved.GT.0) THEN TMA = TL MK = K ENDIF k = knext ENDDO Cr - A vehicle was found which is allowed by capacity to move IF (mk.NE.0) THEN in = veh(mk).curlink j = mk il = in im = 1 DO WHILE (net.movement(net.link(il).dsmoveptr(im)). + tolink.NE.i + .AND. + im.LE.net.link(il).numdslinks) im = im + 1 ENDDO IF (im.GT.net.link(il).numdslinks) THEN STOP 'partco: Bad link connection' ENDIF mv = net.link(il).dsmoveptr(im) net.movement(mv).totmoved = net.movement(mv).totmoved + 1 net.movement(mv).delaysum = net.movement(mv).delaysum + + veh(j).tqwait CRsignal -- Sum up phase movement volumes node = net.link(il).idnod plan = net.node(node).curplan IF (net.node(node).plan(plan).type.EQ.CTL_ACTUATED) THEN mi = LINKMOVEINDEX(net,il,0) IF (mi.EQ.0) THEN CALL DYNA_ERROR('Illegal move index'//CHAR(0) + ,DYNA_FATAL_ERROR + ,DYNA_LOGIC_BUG + ,DYNA_ILLEGAL_MOVEMENT) ENDIF DO phase = 1,net.node(node).plan(plan).numphases phptr = net.node(node).plan(plan).phaselist(phase) IF (phptr.LE.0) THEN CALL DYNA_ERROR( + 'Error updating phase volumes'//CHAR(0) + ,DYNA_FATAL_ERROR + ,DYNA_LOGIC_BUG + ,DYNA_UNKNOWN_ERROR) ENDIF mt = net.movement(mv).type CR - Add this vehicle to the active phase's movement: CR - NOTE: because more than one phase may be active, we CR - might have a *slight* over estimation in movement CR - volume on phases which follow phases with the same CR - movement(s) active since the vehicle will be counted CR - as moving during both phases. IF (net.phase(phptr).movelist(mi,mt).NE.0) THEN CR - This phase allows this movement to move, add the CR - vehicle to the count net.phase(phptr).movevol(mi,mt) = + net.phase(phptr).movevol(mi,mt) + 1 ENDIF ENDDO ENDIF IF (veh(j).qstatus.EQ.IN_ENDQ) THEN Cr - This vehicle was queued, update its queuing info and Cr - add its delay to the move delay rolling horizon. To Cr - average all vehicles which make this movement during the Cr - current time step, use dt = qt*1/n + dt*(1-1/n) to get Cr - average (similar to method of sucessive averages in Cr - assignment c$$$ movedelaycnt(im) = movedelaycnt(im) + 1 c$$$ net.movement(mv).delaytime(sim.delayrhind) = c$$$ + (1.0/movedelaycnt(im))*veh(j).tqwait + c$$$ + (1-1.0/movedelaycnt(im))*net.movement(mv) c$$$ + .delaytime(sim.delayrhind) net.movement(mv).delaytime(sim.delayrhind) = + net.movement(mv).delaytime(sim.delayrhind) + + veh(j).tqwait + 10000.0 veh(j).qstatus = IN_NETWORK veh(j).tqwait = 0.0 net.link(in).ndque = net.link(in).ndque - 1 ENDIF indexl = 0 DO iii = 1,net.link(in).numdslinks IF (net.movement(net.link(in).dsmoveptr(iii)).tolink + .EQ.i) indexl = iii ENDDO IF (indexl.EQ.0) THEN CALL DYNA_ERROR( + 'link2link: Link not found'//CHAR(0) + ,DYNA_FATAL_ERROR + ,DYNA_LOGIC_BUG + ,DYNA_INVALID_LINK) ENDIF i1 = net.link(in).dsmoveptr(indexl) net.movement(i1).moved = net.movement(i1).moved + 1 c verify this is a switch IF (veh(j).info.eq.1) THEN IF (veh(j).switch.lt.0) THEN veh(j).switch = iabs(veh(j).switch) veh(j).switch = veh(j).switch + 1 ENDIF ENDIF c -- c -- outflow record c -- DO ii=1,net.link(in).numdslinks IF (i.eq.net.movement( + net.link(in).dsmoveptr(ii)).tolink) + moveturn = ! what's this for? + net.movement(net.link(in).dsmoveptr(ii)).type ENDDO C FIX THE PARTICLE POSITION FROM LINK-END. **** C ADD THE TIME LEFT TO ITS TIME-TILL-NOW ARRAY. **** xspd = net.link(i).speed CR - Set vehicle's position on its new link veh(j).xpar = net.link(i).length - + (xspd*veh(j).tleft) veh(j).distans = veh(j).distans + + (xspd*veh(j).tleft) veh(j).ttilnow = veh(j).ttilnow + veh(j).tleft CR: I REMOVED SOME CONGESTION CALCS THAT WERE HERE BUT COMMENTED OUT. CR - Remove the vehicle from the into list CALL REMOVEVEH(net.link(i).into.first + ,net.link(i).into.last,veh,j) net.link(in).npar = net.link(in).npar - 1 net.link(in).nmov = net.link(in).nmov + 1 IF (net.link(in).nenaflg.EQ.0) net.link(in).nenaflg = 1 c veh(j).distans = veh(j).distans + net.link(in).length CR -- Check path consistency: verify that the next node in this CR -- vehicle's path is connected to the vehicle's current link nll = 1 DO WHILE( + net.link(net.movement( + net.link(in).dsmoveptr(nll)).tolink).idnod + .NE. + veh(j).jpath(veh(j).icurrnt+1) + .AND. + nll.LE.net.link(in).numdslinks) nll = nll + 1 ENDDO IF (nll.GT.net.link(in).numdslinks) THEN CALL DYNA_ERROR( + 'link2link: Vehicle path not consistent'//CHAR(0) + ,DYNA_FATAL_ERROR + ,DYNA_LOGIC_BUG + ,DYNA_INVALID_PATH) ENDIF Cr - Add the vehicle to link i's on link list CALL ADDVEH(net.link(i).on_link.first + ,net.link(i).on_link.last,veh,j) net.link(i).npar = net.link(i).npar + 1 net.link(i).nin = net.link(i).nin + 1 veh(j).curlink = i veh(j).icurrnt = veh(j).icurrnt + 1 crxxxC --- IF THERE IS AN EXTERNALLY SPECIFIED PATH (MAY BE AN **** crxxxC --- EQUILIBRIUM PATH) FROM THE NEW DOWNSTREAM NODE TO BE **** crxxxC --- COPIED, THEN CALL PATHCOPY **** crxxx crxxx IF ((veh(j).info.NE.1) crxxx + .AND. crxxx + (veh(j).jpflag.EQ.1) crxxx + .AND.(sim.ipinit.EQ.2) ) THEN crxxx crxxx ipp = net.link(i).linkdest( crxxx + act.zone(act.dest2zone(veh(j).jdest)).destnode) crxxx crxxx IF (ipp.NE.0) THEN crxxx crxxx DO kn = 1,NU_PA crxxx veh(j).jpath(kn) = net.eqpath(ipp).list(kn) crxxx IF (veh(j).jpath(kn).EQ. crxxx + act.zone( crxxx + act.dest2zone(veh(j).jdest)).destnode) crxxx + GOTO 451 crxxx ENDDO crxxx crxxx 451 CONTINUE crxxx crxxx veh(j).jpflag = 2 crxxx veh(j).icurrnt = 1 crxxx ENDIF crxxx crxxx ENDIF ENDIF C 11 ENDDO C C IF THE AVAILABLE CAPACITY IS LESS THAN THE DEMAND FOR **** C MOVEMENT INTO THE LINK, THEN KEEP THE REMAINING VEHICLES **** C IN THE PREVIOUS LINKS. **** C We need to move them from the into list back on to their previous C link lists (also, update congestion/queue stuff) j = net.link(i).into.first DO WHILE (j.NE.NULLP) jnext = veh(j).nextveh in = veh(j).curlink DO nlii = 1,net.link(in).numdslinks i1 = net.link(in).dsmoveptr(nlii) IF (net.movement(i1).tolink.EQ.i) THEN nlindex = nlii ENDIF ENDDO i1 = net.link(in).dsmoveptr(nlindex) net.movement(i1).queued = net.movement(i1).queued + 1 IF (veh(j).qstatus.EQ.IN_NETWORK) THEN net.link(in).ndque = net.link(in).ndque + 1 veh(j).qstatus = IN_ENDQ veh(j).xpar = 0.0 ENDIF cd veh(j).cflag = veh(j).cflag + veh(j).tleft veh(j).tqwait = veh(j).tqwait + veh(j).tleft veh(j).tqtot = veh(j).tqtot + veh(j).tleft veh(j).ttilnow = veh(j).ttilnow + veh(j).tleft Cr - Take off of into list CALL REMOVEVEH(net.link(i).into.first + ,net.link(i).into.last,veh,j) Cr - Put (back) on link in's end queue list CALL ADDVEH(net.link(in).on_endq.first + ,net.link(in).on_endq.last,veh,j) j = jnext ENDDO 9 CONTINUE LINK_LINK2LINK = sim.status RETURN END