Network Development ABM

Network Development ABM preview image

2 collaborators

Default-person Natalie Davis (Author)
Default-person Gary Polhill (Advisor)

Tags

heterogeneity 

Tagged by Natalie Davis almost 3 years ago

inequality 

Tagged by Natalie Davis almost 3 years ago

socio-ecological systems 

Tagged by Natalie Davis almost 3 years ago

Visible to everyone | Changeable by the author
Model was written in NetLogo 6.1.1 • Viewed 208 times • Downloaded 11 times • Run 0 times
Download the 'Network Development ABM' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


WHAT IS IT?

The purpose of the model is to explore the network structures that emerge under different agent and resource characteristics, and the feedback between the resulting network structure and dynamics and the level of inequality experienced by agents.

HOW IT WORKS

The agents consume a generalised form of energy from the resource nodes, and build, repair, and walk along links between resources. Agents who are not building or walking choose the action and resource that will yield them the highest energy returns, considering the energy offered by the resources, the energy required to build and walk along a link, and whether the link could be improved to lessen the energy required for walking. Agents with enough energy can also spawn new agents.

HOW TO USE IT

Add a filepath to a comma-separated-value (CSV) file holding resource locations as x, y coordinates (with one header line containing names of the columns - see provided example). A CSV containing patch resistances can also be added, or they will be assigned from a random uniform distribution between min-patch-resistance and max-patch-resistance. Set all the parameters using the sliders provided, and click 'setup.' A full description of the model parameters and example resource and patch CSVs can be found in the ODD - please contact the author.

The profiler should only be used to check timings if working on improving efficiency.

THINGS TO NOTICE

How does the consumer inequality - measured as the standard deviation of energy reserves - change as the network structure and population size change?

THINGS TO TRY

Try changing the resource regrowth regime, and see how that affects the emergence of inequality and network structure. Also try changing the consumers' time discounting parameters, like rho - what sort of network structures emerge?

EXTENDING THE MODEL

It would be good to make it so links decay even if their end patches, under resources, are maintained.

NETLOGO FEATURES

This model made heavy use of the Table extension for consumers to store information about resources in their vision radius, and make decisions about building, repairing, and crossing links.

RELATED MODELS

The model builds off some ideas presented in Davis et al., 2021 (https://doi.org/10.1016/j.ecolmodel.2020.109308), and the related model, http://doi.org/10.5281/zenodo.4001622 (which can also be found at http://www.modelingcommons.org/browse/one_model/6309)

CREDITS AND REFERENCES

N/A

Comments and Questions

Where can we find parameter description and example CSVs? (Question)

The info tab says that "A full description of the model parameters and example resource and patch CSVs can be found in the ODD". Where can we access these?

Posted almost 3 years ago

ODD and example patch and resource files uploaded

I have uploaded the ODD and example patch and resource files for the model under the 'files' tab. Upcoming publications using this model will be uploaded there as they become available.

Posted almost 3 years ago

Click to Run Model

;--------------------------------------------------------------------------------------;
;    Network Development ABM is free software: you can redistribute it and/or modify   ;
;    it under the terms of the GNU General Public License as published by the          ;
;    Free Software Foundation, either version 3 of the License, or (at your option)    ;
;    any later version.                                                                ;
;                                                                                      ;
;    This program is distributed in the hope that it will be useful, but               ;
;    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY        ;
;    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License           ;
;    for more details.                                                                 ;
;                                                                                      ;
;    For the full GNU General Public License, please see                               ;
;    .                                                  ;
;                                                                                      ;
;    Author: Natalie Davis                                                             ;
;--------------------------------------------------------------------------------------;
extensions [ table csv profiler array ]

breed [ resources resource ]
breed [ consumers consumer ]

globals [
  this-seed
  build-energy-consumed
  repair-energy-consumed
  walk-energy-consumed
  basal-energy-consumed
  total-energy-intake
  total-offspring-produced
  initial-consumer-energy
  total-regrowth
  patches-between-resources-tbl
  is-pulsing?
  season
  pulse-timer
  season-timer
]

consumers-own [
  location
  target-location
  initial-energy-reserves
  energy-reserves
  basal-metabolism
  consumption-rate
  risk-penchant
  vision-radius
  time-horizon
  rho
  building?
  repairing?
  walking?
  current-intake-table
  current-access-table
  exp-consumption-table
  costs-table
  repairs-table
  my-build-energy-consumed
  my-repair-energy-consumed
  my-walk-energy-consumed
  my-basal-energy-consumed
  my-total-energy-intake
  my-offspring-produced
]
resources-own [
  current-supply
  resource-capacity
  regrow-rate
  baseline-regrow-rate
  baseline-resource-capacity
]
links-own [
  link-resistance
  mean-resistance
  decay-rate
  link-crossing-count
  under-construction?
  past-lifespan?
  patches-list
]
patches-own [
  under-link?
  embodied-energy
  initial-patch-resistance
  current-patch-resistance
  patch-crossing-count
]

to setup
  clear-all
  ifelse my-seed != 0 and round my-seed = my-seed [ set this-seed my-seed ] [ set this-seed new-seed ]
  random-seed this-seed
  set patches-between-resources-tbl table:make
  make-patches
  make-resources
  make-consumers
  set is-pulsing? false
  set pulse-timer 0
  if resource-growth-regime = "seasonal" [
    set season 1
    set season-timer season-one-length
  ]
  reset-ticks
  record-all-consumers-states
  record-all-patches-states
  record-all-link-states
end 

to go
  if count consumers = 0 [ stop ]
  ; Update resource capacity and growth rate for pulsing and seasonal resources
  if resource-growth-regime = "pulsing" or resource-growth-regime = "seasonal" [ update-resources ]
  ; Consume energy required for basal metabolism and update vision radius
  update-energy-stores
  update-vision-radius
  ifelse early-mover-advantage? = true [
    ; Sort by energy reserves so 'wealthiest' agents decide and act first
    foreach sort-on [ (- energy-reserves) ] consumers [ the-consumer ->
      ; All consumers who are not currently building, repairing, or walking should choose and initiate a new action
      ifelse [ building? ] of the-consumer = false and [ repairing? ] of the-consumer = false and [ walking? ] of the-consumer = false [
        ask the-consumer [
          build-action-table
          initiate-action max-utility-action
        ]
      ] [
        ; Consumers who are building/repairing/walking should continue their actions
        ask the-consumer [
          build-or-move
        ]
      ]
    ]
  ] [
    ; Execute decision/action sequence in a random order
    ask consumers [
      ifelse building? = false and repairing? = false and walking? = false [
        ; Choose and initiate a new action
        build-action-table
        initiate-action max-utility-action
      ] [
        ; Continue existing actions
        build-or-move
      ]
    ]
  ]
  ; Consumers eat available resources, resources regrow, links decay, consumers spawn
  consume-resource
  regrow-resource
  check-construction-status
  decay-links
  spawn
  tick
;  record-all-consumers-states
;  record-all-patches-states
;  record-all-link-states
end 

; For checking timings

to profiler-go
  profiler:start
  repeat 250 [ go ]
  profiler:stop
  print profiler:report
  profiler:reset
end 

; Update the resource regrowth rates and capacities for pulsing and seasonal resources based on whether a pulse is occurring, or the season and 'date' within it, respectively
; Observer function

to update-resources
  if resource-growth-regime = "pulsing" [
    if is-pulsing? = false and random-float 1 < resource-pulse-probability [
      ; Start resource pulse and increase/decrease resources as applicable
      set is-pulsing? true
      set pulse-timer round random-exponential resource-pulse-mean-duration
      ask resources [
        set regrow-rate regrow-rate + (regrow-rate * regrow-rate-pct-change)
        set resource-capacity resource-capacity + (resource-capacity * resource-capacity-pct-change)
      ]
    ]
    if is-pulsing? = true and pulse-timer = 0 [
      ; Stop resource pulse and reset resources to baseline
      set is-pulsing? false
      ask resources [
        set regrow-rate baseline-regrow-rate
        set resource-capacity baseline-resource-capacity
      ]
    ]
    if is-pulsing? = true and pulse-timer > 0 [ set pulse-timer pulse-timer - 1 ]
  ]
  if resource-growth-regime = "seasonal" [
    ifelse season = 1 [
      ifelse season-timer > 0 [
        ifelse season-timer > season-one-length / 2 [
          ; Resources increasing during first half of season 1
          ask resources [
            set regrow-rate regrow-rate + (regrow-rate * (season-one-regrow-rate-change / season-one-length / 2))
            set resource-capacity resource-capacity + (resource-capacity * (season-one-capacity-change / season-one-length / 2))
          ]
        ] [
          ; Resources decreasing during second half of season 1
          ask resources [
            set regrow-rate regrow-rate - (regrow-rate * (season-one-regrow-rate-change / season-one-length / 2))
            set resource-capacity resource-capacity - (resource-capacity * (season-one-capacity-change / season-one-length / 2))
          ]
        ]
      ] [
        ; Change to season 2, change timer to season 2 length (+1 for in-between-seasons timestep)
        set season 2
        set season-timer season-two-length + 1
      ]
    ] [
      ifelse season-timer > 0 [
        ifelse season-timer > season-two-length / 2 [
          ; Resources decreasing during first half of season 2 (season-two-regrow-rate-change and season-two-capacity-change are negative)
          ask resources [
            set regrow-rate regrow-rate + (regrow-rate * (season-two-regrow-rate-change / season-two-length / 2))
            set resource-capacity resource-capacity + (resource-capacity * (season-two-capacity-change / season-two-length / 2))
          ]
        ] [
          ; Resources increasing during second half of season 2
          ask resources [
            set regrow-rate regrow-rate - (regrow-rate * (season-two-regrow-rate-change / season-two-length / 2))
            set resource-capacity resource-capacity - (resource-capacity * (season-two-capacity-change / season-two-length / 2))
          ]
        ]
      ] [
        ; Change to season 1,  change timer to season 1 length (+1 for in-between-seasons timestep)
        set season 1
        set season-timer season-one-length + 1
      ]
    ]
    set season-timer season-timer - 1
  ]
end 

; Update vision radius to match current energy reserves
; Observer function

to update-vision-radius
  ask consumers [
    set vision-radius risk-penchant * energy-reserves
  ]
end 

; Regrow non-finite resources by regrow-rate units, up to (but not more than) full capacity
; Observer function

to regrow-resource
  if resource-growth-regime != "finite" [
    ask resources with [ current-supply < resource-capacity ] [
      ifelse resource-growth-regime = "fixed" [
        ; Always regrow to full capacity
        set current-supply resource-capacity
      ] [
        ifelse current-supply + regrow-rate <= resource-capacity [
          ; Fill up by regrow-rate units
          set current-supply current-supply + regrow-rate
          set total-regrowth total-regrowth + regrow-rate
        ] [
          ; Fill up to full capacity but not beyond that
          set total-regrowth total-regrowth + (resource-capacity - current-supply)
          set current-supply resource-capacity
        ]
      ]
    ]
  ]
end 

; Build action table - list of all resources in vision radius and the energy return from accessing them,
;  via building a new link, or repairing and/or walking an existing link.
; Consumer function - executed by consumers who are not already building or walking a link.

to build-action-table
  ; Clear tables
  table:clear current-intake-table
  table:clear current-access-table
  table:clear exp-consumption-table
  table:clear costs-table
  table:clear repairs-table
  let my-patch patch-here

  ; Make a list of all resources in field of vision, not including resource you're on - that is counted separately later
  let visible-resources (resources in-radius vision-radius) with [ patch-here != my-patch ]
  ; Split visible resources list by whether there is a link to them or not
  let linked-resources visible-resources with [ link-neighbor? [ location ] of myself = true ]
  let non-linked-resources visible-resources with [ link-neighbor? [ location ] of myself = false ]

  ; Calculate expected consumption if staying at current resource
  ask location [
    table:put [ current-intake-table ] of myself (word who "-stay") (list self expected-consumption-current-resource
      [ consumption-rate ] of myself
      [ time-horizon ] of myself)
  ]

  ask linked-resources [
    let link-to link [ who ] of [ location ] of myself who
    ; If link is not under construction or past lifespan, calculate expected cost and consumption from repair and walk
    ifelse ([ under-construction? ] of link-to = false and [ past-lifespan? ] of link-to = false) [
      ; If link is reparable, check repair costs
      if [ mean-resistance ] of link-to > 1 [
        ; Calculate expected costs and consumption of repair
        let repair-costs-returns calc-repair-cost
          [ location ] of myself
          [ basal-metabolism ] of myself
          [ time-horizon ] of myself
        let repair-returns item 0 repair-costs-returns
        let repair-costs item 1 repair-costs-returns
        table:put [ costs-table ] of myself (word who "-repair") (list self "repair" repair-costs)
        table:put [ repairs-table ] of myself (word who "-repair") repair-returns
        table:put [ exp-consumption-table ] of myself (word who "-repair") (list self "repair" expected-consumption-other-resource
          [ link-length ] of link-to
          [ consumption-rate ] of myself
          [ time-horizon ] of myself)
      ]

      ; Calculate expected costs and consumption of walk
      table:put [ costs-table ] of myself (word who "-walk") (list self "walk" calc-walk-cost
        link-to
        [ time-horizon ] of myself)
      table:put [ exp-consumption-table ] of myself (word who "-walk") (list self "walk" expected-consumption-other-resource
        [ link-length ] of link-to
        [ consumption-rate ] of myself
        [ time-horizon ] of myself)

    ] [
      if [ past-lifespan? ] of link-to = false [
        ; Calculate expected costs of helping build the link
        table:put [ costs-table ] of myself (word who "-help-build") (list self "help-build" calc-help-build-cost
          [ location ] of myself
          [ time-horizon ] of myself)

        ; Calculate expected consumption
        table:put [ exp-consumption-table ] of myself (word who "-help-build") (list self "help-build" expected-consumption-other-resource
          distance myself
          [ consumption-rate ] of myself
          [ time-horizon ] of myself)
      ]
    ]
  ]

  ask non-linked-resources [
    ; Calculate expected costs of building a link
    table:put [ costs-table ] of myself (word who "-build") (list self "build" calc-build-cost
      [ location ] of myself
      [ time-horizon ] of myself)

    ; Calculate expected consumption
    table:put [ exp-consumption-table ] of myself (word who "-build") (list self "build" expected-consumption-other-resource
      distance myself
      [ consumption-rate ] of myself
      [ time-horizon ] of myself)
  ]
end 

; Consumer procedure to initiate whatever action it chose (passed as list in action-data parameter)

to initiate-action [ action-data ]
  let action item 1 action-data
  let target-resource item 2 action-data
  set target-location target-resource
  face target-location

  (ifelse
    action = "build" [
      start-build
    ]
    action = "help-build" [
      start-help-build
    ]
    action = "repair" [
      start-repair
    ]
    action = "walk" [
      start-walk
  ])
end 

; Consumer function to initiate walking a link, first checking that the link exists

to start-walk
  let this-link link [ who ] of location [ who ] of target-location
  let reverse-link link [ who ] of target-location [ who ] of location
  if this-link != nobody and reverse-link != nobody [ set walking? true ]
end 

; Consumer function to initate building a link

to start-build
  set building? true
  ; Build link objects (two directed links)
  ask location [
    make-link self [ target-location ] of myself
    make-link [ target-location ] of myself self
  ]
  let this-link link [ who ] of location [ who ] of target-location
  let reverse-link link [ who ] of target-location [ who ] of location
  ; Build link over patch of resource currently located on
  let energy-used [ current-patch-resistance ] of patch-here - 1
  ; Update consumer's energy reserves and total/consumer build energy used tally
  set energy-reserves energy-reserves - energy-used
  set build-energy-consumed build-energy-consumed + energy-used
  set my-build-energy-consumed my-build-energy-consumed + energy-used
  ; Update patch resistance
  ask patch-here [
    set under-link? true
    set current-patch-resistance 1
    set embodied-energy embodied-energy + energy-used
    set patch-crossing-count patch-crossing-count + 1
  ]
  ; Update resistance arrays of link objects - first item for this-link and last item for reverse-link
  ask this-link [ set link-resistance replace-item 0 link-resistance 1 ]
  ask reverse-link [ set link-resistance replace-item (length link-resistance - 1) link-resistance 1 ]
end 

; Consumer function to initiate help-build action, starting with patch of current location

to start-help-build
  set building? true
  if [ under-link? = false ] of patch-here [
    let energy-used [ current-patch-resistance ] of patch-here - 1
    set energy-reserves energy-reserves - energy-used
    set build-energy-consumed build-energy-consumed + energy-used
    set my-build-energy-consumed my-build-energy-consumed + energy-used
    ask patch-here [
      set under-link? true
      set current-patch-resistance 1
      set embodied-energy embodied-energy + energy-used
      set patch-crossing-count patch-crossing-count + 1
    ]
  ]
end 

; Consumer procedure to initiate repair action, starting by repairing patch of current location

to start-repair
  set repairing? true
  let this-link link [ who ] of location [ who ] of target-location
  let reverse-link link [ who ] of target-location [ who ] of location
  ; Check to make sure link still exists (only an issue for the first fix, link won't be deleted once consumer has started repairing it)
  ifelse this-link != nobody and reverse-link != nobody [
    ; Fix patch of resource currently located on
    let energy-used [ current-patch-resistance ] of patch-here - 1
    ; Update consumer's energy reserves and total repair energy used tally
    set energy-reserves energy-reserves - energy-used
    set repair-energy-consumed repair-energy-consumed + energy-used
    set my-repair-energy-consumed my-repair-energy-consumed + energy-used
    ; Update patch resistance
    ask patch-here [
      set current-patch-resistance 1
      set embodied-energy embodied-energy + energy-used
      set patch-crossing-count patch-crossing-count + 1
    ]
    ; Update resistance arrays of link objects - first item for this-link and last item for reverse-link
    ask this-link [ set link-resistance replace-item 0 link-resistance 1 ]
    ask reverse-link [ set link-resistance replace-item (length link-resistance - 1) link-resistance 1 ]
  ] [
    set repairing? false
  ]
end 

; Consumer procedure to continue executing building and walking actions that are already happening,
;  or switch from building to walking once construction or repair is complete

to build-or-move
  (ifelse building? = true [ build ]
    walking? = true [ walk ]
    repairing? = true [ repair ])
end 

; Consumer procedure to continue walking on an existing link

to walk
  let this-link link [ who ] of location [ who ] of target-location
  let reverse-link link [ who ] of target-location [ who ] of location
  ; Check to make sure link still exists (only an issue for the first step, otherwise link won't be deleted once consumer is crossing it)
  ifelse this-link != nobody and reverse-link != nobody [
    let next-patch item (position patch-here [ patches-list ] of this-link + 1) [ patches-list ] of this-link
    ; If consumer doesn't have the energy to keep moving, it dies, but link still updates crossing count
    if energy-reserves <= ([ current-patch-resistance ] of next-patch) [
      ask this-link [ set link-crossing-count link-crossing-count + 1 ]
      ask reverse-link [ set link-crossing-count link-crossing-count + 1 ]
      die
    ]
    ; Take another step toward target
    move-to next-patch
    ; Consume energy: resistance ( * 1 step)
    let energy-used [ current-patch-resistance ] of patch-here
    set energy-reserves energy-reserves - energy-used
    ; Increase total walk energy used tally
    set walk-energy-consumed walk-energy-consumed + energy-used
    set my-walk-energy-consumed my-walk-energy-consumed + energy-used
    ; Update crossing count of current patch
    ask patch-here [ set patch-crossing-count patch-crossing-count + 1 ]
    ; Check if consumer has reached target location
    if patch-here = [ patch-here ] of target-location [
      ; Update crossing count of links
      ask this-link [ set link-crossing-count link-crossing-count + 1 ]
      ask reverse-link [ set link-crossing-count link-crossing-count + 1 ]
      ; Set consumer's walking flag to false and update location
      set location target-location
      set walking? false
    ]
  ] [
    ; Link doesn't exist anymore (decayed away) - stop walking and pick a new action in next timestep
    set walking? false
  ]
end 

; Consumer procedure to continue walking/building a link

to build
  let this-link link [ who ] of location [ who ] of target-location
  let reverse-link link [ who ] of target-location [ who ] of location
  let next-patch item (position patch-here [ patches-list ] of this-link + 1) [ patches-list ] of this-link
  ; If consumer doesn't have the energy to keep moving, it dies, and link remains under construction
  if ([ under-link? ] of next-patch = true and energy-reserves <= ([ current-patch-resistance ] of next-patch) or
    energy-reserves <= ([ current-patch-resistance ] of next-patch - 1)) [
    ask this-link [ set link-crossing-count link-crossing-count + 1 ]
    ask reverse-link [ set link-crossing-count link-crossing-count + 1 ]
    die
  ]
  ; Keep moving toward target location
  move-to next-patch
  let array-pos position patch-here [ patches-list ] of this-link
  let reverse-array-pos length [ patches-list ] of reverse-link - array-pos - 1
  ifelse [ under-link? ] of patch-here = false [
    ; Consume energy for building from reserves
    let energy-used [ current-patch-resistance ] of patch-here - 1
    set energy-reserves energy-reserves - energy-used
    set build-energy-consumed build-energy-consumed + energy-used
    set my-build-energy-consumed my-build-energy-consumed + energy-used
    ask patch-here [
      set under-link? true
      set embodied-energy embodied-energy + energy-used
      set current-patch-resistance 1
      set patch-crossing-count patch-crossing-count + 1
    ]
  ] [
    ; Consumer doesn't have to build this link-patch - consume energy for walking from reserves
    let energy-used [ current-patch-resistance ] of patch-here
    set energy-reserves energy-reserves - energy-used
    ; Increase total walk energy consumed tally (since not building)
    set walk-energy-consumed walk-energy-consumed + energy-used
    set my-walk-energy-consumed my-walk-energy-consumed + energy-used
  ]
  ; Check whether both this-link and reverse-link store the same patch for this position - not always if link is on a diagonal
  if not member? item reverse-array-pos [ patches-list ] of reverse-link [ patches-list ] of this-link [
    let reverse-link-patch item reverse-array-pos [ patches-list ] of reverse-link
    ; Check if reverse-link's patch at this point in the link needs to be built as well
    if [ under-link? ] of reverse-link-patch = false [
      ; If the patch needs building but consumer doesn't have enough energy to build, it increments links' crossing counts then dies
      if energy-reserves <= ([ current-patch-resistance ] of reverse-link-patch - 1) [
        ask this-link [ set link-crossing-count link-crossing-count + 1 ]
        ask reverse-link [ set link-crossing-count link-crossing-count + 1 ]
        die
      ]
      ; Consume energy for building from reserves (but not crossing since this isn't the patch being crossed)
      let energy-used [ current-patch-resistance ] of reverse-link-patch - 1
      set energy-reserves energy-reserves - energy-used
      set build-energy-consumed build-energy-consumed + energy-used
      set my-build-energy-consumed my-build-energy-consumed + energy-used
      ask reverse-link-patch [
        set under-link? true
        set embodied-energy embodied-energy + energy-used
        set current-patch-resistance 1
      ]
    ]
  ]
  ; Update link resistance arrays and mean resistance
  ask this-link [
    set link-resistance replace-item array-pos link-resistance 1
    set mean-resistance mean link-resistance
  ]
  ask reverse-link [
    set link-resistance replace-item reverse-array-pos link-resistance 1
    set mean-resistance mean link-resistance
  ]
  ; Check if consumer has reached target location
  if patch-here = [ patch-here ] of target-location [
    ; Update links' crossing counts
    ask this-link [ set link-crossing-count link-crossing-count + 1 ]
    ask reverse-link [ set link-crossing-count link-crossing-count + 1 ]
    ; Update building flag and working timer, whether construction completed by this consumer or another
    set building? false
    set location target-location
  ]
end 

; Consumer procedure to continue walking/repairing a link

to repair
  let this-link link [ who ] of location [ who ] of target-location
  let reverse-link link [ who ] of target-location [ who ] of location
  let next-patch item (position patch-here [ patches-list ] of this-link + 1) [ patches-list ] of this-link
  ; If consumer doesn't have the energy to keep moving, it dies, but link still updates crossing count
  if energy-reserves <= ([ current-patch-resistance ] of next-patch - 1) [
    ask this-link [ set link-crossing-count link-crossing-count + 1 ]
    ask reverse-link [ set link-crossing-count link-crossing-count + 1 ]
    die
  ]
  move-to next-patch
  let array-pos position patch-here [ patches-list ] of this-link
  let reverse-array-pos length [ patches-list ] of reverse-link - array-pos - 1
  ; Update consumer energy reserves
  let energy-used 0
  ifelse [ current-patch-resistance ] of patch-here > 1 [
    ; Patch requires repair - remove energy for repairs, walking (over repaired link) from consumer's energy store
    set energy-used [ current-patch-resistance ] of patch-here - 1
    ; Update consumer energy stores
    set energy-reserves energy-reserves - energy-used
    set repair-energy-consumed repair-energy-consumed + energy-used
    set my-repair-energy-consumed my-repair-energy-consumed + energy-used
    ; Update patch resistance
    ask patch-here [
      set current-patch-resistance 1
      set embodied-energy embodied-energy + energy-used
      set patch-crossing-count patch-crossing-count + 1
    ]
  ] [
    ; Patch has already been repaired, just walk across it
    set energy-used [ current-patch-resistance ] of patch-here
    set energy-reserves energy-reserves - energy-used
    ; Increase total walk energy consumed tally (since not repairing)
    set walk-energy-consumed walk-energy-consumed + energy-used
    set my-walk-energy-consumed my-walk-energy-consumed + energy-used
  ]
  ; Check whether reverse-link stores the same patch for this position - not always if link is on a diagonal
  if not member? item reverse-array-pos [ patches-list ] of reverse-link [ patches-list ] of this-link [
    let reverse-link-patch item reverse-array-pos [ patches-list ] of reverse-link
    if [ current-patch-resistance ] of reverse-link-patch > 1 [
      if energy-reserves <= ([ current-patch-resistance ] of reverse-link-patch - 1) [
        ask this-link [ set link-crossing-count link-crossing-count + 1 ]
        ask reverse-link [ set link-crossing-count link-crossing-count + 1 ]
        die
      ]
      ; Patch requires repair - remove energy for repairs (but not walking - already did that) from consumer's energy store
      set energy-used [ current-patch-resistance ] of reverse-link-patch - 1
      ; Update consumer energy stores
      set energy-reserves energy-reserves - energy-used
      set repair-energy-consumed repair-energy-consumed + energy-used
      set my-repair-energy-consumed my-repair-energy-consumed + energy-used
      ; Update patch resistance and crossing count for other patch
      ask reverse-link-patch [
        set current-patch-resistance 1
        set embodied-energy embodied-energy + energy-used
      ]
    ]
  ]
  ; Update link resistance arrays and mean resistance
  ask this-link [
    set link-resistance replace-item array-pos link-resistance 1
    set mean-resistance mean link-resistance
  ]
  ask reverse-link [
    set link-resistance replace-item reverse-array-pos link-resistance 1
    set mean-resistance mean link-resistance
  ]
  ; Check if consumer has reached target location
  if patch-here = [ patch-here ] of target-location [
    ; Update crossing count of links
    ask this-link [ set link-crossing-count link-crossing-count + 1 ]
    ask reverse-link [ set link-crossing-count link-crossing-count + 1 ]
    ; Update consumer's repairing? flag and location status (done last to avoid messing up this-link variable)
    set repairing? false
    set location target-location
  ]
end 

; Consumers who are located on resources (including those currently building links) consume them
; If there is more than one consumer on a resource node, they split the energy that is available at that node.
; Written from perspective of resource to simplify sharing process.

to consume-resource
  ; Only check resources that have energy supply for consumers to take, and where there are consumers
  ask resources with [ current-supply > 0 and any? consumers-here ] [
    ; Check how much resource is required by all consumers
    let total-resource-req sum [ consumption-rate ] of consumers-here
    ifelse total-resource-req <= current-supply [
      ; If there's enough resource, let everyone take their fill
      ask consumers-here [
        set energy-reserves energy-reserves + consumption-rate
        set my-total-energy-intake my-total-energy-intake + consumption-rate
      ]
      ; Deplete resource by what is consumed
      set current-supply current-supply - total-resource-req
      set total-energy-intake total-energy-intake + total-resource-req
    ] [
      ; If there's not enough for everyone to take their fill, have consumers split what's available
      ; In equal-sharing scenario, consumers split what is available equally
      ; Equal sharing also occurs if all consumers are starving
      ifelse equal-sharing? = true or sum [ energy-reserves ] of consumers-here = 0 [
        let total-taken-resource 0
        let split-supply current-supply / count consumers-here
        ask consumers-here [
          ; Consumers can still only take up to their consumption rate
          let my-taken-resource min (list split-supply consumption-rate)
          set energy-reserves energy-reserves + my-taken-resource
          set total-taken-resource total-taken-resource + my-taken-resource
          set my-total-energy-intake my-total-energy-intake + my-taken-resource
        ]
        ; Drain resource by amount taken (there may be some left over if consumers are allotted more than their consumption rate)
        set current-supply current-supply - total-taken-resource
        set total-energy-intake total-energy-intake + total-taken-resource
      ] [
        ; In unequal-sharing scenario, consumers split what is available, but weighted by energy reserves already held (i.e. 'rich get richer')
        let total-taken-resource 0
        let total-resources-held sum [ energy-reserves ] of consumers-here
        ask consumers-here [
          ; Consumers can still only take up to their consumption rate
          let my-taken-resource min (list (energy-reserves / total-resources-held * [ current-supply ] of myself) consumption-rate)
          set energy-reserves energy-reserves + my-taken-resource
          set total-taken-resource total-taken-resource + my-taken-resource
          set my-total-energy-intake my-total-energy-intake + my-taken-resource
        ]
        ; Drain resource by amount taken (there may be some left over if consumers are allotted more than their consumption rate)
        set current-supply current-supply - total-taken-resource
        set total-energy-intake total-energy-intake + total-taken-resource
      ]
    ]
  ]
end 

; Consumer function to take their basal metabolism from energy reserves each timestep

to update-energy-stores
  ask consumers [
    ; If consumer has enough energy to maintain basal functioning, it consumes the energy from reserves
    ifelse energy-reserves >= basal-metabolism [
      set energy-reserves energy-reserves - basal-metabolism
      ; Increase consumer's total basal energy consumed tally
      set basal-energy-consumed basal-energy-consumed + basal-metabolism
      set my-basal-energy-consumed my-basal-energy-consumed + basal-metabolism
    ][
      ; Otherwise, the consumer dies
      die
    ]
  ]
end 

; Observer procedure to decay link-patches each timestep proportionally to the embodied energy (energy invested for building and repairs that hasn't been decayed),
;    and update link objects to match

to decay-links
  ask patches [
    if embodied-energy > 1 [
      set embodied-energy max list 1 (embodied-energy - link-decay-rate * embodied-energy)
    ]
    if current-patch-resistance < initial-patch-resistance [
      set current-patch-resistance min list (initial-patch-resistance / embodied-energy) initial-patch-resistance
    ]
  ]
  ask links [
    set link-resistance []
    foreach ( patches-list ) [ the-patch ->
      ; Add new resistance of this patch to the link-resistance array
      set link-resistance lput [ current-patch-resistance ] of the-patch link-resistance
    ]
    ; If all patches on link have decayed to their initial resistance, and the link is not under construction, mark it as past-lifespan
    let patches-list-as-set patch-set patches-list
    ifelse all? patches-list-as-set [ current-patch-resistance = initial-patch-resistance ] and under-construction? = false [
      set past-lifespan? true
    ] [
      ; If a link has been marked as past-lifespan but was then repaired so not all patches are at initial resistance, turn off flag
      set past-lifespan? false
    ]
    ; Update resistance array and mean resistance of link object
    set mean-resistance mean link-resistance
    ; If link is past lifespan, check that no agents are crossing it, then kill it
    if max-link-lifespan? = true and past-lifespan? = true [
      let reverse-link link [ who ] of end2 [ who ] of end1
      if reverse-link != nobody [
        ask reverse-link [ set past-lifespan? true ]
      ]
      ; Once there are no more consumers on that link's patches (besides start and end patches, which are resource patches) or starting to cross it, it dies
      if (not any? consumers-on patch-set but-first but-last patches-list and
        not any? consumers with [ (location = [ end1 ] of myself and target-location = [ end2 ] of myself) or (location = [ end2 ] of myself and target-location = [ end1 ] of myself) ] and
        (reverse-link = nobody or empty? [ patches-list ] of reverse-link or not any? consumers-on patch-set but-first but-last [ patches-list ] of reverse-link)) [
        ; Loop through patches list and remove patches from reverse-link, then check if they're on any other links' patches-lists - if not, set under-link as false
        foreach patches-list [ p ->
          if not empty? [ patches-list ] of reverse-link and member? p [ patches-list ] of reverse-link [
            ask reverse-link [ set patches-list remove p patches-list ]
          ]
          ifelse length [ patches-list ] of other links = 1 [
            let other-links-patches reduce sentence [ patches-list ] of other links
            if not empty? other-links-patches and not member? p other-links-patches [
              ask p [ set under-link? false ]
            ]
          ] [
            let other-links-patches reduce sentence reduce sentence [ patches-list ] of other links
            if not empty? other-links-patches and not member? p other-links-patches [
              ask p [ set under-link? false ]
            ]
          ]
        ]
        if reverse-link != nobody [
          ask reverse-link [
            ; If there are any patches on reverse-link's list that haven't been removed yet, check if they're on any other links' patches-lists, and if not, set under-link as false
            if not empty? patches-list [
              let other-links-patches reduce sentence reduce sentence [ patches-list ] of other links
              ifelse empty? other-links-patches [
                ask patch-set patches-list [ set under-link? false ]
              ] [
                foreach patches-list [ p ->
                  if not member? p other-links-patches [
                    ask p [ set under-link? false ]
                  ]
                ]
              ]
            ]
            die
          ]
        ]
        die
      ]
    ]
  ]
end 

; Observer procedure to check the construction status of links, and update any that have been completed through collaboration
;  (e.g. agents starting at opposite ends and meeting in middle)

to check-construction-status
  ask links with [ under-construction? = true ] [
    ; If all patches are listed as 'under link' then the link is no longer under construction
    if all? patch-set patches-list [ under-link? = true ] [
      set under-construction? false
    ]
  ]
end 

; --------------------------------------------------------- ;
;            Action table reporter functions                ;
; --------------------------------------------------------- ;

; Resource procedure to calculate expected intake for a consumer located at that resource

to-report expected-consumption-current-resource [ my-consumption-rate my-time-horizon ]
  ; Calculate current resource supply (renamed so as not to overwrite actual value), total demand
  let current-resource-supply current-supply
  let total-demand sum [ consumption-rate ] of consumers-here
  let exp-consumption []
  ; Calculate expected consumption at each step in time horizon
  foreach n-values my-time-horizon [t -> t + 1] [t ->
    ifelse current-resource-supply > total-demand [
      ; If there is enough resource, expect to consume full consumption rate
      set exp-consumption lput my-consumption-rate exp-consumption
      ; Update resource supply
      set current-resource-supply current-resource-supply - total-demand + regrow-rate
    ][
      ; If there's not enough resource, expect to consume proportion of consumption rate (assumes equal sharing)
      set exp-consumption lput min (list my-consumption-rate ((current-resource-supply / total-demand) * my-consumption-rate)) exp-consumption
      ; Update resource supply - assume resource was drained
      set current-resource-supply regrow-rate
    ]
  ]
  report exp-consumption
end 

; Resource procedure to calculate expected intake for a consumer located at that resource
; Assumes no other consumers present, and consumer does not know resource's regrow rate

to-report expected-consumption-other-resource [ walk-time my-consumption-rate my-time-horizon ]
  ; Calculate how many timesteps resource could support consumer eating at full consumption rate
  let timesteps-full-consumption current-supply / my-consumption-rate
  let exp-consumption []
  ; Calculate expected consumption for each step in time horizon
  foreach n-values my-time-horizon [ t -> t + 1 ] [ t ->
    set exp-consumption lput (ifelse-value
      t <= walk-time [ 0 ] ; Consumer is building/repairing, walking link
      t > walk-time and t <= walk-time + timesteps-full-consumption [ my-consumption-rate ] ; Consumer is eating at full consumption rate
      [ 0 ]) exp-consumption ; Resource has run out (since consumer assumed not to know regrow rate)
  ]
  report exp-consumption
end 

; Resource procedure to calculate expected costs of building link to this resource, using mean patch resistance between consumer and this resource

to-report calc-build-cost [ start-loc my-time-horizon ]
  let patches-to-cross table:get patches-between-resources-tbl (word [ who ] of start-loc ":" who)
  let reverse-patches table:get patches-between-resources-tbl (word who ":" [ who ] of start-loc)
  let l length patches-to-cross
  ; Check whether there are any differences between lists - would indicate that the links cross 2 patches at certain points (common for diagonal links)
  let extra-build-costs []
  ifelse (sort patches-to-cross != sort reverse-patches) [
    foreach reverse-patches [ p ->
      ; If the patch isn't in the list of those crossed by this link, add it to front of list (since order is reversed) - otherwise will be built when this link is built
      ifelse not member? p patches-to-cross [
        set extra-build-costs fput ([ current-patch-resistance ] of p - 1) extra-build-costs
      ] [
        set extra-build-costs fput 0 extra-build-costs
      ]
    ]
  ] [
    set extra-build-costs n-values length reverse-patches [ 0 ]
  ]
  let exp-build-cost []
  ; Calculate expected build cost for each step in time horizon
  foreach n-values my-time-horizon [ t -> t ] [ t ->
    set exp-build-cost lput (ifelse-value
      t = 0 [ [ current-patch-resistance ] of item t patches-to-cross - 1 ] ; Decision stage and building link under current patch
      l - t > 0 [ [ current-patch-resistance ] of item t patches-to-cross - 1 + item t extra-build-costs ]; Building/walking link, possibly including >1 patch
      [ 0 ]) exp-build-cost ; Consumer has reached resource
  ]
  report exp-build-cost
end 

; Resource procedure to calculate expected costs of consumer assisting in building link to this resource (assuming another consumer has already
;   started the building from the other end, or has started building from this consumer's end but died en route).

to-report calc-help-build-cost [ start-loc my-time-horizon ]
  let patches-to-cross table:get patches-between-resources-tbl (word [ who ] of start-loc ":" who)
  let reverse-patches table:get patches-between-resources-tbl (word who ":" [ who ] of start-loc)
  let l length patches-to-cross
  ; Check whether there are any differences between lists - would indicate that the links cross 2 patches at certain points (common for diagonal links)
  let extra-build-costs []
  ifelse (sort patches-to-cross != sort reverse-patches) [
    foreach reverse-patches [ p ->
      ; If the patch isn't in the list of those crossed by this link, add it to front of list (since order is reversed) - otherwise will be built when this link is built
      ifelse not member? p patches-to-cross [
        set extra-build-costs fput ([ current-patch-resistance ] of p - 1) extra-build-costs
      ] [
        set extra-build-costs fput 0 extra-build-costs
      ]
    ]
  ] [
    set extra-build-costs n-values length reverse-patches [ 0 ]
  ]
  let patches-to-cross-set patch-set patches-to-cross
  let patches-to-build patches-to-cross-set with [ under-link? = false ]
  let exp-build-cost []
  ; Calculate expected build cost for each step in time horizon
  foreach n-values my-time-horizon [ t -> t ] [ t ->
    set exp-build-cost lput (ifelse-value
      t = 0 [ [ current-patch-resistance ] of item t patches-to-cross - 1 ] ; Decision stage and building link under current patch
      l - t > 0 and member? item t patches-to-cross patches-to-build [ [ current-patch-resistance ] of item t patches-to-cross - 1 + item t extra-build-costs ] ; Building/walking link, possibly including >1 patch
      l - t > 0 [ resistance-after-decay [ initial-patch-resistance ] of item t patches-to-cross [ embodied-energy ] of item t patches-to-cross t + item t extra-build-costs ] ; Consumer is walking link, possibly building patch on other side
      [ 0 ]) exp-build-cost ; Consumer has reached resource
  ]
  report exp-build-cost
end 

; Resource procedure to calculate expected costs of repairing an existing link to this resource

to-report calc-repair-cost [ start-loc basal-metab my-time-horizon ]
  let this-link link [ who ] of start-loc who
  let reverse-link link who [ who ] of start-loc
  let this-link-patches [ patches-list ] of this-link
  let reverse-link-patches [ patches-list ] of reverse-link
  let resistance-list [ link-resistance ] of this-link
  let l length reverse-link-patches
  let possible-reverse-repairs []
  ; Check if links include different patches (common for diagonal links) - if so, calculate possible repairs for any patches in reverse-link that aren't in this-link
  ifelse (sort [ patches-list ] of reverse-link != sort [ patches-list ] of this-link) [
    ; Calculate decay in reverse, since patches are in reverse order of when consumer will cross (next to) them
    let t length reverse-link-patches
    foreach reverse-link-patches [ p ->
      ; If the patch isn't in the list of those crossed by this-link, calculate its repair requirements (including decay) - otherwise will be repaired when this-link is repaired
      ifelse not member? p this-link-patches [
        set possible-reverse-repairs lput ((resistance-after-decay [ initial-patch-resistance ] of p [ embodied-energy ] of p t) - 1) possible-reverse-repairs
      ] [
        set possible-reverse-repairs lput 0 possible-reverse-repairs
      ]
      ; Decrement t either way to keep track of decay
      set t t - 1
    ]
  ] [
    set possible-reverse-repairs n-values length resistance-list [ 0 ]
  ]
  ; Calculate possible repairs for each patch in this-link: distance from current resistance to 1 (minimum resistance) + any accumulated decay while walking to that patch
  let possible-repairs (map [ [ p r t ] -> (resistance-after-decay [ initial-patch-resistance ] of p [ embodied-energy ] of p t) - 1 + r ]
    (this-link-patches) (possible-reverse-repairs) (n-values length this-link-patches [ t -> t ]))
  ; Calculate possible repairs divided by number of steps (since link length might be longer than number of patches for links on the diagonal)
  let exp-repair-cost []
  ; Calculate expected repairs array - per-step values are approximation since consumer might spend >1 step per patch but total should be equal
  foreach n-values my-time-horizon [ t -> t ][ t ->
    set exp-repair-cost lput (ifelse-value
      t = 0 [ first possible-repairs ] ; Decision stage and repair patch of current resource
      l - t > 0 [ item t possible-repairs ] ; Consumer is walking/repairing link
      [ 0 ]) exp-repair-cost ; Consumer has reached destination
  ]
  report (list possible-repairs exp-repair-cost)
end 

; Resource procedure to calculate expected costs of walking an existing link to this resource, using mean resistance

to-report calc-walk-cost [ this-link my-time-horizon ]
  let exp-walk-cost []
  let p [ patches-list ] of this-link
  let l length p
  ; Calculate expected costs for each step in time horizon
  foreach n-values my-time-horizon [ t -> t ] [ t ->
    set exp-walk-cost lput (ifelse-value
      t = 0 [ 0 ] ; Decision stage
      l - t > 0 [ resistance-after-decay [ initial-patch-resistance ] of item t p [ embodied-energy ] of item t p t ] ; Consumer is walking link
      [ 0 ]) exp-walk-cost ; Consumer has reached destination
  ]
  report exp-walk-cost
end 

; Consumer procedure to choose action with highest utility

to-report max-utility-action
  let sum-table table:make
  foreach (table:keys exp-consumption-table) [
    [key] -> let consumption-list table:get exp-consumption-table key
    ; Sum expected consumption and costs for each resource-acitivty pair
    let target-resource item 0 consumption-list
    let action item 1 consumption-list
    let consumption-utility utility item 2 consumption-list
    let costs-list item 2 table:get costs-table key
    let net-utility sum (map [ [ consumption cost ] -> consumption - cost ] consumption-utility costs-list)
    ; Subtract expected costs from expected consumption for each resource-activity pair
    table:put sum-table key (list action target-resource net-utility)
  ]
  ; Select resource-activity pair with highest expected consumption - expected cost difference
  ; Initialise max-return as expected consumption from current resource over time horizon as first comparator
  let max-return sum table:values current-intake-table
  let max-return-list (list word [ who ] of location "-stay" "stay" location max-return)
  ; Loop through table of net consumption calculated above and compare net consumption with current max return
  foreach (table:keys sum-table) [
    [key] -> let net-consumption item 2 table:get sum-table key
    if net-consumption > max-return [
      set max-return net-consumption
      set max-return-list (list key item 0 table:get sum-table key item 1 table:get sum-table key net-consumption)
    ]
  ]
  ; Return data about resource, action, and energetic returns
  report max-return-list
end 

; --------------------------------------------------------- ;
;               Assorted helper functions                   ;
; --------------------------------------------------------- ;

; Turtle or observer function to create a directed link from start-loc to end-loc and initialise all link variables

to make-link [ start-loc end-loc ]
  ask start-loc [
    create-link-to end-loc [
      set decay-rate link-decay-rate
      set link-crossing-count 0
      set under-construction? true
      set past-lifespan? false
      set color mean-resistance
      set shape "resource-link"
      set link-resistance []
    ]
  ]
  let this-link link [ who ] of start-loc [ who ] of end-loc
  ask this-link [
    set patches-list patches-under-link
  ]
  foreach [ patches-list ] of this-link [ the-patch ->
    let this-resistance [ current-patch-resistance ] of the-patch
    ask this-link [ set link-resistance lput this-resistance link-resistance ]
  ]
  ask this-link [
    set mean-resistance mean link-resistance
  ]
end 

; Link procedure to identify the patches it crosses, as a consumer walking along this link would cross them
;   (may not include all patches if only a corner is under the link and the consumer would 'skip' that segment as it strides forward by 1)

to-report patches-under-link
  let curr-xcor [ xcor ] of end1
  let curr-ycor [ ycor ] of end1
  let this-patch [ patch-here ] of end1
  let last-patch [ patch-here ] of end2
  let this-heading link-heading
  let link-patches []
  while [ this-patch != last-patch ] [
    if empty? link-patches or last link-patches != this-patch [
      set link-patches lput this-patch link-patches
    ]
    set curr-xcor curr-xcor + sin this-heading
    set curr-ycor curr-ycor + cos this-heading
    set this-patch patch curr-xcor curr-ycor
  ]
  set link-patches lput last-patch link-patches
  report link-patches
end 

; Procedure to identify patches between two resources - can be called by observer, consumer, resource, or link
;   Modified from patches-under-link

to-report patches-between-resources [ start-loc end-loc ]
  let curr-xcor [ xcor ] of start-loc
  let curr-ycor [ ycor ] of start-loc
  let this-patch [ patch-here ] of start-loc
  let last-patch [ patch-here ] of end-loc
  let this-heading 0
  ask this-patch [ set this-heading towards last-patch ]
  let link-patches []
  while [ this-patch != last-patch ] [
    if empty? link-patches or last link-patches != this-patch [
      set link-patches lput this-patch link-patches
    ]
    set curr-xcor curr-xcor + sin this-heading
    set curr-ycor curr-ycor + cos this-heading
    set this-patch patch curr-xcor curr-ycor
  ]
  set link-patches lput last-patch link-patches
  report link-patches
end 

; Consumer procedure to calculate discounted utility of consumption

to-report utility [ consumption-list ]
  ifelse rho = 1 [
    report (map [ [ c t ] -> ifelse-value c = 0 [ 0 ] [ (log c 10) + ((log c 10) ^ (- t)) ] ] (consumption-list) (n-values length consumption-list [ t -> t ]))
  ] [
    report (map [ [ c t ] -> ifelse-value c = 0 [ 0 ] [ ((c ^ (1 - rho) - 1) / (1 - rho)) * (1 + rho ^ (- t)) ] ] (consumption-list) (n-values length consumption-list [ t -> t ]))
  ]
end 

to-report resistance-after-decay [ baseline-r current-embodied-energy t ]
  report min list baseline-r (baseline-r / (current-embodied-energy * exp (- link-decay-rate * t)))
end 

; --------------------------------------------------------- ;
;                     Setup functions                       ;
; --------------------------------------------------------- ;

to make-patches
  ifelse not empty? patches-file and file-exists? patches-file [
    file-open patches-file
    ; Skip headers
    let headers file-read-line
    while [ not file-at-end? ] [
      let patch-data csv:from-row file-read-line
      let this-patch patch item 0 patch-data item 1 patch-data
      ask this-patch [
        ;set pcolor 59
        set under-link? false
        set embodied-energy 1
        set initial-patch-resistance (ifelse-value item 2 patch-data = 0 [ min-patch-resistance ] [ max (list min-patch-resistance (item 2 patch-data * max-patch-resistance)) ])
        set current-patch-resistance initial-patch-resistance
        set pcolor scale-color green initial-patch-resistance 10 0
        set patch-crossing-count 0
      ]
    ]
    file-close
  ] [
    ask patches [
      set pcolor 59
      set under-link? false
      set embodied-energy 1
      set initial-patch-resistance random (max-patch-resistance - min-patch-resistance) + min-patch-resistance
      set current-patch-resistance initial-patch-resistance
      set patch-crossing-count 0
    ]
  ]
end 

to make-resources
  ifelse not empty? resources-file and file-exists? resources-file [
    file-open resources-file
    ; Skip headers
    let headers file-read-line
    while [ not file-at-end? ] [
      let resource-data csv:from-row file-read-line
      create-resources 1 [
        setxy item 0 resource-data item 1 resource-data
        move-to patch-here
      ]
    ]
    file-close
  ] [
    print "No resource file listed, or no valid resources in file"
    stop
  ]
  ask resources [
    set baseline-regrow-rate (ifelse-value
      resource-growth-regime = "finite" [ 0 ]
      resource-growth-regime = "fixed" [ resource-capacity ]
      [ max list 1 (round random-normal mean-resource-regrow-rate sd-resource-regrow-rate) ])
    set color 26
    set shape "square"
    set baseline-resource-capacity max list 1 (round random-normal mean-resource-capacity sd-resource-capacity)
    set resource-capacity baseline-resource-capacity
    set current-supply resource-capacity
    set regrow-rate baseline-regrow-rate
  ]
  set total-regrowth 0
  ask resources [
    ask other resources [
      table:put patches-between-resources-tbl (word [ who ] of myself ":" who) patches-between-resources myself self
    ]
  ]
end 

to make-consumers
  create-consumers n-consumers [
    set color 103
    set shape "person"
    set initial-energy-reserves max list 1 (round random-normal mean-initial-energy-reserves sd-initial-energy-reserves)
    set energy-reserves initial-energy-reserves
    set basal-metabolism max list 0.01 random-normal mean-basal-metabolism sd-basal-metabolism
    set consumption-rate max list 1 (round random-normal mean-consumption-rate sd-consumption-rate)
    set risk-penchant max list 0.01 random-normal mean-risk-penchant sd-risk-penchant
    set vision-radius risk-penchant * energy-reserves
    set time-horizon max list 1 (round random-normal mean-time-horizon sd-time-horizon)
    set rho max list 0.01 random-normal mean-rho sd-rho
    set building? false
    set repairing? false
    set walking? false
    set current-intake-table table:make
    set current-access-table table:make
    set exp-consumption-table table:make
    set costs-table table:make
    set repairs-table table:make
    set my-build-energy-consumed 0
    set my-repair-energy-consumed 0
    set my-walk-energy-consumed 0
    set my-basal-energy-consumed 0
    set my-total-energy-intake 0
    set my-offspring-produced 0
    set location one-of resources
    set target-location location
    move-to location
  ]
  set initial-consumer-energy sum [ energy-reserves ] of consumers
end 

to spawn
  ask consumers with [ energy-reserves > ( initial-energy-reserves * 2 ) and walking? = false and building? = false and repairing? = false ] [
    let my-init-energy-reserves initial-energy-reserves
    ; Spawn a new consumer, set initial resource stock to the amount it took to spawn
    hatch-consumers 1 [
      set initial-energy-reserves my-init-energy-reserves
      set energy-reserves initial-energy-reserves
      set building? false
      set repairing? false
      set walking? false
      set target-location location
      set current-intake-table table:make
      set current-access-table table:make
      set exp-consumption-table table:make
      set costs-table table:make
      set repairs-table table:make
      set my-build-energy-consumed 0
      set my-repair-energy-consumed 0
      set my-walk-energy-consumed 0
      set my-basal-energy-consumed 0
      set my-total-energy-intake 0
      set my-offspring-produced 0
    ]
    ; Deplete parent's resource stock by the amount it took to spawn, update offspring counter
    set energy-reserves energy-reserves - initial-energy-reserves
    set my-offspring-produced my-offspring-produced + 1
  ]
end 

; --------------------------------------------------------- ;
;          Reporter functions for data collection           ;
; --------------------------------------------------------- ;

to-report total-link-length
  report sum [ link-length ] of links
end 

to-report total-link-repair
  report repair-energy-consumed
end 

to-report total-movement
  report walk-energy-consumed
end 

to record-all-consumers-states
  let consumer-output-file-bspace (word "x_" this-seed "_consumerdata.csv")
  if ticks = 0 and file-exists? consumer-output-file-bspace [ file-delete consumer-output-file-bspace ]
  file-open consumer-output-file-bspace
  if ticks = 0 [ file-print "ticks,consumer,x,y,energy_reserves,basal_metabolism,consumption_rate,risk_penchant,vision_radius,time_horizon,rho,is_building,is_repairing,is_walking,build_energy_consumed,repair_energy_consumed,walk_energy_consumed,basal_energy_consumed,total_energy_intake,offspring_produced" ]
  ask consumers [
    file-print (word ticks "," who "," xcor "," ycor "," energy-reserves "," basal-metabolism "," consumption-rate "," risk-penchant "," vision-radius "," time-horizon ","
      rho "," building? "," repairing? "," walking? "," my-build-energy-consumed "," my-repair-energy-consumed "," my-walk-energy-consumed "," my-basal-energy-consumed ","
      my-total-energy-intake "," my-offspring-produced)
  ]
  file-close
end 

to record-all-patches-states
  let patch-output-file-bspace (word "x_" this-seed "_patchdata.csv")
  if ticks = 0 and file-exists? patch-output-file-bspace [ file-delete patch-output-file-bspace ]
  file-open patch-output-file-bspace
  if ticks = 0 [ file-print "ticks,x,y,is_under_link,embodied_energy,initial_patch_resistance,current_patch_resistance,patch_crossing_count" ]
  ask patches [
    file-print (word ticks "," pxcor "," pycor "," under-link? "," embodied-energy "," initial-patch-resistance "," current-patch-resistance "," patch-crossing-count)
  ]
  file-close
end 

to record-all-link-states
  let link-output-file-bspace (word "x_" this-seed "_linkdata.csv")
  if ticks = 0 and file-exists? link-output-file-bspace [ file-delete link-output-file-bspace ]
  file-open link-output-file-bspace
  if ticks = 0 [ file-print "ticks,end1_xcor,end1_ycor,end2_xcor,end2_ycor,mean_resistance,decay_rate,link_crossing_count,is_under_construction,is_past_lifespan,straight_line_length,patch_count" ]
  ask links [
    file-print (word ticks "," [ xcor ] of end1 "," [ ycor ] of end1 "," [ xcor ] of end2 "," [ ycor ] of end2 "," mean-resistance "," decay-rate "," link-crossing-count "," under-construction? "," past-lifespan? "," link-length "," length patches-list)
  ]
  file-close
end 

; --------------------------------------------------------- ;
;                   Energy balance checks                   ;
; --------------------------------------------------------- ;

to-report consumer-energy-balance
  report (initial-consumer-energy + total-energy-intake) - ; input
  (build-energy-consumed + repair-energy-consumed + walk-energy-consumed + basal-energy-consumed + ; output
    sum [ energy-reserves ] of consumers) ; storage
end 

to-report resource-energy-balance
  report (sum [ resource-capacity ] of resources + total-regrowth) - ; input
  (total-energy-intake + ; output
    sum [ current-supply ] of resources) ; storage
end 

to-report total-energy-balance
  report (sum [ resource-capacity ] of resources + initial-consumer-energy + total-regrowth) - ; input
  (build-energy-consumed + repair-energy-consumed + walk-energy-consumed + basal-energy-consumed + ; output
    sum [ energy-reserves ] of consumers + sum [ current-supply ] of resources) ; storage
end 

There is only one version of this model, created almost 3 years ago by Natalie Davis.

Attached files

File Type Description Last updated
NetDevABM_ODD.docx word ODD for 'Network Development ABM' about 2 years ago, by Natalie Davis Download
Network Development ABM.png preview Preview for 'Network Development ABM' almost 3 years ago, by Natalie Davis Download
sample_patches.csv data Sample patches file almost 3 years ago, by Natalie Davis Download
sample_resources.csv data Sample resources file almost 3 years ago, by Natalie Davis Download

This model does not have any ancestors.

This model does not have any descendants.