;;netlogo sim - timm03 globals [ ;; Sliders / Switch in Interface: ;; - number-of-cars (int) ;; - road-spacing (int) ;; - base-speed (float) ;; - driver-error-rate (float) ;; - accident-duration (int) ;; - traffic-lights? (boolean switch) ;; Statistics total-cars-reached-destination total-cars-accident ;; how many cars died in accidents (cumulative) accident-count ;; how many total accidents have started average-speed average-congestion accident-percentage sum-travel-time ;; sum of time in system for all cars that exit count-completed-cars ;; how many cars reached destination average-travel-time ;; output metric accident-count-good accident-count-bad accident-count-very-bad sum-time-until-accident sum-distance-until-accident average-time-until-accident average-distance-until-accident ] patches-own [ is-road? ;; boolean: is this patch part of a road? is-intersection? ;; boolean: is this patch an intersection? lane-direction ;; forced heading: 0, 90, 180, 270, or -1 if intersection traffic-light? ;; does this patch have a traffic light? light-state ;; true=green, false=red has-accident? ;; boolean: accident currently on this patch? accident-lifetime ;; integer: how many ticks remain for this accident? road-condition ;; 0=good, 1=bad, 2=very bad (affects accident prob) ] breed [ cars car ] cars-own [ speed max-speed stopped-ticks destination ;; patch or nobody birth-tick ;; store the tick when the car is created distance-traveled ;; accumulates how far the car has moved ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 1. SETUP ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to setup clear-all ;; Initialize stats set total-cars-reached-destination 0 set total-cars-accident 0 set accident-count 0 set average-speed 0 set average-congestion 0 set sum-travel-time 0 set count-completed-cars 0 set average-travel-time 0 set accident-count-good 0 set accident-count-bad 0 set accident-count-very-bad 0 set sum-time-until-accident 0 set sum-distance-until-accident 0 set average-time-until-accident 0 set average-distance-until-accident 0 setup-roads setup-intersections setup-traffic-lights setup-road-conditions reset-ticks create-initial-cars end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 2. CREATE ROADS (TWO LANE, ONE-WAY) ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to setup-roads ask patches [ set is-road? false set is-intersection? false set traffic-light? false set light-state false set has-accident? false set accident-lifetime 0 set lane-direction 0 set road-condition 0 set pcolor green ] ;; 2-lane roads in x or y dimension let road-patches patches with [ (abs pxcor mod road-spacing <= 1) or (abs pycor mod road-spacing <= 1) ] ask road-patches [ set is-road? true set pcolor grey ] ;; Assign forced lane headings for non-intersection road patches ask road-patches [ let x-road? (abs pxcor mod road-spacing <= 1) let y-road? (abs pycor mod road-spacing <= 1) ;; purely vertical lane: pick 0 or 180 if (x-road? and not y-road?) [ ifelse (pxcor mod 2 = 0) [ set lane-direction 0 ] ;; "northbound" [ set lane-direction 180 ] ;; "southbound" ] ;; purely horizontal lane: pick 90 or 270 if (y-road? and not x-road?) [ ifelse (pycor mod 2 = 0) [ set lane-direction 90 ] ;; "eastbound" [ set lane-direction 270 ] ;; "westbound" ] ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 3. INTERSECTIONS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to setup-intersections ask patches with [is-road?] [ let x-road? (abs pxcor mod road-spacing <= 1) let y-road? (abs pycor mod road-spacing <= 1) ;; Intersection = patch that is both x-road & y-road if (x-road? and y-road?) [ set is-intersection? true set pcolor yellow set lane-direction -1 ;; means "all directions possible here" ] ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 4. TRAFFIC LIGHTS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to setup-traffic-lights if traffic-lights? [ ;; Turn on lights at each intersection ask patches with [is-intersection?] [ set traffic-light? true set light-state true ] ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 5. ROAD CONDITIONS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to setup-road-conditions let sum-prob (good-road-probability + bad-road-probability) ask patches with [is-road?] [ let r random-float 1 ifelse (r < good-road-probability) [ ;; (1) "Good" road set road-condition 0 set pcolor grey ] [ ifelse (r < sum-prob) [ ;; (2) "Bad" road set road-condition 1 set pcolor (grey - 2) ;; 5% chance to become "Very Bad" instead: if random-float 1 < 0.05 [ set road-condition 2 set pcolor orange ] ] [ set road-condition 0 set pcolor grey ] ] ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 6. CREATE INITIAL CARS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to create-initial-cars ask cars [ die ] ;; remove any old cars let valid-starts patches with [ is-road? and not has-accident? and not any? cars-here ] if not any? valid-starts [ user-message "No valid road patches for car creation!" stop ] create-cars min list number-of-cars (count valid-starts) [ set shape "car" set color blue set size 0.8 ;; pick a random road patch let start-patch one-of valid-starts move-to start-patch set valid-starts valid-starts with [self != start-patch] ;; If this patch is an intersection => pick a direction ifelse ([lane-direction] of patch-here = -1) [ set heading one-of [0 90 180 270] ] [ set heading [lane-direction] of patch-here ] set speed 0 set max-speed base-speed set stopped-ticks 0 set destination nobody set distance-traveled 0 set birth-tick ticks ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 7. GO (MAIN LOOP) ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to go if not any? cars [ stop ] update-traffic-lights move-cars check-accidents clear-old-accidents update-statistics tick end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 8. UPDATE TRAFFIC LIGHTS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to update-traffic-lights if traffic-lights? [ ask patches with [is-intersection? and traffic-light?] [ ;; simple toggle every 30 ticks if (ticks mod 30 = 0) [ set light-state not light-state set pcolor ifelse-value light-state [green] [red] ] ] ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 9. MOVE CARS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to move-cars ask cars [ ;; Force lane direction let patch-lane [lane-direction] of patch-here ifelse patch-lane = -1 [ ;; intersection => pick a new direction each tick or once set heading one-of [0 90 180 270] ] [ ;; normal lane => enforce that heading set heading patch-lane ] ;; Decide if it's safe to move let safe-to-move? true ;; Check traffic light if [traffic-light?] of patch-here [ if not ([light-state] of patch-here) [ set safe-to-move? false ] ] ;; Check for cars ahead in same lane if any? cars-on patch-ahead 1 [ set safe-to-move? false ] ;; Move or slow ifelse safe-to-move? [ set speed min (list (speed + 0.1) max-speed) forward speed set distance-traveled distance-traveled + speed set stopped-ticks 0 ] [ set speed max (list (speed - 0.2) 0) set stopped-ticks (stopped-ticks + 1) ] ;; if the car leaves the grid: if not is-patch? patch-here [ set count-completed-cars (count-completed-cars + 1) ;; Add to sum-travel-time: set sum-travel-time (sum-travel-time + (ticks - birth-tick)) ;; Then die die ] if (max-pxcor - abs xcor) < 1 or (max-pycor - abs ycor) < 1 [ set total-cars-reached-destination (total-cars-reached-destination + 1) set count-completed-cars (count-completed-cars + 1) set sum-travel-time (sum-travel-time + (ticks - birth-tick)) die ] ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 10. ACCIDENT LOGIC (EXPANDED) ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to check-accidents ;; For each car, compute probability of an accident ask cars [ if random-float 1 < calculate-accident-probability self [ create-accident self ] ] end to-report calculate-accident-probability [ c ] ;; Base accident probability from driver error let base (driver-error-rate * 0.00025) ;; Find the patch under turtle c (using c's pxcor, pycor) let p patch ([pxcor] of c) ([pycor] of c) ;; Road condition effect if [road-condition] of p = 1 [ set base (base * 2) ] if [road-condition] of p = 2 [ set base (base * 2.6) ] ;; Speed factor let speed-ratio ([speed] of c / [max-speed] of c) set base (base * (speed-ratio + 0.1)) ;; +0.1 so even slow cars have some chance ;; Congestion effect: how many other cars are within radius 1.5 of c let nearby-cars count cars with [ distance c < 1.5 ] set base (base + (nearby-cars * 0.0005)) ;; Intersection effect if [is-intersection?] of p [ set base (base * 1.5) ] ;; Cap at 1% (0.01) to avoid extreme probabilities report min (list base 0.1) end to create-accident [ c ] set accident-count (accident-count + 1) set total-cars-accident (total-cars-accident + 1) ;; Mark the patch let px ([pxcor] of c) let py ([pycor] of c) ask patch px py [ set has-accident? true set pcolor red set accident-lifetime accident-duration ;; Accidents by Road Condition: if (road-condition = 0) [ set accident-count-good (accident-count-good + 1) ] if (road-condition = 1) [ set accident-count-bad (accident-count-bad + 1) ] if (road-condition = 2) [ set accident-count-very-bad (accident-count-very-bad + 1) ] ] ;; Time & Distance to Accident: let time-until-accident (ticks - [birth-tick] of c) let dist-until-accident ([distance-traveled] of c) set sum-time-until-accident (sum-time-until-accident + time-until-accident) set sum-distance-until-accident (sum-distance-until-accident + dist-until-accident) ;; kill the car ask c [ die ] end to clear-old-accidents ;; Decrement accident-lifetime. When it hits 0, clear the patch. ask patches with [has-accident?] [ set accident-lifetime (accident-lifetime - 1) if (accident-lifetime <= 0) [ set has-accident? false ;; restore color based on road-condition if (road-condition = 0) [ set pcolor grey ] if (road-condition = 1) [ set pcolor (grey - 2) ] if (road-condition = 2) [ set pcolor orange ] ] ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 11. STATISTICS & PLOTS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to update-statistics let car-count count cars let total-speed 0 if car-count > 0 [ set total-speed sum [speed] of cars set average-speed (total-speed / car-count) ] if car-count = 0 [ set average-speed 0 ] set average-congestion count cars with [ (stopped-ticks >= 2) and (any? cars-on patch-ahead 1) ] if number-of-cars > 0 [ set accident-percentage ((accident-count / number-of-cars) * 100) ] ;;Average travel time for cars that completed trip if count-completed-cars > 0 [ set average-travel-time (sum-travel-time / count-completed-cars) ] ;;Averages for time & distance until accident if accident-count > 0 [ set average-time-until-accident (sum-time-until-accident / accident-count) set average-distance-until-accident (sum-distance-until-accident / accident-count) ] ;; Plot them carefully [ set-current-plot "Average Speed" plot average-speed set-current-plot "Total Accidents" plot accident-count set-current-plot "Average Congestion" plot average-congestion ] [] end