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 26 days ago

marketing 

Tagged by Steven D'Alessandro 23 days ago

panic buying& 

"This part of understanding this process"

Tagged by Steven D'Alessandro 26 days ago

petrol shortages` 

"Dynamics of how people deal with shortages"

Tagged by Steven D'Alessandro 26 days ago

Visible to everyone | Changeable by the author
Model was written in NetLogo 7.0.3 • Viewed 208 times • Downloaded 11 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
  
  ;; Station outages
  station-outages-percent  ;; percentage of stations with zero stock
  
  ;; 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
  strategic-reserves-available  ;; remaining strategic reserves that can be released (in days)
  
  ;; Data recording
  historical-data        ;; list of data records for export
 
]

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
  daily-fuel-purchased ;; total fuel purchased today (for purchase limits)
  last-purchase-day    ;; last day when purchase counter was reset
]

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
  reset-ticks
  update-turtles
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
  set strategic-reserves-available strategic-reserves-pool
end 

to setup-cars
  set-default-shape turtles "car"
  create-turtles number-of-cars
  [ setxy (random-xcor * 0.95) (random-ycor * 0.95)
    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
    set fuel-consumption 1 + random 2
    set price-sensitivity 0.5 + random-float 0.5
    set in-queue? false
    set queue-time 0
    set daily-fuel-purchased 0
    set last-purchase-day 0
  ]
  
  ;; Panic the correct percentage of cars
  let panic-count round (initial-panic-size / 100 * number-of-cars)
  ask n-of panic-count turtles
    [ become-panicked ]
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
  ;; Make sure setup has been run first
  if not is-list? historical-data [ setup ]
  
  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-reserves
  update-patches
  update-turtles
  consume-fuel
  update-queues
  resupply
  spread-panic
  record-data  ;; Record data each tick for export
  tick
 ; AUTO-TRIGGER INTERVENTIONS
  ; Messaging
  if ticks = messaging-start-day and auto-trigger-messaging [
    coordinated-gov-messaging
  ]
  
  ; Purchase limits
  if ticks = purchase-limit-start-day and auto-trigger-limits [
    implement-purchase-limits
  ]
  
  ; Reserve release
  if ticks = reserve-release-start-day and auto-trigger-release [
    release-strategic-reserves
  ]
  
  ; Price controls
  if ticks = price-control-start-day and price-controls-active [
    ; Price controls are already implemented in your model
    ; This just documents when they start
  ]
  
  ; News broadcasts
  if auto-trigger-broadcasts [
    let broadcast-list read-from-string broadcast-days
    if member? ticks broadcast-list [
      news-broadcast
    ]
  ]  
end 

to record-data
  ;; Record current state for later export
  let panic-pct (count turtles with [not (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 
                     station-outages-percent total-broadcasts purchase-limit-active? price-control-active? coordinated-messaging?)
  set historical-data lput data-row historical-data
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 station-outages-percent 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
end 

to news-broadcast
  ;; Simulate a breaking news event that triggers panic
  ;; Government messaging reduces the effectiveness of media panic
  set total-broadcasts total-broadcasts + 1
  set ticks-since-broadcast 0
  
  ;; Government messaging reduces media influence effectiveness by 50%
  let effective-media-influence media-influence-strength
  if coordinated-messaging? = true
  [ set effective-media-influence media-influence-strength * 0.5 ]
  
  ;; News affects a percentage of calm drivers based on effective media influence
  let affected-count floor (effective-media-influence * count turtles with [not (breed = station-markers) and not panicked?] / 100)
  ask n-of affected-count turtles with [not (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 [not (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 ]
  
  ;; Calculate station outages percentage
  let stations-out-of-stock count patches with [is-station? and stock <= 0]
  ifelse petrol-stations > 0
  [ set station-outages-percent (stations-out-of-stock / petrol-stations * 100) ]
  [ set station-outages-percent 0 ]
  
  ;; Cars in queues trigger panic in observers
  if queues-trigger-panic = true
  [ ask turtles with [not (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 into market (reduces overall reserve days)
  ;; This captures the tradeoff: using reserves to calm panic but depleting overall supply
  ;; Can only release what's available in the strategic reserve pool
  
  ifelse strategic-reserves-available >= reserve-release-days
  [ ;; Enough strategic reserves available - release full amount
    let release-amount reserve-release-days
    set reserve-days reserve-days - release-amount
    set reserves-released reserves-released + release-amount
    set strategic-reserves-available strategic-reserves-available - release-amount
    print (word "Released " release-amount " days of strategic reserves. " 
                 strategic-reserves-available " days remaining in storage.")
  ]
  [ ;; Not enough strategic reserves - release only what's left
    ifelse strategic-reserves-available > 0
    [ let release-amount strategic-reserves-available
      set reserve-days reserve-days - release-amount
      set reserves-released reserves-released + release-amount
      set strategic-reserves-available 0
      print (word "Released final " release-amount " days of strategic reserves. Storage now EMPTY.")
    ]
    [ ;; No strategic reserves left
      print "ERROR: No strategic reserves remaining! Cannot release more."
    ]
  ]
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?
  
  ifelse price-control-active?
  [ ;; Cap prices at 15% above base (allows some price signaling while preventing gouging)
    ask patches with [is-station?]
    [ ifelse reserve-days < (initial-reserve-days * 0.3)
      [ let market-price base-price * (1 + ((initial-reserve-days - reserve-days) / initial-reserve-days) * price-volatility)
        set current-price min (list market-price (base-price * 1.15))
      ]
      [ ;; If reserves are still adequate, keep at base price
        set current-price base-price
      ]
    ]
  ]
  [ ;; Deactivating controls - restore market pricing
    ask patches with [is-station?]
    [ if reserve-days < (initial-reserve-days * 0.3)
      [ set current-price base-price * (1 + ((initial-reserve-days - reserve-days) / initial-reserve-days) * price-volatility) ]
    ]
  ]
end 

to coordinated-gov-messaging
  ;; Government coordinated messaging reduces panic contagion
  set coordinated-messaging? not coordinated-messaging?
end 

to export-data
  ;; Export all historical simulation data to CSV file
  let default-filename (word "panic_buying_data_" number-of-cars "cars_" petrol-stations "stations.csv")
  
  ;; Let user choose where to save the file
  let filename user-new-file
  
  ;; If user cancelled, exit
  if filename = false [ 
    print "Export cancelled by user"
    stop 
  ]
  
  ;; Delete old file if exists
  carefully
  [ file-delete filename ]
  [ ]
  
  ;; Write header
  file-open filename
  file-print "day,panic_percentage,avg_stock,reserve_days,avg_price,avg_queue_length,station_outages_percent,total_broadcasts,purchase_limit_active,price_control_active,coordinated_messaging"
  
  ;; Write all historical data
  foreach historical-data
  [ data-row ->
    file-print (word 
      (item 0 data-row) ","  ;; day
      (item 1 data-row) ","  ;; panic_percentage
      (item 2 data-row) ","  ;; avg_stock
      (item 3 data-row) ","  ;; reserve_days
      (item 4 data-row) ","  ;; avg_price
      (item 5 data-row) ","  ;; avg_queue_length
      (item 6 data-row) ","  ;; station_outages_percent
      (item 7 data-row) ","  ;; total_broadcasts
      (item 8 data-row) ","  ;; purchase_limit_active
      (item 9 data-row) ","  ;; price_control_active
      (item 10 data-row))     ;; coordinated_messaging
  ]
  
  file-close
  
  print (word "Exported " length historical-data " days of data to: " filename)
end 

to update-reserves
  ;; Calculate daily consumption rate (total fuel consumed per day)
  set daily-consumption sum [fuel-consumption] of turtles with [not (breed = station-markers)]
  
  ;; Reserves deplete based on overall demand and panic level
  let panic-multiplier 1 + (count turtles with [not (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 ]
  
  ;; Low reserves trigger price increases
  if reserve-days < (initial-reserve-days * 0.3)
  [ ask patches with [is-station?]
    [ let market-price base-price * (1 + ((initial-reserve-days - reserve-days) / initial-reserve-days) * price-volatility)
      ;; Apply price controls cap if active (max 15% increase), otherwise use market price
      ifelse price-control-active?
      [ set current-price min (list market-price (base-price * 1.15)) ]
      [ set current-price market-price ]
    ]
  ]
end 

to spread-panic
  if shortage-makes-panic = true
  [ ask turtles with [not (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 [not (breed = station-markers)]
    [ if price-perception > (mean_price * price-panic-threshold * 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 [not (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 [not (breed = station-markers) and panicked?]
    [ ask turtles with [not (breed = station-markers)] in-radius communication-radius
        [ if random 100 < effective-contagion-rate
            [ become-panicked ]
        ]
    ]
  ]
end 

to consume-fuel
  ask turtles with [not (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 [not (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 [not (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 ]
  ]

  ;; Reset daily purchase counter at start of each new day
  ask turtles with [not (breed = station-markers)]
  [ if ticks != last-purchase-day
    [ set daily-fuel-purchased 0
      set last-purchase-day ticks ]
  ]

  ;; Regular (non-panicked) cars buy normal amounts
  ask turtles with [not (breed = station-markers) and not panicked?]
  [ if fuel-tank < 80  ;; refuel if below 80%
    [ let desired-amount 20
      
      ;; Apply daily purchase limit if active
      let purchase-amount desired-amount
      if purchase-limit-active?
      [ ;; Check if we've hit daily limit
        if daily-fuel-purchased >= purchase-limit-amount
        [ set purchase-amount 0 ]  ;; Already bought daily limit
        ;; Otherwise buy what we can up to remaining allowance
        if daily-fuel-purchased < purchase-limit-amount
        [ set purchase-amount min (list desired-amount (purchase-limit-amount - daily-fuel-purchased)) ]
      ]
      
      ;; Make purchase if allowed
      if purchase-amount > 0
      [ ask patch-here
        [ if is-station? and stock >= purchase-amount
          [ set stock ( stock - purchase-amount)
            ask myself [ set daily-fuel-purchased daily-fuel-purchased + purchase-amount ]
          ]
        ]
      ]
    ]
  ]
  
  ;; Panicked cars try to fill up completely and hoard
  ask turtles with [not (breed = station-markers) and panicked?]
  [ ifelse panic-hoarding = true
    [ ;; With daily limits, panicked cars are capped at daily allowance
      ifelse purchase-limit-active?
      [ ;; Check remaining daily allowance
        let remaining-allowance purchase-limit-amount - daily-fuel-purchased
        if remaining-allowance > 0
        [ ask patch-here
          [ if is-station?
            [ let actual-purchase min (list remaining-allowance stock)
              set stock max (list 0 (stock - actual-purchase))
              ask myself [ set daily-fuel-purchased daily-fuel-purchased + actual-purchase ]
            ]
          ]
        ]
      ]
      [ ;; Without limits, buy everything at current station and neighbors
        ask patch-here
        [ if is-station?
          [ ask neighbors with [is-station?]
            [ set stock 0 ]
            set stock 0
          ]
        ]
      ]
    ]
    [ ;; Just buy maximum at current station (60L default for panicked without hoarding)
      let desired-amount 60
      
      ;; Apply daily purchase limit if active
      let purchase-amount desired-amount
      if purchase-limit-active?
      [ let remaining-allowance purchase-limit-amount - daily-fuel-purchased
        set purchase-amount min (list desired-amount remaining-allowance)
      ]
      
      if purchase-amount > 0
      [ ask patch-here
        [ if is-station?
          [ let actual-purchase min (list purchase-amount stock)
            set stock max (list 0 (stock - actual-purchase))
            ask myself [ set daily-fuel-purchased daily-fuel-purchased + actual-purchase ]
          ]
        ]
      ]
    ]
  ]
end 

There are 2 versions of this model.

Uploaded by When Description Download
Steven D'Alessandro 10 days ago Fixed intervention and contagion size effects Download this version
Steven D'Alessandro 26 days ago Initial upload Download this version

Attached files

File Type Description Last updated
Petrol Panic Buying Dynamics.png preview Preview for 'Petrol Panic Buying Dynamics' 26 days ago, by Steven D'Alessandro Download

This model does not have any ancestors.

This model does not have any descendants.