FishCensus

FishCensus preview image

1 collaborator

Elphinstone_se_040 Miguel Pais (Author)

Tags

(This model has yet to be categorized with any tags)
Visible to everyone | Changeable by the author
Model was written in NetLogo 6.0 • Viewed 273 times • Downloaded 19 times • Run 0 times
Download the 'FishCensus' modelDownload this modelEmbed this model

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


Info tab cannot be displayed because of an encoding error

Comments and Questions

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

Click to Run Model

extensions [
  csv              ; used to import species parameters through a csv file

  rnd              ; used by fishes to calculate next behavior with a weighted random pick

  ]

;Global variables not represented on the interface tab


globals[
  world.area
  species.data              ; imported input data from the csv file

  nr.species                ; number of species in the csv file. Variable updated by the go procedure

  total.density
  wat.dens.value            ; just a step to calculate drag.formula for each species when fish are created

  numb.fishes
  timed.transect.diver.mean.speed
  distance.transect.diver.mean.speed
  transect.time.secs
  stationary.time.secs
  roving.time.secs
  roving.diver.mean.speed
  sampling.area
  persons                   ; an agentset of diver and buddy

  hours                     ; variables for the model clock

  minutes
  seconds
  real.densities
  snapshot.estimates
  density.estimates
  bias.estimates
  output.real              ; outputs for behaviorspace experiments (only works with 1st species in input file)

  output.estimated
  output.difference
  output.inaccuracy
  output.bias
  output.instantaneous
]

;Agent types


breed [fishes fish]

breed [divers diver]

breed [buddies buddy]

;Agent variables


fishes-own [                     ; fish variables

  drag.formula                   ; the coefficient used to calculate drag, given speed and fish size

  current.behavior               ; picked from behavior.list

  behavior.set?                  ; boolean that tells if fish has set its behavior this turn

  schoolmates                    ; for schooling species, agentset of nearby fishes

  velocity                       ; vector with x and y components determined by the previous velocity and the current acceleration at each step

  acceleration                   ; vector with x and y components, determined by the sum of all urges

  species                        ; this separates the different types within the fish breed. This is the variable recorded by divers while counting

  prey.type                      ; "benthic" or "fish". Defines the type of feeding behavior (gather around a patch or chase prey)

  detectability                  ; probability of being missed (if = 1 fish is always counted if within id.distance)

  visible?                       ; boolean variable that is set by detectability every second

  id.distance                    ; maximum distance from diver at which it is still possible to identify the species (and count the fish)

  approach.dist                  ; minimum distance from diver that the fish tolerate

  behavior.list                  ; list of up to 4 distinct behaviors

  behavior.freqs                 ; frequency of each behavior

  behavior.params                ; a list of lists with constants for the movement model per behavior

  picked.patch                   ; patch picked by the school to feed on (if prey is benthic)

  picked.patch.dist              ; maximum distance from the feeding patch

  patch.gathering.w              ; weighs the urge to gather at a feeding patch

  perception.dist                ; fish perception distance

  perception.angle               ; fish perception angle (360 for full directional awareness)

  max.sustained.speed            ; maximum attainable velocity with low energy consumption (cruise)

  burst.speed                    ; maximum attainable velocity with high energy consumption (chase and escape)

  max.acceleration               ; maximum attainable acceleration

  diver.avoidance.w              ; weighs the urge to avoid divers. If negative, fish are attracted to divers

  predator.avoidance.w           ; weighs the urge to avoid fish with prey.type = "fish"

  prey.chasing.w                 ; weighs the urge to chase other fish

  schoolmate.dist                ; distance among schoolmates in a school (in body lengths)

  align.w                        ; weighs the urge to match school direction

  center.w                       ; weighs the urge to stand between nearby schoolmates

  spacing.w                      ; weighs the urge to maintain crusing.distance from schoolmates

  wander.w                       ; weighs the urge to wander around randomly

  rest.w                         ; weighs the urge to stop and rest

  cruise.w                       ; wighs the urge to keep a constant speed and heading

  schooling?                     ; boolean variable that determines if fish exhibit schooling behavior

]


divers-own [             ; distance transect diver variables

  counted.fishes
  snapshot.fishes
  speed
  memory
  viewangle
  initial.ycor                   ; for distance transects

  final.ycor                     ; for distance transects

  finished?
]


;Interface procedures


to startup
  set file.name "example"
  set override.density 0
end 

to setup
  ca
  stop-inspecting-dead-agents                           ; clears diver detail windows from previous simulation runs

  output-print "Importing species data..."
  let full.file.name word file.name ".csv"
  carefully [set species.data (csv:from-file full.file.name file.delimiter)]                             ; import csv file into a list of lists

  [user-message (word "File " file.name " not found in model folder. Import the example.csv file or create one using the FishCensus species creator.") stop] ; ERROR MESSAGE

  if species.data = 0 [user-message "You need to import a dataset. Import the example.csv file or create one using the FishCensus species creator." stop] ; ERROR MESSAGE

  if length species.data < 2 [user-message "ERROR: input file has only 1 row or is empty. Check if input file has a header plus 1 line per species." stop] ; ERROR MESSAGE

  if length item 0 species.data != 82 [user-message "ERROR: unable to separate parameters in the file. Ensure the correct file delimiter was picked." stop] ; ERROR MESSAGE

  set nr.species length species.data - 1                                                            ; all filled lines minus the header

  set real.densities []                                                                             ; establishes real.densities as a list

  foreach n-values nr.species [[x] -> x + 1] [                                                      ; Fills real densities with data from file   UPDATED TO NEW CODE SYNTAX FOR NETLOGO 6.0

    [n] -> let sp.param item n species.data
  let real.dens.pair list item 0 sp.param item 4 sp.param
  set real.densities lput real.dens.pair real.densities
    ]
  if fixed.seed? [random-seed seed]
  output-print "Painting floor tiles..."
  ask patches with [pycor mod 2 = 0 and pxcor mod 2 = 0] [set pcolor 103]
  ask patches with [pycor mod 2 = 1 and pxcor mod 2 = 1] [set pcolor 103]
  ask patches with [pcolor = black] [set pcolor 105]
  set world.area world-height * world-width
  set transect.time.secs transect.time * 60             ; convert survey times from minutes to seconds

  set stationary.time.secs stationary.time * 60
  set roving.time.secs roving.time * 60
  set timed.transect.diver.mean.speed (timed.transect.diver.speed / 60)  ; these lines just convert interface speeds (in m/min) to m/s

  set distance.transect.diver.mean.speed (distance.transect.diver.speed / 60)
  set roving.diver.mean.speed (roving.diver.speed / 60)
  set density.estimates []                                               ; establish diver record lists

  set snapshot.estimates []
  set bias.estimates []
  set persons no-turtles                                                  ; resets the "persons" agentset (otherwise it would be set to 0 and generate errors during setup)


; for the timed transect, the sampled area is distance * width plus max visibility * width at the end (an approximation that ignores the fact that visibility is the radius of a circle).


  if sampling.method = "Fixed time transect" [
    set sampling.area timed.transect.width * (timed.transect.diver.mean.speed * transect.time.secs) + (timed.transect.width * max.visibility)
  ]

; for the distance transect, the sampled area is only distance * width


  if sampling.method = "Fixed distance transect" [
    set sampling.area distance.transect.width * transect.distance
  ]

; for the stationary diver, it is the area of the circle around the diver


  if sampling.method = "Stationary point count" [
    set sampling.area pi * stationary.radius ^ 2
  ]

; the roving diver only records counts, so sampling area can be set to 1


  if sampling.method = "Random path" [
    set sampling.area 1
  ]

; read the information stored in species.data to place fishes


  output-print "Placing fishes..."
  foreach n-values nr.species [[x] -> x + 1] [           ; loop that creates fish for each species and sets all fish variables

    [n] -> let sp.param item n species.data
    ifelse override.density = 0 [set total.density item 4 sp.param]
    [set total.density override.density]
    create-fishes (total.density * world.area) [
      setxy random-xcor random-ycor
      set velocity [0 0]
      set acceleration [0 0]
      set picked.patch false
      set schoolmates no-turtles                  ; sets schoolmates as an empty agentset

      set species item 0 sp.param
      if length sp.param != 82 [user-message (word "ERROR: species number " n " '" species "' has a parameter list that is incomplete or too long. Check file.") stop] ; ERROR MESSAGE

      set shape item 1 sp.param
      set size item 2 sp.param
      ifelse item 17 sp.param = "Seawater - 1027 Kg/m3" [set wat.dens.value 1027] [set wat.dens.value 1000]
      set drag.formula ((0.5 * (item 14 sp.param) * wat.dens.value * (((item 13 sp.param) * ((size * 100) ^ 2)) * 0.0001))/(((item 15 sp.param) * ((size * 100) ^ (item 16 sp.param))) * 0.001))   ; formula to calculate k in order to calculate the deceleration due to drag in the form of a = kv^2 (v for velocity).

      set color item 3 sp.param
      set id.distance item 5 sp.param
      set approach.dist item 6 sp.param
      set perception.dist item 7 sp.param
      set perception.angle item 8 sp.param
      set prey.type item 9 sp.param
      set max.acceleration item 10 sp.param
      set max.sustained.speed item 11 sp.param
      set burst.speed item 12 sp.param
      set behavior.list (list item 18 sp.param item 34 sp.param item 50 sp.param item 66 sp.param)
      set behavior.freqs (list item 19 sp.param item 35 sp.param item 51 sp.param item 67 sp.param)
      if reduce + behavior.freqs != 1 [
       user-message (word "ERROR! Behavior frequencies for " species " do not add up to 1.") stop]   ; ERROR MESSAGE

      set behavior.params (list                                ; lists parameter values for all 4 behaviors

        sublist sp.param 18 34
        sublist sp.param 34 50
        sublist sp.param 50 66
        sublist sp.param 66 82)
      set visible? true
      set behavior.set? false
      set.first.behavior                     ; fish procedure that picks the first behavior in behavior.list as the starting behavior and fills in parameters (this sets "visible?" depending on detectability of first behavior)

    ]
  ]
  set total.density (count fishes / world.area) ; this takes into account the actual number of fishes in the area, and not the original input number.

  set numb.fishes count fishes
  output-print (word "Imported " count fishes " fishes belonging to " nr.species " species,")
  output-print (word "with a total density of " total.density " fish per square meter.")
  output-print (word "Stabilizing fish movement for " initial.time.to.stabilize.movement " model seconds...")
  ask fishes [repeat movement.time.step * initial.time.to.stabilize.movement [do.fish.movement]] ; lets the fish movement model stabilize for a pre-determined amount of model seconds (20 by default).



  output-print "Placing diver..."

if sampling.method = "Fixed time transect" [                                         ;timed transect diver setup

  create-divers 1 [
 set heading 0
 set shape "diver"
 set color cyan
 set size 2
 setxy (world-width / 2) 5
 if show.paths? = true [pen-down]                                                           ;this shows the path of the diver

 set speed timed.transect.diver.mean.speed
 set viewangle transect.viewangle
 set counted.fishes [] ; sets counted.fishes as an empty list

 set snapshot.fishes ([species] of (fishes with [(xcor >= (world-width / 2) - timed.transect.width) and (xcor <= (world-width / 2) + timed.transect.width) and (ycor >= (world-height / 4)) and (ycor <= ((world-height / 4) + (transect.time * timed.transect.diver.speed)))]))
  ]
  if buddy? [
   create-buddies 1 [
    set heading 0
    set shape "diver"
    set color cyan
    set size 2
    setxy ([xcor] of one-of divers + 1) ([ycor] of one-of divers - 1)
   ]
  ]
]

if sampling.method = "Fixed distance transect" [                                         ;distance transect diver setup

  create-divers 1 [
 set heading 0
 set shape "diver"
 set color green
 set size 2
 setxy (world-width / 2) 5
 if show.paths? = true [pen-down]                                                           ;this shows the path of the diver

 set speed distance.transect.diver.mean.speed
 set viewangle transect.viewangle
 set initial.ycor ycor                                                              ; fixed distance transect divers record their start and end points as given by "transect.distance" initially

 set final.ycor ycor + transect.distance                                            ; because coordinates are in meters

 set counted.fishes [] ; sets counted.fishes as an empty list

 set snapshot.fishes ([species] of (fishes with [(xcor >= (world-width / 2) - distance.transect.width) and (xcor <= (world-width / 2) + distance.transect.width) and (ycor >= (world-height / 4)) and (ycor <= ((world-height / 4) + (transect.distance)))]))
  ]
  if buddy? [
   create-buddies 1 [
    set heading 0
    set shape "diver"
    set color green
    set size 2
    setxy ([xcor] of one-of divers + 1) ([ycor] of one-of divers - 1)
   ]
  ]
]

if sampling.method = "Stationary point count" [                                               ;stationary diver setup

  create-divers 1 [
 set heading 0
 set shape "diver"
 set color red
 set size 2
 setxy (world-width / 2) (world-height / 2)
 set viewangle stationary.viewangle
 set counted.fishes [] ; sets counted.fishes as an empty list

 set snapshot.fishes ([species] of (fishes in-radius stationary.radius))
]
  if buddy? [
   create-buddies 1 [
    set heading 0
    set shape "diver"
    set color red
    set size 2
    setxy ([xcor] of one-of divers + 1) ([ycor] of one-of divers - 1)
   ]
  ]
]

if sampling.method = "Random path" [                                                      ;roving diver setup

  create-divers 1 [
 set heading 0
 set shape "diver"
 set color magenta
 set size 2
 setxy (world-width / 2) 5
 if show.paths? = true [pen-down]                                                           ;this shows the path of the diver

 set speed roving.diver.mean.speed
 set viewangle rpath.viewangle
 set counted.fishes [] ; sets counted.fishes as an empty list

 set snapshot.fishes []  ; sets snapshot.fishes as an empty list (no snapshot possible for roving divers, as their path is random)

]
  if buddy? [
   create-buddies 1 [
    set heading 0
    set shape "diver"
    set color magenta
    set size 2
    setxy ([xcor] of one-of divers + 1) ([ycor] of one-of divers - 1)
   ]
  ]
]

set persons (turtle-set divers buddies) ; creates the agentset containing divers and buddies


ask divers [
 set finished? false                                            ; reset the "finished?" variable

 set memory []                                                  ; reset the memory list

]

output-print "Setup complete. Press GO to run the model"

reset-ticks

; open diver detail window


if show.diver.detail.window? = true [inspect one-of divers]
end  ;of setup procedure


to go
  if count divers = count divers with [finished?] [                                                               ; do.outputs and stop if diver is finished

    do.outputs
    stop]
  if sampling.method = "Stationary point count" and stationary.radius > max.visibility [
    user-message "ERROR: stationary.radius is greater than max.visibility. Diver will not be able to see the sample area."              ; if the stationary radius is higher than visibility, stop and output an error description«

    stop
  ]


  if sampling.method = "Fixed distance transect" [ask divers [                              ; divers count the fishes and then check if finishing conditions are met

    d.count.fishes
    set finished? ycor > final.ycor
  ]
  ]
  if sampling.method = "Fixed time transect" [ask divers [
    t.count.fishes
    set finished? ticks > transect.time.secs
  ]
  ]
  if sampling.method = "Stationary point count" [ask divers [
    s.count.fishes
    set finished? ticks > stationary.time.secs
  ]
  ]
  if sampling.method = "Random path" [ask divers [
    r.count.fishes
    set finished? ticks > roving.time.secs
  ]
  ]



  repeat movement.time.step [

    if sampling.method = "Fixed distance transect" [ask divers [do.ddiver.movement]]         ; move the diver

    if sampling.method = "Fixed time transect" [ask divers [do.tdiver.movement]]
    if sampling.method = "Stationary point count" [ask divers [do.stdiver.movement]]
    if sampling.method = "Random path" [ask divers [do.rdiver.movement]]


    ask buddies [                                                                           ; move the buddy

      move-to one-of divers
      set heading [heading] of one-of divers
      rt 135 fd sqrt 2                           ; keep 1m behind and 1m to the right of the diver

      set heading [heading] of one-of divers

    ]

    ask fishes [                                                                            ; move the fishes

      do.fish.movement
    ]
    if smooth.animation? [display]
  ] ; closes repeat movement.time.step


  if sampling.method = "Random path" and ticks mod 2 = 0 [
    ask divers[set heading heading + random-float-between (- roving.diver.turning.angle) roving.diver.turning.angle]]         ;random path turning happens every 2 seconds (must be out of the "repeat" cycle)



  if not super.memory? [ask divers [forget.fishes]]       ; if super memory is disabled, divers forget fishes they no longer see



  if ticks mod behavior.change.interval = 0 [
    ask fishes [
      set behavior.set? false
      set.behavior
    ]                                      ; fishes set a new behavior in the end of the go procedure, every x seconds (determined by behavior.change.interval)

  ]
  advance-clock
  tick
end   ; of go procedure


to advance-clock
  set seconds seconds + 1
  if seconds = 60 [set minutes minutes + 1 set seconds 0]
  if minutes = 60 and seconds = 0 [set hours hours + 1 set minutes 0]
end 



;OBSERVER PROCEDURES


to do.outputs
  ask divers [
    output-print "Density estimates:"
    foreach n-values nr.species [[x] -> x + 1] [
      [n] -> let sp.param item n species.data
      let name item 0 sp.param
      let sp.dens.pair list name precision (occurrences name counted.fishes / sampling.area) 3
      set density.estimates lput sp.dens.pair density.estimates
      output-print (word first sp.dens.pair ": " last sp.dens.pair)
    ]
    output-print "Bias due to non-instantaneous sampling:"
    foreach n-values nr.species [[x] -> x + 1] [
      [n] -> let sp.param item n species.data
      let name item 0 sp.param
      let snapshot.dens.pair list name precision (occurrences name snapshot.fishes / sampling.area) 3
      set snapshot.estimates lput snapshot.dens.pair snapshot.estimates ; this just stores snapshot densities in a variable

      ifelse last snapshot.dens.pair = 0 [
        let bias.pair list name "n/a"       ; if snapshot.density is 0, do not calculate bias due to non-instantaneous sampling

        set bias.estimates lput bias.pair bias.estimates ; this just stores bias estimates in a variable

        output-print (word first bias.pair ": " last bias.pair)
      ] [
        let bias.pair list name precision ((((last item (n - 1) density.estimates)) - (last snapshot.dens.pair)) / (last snapshot.dens.pair)) 3 ; bias is calculated as (counted density - snapshot density) / snapshot density

        set bias.estimates lput bias.pair bias.estimates ; this just stores bias estimates in a variable

        output-print (word first bias.pair ": " last bias.pair)
      ]
    ]
    set output.real total.density                             ; fill output variables for BehaviourSpace (if more than 1 species, these outputs only apply to the 1st)

    set output.estimated last first density.estimates
    set output.difference output.estimated - output.real
    set output.inaccuracy output.difference / output.real
    set output.instantaneous last first snapshot.estimates
    set output.bias last first bias.estimates
  ]
end  ; of do.outputs



;FISH PROCEDURES



;fish movement submodel


to do.fish.movement
  if schooling? [set schoolmates other fishes in-cone perception.dist perception.angle with [species = [species] of myself]]    ; if schooling is true,look for conspecifics in my vicinity


  set acceleration (list 0 0)                                                                                                   ; acceleration at each step is determined entirely by the urges


;check if weights are not 0 (to prevent useless calculations) and calculate all urge vectors


  if patch.gathering.w != 0 [add-urge patch-center-urge patch.gathering.w]                    ; check if weights are not 0 (to prevent useless calculations) and calculate all urge vectors

  if wander.w != 0 [add-urge wander-urge wander.w]
  if predator.avoidance.w != 0 [add-urge avoid-predator-urge predator.avoidance.w]
  if diver.avoidance.w != 0 [add-urge avoid-diver-urge diver.avoidance.w]
  if rest.w != 0 [add-urge rest-urge rest.w]
  if cruise.w != 0 [add-urge cruise-urge cruise.w]

  if count schoolmates > 0 and schooling?                                                        ; if I'm not in a school ignore the school related urges. If schooling is disabled, ignore them as well

  [ add-urge spacing-urge spacing.w
    add-urge center-urge center.w
    add-urge align-urge align.w ]

  let deceleration (scale ((drag.formula * ((magnitude velocity) ^ 2))) (subtract (list 0 0) (normalize velocity)))    ; subtract the deceleration due to drag from the acceleration vector

  set acceleration (add acceleration deceleration)

  if magnitude acceleration > max.acceleration                                                   ; keep the acceleration within the accepted range. It is important that this is done after accounting for drag, so that max.acceleration can be reached.

  [ set acceleration
    (scale
        max.acceleration
        normalize acceleration) ]

  set velocity (add velocity acceleration)                                                       ; the new velocity of the fish is sum of the acceleration and the old velocity.


 ;keep velocity within accepted range. When near threats, use burst.speed as limit, but only if avoidance urge weight is greater than 0


  ifelse ((any? (fishes with [prey.type = "fish"]) in-cone approach.dist perception.angle) and (predator.avoidance.w > 0)) or ((any? divers in-cone approach.dist perception.angle) and (diver.avoidance.w > 0)) [
   if magnitude velocity > burst.speed [
     set velocity (scale burst.speed normalize velocity)
     ]
  ] [

  if magnitude velocity > max.sustained.speed
  [ set velocity
    (scale
        max.sustained.speed
        normalize velocity) ]
  ]

  let nxcor xcor + ( first velocity )
  let nycor ycor + ( last velocity )
  if magnitude velocity > 0.2 [                                ; minimum velocity that triggers movement. This is to prevent erratic movement when stopped.

    facexy nxcor nycor
    fd (magnitude velocity) / movement.time.step]
end  ;of do.fish.movement


to add-urge [urge factor]                                              ;fish procedure

  set acceleration add acceleration scale factor normalize urge
end 

to pick.patch                                                          ;fish procedure

  if picked.patch = false [
   let chosen.patch patch-ahead 2 ; second patch ahead of the fish


   if [pxcor] of chosen.patch > (world-width - (picked.patch.dist + 1)) [                                              ; create a (picked.patch.dist + 1) -wide buffer so that picked patches are not too close to the edges

    let new.chosen.patch patch ([pxcor] of chosen.patch - (picked.patch.dist + 1)) ([pycor] of chosen.patch)
    set chosen.patch new.chosen.patch
   ]
   if [pxcor] of chosen.patch < (picked.patch.dist + 1) [
    let new.chosen.patch patch ([pxcor] of chosen.patch + (picked.patch.dist + 1)) ([pycor] of chosen.patch)
    set chosen.patch new.chosen.patch
   ]
   if [pycor] of chosen.patch > (world-height - (picked.patch.dist + 1)) [
    let new.chosen.patch patch ([pxcor] of chosen.patch) ([pycor] of chosen.patch - (picked.patch.dist + 1))
    set chosen.patch new.chosen.patch
   ]
   if [pycor] of chosen.patch < (picked.patch.dist + 1) [
    let new.chosen.patch patch ([pxcor] of chosen.patch) ([pycor] of chosen.patch + (picked.patch.dist + 1))
    set chosen.patch new.chosen.patch
   ]

   set picked.patch chosen.patch
   if any? schoolmates [
    ask schoolmates [
     set picked.patch chosen.patch
    ]
   ]]
end 

;procedure that selects a new behavior and fills in behavior parameters


to set.behavior                                                        ; fish procedure

  if not behavior.set? [
    let pairs (map list behavior.list behavior.freqs)                          ; pairs behavior names with probabilities as lists within a list, to work better with the rnd extension: [[b1 0.2] [b2 0.3] [b3 0.5]]

    set current.behavior first rnd:weighted-one-of-list pairs [[p] -> last p]  ; pick a random behavior from behavior list, using a weighted random pick

    let param.pos position current.behavior behavior.list                      ; check which behavior was picked (1, 2, 3 or 4)

    let params item param.pos behavior.params                                  ; retreive list of parameters from the correct position in behavior.params

    set detectability item 2 params
    set schooling? item 3 params
    set schoolmate.dist item 4 params
    set align.w item 5 params
    set center.w item 6 params
    set spacing.w item 7 params
    set wander.w item 8 params
    set rest.w item 9 params
    set cruise.w item 10 params
    set picked.patch.dist item 11 params
    set patch.gathering.w item 12 params
    set predator.avoidance.w item 13 params
    set prey.chasing.w item 14 params
    set diver.avoidance.w item 15 params
    ifelse detectability < 1 [
      set visible? random-bernoulli detectability    ; visibility of individual fish is set when behavior changes, using a Bernoulli trial

      ] [
      set visible? true
      ]
    set behavior.set? true
    if any? schoolmates [
      ask schoolmates [
        set current.behavior [current.behavior] of myself
        set detectability item 2 params
        set schooling? item 3 params
        set schoolmate.dist item 4 params
        set align.w item 5 params
        set center.w item 6 params
        set spacing.w item 7 params
        set wander.w item 8 params
        set rest.w item 9 params
        set cruise.w item 10 params
        set picked.patch.dist item 11 params
        set patch.gathering.w item 12 params
        set predator.avoidance.w item 13 params
        set prey.chasing.w item 14 params
        set diver.avoidance.w item 15 params
        ifelse detectability < 1 [
          set visible? random-bernoulli detectability    ; visibility of schoolmates is set independently

          ] [
          set visible? true
          ]
        set behavior.set? true
      ]
    ]
    ifelse patch.gathering.w > 0 [                                       ; if selected behavior has patch gathering urge, pick a patch. If in a school, ask schoolmates to pick a patch collectively.

      pick.patch] [set picked.patch false]                               ; if patch gathering urge has zero weight, variable picked.patch is set to false (important for pick.patch procedure).

  ]
end 

to set.first.behavior                                                    ; fish procedure

    set current.behavior first behavior.list                             ; set behavior to first in the list (this should be the most frequent and/or the most typical for the species)

    let params first behavior.params                                     ; retreive list of parameters from the first position in behavior.params

    set detectability item 2 params
    set schooling? item 3 params
    set schoolmate.dist item 4 params
    set align.w item 5 params
    set center.w item 6 params
    set spacing.w item 7 params
    set wander.w item 8 params
    set rest.w item 9 params
    set cruise.w item 10 params
    set picked.patch.dist item 11 params
    set patch.gathering.w item 12 params
    set predator.avoidance.w item 13 params
    set prey.chasing.w item 14 params
    set diver.avoidance.w item 15 params
    ifelse detectability < 1 [
      set visible? random-bernoulli detectability    ; visibility of individual fish is set when behavior changes, using a Bernoulli trial

      ] [
      set visible? true
      ]
    set behavior.set? true
    ifelse patch.gathering.w > 0 [                                       ; if selected behavior has patch gathering urge, pick a patch. If in a school, ask schoolmates to pick a patch collectively.

      pick.patch] [set picked.patch false]                               ; if patch gathering urge has zero weight, variable picked.patch is set to false (important for pick.patch procedure).

end 

; fish urges


to-report patch-center-urge  ; a vector directed at the center of the picked patch

  ifelse picked.patch != false [
    let patch-x [pxcor] of picked.patch
    let patch-y [pycor] of picked.patch
    ifelse distancexy patch-x patch-y > picked.patch.dist   ; distance to picked patch

     [ report (list (patch-x - xcor) (patch-y - ycor)) ]   ; number of coordinate units (vertical and horizontal) needed to get to picked.patch

     [ report (list 0 0) ]
    ] [ report (list 0 0) ]
end 

to-report center-urge  ; a vector directed at the average location of my schoolmates


  if count schoolmates = 0 or center.w = 0
  [ report (list 0 0) ]
  report
    (map -
      (list mean [ xcor ] of schoolmates mean [ ycor ] of schoolmates)
      (list xcor ycor)
  )
end 

to-report align-urge ; a vector obtained by averaging the velocity of schoolmates

  if count schoolmates = 0 or align.w = 0
  [ report (list 0 0) ]
  report
    (map - (list
      mean [ first velocity ] of schoolmates   ; x component

     mean [ last velocity ] of schoolmates     ; y component

     )
  velocity
  )
end 

to-report rest-urge ;a vector opposite to current velocity (counters current movement)

  report subtract [0 0] velocity
end 

to-report cruise-urge ; a vector that simply reinforces the current velocity

  report normalize velocity
end 

to-report wander-urge ; reports 2 random numbers between -1 and 1, leading to a vector with random direction

  report n-values 2 [ (random-float 2) - 1 ]
end 

to-report spacing-urge
  let urge [ 0 0 ]
  ;; report the sum of the distances to fishes

  ;; in my school that are closer to me than

  ;; schoolmate.dist (in body lengths)

  ask schoolmates with [ distance myself < (schoolmate.dist * size) ] [
    set urge
      add
        urge
        (subtract
          (list [xcor] of myself [ycor] of myself)
          (list xcor ycor))
  ]
  report urge
end 

to-report avoid-predator-urge ; a normalized vector that is opposite to the position of the closest predator

 let urge (list 0 0)
  if predator.avoidance.w = 0 [ report urge ]
  let predators fishes in-cone approach.dist perception.angle with [species != [species] of myself and prey.type = "fish"]
  if any? predators [ask min-one-of predators [distance myself]
  [set urge normalize (add urge subtract (list [xcor] of myself [ycor] of myself) (list xcor ycor))
    ]]
  report urge
end 

to-report avoid-diver-urge ; a normalized vector that is opposite to the position of the closest person

 let urge (list 0 0)
  if diver.avoidance.w = 0 [ report urge ]
  let threats persons in-cone approach.dist perception.angle                        ; persons is an agenteset that includes divers and buddies

  if any? threats [ask min-one-of threats [distance myself]
  [set urge normalize (add urge subtract (list [xcor] of myself [ycor] of myself) (list xcor ycor))
    ]]
  report urge
end 

;VECTOR OPERATIONS


to-report add [ v1 v2 ]
  report (map + v1 v2)
end 

to-report subtract [ v1 v2 ]
  report (map - v1 v2)
end 

to-report scale [ scalar vector ]
  report map [ [v] -> scalar * v ] vector
end 

to-report magnitude [ vector ]
  report sqrt sum map [ [v] -> v * v ] vector
end 

to-report normalize [ vector ]
  let m magnitude vector
  if m = 0 [ report vector ]
  report map [ [v] -> v / m ] vector
end 

;DIVER PROCEDURES


;movement


to do.ddiver.movement           ; fixed distance transect diver movement

  fd speed / movement.time.step ; each step is a second, so the speed is basically the distance divided by the movement.time.step

end 

to do.tdiver.movement           ; fixed time transect diver movement

  fd speed / movement.time.step ; each step is a second, so the speed is basically the distance divided by the movement.time.step

end 

to do.stdiver.movement          ; stationary point count diver movement

  set heading heading + (stationary.turning.angle / movement.time.step)        ; turns clockwise at a constant speed (in degrees per second)

end 

to do.rdiver.movement           ; roving diver movement NOTE: turning happens every two seconds, so this part is coded separately in the go procedure

  fd speed / movement.time.step ; each step is a second, so the speed is basically the distance divided by the movement.time.step

end 

;count procedures


to d.count.fishes                      ; for fixed distance transects, there is a limit to the y coordinate (the diver does not count beyond the end mark of the transect)

  let myxcor xcor
  let my.final.ycor final.ycor
  let seen.fishes fishes in-cone max.visibility viewangle
  let eligible.fishes seen.fishes with [(xcor > myxcor - (distance.transect.width / 2)) and (xcor < myxcor + (distance.transect.width / 2)) and (ycor < my.final.ycor)]  ; distance transects have a limit in ycor as well

  let identifiable.fishes eligible.fishes with [id.distance >= distance myself and visible?]      ; only fish that within their id.distance and are visible are counted

  let diver.memory memory
  let new.fishes (identifiable.fishes with [not member? who diver.memory]) ; only fishes that are not remembered are counted

  ifelse count new.fishes > count.saturation [                       ; even if there are more, only the max number of fishes per second is counted (count.saturation)

    let new.records ([species] of min-n-of count.saturation new.fishes [distance myself]) ; priority is given to closest fishes

    set counted.fishes sentence counted.fishes new.records
    set memory sentence memory [who] of new.fishes
  ] [
  if any? new.fishes [                                      ; if there are new fishes, but they do not exceed count.saturation, just count them

    let new.records ([species] of new.fishes)
    set counted.fishes sentence counted.fishes new.records
    set memory sentence memory [who] of new.fishes
  ]]
end 

to t.count.fishes
  let myxcor xcor
  let seen.fishes fishes in-cone max.visibility viewangle
  let eligible.fishes seen.fishes with [(xcor >= myxcor - (timed.transect.width / 2)) and (xcor <= myxcor + (timed.transect.width / 2))]  ; this only works for transects heading north, of course

  let identifiable.fishes eligible.fishes with [id.distance >= distance myself and visible?]
  let diver.memory memory
  let new.fishes identifiable.fishes with [not member? who diver.memory] ; only fishes that are not remembered are counted

  ifelse count new.fishes > count.saturation [                       ; even if there are more, only the max number of fishes per second is counted (count.saturation)

    let new.records ([species] of min-n-of count.saturation new.fishes [distance myself]) ; priority is given to closest fishes

    set counted.fishes sentence counted.fishes new.records
    set memory sentence memory [who] of new.fishes
  ] [
  if any? new.fishes [                                      ; if there are new fishes, but they do not exceed count.saturation, just count them

    let new.records ([species] of new.fishes)
    set counted.fishes sentence counted.fishes new.records
    set memory sentence memory [who] of new.fishes
  ]]
end 

to s.count.fishes
  let eligible.fishes fishes in-cone stationary.radius viewangle
  let identifiable.fishes eligible.fishes with [id.distance >= distance myself and visible?]
  let diver.memory memory
  let new.fishes identifiable.fishes with [not member? who diver.memory] ; only fishes that are not remembered are counted

  ifelse count new.fishes > count.saturation [                       ; even if there are more, only the max number of fishes per second is counted (count.saturation)

    let new.records ([species] of min-n-of count.saturation new.fishes [distance myself]) ; priority is given to closest fishes

    set counted.fishes sentence counted.fishes new.records
    set memory sentence memory [who] of new.fishes
  ] [
  if any? new.fishes [                                      ; if there are new fishes, but they do not exceed count.saturation, just count them

    let new.records ([species] of new.fishes)
    set counted.fishes sentence counted.fishes new.records
    set memory sentence memory [who] of new.fishes
  ]]
end 

to r.count.fishes
  let eligible.fishes fishes in-cone max.visibility viewangle
  let identifiable.fishes eligible.fishes with [id.distance >= distance myself and visible?]
  let diver.memory memory
  let new.fishes identifiable.fishes with [not member? who diver.memory] ; only fishes that were not previously counted are counted

  ifelse count new.fishes > count.saturation [                       ; even if there are more, only the max number of fishes per second is counted (count.saturation)

    let new.records ([species] of min-n-of count.saturation new.fishes [distance myself]) ; priority is given to closest fishes

    set counted.fishes sentence counted.fishes new.records
    set memory sentence memory [who] of new.fishes
  ] [
  if any? new.fishes [                                      ; if there are new fishes, but they do not exceed count.saturation, just count them

    let new.records ([species] of new.fishes)
    set counted.fishes sentence counted.fishes new.records
    set memory sentence memory [who] of new.fishes
  ]]
end 

;forget fishes


to forget.fishes                                                        ; runs if super memory is off

  let seen.fish.id [who] of fishes in-cone max.visibility viewangle
  let diver.memory memory
  set memory filter [[id] -> member? id seen.fish.id] diver.memory
end 


; USEFUL REPORTERS


to-report random-bernoulli [probability-true]
  if probability-true < 0.0 or probability-true > 1.0 [user-message "WARNING: probability outside 0-1 range in random-bernoulli."]
  report random-float 1.0 < probability-true
end 

to-report random-float-between [a b]           ; generate a random float between two numbers

  report random-float a + (b - a)
end 

to-report occurrences [x the-list]             ; count the number of occurrences of an item in a list (useful for summarizing species lists)

  report reduce
    [[occurrence-count next-item] -> ifelse-value (next-item = x) [occurrence-count + 1] [occurrence-count]] (fput 0 the-list)
end 

There are 2 versions of this model.

Uploaded by When Description Download
Miguel Pais about 7 years ago Model version 2.0 updated to NetLogo 6 Download this version
Miguel Pais over 7 years ago Initial upload Download this version

Attached files

File Type Description Last updated
FishCensus.png preview Preview for 'FishCensus' over 7 years ago, by Miguel Pais Download

This model does not have any ancestors.

This model does not have any descendants.