Petrol Panic Buying Dynamics

Petrol Panic Buying Dynamics preview image

2 collaborators

Default-person Hume Winzar (Team member)

Tags

government interventions 

"What if anything governments can do"

Tagged by Steven D'Alessandro 5 days ago

marketing 

Tagged by Steven D'Alessandro 2 days ago

panic buying& 

"This part of understanding this process"

Tagged by Steven D'Alessandro 5 days ago

petrol shortages` 

"Dynamics of how people deal with shortages"

Tagged by Steven D'Alessandro 5 days ago

Visible to everyone | Changeable by the author
Model was written in NetLogo 6.2.2 • Viewed 72 times • Downloaded 2 times • Run 0 times
Download the 'Petrol Panic Buying Dynamics' modelDownload this modelEmbed this model

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

  1. Shortage-Based Panic: Cars become panicked when perceived stock falls below threshold
  2. Price-Based Panic: High prices trigger panic in price-sensitive drivers
  3. Reserves-Based Panic: Low national reserves (measured in days) cause widespread panic
  4. Social Contagion: Panicked drivers influence others nearby
  5. 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

  1. Supply Shock Scenario: Set reserve-days to 30, restock rate to 14 days, observe cascading panic

  2. Price Sensitivity Test: Enable price-triggers-panic, set high price-volatility, watch price-driven panic

  3. Memory Effects: Compare runs with memory = 2 days vs 28 days to see how historical awareness affects outcomes

  4. Communication Intensity: Vary communication-radius and panic-contagion-rate to model social media effects

  5. Reserve Communication: Toggle reserves-trigger-panic to see impact of public awareness of "days remaining"

  6. Strategic Reserve: Start with 90 days (typical government reserve), watch how depletion triggers panic

EXTENDING THE MODEL

Possible Extensions

  1. Media Influence: Add global news broadcasts that increase panic across all agents

  2. Station Types: Differentiate between major brands and independent stations with different pricing strategies

  3. Government Intervention: Model strategic reserve releases or price controls

  4. Electric Vehicles: Add EVs that don't need petrol but may trigger panic among conventional car owners

  5. Regional Variations: Model different geographic areas with varying access to fuel infrastructure

  6. 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

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

;; 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.