Petrol Panic Buying Dynamics
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
Petrol Panic Buying Simulation
Extended from the original panic buying model by Steve D'Alessandro and Hume Winzar
WHAT IS IT?
This model simulates panic buying behaviour in the context of petrol/fuel shortages. Unlike the original model focused on general retail goods, this version incorporates fuel-specific dynamics including:
- Cars as agents with fuel tanks that deplete over time
- Petrol stations with limited stock and variable pricing
- National fuel reserves measured in days of supply (e.g., 90 days)
- Price dynamics influenced by reserve levels
- Multiple panic triggers including stock shortages, high prices, and low reserves
HOW IT WORKS
Agents (Cars/Drivers)
Each car has: - A fuel tank (0-100%) that depletes each tick - Perception of nearby fuel availability and prices - Memory of past stock levels - Price sensitivity - Panic state (calm or panicked)
Environment
- Petrol Stations: Patches that hold fuel stock and set prices (marked with yellow petrol pump symbols)
- National Reserves: Global fuel reserve measured in days of supply remaining (e.g., "90 days of fuel")
- Price Mechanism: Prices increase when reserves drop below 30% of initial level
Panic Mechanisms
- Shortage-Based Panic: Cars become panicked when perceived stock falls below threshold
- Price-Based Panic: High prices trigger panic in price-sensitive drivers
- Reserves-Based Panic: Low national reserves (measured in days) cause widespread panic
- Social Contagion: Panicked drivers influence others nearby
- Empty Tank Panic: Cars with very low fuel become panicked
Panic Behaviour
- Panicked drivers attempt to fill tanks completely
- May hoard fuel by buying at multiple stations
- Spread panic to other drivers through social influence
INTERFACE CONTROLS
Sliders
Number of Cars (50-500): Total number of car agents in the simulation
Petrol Stations (10-80): Number of fuel stations in the world
Initial Stock per Station (200-1000 litres): Starting fuel inventory at each station
Average Startup Price ($1.00-$3.00/L): Average base price per liter across all stations (default $1.65, actual prices vary ±$0.15 around this average)
Initial Panic Size (0-20): Number of drivers who start panicked
Randomness (1-50): Adds variation to panic threshold decisions
Stock Perception Radius (2-15): How far cars can perceive fuel availability
Communication Radius (2-10): Distance over which panic can spread socially
Restock Rate (1-28 days): How often stations receive new fuel deliveries
Memory (1-28 days): How many days of stock history cars remember
National Reserve Days (0-300 days): National fuel reserves in days of supply (typical: 90 days)
Price Volatility (0.1-2.0): How much prices fluctuate with reserve levels
Reserves Panic Threshold (10-50%): Reserve level (as % of initial) below which panic spreads
Panic Contagion Rate (1-20%): Probability of panic spreading between cars
Switches
Shortage Makes Panic: Stock shortages can trigger panic
Panic Makes Panic: Panicked drivers can influence others
Panic Hoarding: Panicked drivers buy out multiple stations
Memory Moderates Panic: Historical stock memory affects panic decisions
Price Triggers Panic: High prices can trigger panic
Reserves Trigger Panic: Low national reserves (in days) can trigger panic
THINGS TO NOTICE
- How quickly panic spreads when reserve days drop below threshold
- The relationship between price increases and panic levels
- How memory of past availability moderates panic responses
- The clustering of panicked cars around depleted stations
- The feedback loop between panic, hoarding, and actual shortages
- How "days of reserves" provides clear public communication metric
THINGS TO TRY
Supply Shock Scenario: Set reserve-days to 30, restock rate to 14 days, observe cascading panic
Price Sensitivity Test: Enable price-triggers-panic, set high price-volatility, watch price-driven panic
Memory Effects: Compare runs with memory = 2 days vs 28 days to see how historical awareness affects outcomes
Communication Intensity: Vary communication-radius and panic-contagion-rate to model social media effects
Reserve Communication: Toggle reserves-trigger-panic to see impact of public awareness of "days remaining"
Strategic Reserve: Start with 90 days (typical government reserve), watch how depletion triggers panic
EXTENDING THE MODEL
Possible Extensions
Media Influence: Add global news broadcasts that increase panic across all agents
Station Types: Differentiate between major brands and independent stations with different pricing strategies
Government Intervention: Model strategic reserve releases or price controls
Electric Vehicles: Add EVs that don't need petrol but may trigger panic among conventional car owners
Regional Variations: Model different geographic areas with varying access to fuel infrastructure
Queue Formation: Explicit modeling of queuing behaviour at popular stations
NETLOGO FEATURES
This model uses: - Custom car shapes for agents - Dynamic price calculations based on reserve days - Memory vectors with decay weights for temporal discounting - Multiple panic triggering mechanisms - Spatial perception using in-radius operations - Real-world reserve metrics (days of supply)
RELATED MODELS
Original Panic Buying Simulation by D'Alessandro & Winzar (2022) for COVID-19 consumer goods
CREDITS AND REFERENCES
Model adapted for petrol context (2024) based on: D'Alessandro, S. & Winzar, H. (2022). Don't panic! An agent-based model approach to understanding panic buying. ANZMAC Conference.
THEORETICAL BACKGROUND
National Reserves in Days
Governments typically maintain strategic petroleum reserves measured in days of import cover or days of consumption. For example: - International Energy Agency (IEA) recommends 90 days - United States: Strategic Petroleum Reserve provides ~140 days (historically) - European Union: 90 days mandatory for member states - Australia: Maintains reserves to meet IEA obligations
Expressing reserves in "days of supply" provides: - Clear public communication metric - Intuitive understanding of crisis severity - Direct comparability across countries - Basis for panic threshold decisions
Recent Examples
- 2021 Colonial Pipeline hack (US): Public feared days of shortage
- 2022 fuel shortages following Russia-Ukraine conflict (Europe): Reserve day counts widely reported
- 2021 UK fuel crisis: Media reported "days until stations run dry"
When reserve days drop below ~30 days, public panic typically intensifies significantly.
Comments and Questions
;; Petrol Panic Buying Simulation ;; Extended from panic buying model by Steve D'Allessandro and Hume Winzar ;; Adaptation for petrol/fuel context globals [ initial-mean-stock ;; at startup - average fuel perceptions of all agents mean_stock ;; at each iteration - average fuel perceptions of all agents mean_price ;; average petrol price across stations decay ;; a vector of decay coefficients: if memory slider = 5 then decay = [ 1 2 3 4 5 ] decay-vector ;; for rescaling the memory decay values daily-consumption ;; daily fuel consumption rate across all vehicles reserve-days ;; current reserves expressed in days of supply initial-reserve-days ;; starting reserve level in days ;; Media influence ticks-since-broadcast ;; time since last news broadcast total-broadcasts ;; count of news broadcasts triggered ;; Queue tracking total-queue-length ;; sum of all queue lengths across stations avg-queue-length ;; average queue length per station ;; Government interventions purchase-limit-active? ;; whether purchase limits are in effect price-control-active? ;; whether price controls are active coordinated-messaging? ;; whether gov messaging is reducing panic reserves-released ;; total reserve days released by government ;; Data recording historical-data ;; list of data records for export ;; World market dynamics world-market-price-factor ;; current global market price multiplier ] breed [station-markers station-marker] ;; visual markers for petrol stations turtles-own [ panicked? ;; if true, the car/driver is panicked stock-perception ;; average of fuel in surrounding stations price-perception ;; average price perception stock-memory ;; a list record of last few stock levels weighted-memory ;; a vector of length memory: most recent stock perceptions have greater salience sum-weighted-memory ;; a single score: the sum of weighted-memory fuel-tank ;; current fuel level in tank (0-100%) fuel-consumption ;; rate of fuel consumption per tick price-sensitivity ;; how sensitive driver is to price changes in-queue? ;; whether car is currently waiting in queue queue-time ;; how long car has been in queue ] patches-own [ stock ;; available petrol for purchase (in litres) stock-order ;; usual resupply brings stock up to usual level base-price ;; base price per litre current-price ;; current price (affected by reserves and demand) is-station? ;; whether this patch is a petrol station queue-length ;; number of cars waiting at this station ] to setup clear-all setup-memory setup-patches setup-reserves initialize-interventions update-patches set initial-mean-stock mean [stock] of patches with [is-station?] setup-cars update-turtles reset-ticks end to setup-memory set decay n-values memory [ i -> i + 1 ] ;; creates a vector of values 1 thru size of memory set decay-vector n-values memory [ i -> ( reduce + decay ) ] ;; a vector of length memory all with the same value end to setup-reserves set initial-reserve-days national-reserve-days set reserve-days national-reserve-days set daily-consumption 0 end to setup-cars set-default-shape turtles "car" create-turtles number-of-cars [ setxy (random-xcor * 0.95) (random-ycor * 0.95) ;; spread cars randomly set panicked? false set color blue set stock-memory ( list ( initial-mean-stock ) ) repeat ( memory - 1 ) [ set stock-memory lput initial-mean-stock stock-memory ] set fuel-tank 50 + random 50 ;; start with 50-100% fuel set fuel-consumption 1 + random 2 ;; consume 1-3% per tick set price-sensitivity 0.5 + random-float 0.5 ;; sensitivity 0.5-1.0 set in-queue? false set queue-time 0 ] ask n-of initial-panic-size turtles with [breed != station-markers] [ become-panicked ] update-turtles end to setup-patches ask patches [ set is-station? false set stock 0 set pcolor green - 2 ;; road color set queue-length 0 ] ;; Create petrol stations (fewer, larger stock areas) ask n-of petrol-stations patches [ set is-station? true set stock (initial-stock-per-station + random 50) set stock-order stock set base-price (average-startup-price - 0.15) + random-float 0.30 ;; base price varies ±15 cents around average set current-price base-price set pcolor scale-color orange stock 0 (initial-stock-per-station * 2) set queue-length 0 ;; Create visual station marker sprout-station-markers 1 [ set shape "petrol-pump" set color yellow set size 2.5 ] ] end to go if ticks >= max-days [ stop ] ;; Stop if reserves reach zero (if switch is on) if stop-at-zero-reserves and reserve-days <= 0 [ print (word "Simulation stopped: Reserves depleted at day " ticks) stop ] set ticks-since-broadcast ticks-since-broadcast + 1 update-world-market-prices update-reserves update-patches update-turtles consume-fuel update-queues resupply spread-panic record-data ;; Record data each tick for export tick end to record-data ;; Record current state for later export let panic-pct (count turtles with [breed != station-markers and panicked?] / number-of-cars * 100) let data-row (list ticks panic-pct mean_stock reserve-days mean_price avg-queue-length total-broadcasts purchase-limit-active? price-control-active? coordinated-messaging?) set historical-data lput data-row historical-data end to update-world-market-prices ;; Simulate random world market price fluctuations ;; Price factor fluctuates randomly based on world-market-volatility slider let volatility-strength (world-market-volatility / 100) let random-change (random-float 0.02 - 0.01) * volatility-strength ;; ±1% change scaled by volatility set world-market-price-factor world-market-price-factor + random-change ;; Keep price factor in reasonable bounds (0.7 to 1.5 = -30% to +50%) if world-market-price-factor < 0.7 [ set world-market-price-factor 0.7 ] if world-market-price-factor > 1.5 [ set world-market-price-factor 1.5 ] end to become-panicked ;; turtle procedure set panicked? true set color red set size 1.5 ;; panicked cars appear larger end to initialize-interventions set ticks-since-broadcast 0 set total-broadcasts 0 set total-queue-length 0 set avg-queue-length 0 set purchase-limit-active? false set price-control-active? false set coordinated-messaging? false set reserves-released 0 set historical-data [] ;; empty list to start set world-market-price-factor 1.0 ;; start at neutral (1.0 = no change) end to news-broadcast ;; Simulate a breaking news event that triggers panic set total-broadcasts total-broadcasts + 1 set ticks-since-broadcast 0 ;; News affects a percentage of calm drivers based on media-influence-strength let affected-count floor (media-influence-strength * count turtles with [breed != station-markers and not panicked?] / 100) ask n-of affected-count turtles with [breed != station-markers and not panicked?] [ become-panicked ] end to update-queues ;; Update queue lengths at each station ask patches with [is-station?] [ set queue-length count turtles with [breed != station-markers and in-queue?] in-radius 2 ] ;; Calculate global queue statistics set total-queue-length sum [queue-length] of patches with [is-station?] ifelse petrol-stations > 0 [ set avg-queue-length total-queue-length / petrol-stations ] [ set avg-queue-length 0 ] ;; Cars in queues trigger panic in observers if queues-trigger-panic = true [ ask turtles with [breed != station-markers and not panicked?] [ let nearby-queue-length sum [queue-length] of patches with [is-station?] in-radius 5 if nearby-queue-length > 3 ;; seeing 3+ cars queued triggers panic [ if random 100 < 10 ;; 10% chance per tick when seeing queues [ become-panicked ] ] ] ] end to release-strategic-reserves ;; Government releases strategic reserves (uses stored fuel to supply the market) ;; Decreases reserve-days but adds stock to stations let release-amount reserve-release-days ifelse reserve-days >= release-amount [ ;; Have enough reserves to release set reserve-days reserve-days - release-amount ;; Decrease stored reserves set reserves-released reserves-released + release-amount ;; Add the released fuel to market (distribute to stations) let fuel-per-station (release-amount * initial-stock-per-station / petrol-stations) ask patches with [is-station?] [ set stock stock + fuel-per-station ;; Cap at maximum stock level if stock > (stock-order * 1.5) [ set stock (stock-order * 1.5) ] ] print (word "Released " release-amount " days of reserves to market. Reserves now: " reserve-days " days") ] [ ;; Not enough reserves to release full amount if reserve-days > 0 [ let actual-release reserve-days let fuel-per-station (actual-release * initial-stock-per-station / petrol-stations) ask patches with [is-station?] [ set stock stock + fuel-per-station if stock > (stock-order * 1.5) [ set stock (stock-order * 1.5) ] ] set reserves-released reserves-released + actual-release set reserve-days 0 print (word "Released all remaining reserves (" actual-release " days). Reserves now: 0 days") ] if reserve-days <= 0 [ print "Cannot release: No reserves remaining!" ] ] end to implement-purchase-limits ;; Toggle purchase limits on/off set purchase-limit-active? not purchase-limit-active? end to implement-price-controls ;; Toggle price controls on/off set price-control-active? not price-control-active? if price-control-active? [ ;; Freeze prices at current base prices ask patches with [is-station?] [ set current-price base-price ] ] end to coordinated-gov-messaging ;; Government coordinated messaging reduces panic contagion set coordinated-messaging? not coordinated-messaging? end to export-data ;; NOTE: File export only works in NetLogo Desktop, not in web version ;; In desktop version, this exports all historical simulation data to CSV file ;; For web version, data is still recorded and visible in plots/monitors print (word "Data recording active: " length historical-data " days recorded") print "Note: CSV export only available in NetLogo Desktop version" print "Download the .nlogo file to use export feature locally" end to update-reserves ;; Calculate daily consumption rate (total fuel consumed per day) set daily-consumption sum [fuel-consumption] of turtles with [breed != station-markers] ;; Reserves deplete based on overall demand and panic level let panic-multiplier 1 + (count turtles with [breed != station-markers and panicked?] / number-of-cars) let reserve-depletion (daily-consumption * panic-multiplier) / (initial-stock-per-station * petrol-stations) ;; Update reserve days (depletes faster when panic buying occurs) set reserve-days reserve-days - reserve-depletion if reserve-days < 0 [ set reserve-days 0 ] ;; Price calculation: combines reserve-based changes + world market fluctuations if price-control-active? = false [ ;; Calculate reserve-based price multiplier let reserve-multiplier 1.0 if reserve-days < (initial-reserve-days * 0.3) [ set reserve-multiplier (1 + ((initial-reserve-days - reserve-days) / initial-reserve-days) * price-volatility) ] ;; Apply both world market factor and reserve multiplier ask patches with [is-station?] [ set current-price base-price * world-market-price-factor * reserve-multiplier ] ] end to spread-panic if shortage-makes-panic = true [ ask turtles with [breed != station-markers] [ ifelse memory-moderates-panic = true [ set weighted-memory ( map * stock-memory decay) set weighted-memory ( map / weighted-memory decay-vector ) set sum-weighted-memory reduce + weighted-memory if sum-weighted-memory < ( initial-mean-stock * (( random randomness) / 100 )) [ become-panicked ] ] [ if stock-perception < ( initial-mean-stock * (( random randomness) / 100 )) [ become-panicked ] ] ] ] ;; Price panic - high prices can trigger panic if price-triggers-panic = true [ ask turtles with [breed != station-markers] [ if price-perception > (mean_price * 1.2 * price-sensitivity) [ become-panicked ] ] ] ;; Reserves panic - awareness of low national reserves (measured in days) if reserves-trigger-panic = true [ if reserve-days < (initial-reserve-days * reserves-panic-threshold / 100) [ ask turtles with [breed != station-markers] [ if random 100 < 5 ;; 5% chance per tick when reserves low [ become-panicked ] ] ] ] if panic-makes-panic = true [ ;; Coordinated messaging reduces panic contagion rate by 50% let effective-contagion-rate panic-contagion-rate if coordinated-messaging? = true [ set effective-contagion-rate panic-contagion-rate * 0.5 ] ask turtles with [breed != station-markers and panicked?] [ ask turtles with [breed != station-markers] in-radius communication-radius [ if random 100 < effective-contagion-rate [ become-panicked ] ] ] ] end to consume-fuel ask turtles with [breed != station-markers] [ set fuel-tank fuel-tank - fuel-consumption ;; Cars with very low fuel become panicked if fuel-tank < 20 and not panicked? [ if random 100 < 30 [ become-panicked ] ] ;; Refuel tank if possible if fuel-tank < 100 [ let available-fuel [stock] of patch-here ifelse available-fuel > 0 [ let fuel-needed min (list (100 - fuel-tank) available-fuel) set fuel-tank fuel-tank + fuel-needed ask patch-here [ if is-station? [ set stock stock - fuel-needed ] ] ] [ ;; No fuel at current location, move towards nearest station let nearest-station min-one-of patches with [is-station? and stock > 0] [distance myself] if nearest-station != nobody [ face nearest-station forward 1 ] ] ] ] end to resupply if ticks mod restock-rate = 0 [ ask patches with [is-station?] [ ;; Resupply depends on national reserves (days available) let supply-multiplier min (list 1.0 (reserve-days / initial-reserve-days)) set stock stock + (stock-order * supply-multiplier * 0.5) if stock > stock-order [ set stock stock-order ] set pcolor scale-color orange stock 0 (initial-stock-per-station * 2) ] ] end to update-patches set mean_stock mean [stock] of patches with [is-station?] set mean_price mean [current-price] of patches with [is-station?] ask patches with [is-station?] [ set pcolor scale-color orange stock 0 (initial-stock-per-station * 2) ] end to update-turtles ask turtles with [breed != station-markers] [ ;; Move if no fuel at current location if ( [stock] of patch-here <= 0 ) or ( not [is-station?] of patch-here ) [ set heading random 360 forward 1 ] ;; Update perceptions let nearby-stations patches with [is-station?] in-radius stock-perception-radius ifelse any? nearby-stations [ set stock-perception mean [stock] of nearby-stations set price-perception mean [current-price] of nearby-stations ] [ set stock-perception 0 set price-perception mean_price ] set stock-memory lput stock-perception stock-memory if length stock-memory > memory [ set stock-memory remove-item 0 stock-memory ] ] ;; Update queue status ask turtles with [breed != station-markers] [ ifelse [is-station?] of patch-here and fuel-tank < 90 [ set in-queue? true set queue-time queue-time + 1 ] [ set in-queue? false set queue-time 0 ] ] ;; Regular (non-panicked) cars buy normal amounts ask turtles with [breed != station-markers and not panicked?] [ if fuel-tank < 80 ;; refuel if below 80% [ let purchase-amount 20 if purchase-limit-active? [ set purchase-amount min (list 20 purchase-limit-amount) ] ask patch-here [ if is-station? and stock >= purchase-amount [ set stock ( stock - purchase-amount) ] ] ] ] ;; Panicked cars try to fill up completely and hoard ask turtles with [breed != station-markers and panicked?] [ ifelse panic-hoarding = true [ ;; Buy out all fuel at current station and neighbors (unless limits active) ifelse purchase-limit-active? [ ;; With limits, can only buy limited amount let purchase-amount purchase-limit-amount ask patch-here [ if is-station? [ set stock max (list 0 (stock - purchase-amount)) ] ] ] [ ;; Without limits, buy everything ask patch-here [ if is-station? [ ask neighbors with [is-station?] [ set stock 0 ] set stock 0 ] ] ] ] [ ;; Just buy maximum at current station let panic-purchase 60 if purchase-limit-active? [ set panic-purchase min (list 60 purchase-limit-amount) ] ask patch-here [ if is-station? [ set stock max (list 0 (stock - panic-purchase)) ] ] ] ] end
There is only one version of this model, created 5 days ago by Steven D'Alessandro.
Attached files
| File | Type | Description | Last updated | |
|---|---|---|---|---|
| Petrol Panic Buying Dynamics.png | preview | Preview for 'Petrol Panic Buying Dynamics' | 5 days ago, by Steven D'Alessandro | Download |
This model does not have any ancestors.
This model does not have any descendants.
Download this model