C ---------------------------------------------------------------------- INTEGER FUNCTION STD_IGETLINK(sim,net,act,i,veh) C ---------------------------------------------------------------------- C - Returns the next link in a given vehicle's (veh) path. If the C - vehicle is receiving route information, a (boundedly rational) C - decision rule is applied to updated the vehicle's path based on C - the current shortest paths in the network C - INCLUDED FILES: #include "dyna.inc" #include "sim.inc" #include "network.inc" #include "activity.inc" #include "vehicle.inc" C - UNMODIFIED ARGUMENTS: INTEGER i ! Vehicle's current link C - MODIFIED ARGUMENTS: RECORD /Sim_Data/ sim RECORD /Road_Network/ net RECORD /Activity/ act RECORD /Vehicle_Data/ veh ! Vehicle for which to find link C - MODIFIED GLOBAL DATA: ! NONE C - LOCAL VARIABLES: INTEGER ikp,kbest INTEGER icu,idn,nexnod,k,nodcur,movetmp,m,know,ibest INTEGER ifrom,itodz,itodn INTEGER icp,icpo,kn1,kn,kk INTEGER nl REAL tmthis,best REAL bsum REAL rhold REAL cum INTEGER icrnt INTEGER rindex,aindex INTEGER numpath C - FUNCTIONS CALLED: REAL PATHTIME INTEGER LINKNUM INTEGER LINKMOVEINDEX C - RETURN VALUE: ! The next link (by number) in the vehicle's path ! (still need error condition) C ---------------------------------------------------------------------- c -- current link icu = i idn = net.link(i).idnod C FIRST, THE CASE OF THE NO-INFORMATION VEHICLES. **** C JUST USE THE ROUTE STORED WHEN THEY STARTED THE TRIP. **** c -- c -- if the node has a cms associated w/it select next path on priority c -- if the driver cannot switch, then pick a next link in the path c -- if the driver can switch, follows the behavioral rule CR: NOTE: ipinit=2: use external paths, CR: ipinit=1: use eq paths, CR: ipinit=0: all drivers have info ibest = 0 IF (veh.info.EQ.1 + .OR. + (sim.time.minutes.LT.sim.starttm + .AND. + sim.ipinit.EQ.1) + .OR. + sim.ipinit.EQ.0) THEN C Here we have a vehicle receiving information (or we've not C reached the start time yet. See if this vehicle will select a C new path. C - The current travel time of the driver's present C - path. (Shouldn't this be different for BR vs. LOGIT split?) tmthis = PATHTIME(veh,net,act) C - The downstream node of the driver's current link. nodcur = veh.jpath(veh.icurrnt) CR Include the current node's penalty in the movement. To do this CR we must find the movement index related to the current movement CR from which the vehicle is coming. This whole procedure is CR terribly inefficient and should be re-coded. CR - Find out what the movement index of the link is m = LINKMOVEINDEX(net,icu,0) C - Check to make sure we found an approach link matching the one C - the vehicle is on IF (m.LE.0) THEN CALL DYNA_ERROR('getlink: movement not found!!!'//CHAR(0) + ,DYNA_FATAL_ERROR,DYNA_LOGIC_BUG + ,DYNA_PATH_NOMOVE) ENDIF C - Store the movement index for later use movetmp = m IF (sim.route_choice_rule.EQ.1) THEN C --- USE LOGIT SPLIT ----- CR - Determine logit split of kshortest path selections: c - NOTE: This is based on the path travel times computed during c - the last shortest path update. Jay's last version of the code c - (see BOUNDEDLY RATIONAL SPLIT below updated path travel times c - of the k-shortest paths *every* time step. Using the Austin c - storage (with movements) this becomes a very expensive c - procedure, so we'll use a probablistic logit split instead C - First, loop over each of the paths from this approach link to C - the vehicle's downstream node to the vehicle's destination, and C - sum their neg. exp. disutility bsum = 0.D0 know = 1 ikp = 1 DO WHILE(ikp.LE.sim.kay + .AND.know.NE.0) crlp know = net.spd.od. crlp + labelpointerout(veh.jdest,nodcur,ikp,movetmp) know = net.spd.lod.labelpointerout(veh.jdest,icu,ikp) IF (know.GT.0) THEN crlp BEST = net.spd.od.labelout(veh.jdest,nodcur,know crlp + ,movetmp) BEST = net.spd.lod.labelout(veh.jdest,icu,know) bsum = bsum + exp(-1.D0*best*sim.logit_smooth_factor) ikp = ikp + 1 ENDIF ENDDO numpath = ikp - 1 IF (ikp.LT.1) THEN WRITE(ostr,692) net.link(i).iunod + ,net.link(i).idnod,veh.jdest 692 FORMAT('Path error from ['I5'->'I5'] to dest ['I5']'A) ENDIF C - Get a random number for this path switch possibility rhold = ran1(sim.iseed) C - Now increment the cumulative probability for each possible path C - until it is greater than the driver's random number cum = 0.D0 ikp = 0 DO WHILE(cum.LT.rhold) ikp = ikp + 1 crlp know = net.spd.od. crlp + labelpointerout(veh.jdest,nodcur,ikp,movetmp) crlp best = net.spd.od. crlp + labelout(veh.jdest,nodcur,know,movetmp) know = net.spd.lod.labelpointerout(veh.jdest,icu,ikp) best = net.spd.lod.labelout(veh.jdest,icu,ikp) cum = cum + exp(-1.D0*best*sim.logit_smooth_factor) /bsum ENDDO C - Store the k-now and the best travel time kbest = ikp ELSE IF (sim.route_choice_rule.EQ.0) THEN C --- USE BOUNDEDLY RATIONAL SPLIT ----- C Using the "boundedly rational" driver behavior model, compare the C driver's current route with the best alternative route (from C among the k-shortest paths). This choice rule means that we need C to update the travel times on the current k-shortest paths every C time step (or at least on some interval which matches how often C and information provider would update travel times). C - Determine the best of the possible K-shortest paths best = INFINITY kbest = 0 know = 1 ikp = 1 DO WHILE (ikp.LE.sim.kay + .AND. + know.NE.0) C - k now for the ikp'th shortest path from the end of the C - driver's present link to his/her (oooo, PC!) destination crlp know = net.spd.od. crlp + labelpointerout(veh.jdest,nodcur,ikp,movetmp) know = net.spd.lod.labelpointerout(veh.jdest,icu,ikp) IF (know.GT.0) THEN C - The travel time for this path crlp cum = net.spd.od.labelout(veh.jdest crlp + ,nodcur,know,movetmp) cum = net.spd.lod.labelout(veh.jdest,icu,know) IF (cum.LT.best) THEN best = cum kbest = ikp ENDIF ikp = ikp + 1 ENDIF ENDDO numpath = ikp - 1 C - Check to make sure we found a path IF (kbest.EQ.0.OR.numpath.LE.0) THEN CALL DYNA_ERROR( + 'No best path found in the k-best paths'//CHAR(0) + ,DYNA_FATAL_ERROR + ,DYNA_INVALID_PATH + ,DYNA_PATH_NOMOVE) ENDIF ELSE WRITE(ostr,'(A,I1,A)') 'Invalid route choice rule: [' + ,sim.route_choice_rule + ,']'//CHAR(0) CALL DYNA_ERROR(ostr + ,DYNA_FATAL_ERROR + ,DYNA_INPUT_ERROR + ,DYNA_INVALID_CHOICE_RULE) ENDIF IF (((sim.route_choice_rule.EQ.0).AND. + best.LT.AMAX0(tmthis*(1-veh.ribf),tmthis-act.dem.bound)) + .OR. + ((sim.route_choice_rule.EQ.1).AND. + best.NE.tmthis) + ) THEN c -- switch to another path veh.decision = veh.decision + 1 if (veh.switch.gt.0) veh.switch = (-1)*veh.switch c -- define destination and origin ibest = kbest !1 ifrom = nodcur itodz = veh.jdest itodn = act.destlist(itodz) icrnt = veh.icurrnt CALL PATHUPDATE(ibest,net,act,icu,veh,icrnt) ENDIF c -- c -- Find the next node in the path c -- DO k = net.fs.npoint(veh.jpath(veh.icurrnt+1)), + net.fs.npoint(veh.jpath(veh.icurrnt+1)+1)-1 IF (net.link(i).idnod.EQ.net.fs.ifwdarc(k,1)) + nl = net.fs.ifwdarc(k,2) ENDDO ELSE C CMS PATH CIRCUMVENTION!!!! CRCR icp = net.link(i).cmslink(veh.jdest) ! start of path list for ! dest at this CMS C - Loop over the paths associated with this list-dest pair to find C - the first one which is active (might consider having drivers C - consider all active paths (via a choice model), the CMS would C - just add one or more paths to their choice list; right now, C - however, the vehicle will select the *last active cms path* in C - the path list for this link/dest pair C - Use the CMS response level (currently the same for all CMS) to C - determine whether this vehicle will use the CMS guidance. C - Currently, this makes a random number call each time a vehicle C - has a CMS path option. Does this make sense, or should the C - response level for a vehicle be a constant parameter associated C - with the vehicle? If the vehicle's parameter (random #) is C - greater than the response level then the vehicle will ignore C - CMS information: set the icp pointer to zero in this case. IF (ran1(sim.iseed).GT.sim.cms_response_level) icp = 0 DO WHILE (icp.NE.0) IF (net.cmspath(icp).on) THEN ibest = -200-1 crmi kn1 = veh.icurrnt - 1 crmi kn = kn1 crmi DO WHILE ( crmi + net.cmspath(icp).list(kn-kn1+1) crmi + .NE.act.destlist(veh.jdest) crmi + .AND. crmi + kn.LE.NU_PA) crmi veh.jpath(kn) = net.cmspath(icp).list(kn-kn1+1) crmi kn = kn + 1 crmi ENDDO crmi veh.jpath(kn) = net.cmspath(icp).list(kn-kn1+1) crmi crmi IF (veh.jpath(kn).NE.act.destlist(veh.jdest)) THEN crmi CALL DYNA_ERROR('getlink error!'//CHAR(0) crmi + ,DYNA_FATAL_ERROR,DYNA_LOGIC_BUG crmi + ,DYNA_CMSPATH_NODEST) crmi ENDIF crmi crmi DO kk = kn+1,NU_PA crmi veh.jpath(kk)=0 crmi ENDDO ENDIF icp = net.cmspath(icp).next ENDDO IF (ibest.NE.0) THEN icrnt = veh.icurrnt CALL PATHUPDATE(ibest,net,act,icu,veh,icrnt) ENDIF nl = LINKNUM(net.fs,INT(net.link(i).idnod) + ,INT(veh.jpath(veh.icurrnt+1)) + ,rindex,aindex) ENDIF IF (nl.GT.net.nlinks) THEN CALL DYNA_ERROR('BOGUS IGETLINK!!!' + ,DYNA_FATAL_ERROR,DYNA_LOGIC_BUG + ,DYNA_INVALID_GETLINK) ENDIF STD_IGETLINK = nl RETURN END