SUBROUTINE STATION_CLEAR(station) #include "dyna.inc" #include "detect.inc" RECORD /Dyna_Detector_Station/ station INTEGER i station.number = 0 station.link = 0 station.dist = 0 station.length = 0 DO i = 1,MAX_TIME_STEPS station.cross(i) = 0 ENDDO DO i = 1,MAX_LANES station.lastact(i) = 0.D0 station.count(i) = 0 station.util(i) = 0.D0 ENDDO station.processed = 0 station.totcross = 0 station.totcount = 0 RETURN END C ---------------------------------------------------------------------- SUBROUTINE SURVEILLANCE_INIT(sim,net) C ---------------------------------------------------------------------- C - INCLUDED FILES: #include "dyna.inc" #include "sim.inc" #include "network.inc" C - UNMODIFIED ARGUMENTS: RECORD /Sim_Data/ sim C - MODIFIED ARGUMENTS: RECORD /Road_Network/ net ! network data [detector data]: is ! updated from the data file C - MODIFIED GLOBAL DATA: INTEGER numact ! the number of unprocessed actuations: ! initialized to zero RECORD /Dyna_Actuation/ + actuation(MAX_ACTUATIONS) ! actuation storage: unchanged COMMON /Act_Data/ numact,actuation C - LOCAL VARIABLES INTEGER i,j ! counters INTEGER rindex,aindex INTEGER lnum C - FUNCTIONS CALLED INTEGER LINKNUM ! Function INTEGER NODENUM ! Function C - RETURN VALUE: ! Non zero if there was an error C ---------------------------------------------------------------------- DO i = 1,net.nstations C - Set the processing flag for each station as unprocessed net.station(i).processed = DET_IDLE C - Zero the cross counter for the next step net.station(i).cross(net.rollpnt) = 0 ENDDO REWIND(DETECTOR_FILE) CALL READSTAT('detectors',DETECTOR_FILE) CALL READ_DETECTORS(DETECTOR_FILE,net) RETURN END C ---------------------------------------------------------------------- INTEGER FUNCTION READ_DETECTORS(unit,net) C ---------------------------------------------------------------------- C - Reads network detector data from the network file specified in io C - into the data structures in the network net. C - INCLUDED FILES: #include "dyna.inc" #include "network.inc" C - UNMODIFIED ARGUMENTS: INTEGER unit C - MODIFIED ARGUMENTS: RECORD /Road_Network/ net ! network data [detector data]: is ! updated from the data file C - MODIFIED GLOBAL DATA: INTEGER numact ! the number of unprocessed actuations: ! initialized to zero RECORD /Dyna_Actuation/ + actuation(MAX_ACTUATIONS) ! actuation storage: unchanged COMMON /Act_Data/ numact,actuation C - LOCAL VARIABLES INTEGER i,j ! counters INTEGER rindex,aindex INTEGER lnum C - FUNCTIONS CALLED INTEGER LINKNUM ! Function INTEGER NODENUM ! Function C - RETURN VALUE: ! Non zero if there was an error C ---------------------------------------------------------------------- READ_DETECTORS = 0 C - Tell what we're doing CALL FND(unit) ! Find the next uncommented/nonblank ! line in the file C - Do some initialization net.nstations = 0 net.rollpnt = 1 ! CR:Pointer for aggregating counts numact = 0 ! CR:Zero number of actuations stored in act vector C - Read lines of the file for detector data until the end is reached DO WHILE (.TRUE.) CALL FND(unit) !FIND NEXT NON-BLANK AND NON !'d LINE IN !FILE READ(unit,464,END=646,ERR=999) + net.station(net.nstations+1).number + ,i,j,net.station(net.nstations+1).dist + ,net.station(net.nstations+1).length 464 FORMAT(I4,I5,I5,I5,I5) net.nstations = net.nstations + 1 i = NODENUM(net,i) j = NODENUM(net,j) IF (i.EQ.0.OR.j.EQ.0) THEN CALL SIMMSG(STATUS,'Ignoring detector entry'//CHAR(0)) GOTO 100 ENDIF lnum = LINKNUM(net.fs,i,j,rindex,aindex) IF (lnum.LE.0) THEN WRITE(ostr,'(A,I4,A,I4,2A)') + 'Illegal link in detector file: [',i,'->',j,']',CHAR(0) CALL DYNA_ERROR(ostr + ,DYNA_NONFATAL_WARNING + ,DYNA_INPUT_ERROR + ,DYNA_INVALID_LINK) CALL SIMMSG(STATUS,'Ignoring detector entry'//CHAR(0)) GOTO 100 ENDIF net.station(net.nstations).link = lnum Cr - If the detector is in an invalid location on the link, Cr - put it at the center of the link IF (net.station(net.nstations).dist.LT.0 + .OR. + net.station(net.nstations).dist + .GT. + net.link(lnum).length*5280/2.0) THEN net.station(net.nstations).dist = + net.link(lnum).length*5280.0/2.0 ENDIF CR: - Store the list of stations on each link (FASTER!!!) net.link(lnum).link_det_num = net.link(lnum).link_det_num + 1 net.link(lnum).link_det_list(net.link(lnum).link_det_num) + = net.nstations CR: NEED TO VERIFY LENGTH IS INSIDE LINK! CR: NEED TO VERIFY LINK IS NOT ENTRY LINK IN SHARED SIM DO i = 1,MAX_TIME_STEPS net.station(net.nstations).cross(i) = 0 ENDDO DO j = 1,MAX_LANES net.station(net.nstations).count(j) = 0 net.station(net.nstations).util(j) = 0.0 net.station(net.nstations).lastact(j) = 0.0 ENDDO net.station(net.nstations).totcount = 0 100 CONTINUE ENDDO 646 CONTINUE RETURN 999 CONTINUE READ_DETECTORS = 1 WRITE(ostr,'(A)') 'Encountered an error reading detectors'// + CHAR(0) CALL SIMMSG(STATUS,ostr) RETURN END C ---------------------------------------------------------------------- INTEGER FUNCTION DETPASS(net,oldpos,newpos,lnum) C ---------------------------------------------------------------------- C - See if a vehicle moving from oldpos to newpos has crossed a C - detector on link lnum. If so, update the cross information for C - the detector C - INCLUDED FILES: #include "dyna.inc" #include "network.inc" C - UNMODIFIED ARGUMENTS: REAL oldpos ! a vehicle's old position REAL newpos ! a vehicle's new position INTEGER lnum ! the index of the vehicle's link C - MODIFIED ARGUMENTS RECORD /Road_Network/ net ! network data [station data]: updated ! to reflect any vehicles which have ! cross detectors in the network C - MODIFIED GLOBAL DATA: ! NONE C - LOCAL VARIABLES INTEGER i,k ! counters C - FUNCTIONS CALLED ! NONE C - RETURN VALUE: ! Non zero if there was an error C ---------------------------------------------------------------------- DETPASS = 0 DO i = 1,net.link(lnum).link_det_num ! Loop over the stations for this link k = net.link(lnum).link_det_list(i) IF (net.link(lnum).number.EQ.net.station(k).link) THEN IF (oldpos.LT.net.station(k).dist-net.station(k).length + .AND. + newpos.GE. + net.station(k).dist-net.station(k).length) THEN net.station(k).cross(net.rollpnt) = + net.station(k).cross(net.rollpnt) + 1 net.station(k).totcross = net.station(k).totcross + 1 ENDIF ENDIF ENDDO RETURN END C ---------------------------------------------------------------------- INTEGER FUNCTION DYNADETECT(sim,net) C ---------------------------------------------------------------------- C - Routine to calculate detector actuations based on the number of C - vehicles crossing each detector. Because DYNASMART is not a C - microscopic model (and therefore cannot reliably detail vehicle C - interactions and positions), detector actuations are determined C - by assuming Poisson arrivals using the current macroscopic C - flowrate across the detector (from the number of vehicles that C - the macroscopic model moved across the detector). A record of C - detector actuation times is stored for use by external routines. C - INCLUDED FILES: #include "dyna.inc" #include "sim.inc" #include "network.inc" C - UNMODIFIED ARGUMENTS RECORD /Sim_Data/ sim ! simuation parameters (and time) C - MODIFIED ARGUMENTS RECORD /Road_Network/ net ! network data [station data]: updated ! to reflect actuations occuring at ! stations in the network C - MODIFIED GLOBAL (COMMON) DATA: INTEGER numact ! the number of unprocessed actuations: ! incremented as appropriate RECORD /Dyna_Actuation/ + actuation(MAX_ACTUATIONS) ! actuation storage: updated (for ! external use) to indicate ! actuations occuring at detector ! stations) COMMON /Act_Data/ numact,actuation C - LOCAL VARIABLES INTEGER i,j,k ! counters INTEGER lane ! lane index INTEGER crosssum ! vehicle passage counter INTEGER detcode ! a code to indicate a detector actuation REAL tmp,tmp2 ! temp storage REAL bflow ! average flow rate across a given detector REAL curtime ! storage for the current time REAL tsum ! the total number of vehicles which have ! crossed the detector over the observation ! period C - FUNCTIONS CALLED REAL MICRODETECT ! Function C - RETURN VALUE: ! Non-zero if there was an error C ---------------------------------------------------------------------- DYNADETECT = 0 curtime = sim.time.minutes C - Loop over the detector stations net.stationacc = 0 DO i = 1,net.nstations IF (net.station(i).processed.EQ.DET_ACTIVE) THEN C - Calc the total number of vehicles that have crossed during the C - observation period crosssum = 0 bflow = 0.D0 tmp = 0.D0 tmp2 = 0.D0 DO j = net.rollpnt,net.rollpnt+MAX_TIME_STEPS-1 k = j IF (k.GT.MAX_TIME_STEPS) k = k - MAX_TIME_STEPS crosssum = crosssum + net.station(i).cross(k) C - Determine average flowrate (may be weighted) over C - detector from history tmp = tmp + 1.0 tmp2 = tmp2 + tmp bflow = bflow +net.station(i).cross(k) / + (sim.timestep) * 60.0 cr + * (MAX_TIME_STEPS - tmp) ENDDO cr bflow = bflow / tmp2 bflow = bflow / REAL(MAX_TIME_STEPS) + / net.link(net.station(i).link).nlanes ! ^^^^^^^^^^^^^^^^^^^^ Assume flow distributed evenly ! across lanes C - Loop over all lanes of the station to process each detector DO lane = 1,net.link(net.station(i).link).nlanes net.station(i).count(lane) = 0 net.station(i).util(lane) = 0.D0 C - IF any vehicles have crossed during the observation period C - (i.e. there is nonzero volume) see if there has been a C - poisson arrival to the detector. IF (bflow.GT.0) THEN tmp = MIN((curtime+sim.timestep)*60.0 + ,net.station(i).lastact(lane)) + C - Loop for the next actuation if the previous actuation C - occured before the end of the current time step DO WHILE (tmp.LT.(curtime+sim.timestep)*60.0) C - Set the new actuation time in the appropriate lane net.station(i).lastact(lane) = tmp C - Determine the next Poisson arrival based on the C - boundary flow tmp = MICRODETECT(sim,bflow + ,MAX(tmp, + (curtime+sim.timestep - + (MAX_TIME_STEPS*sim.timestep))*60.0)) C - An actuation occured...record it IF (tmp.LT.(curtime+sim.timestep)*60.0) THEN C - Make sure we can only record actuations during C - this time step. IF (tmp.LT.curtime*60.0) tmp = curtime C - Add the actuation to the lane count and the C - total count net.station(i).count(lane) = + net.station(i).count(lane) + 1 net.station(i).totcount = + net.station(i).totcount + 1 C - Record utilization (occupancy) based on the C - prevailing speed on the link net.station(i).util(lane) = + net.station(i).util(lane) + + (net.station(i).length+AVGVEHLEN)/5280.0/ + net.link(net.station(i).link).speed/ + sim.timestep C - Record the actuation in the actuation storage C - vector numact = numact + 1 IF (numact.GT.MAX_ACTUATIONS) THEN C CALL SIMMSG(STATUS C ,'Too many actuations to store!') numact = MAX_ACTUATIONS ENDIF actuation(numact).time = tmp * 1000 C - I've assumed dyna detector numbers are: C - MAX_LANES*(station # - 1) + lane C - so that the detector lane 3 of station 15 is: C - 5*(15-1) + 3 = 77 detcode = (net.station(i).number-1)*MAX_LANES + + lane actuation(numact).detcode = + detcode + 10000 C - Need off actuation too! numact = numact + 1 IF (numact.GT.MAX_ACTUATIONS) THEN C CALL SIMMSG(STATUS C ,'Too many actuations to store!') numact = MAX_ACTUATIONS ENDIF actuation(numact).time = (tmp + + (net.station(i).length+AVGVEHLEN)/5280.0/ + net.link(net.station(i).link).speed + *60.0) * 1000 actuation(numact).detcode = detcode ENDIF ENDDO ENDIF ENDDO C - Flag the detector as having been processed net.station(i).processed = DET_IDLE ENDIF net.stationacc = net.stationacc + + net.station(i).totcount - + net.station(i).totcross tsum = tsum + net.station(i).totcross ENDDO IF (tsum.GT.0) THEN net.stationacc = net.stationacc / tsum * 100.0 ELSE net.stationacc = 0 ENDIF RETURN END C ---------------------------------------------------------------------- REAL FUNCTION NEGATIVE_EXP(sim,tau,val) C ---------------------------------------------------------------------- CR - Shifted negative exponential returning a headway based on a CR - negative exponential distribution using tau as a minimum headway CR - (the shifting constant) and val as the avg headway: CR - exp(H) = val C - INCLUDED FILES: #include "dyna.inc" ! needed for RAN1 function def #include "sim.inc" C - UNMODIFIED ARGUMENTS: RECORD /Sim_Data/ sim ! sim data [iseed]: needed to pass to the ! rnum generator: actually, probably not ! needed, should just pass zero!!! REAL tau ! The minimum headway allowed between veh REAL val ! The average headway between vehicles C - MODIFIED ARGUMENTS: ! NONE C - MODIFIED GLOBAL DATA: ! NONE C - LOCAL VARIABLES: ! NONE C - FUNCTIONS CALLED: ! NONE C - RETURN VALUE: ! A REAL value for headway in seconds (?) C ---------------------------------------------------------------------- cr NEGATIVE_EXP = -val*LOG(RAN1(sim.iseed)) NEGATIVE_EXP = -(val-tau) + *LOG(MAX(0.00000001,RAN1(sim.iseed))) + tau RETURN END C ---------------------------------------------------------------------- REAL FUNCTION MICRODETECT(sim,flow,lastact) C ---------------------------------------------------------------------- C - Determines the next actuation occuring at a point given the C - average flow rate across that point and the last actuation which C - occured at that point C - INCLUDED FILES: #include "dyna.inc" ! Needed for sim.inc #include "sim.inc" ! Needed to pass to NEG_EXP (can probably be ! eliminated) C - UNMODIFIED ARGUMENTS: RECORD /Sim_Data/ sim ! simulation parameter data (for iseed) REAL flow ! The average flow rate at the point REAL lastact ! The last actuation at the point C - MODIFIED ARGUMENTS: ! NONE C - MODIFIED GLOBAL DATA: ! NONE C - LOCAL VARIABLES: ! NONE C - FUNCTIONS CALLED: REAL NEGATIVE_EXP ! Function C - RETURN VALUE: ! The next actuation time at the given detector (in "real-time" ! seconds) C ---------------------------------------------------------------------- MICRODETECT = lastact + NEGATIVE_EXP(sim,0.5,3600.0/flow) RETURN END