How can we count agents according to specific variables? - netlogo

We are trying to solve the following problem:
Each agent has its specific code and at each iteration the list of agents alive in that iteration is updated. We want to calculate how many agents are die of each code present in the list per iteration.
We have these procedures below (code). Obs: We need to use the profile list because of the outputs that are exported by turtle profile
Sorry for the big code below, but we tried our best to reduce it to be reproducible code
Thanks in advance
globals [ ListProfiles Death ]
turtles-own [ profiles-code metabolism-code reproduction-code metabolism reproduction resource-turtle ]
patches-own [ resources ]
to setup
ca
prepare
ask patches [ set resources random 100 ]
let list1 ( list 2 4 )
let list2 ( list 5 10 )
(
foreach list1
[
this-metabolism ->
foreach list2
[
this-reproduction ->
ask n-of 1 patches
[
sprout 1
[
set metabolism this-metabolism
set reproduction this-reproduction
setup-turtles
]
]
]
]
)
reset-ticks
end
to setup-turtles
(
ifelse
metabolism = 2 [ set metabolism-code "M1" ]
metabolism = 4 [ set metabolism-code "M2" ]
)
(
ifelse
reproduction = 5 [ set reproduction-code "R1" ]
reproduction = 10 [ set reproduction-code "R2" ]
)
set profiles-code ( word metabolism-code reproduction-code )
print ( word "profiles-code: " profiles-code )
end
to go
ListProfilesProc
MetaboProc
ProbDieProc
output
tick
end
to ListProfilesProc
set ListProfiles [ ]
ask turtles [
set ListProfiles lput profiles-code ListProfiles
]
set ListProfiles remove-duplicates ListProfiles
end
to MetaboProc
ask turtles [
(
ifelse
metabolism = 2
[
set resource-turtle ( resources - metabolism )
if resource-turtle <= 60 [ DieProc ]
(
ifelse
reproduction = 5
[
if resource-turtle >= 5 [ hatch 1 ]
]
reproduction = 10
[
if resource-turtle >= 10 [ hatch 1 ]
]
)
]
)
]
end
to DieProc
let code profiles-code
foreach ListProfiles [ lp -> ;; I think, here's the problem... I can't individualize the kills by code. I've already tried several things. And therefore I can't get the output of the deaths by code. It is always repeated (general calculation)...
if lp = code
[
set Death Death + 1
]
]
die
end
to ProbDieProc
ask turtles
[
let prob-die random-float 1.01
if prob-die < 0.77 [ DieProc ]
]
end
to prepare
carefully
[ file-delete ( word "output.csv" ) ]
[ ]
file-open ( word "output.csv" )
file-print ( word "code_profile,death,tick" )
file-close
end
to output
file-open ( "output.csv" )
foreach ListProfiles
[
t ->
file-print ( word t "," Death "," ticks )
]
file-close
end

Deaths as you have it is a global variable, which means that any time any turtle accesses it (either to update or read), they are all "sharing" the same value. Instead, you need to track deaths for each profile type. The way you have it, where profiles-code differentiates the different turtle types, you can tackle this a few ways- for example: you could create specific Death trackers for each profile type (eg. Death-M1R1, Death-M1R2... etc.) and output that as needed; or you could use a list, where you update the items in the list that correspond to a specific profile; or you could use a list of lists and use position to grab the death value for a different breed; or you could use the tables extension, which is the example I will show below because I think it's the cleanest and most explicit.
The tables extension allows what is similar to a dictionary structure if you've used that in other coding languages, where you have a {KEY: VALUE} pair such that if you enter the KEY you get out the VALUE. So the general workflow here is to build a dictionary to store the name and death count for each profile type. Then, anytime a turtle dies it will update the death count for its profile type in the dictionary.
To keep it simple, I've made only minor changes to your code above, and added comments where I made (most) updates:
extensions [ table ]
globals [ ListProfiles Death NInitial NFinal R Birth deaths-dict ]
turtles-own [ profiles-code metabolism-code reproduction-code metabolism reproduction resource-turtle ]
patches-own [ resources ]
to setup
ca
prepare
; Define deaths-list as a list
set deaths-dict table:make
ask patches [ set resources random 100 ]
let list1 ( list 2 4 )
let list2 ( list 5 10 )
(
foreach list1
[
this-metabolism ->
foreach list2
[
this-reproduction ->
ask n-of 1 patches
[
sprout 1
[
set metabolism this-metabolism
set reproduction this-reproduction
setup-turtles
; Add each metabolism / reproduction to the deaths dictionary with 0 as initial deaths value
table:put deaths-dict ( word metabolism-code reproduction-code ) 0
]
]
]
]
)
print deaths-dict
reset-ticks
end
to setup-turtles
(
ifelse
metabolism = 2 [ set metabolism-code "M1" ]
metabolism = 4 [ set metabolism-code "M2" ]
)
(
ifelse
reproduction = 5 [ set reproduction-code "R1" ]
reproduction = 10 [ set reproduction-code "R2" ]
)
set profiles-code ( word metabolism-code reproduction-code )
print ( word "profiles-code: " profiles-code )
end
to go
; Stop the model if no turtles exist
if not any? turtles [ stop ]
ListProfilesProc
MetaboProc
ProbDieProc
output
tick
end
to ListProfilesProc
; Simple way to get a sorted list of profile types
set ListProfiles sort remove-duplicates [ profiles-code ] of turtles
end
to MetaboProc
ask turtles [
(
ifelse
metabolism = 2
[
set resource-turtle ( resources - metabolism )
if resource-turtle <= 60 [ DieProc ]
(
ifelse
reproduction = 5
[
if resource-turtle >= 5 [ hatch 1 ]
]
reproduction = 10
[
if resource-turtle >= 10 [ hatch 1 ]
]
)
]
)
]
end
to ProbDieProc
print "Running die proc..."
ask turtles
[
let prob-die random-float 1
if prob-die < 0.4 [
DieProc
]
]
end
to DieProc
; Pull current death count for this profile
let current-profile-death-count table:get deaths-dict profiles-code
; Increase that death count by one
let current-profile-new-death-count current-profile-death-count + 1
; Update the death count in the master dictionary
table:put deaths-dict profiles-code current-profile-new-death-count
die
end
to prepare
carefully
[ file-delete ( word "output.csv" ) ]
[ ]
print "opening..."
file-open ( word "output.csv" )
file-print ( word "code_profile,death,tick" )
file-close
end
to output
file-open ( "output.csv" )
foreach ListProfiles
[
t ->
let profile-deaths table:get deaths-dict t
file-print ( word t "," profile-deaths "," ticks )
]
file-close
end
Output then looks something like:

Related

Is it possible to transform a 4-column list into a 4-column table in NetLogo 6.2?

I have a code that generates an output in list form as below:
I would like the output to look like this:
is it possible to do this in netlogo 6.2?
Yes, but- I think your approach may be overcomplicating what you are after. As an alternative, consider something like this toy model:
extensions [ csv ]
turtles-own [ my_xcor my_ycor ]
globals [ output_list ]
to setup
ca
set output_list [["who" "my_xcor" "my_ycor" "tick"]]
crt 2
reset-ticks
end
to go
ask turtles [
rt random 90 - 45
fd 1
set my_xcor pxcor
set my_ycor pycor
set output_list lput ( list who my_xcor my_ycor ticks ) output_list
]
tick
end
to example-experiment
setup
repeat 5 [ go ]
csv:to-file "example_output.csv" output_list
end
If you run the example-experiment procedure, it will export a file that looks something like:
If you must go this other route, and you can't parse your original csv output in something like R instead, which would potentially be simpler, consider this different setup:
extensions [csv]
globals [ output-list ]
turtles-own [ xcor-list ycor-list tick-list]
to setup
ca
reset-ticks
set output-list [["who" "my_xcor" "my_ycor" "tick"]]
crt 2 [
set xcor-list []
set ycor-list []
set tick-list []
]
repeat 5 [
ask turtles [
rt random 90 - 45
fd 1
set xcor-list lput pxcor xcor-list
set ycor-list lput pycor ycor-list
set tick-list lput ticks tick-list
]
]
end
Now, the idea is to loop over the turtles and collapse each of their tracking lists into a list of lists before exporting:
to export-long
; Iterate over each turtle to extract their listed values
foreach sort turtles [
t ->
; Pull values / lists from each turtle in order
let cur-x-list [xcor-list] of t
let cur-y-list [ycor-list] of t
let cur-tick-list [tick-list] of t
let cur-who-list n-values ( length cur-x-list ) [[who] of t]
( foreach cur-who-list cur-x-list cur-y-list cur-tick-list [
[ a b c d ] ->
let to-append ( list a b c d )
set output-list lput to-append output-list
])
]
; Export the list to csv
csv:to-file "list_example_output.csv" output-list
end
Result:

How to create a table to know which turtles visited each patch in the world?

I would like to remove a doubt and have some help.
I have a closed world of 600X600 patches. Each patch spawns a turtle (using the sprout command). Each turtle makes a series of moves and returns a value for its home patch. I would like to have the following result: know which turtle was in each patch in the world and export this result in table form in .csv
I created a list for this. But, NetLogo is running for a while and then it closes and doesn't finish the model. And so I think if I create a table it should work. The question is: will creating a table solve the problem of the model not running? And if so, how can I create a table by generating an output from that table in .csv? But, I haven't found a NetLogo command that I can create a table to adjust my code to.
Any tip is very welcome. I thank the attention
globals [ edge-size output-turtle-visits ]
patches-own [ turtle-visits ]
to setup
ca
random-seed 1
set edge-size 599
set-patch-size 1.2
resize-world 0 edge-size 0 edge-size
let pcolors []
set pcolors [ 85 95 ]
ask patches [ sprout 1 ]
ask patches [
set turtle-visits n-values count turtles [0]
set pcolor item (random 2) pcolors
]
reset-ticks
end
to go
ask turtles [
rt random 360
fd 1
]
ask patches [
foreach [who] of turtles-here [ id ->
let current-num-visits item id turtle-visits
set turtle-visits replace-item id turtle-visits (current-num-visits + 1)
]
]
end
to output
file-open ( output-turtle-visits )
file-print ( word "id_turtle;my_xcor;my_ycor;turtle_visits" )
foreach sort patches
[
t ->
ask t
[
file-print ( word self " ; " xcor " ; " ycor " ; " turtle-visits )
]
]
file-print "" ;; blank line
file-close
end

How to update a proportion used to select among turtles in a loop?

In my model the turtles have two sexes and there are two potential strategies "0" and "1". The females count the number of males in a set radius and choose among that pool based on their strategies.
The females have a limit to their pool of potential mates and they loop through this pool to select the males according to their strategy. This is all in the to-choose procedure.
One issue that a colleague picked up on is that the following line of code should be updated every time a female chooses another mate so that the proportion reflects the remaining potential mates and not the n-max which was set outside of the loop.
set prop_B ( count availa-males with [ strategy = 0 ] ) / n-max
To state the issue another way for clarity if the n-max is 5 and a female sets the prop_B using this value for the first mate then in the next iteration of the loop n-max should deprecate by 1 because there are only 4 remaining males.
So it should be something like: set prop_B ( count availa-males with [ strategy = 0 ] ) / (n-max - count mates-already-chosen)
Please see below for a working example of the model. Hope you can help.
turtles-own [sex availa-males mates mate-count max-mate-count strategy n-max prop_B proba_B]
breed [males male]
breed [females female]
to setup
clear-all
create-males 50
create-females 1
ask turtles [
setxy random-xcor random-ycor
ifelse random 2 = 1 [set strategy 1] [set strategy 0]
]
ask males [set color red]
ask females [set color blue]
reset-ticks
end
to go
ask males [
; fd 1
]
ask turtles [
set mates ( turtle-set )
]
ask females [choose]
tick
end
to choose
; set a cap on possible mates for females; 5, or the number
; available within the radius if less than 5
set availa-males males in-radius 5
set n-max count availa-males
set max-mate-count ifelse-value ( n-max < 5 ) [ n-max ] [ 5 ] ; 5 5
; Until a female has chosen up to her maximum number of mates:
while [ mate-count < max-mate-count ]
[; determine which available males are not already in her 'mates' agentset
set availa-males availa-males with [ not member? self [mates] of myself ]
; assess the proportion of the '0' strategy in remaining available males
set prop_B ( count availa-males with [ strategy = 0 ] ) / n-max
; example probability choice, just meant to choose '0 strategy' males
; with a frequency disproportionate to availability
set proba_B ifelse-value ( prop_B <= 0.1 ) [ 0.8 ] [ 0.2 ]
; use a random float to determine which strategy type is chosen
set mates ( turtle-set mates
ifelse-value ( random-float 1 < proba_B )
[ one-of availa-males with [ strategy = 0] ]
[ one-of availa-males with [ strategy = 1]] )
; count the current mates to break the while loop once
; the maximum number of mates is reached
set mate-count count mates
]
; have the female's males add her to their own mates agentset
ask mates [ set mates ( turtle-set mates myself ) ]
if n-max < count mates [ print "Fewer available males than mates" ]
end
Since you don't need them to be selected sequentially, then one option you should think about is the weighted equivalent of n-of from the rnd extension. The following code is a complete model that uses weighted selection, to show you how it could work. But it won't give quite the same results as your approach. Your mathematics basically forces one choice or the other based on the proportion of each. I thought that might work for you anyway, as the weighting is just a demonstration of disproportional.
extensions [rnd]
turtles-own
[ sex
mates
strategy
]
breed [males male]
breed [females female]
to setup
clear-all
create-males 50 [set color red set sex "M"]
create-females 1 [set color blue set sex "F"]
ask turtles
[ setxy random-xcor random-ycor
set strategy one-of [1 0]
set mates nobody
]
reset-ticks
end
to go
ask males
[ ; fd 1
]
ask females [choose]
tick
end
to choose
let availa-males males in-radius 5
let max-mate-count min (list 5 count availa-males)
if max-mate-count < 5 [ print "Fewer available males than mates" ]
let new-mates rnd:weighted-n-of max-mate-count availa-males [ strategy-weight strategy ]
set mates (turtle-set mates new-mates)
ask new-mates
[ set mates (turtle-set mates myself)
]
end
to-report strategy-weight [ #strategy ]
if #strategy = 1 [ report 0.2 ]
if #strategy = 0 [ report 0.8 ]
report 0
end
You will notice I also removed a bunch of turtle variables. You don't need to have a permanent variable, just create a temporary one with let. I also noticed you have sex as a turtle variable, but you are actually handling sex with different breeds, but I left it in just in case it has some other purpose.

How to select up to a maximum number of turtles using roulette wheel selection

In my model the turtles have two sexes where the males have two potential tactics. The females count the number of males in a set radius.
I want the females to weight their probability of selecting from the group of males (without replacement) depending on the relative frequency of the two male tactics.
I already have the code for the probability of selecting from the males (matingPoolProbAnad and matingPoolProbRes) but I don't know how to implement it, though the rnd extension seems the way to go, specifically rnd:weighted-n-of size agentset [ reporter ].
It's complicated by three things (1) the males can mate with more than one female but (2) only once with a given female and (3) females can only mate with a maximum of five males.
to count-mates ; ask the females to count the number of males in a 10 patch radius & then
; determine the frequency of the resident males in their patch
ask turtles with [sex = "female"]
[
if any? turtles with [sex = "male"] in-radius 10
[ set potentialMates turtles with [sex = "male"] in-radius 10
ifelse any? potentialMates with [anadromousM = 1]
[ set FA count potentialMates with [anadromousM = 1] / count potentialMates ]
[ set FA 0]
ifelse any? potentialMates with [anadromousM = 0]
[ set FR count potentialMates with [anadromousM = 0] / count potentialMates ]
[ set FR 0]
]
]
end
to mating-pool-prob ; negative frequency dependency which is based on the number of male
; resident turtles
ask turtles with [sex = "female"]
[
ifelse (FA = 1) and (FR = 0)[
set matingPoolProbAnad 1
set matingPoolProbRes 0
]
[ifelse (FA > 0) and (FR < 1)
[
set matingPoolProbRes exp(a - b * (FR - c ))/(1 + exp(a - b * (FR - c)))
set matingPoolProbAnad 1 - matingPoolProbRes
]
[
set matingPoolProbAnad 0
set matingPoolProbRes 1
]
]
]
end
This example may approach what you're getting at, but obviously would need to be adapted from this toy version. This setup sprouts 75% of males with strategy A and the rest with strategy B, and gives all turtles an empty agentset of mates to start off:
breed [ males male ]
breed [ females female ]
turtles-own [ mates ]
males-own [ strategy ]
females-own [ max-mate-count mate-count ]
to setup
ca
ask n-of 200 patches [
sprout-males 1 [
ifelse random-float 1 < 0.75 [
set strategy "A"
set color orange
] [
set strategy "B"
set color violet
]
]
]
ask n-of 50 patches with [ not any? turtles-here ] [
sprout-females 1 [
set color green
]
]
ask turtles [
set mates ( turtle-set )
]
reset-ticks
end
Use a while loop to have each female iteratively assess the strategy proportions of the males available to her, then add them to her 'mates' list. More detail in comments:
to choose-mates
ask females [
; set a cap on possible mates for females; 5, or the number
; available within the radius if less than 5
let availa-males males in-radius 10
let n-max count availa-males
set max-mate-count ifelse-value ( n-max < 5 ) [ n-max ] [ 5 ]
; Until a female has chosen up to her maximum number of mates:
while [ mate-count < max-mate-count ] [
; determine which available males are not already in her 'mates' agentset
set availa-males availa-males with [ not member? self [mates] of myself ]
; assess the proportion of B strategy in remaining available males
let prop_B ( count availa-males with [ strategy = "B" ] ) / n-max
; example probability choice, just meant to choose B males
; with a frequency disproportionate to availability
let proba_B ifelse-value ( prop_b * 2 < 0.6 ) [ prop_b * 2 ] [ 0.6 ]
; use a random float to determine which strategy type is chosen
set mates ( turtle-set mates ifelse-value ( random-float 1 < proba_B )
[ one-of availa-males with [ strategy = "B" ] ]
[ one-of availa-males with [ strategy = "A" ] ] )
; count the current mates to break the while loop once
; the maximum number of mates is reached
set mate-count count mates
]
; have the female's males add her to their own mates agentset
ask mates [
set mates ( turtle-set mates myself )
]
]
end
To check that 'B' males are being chosen disproportionately to their availability:
to check-values
let all-mates map [ i -> [strategy] of i ] [mates] of females
print word "Average proportion of 'B' mates chosen: " mean map b-proportion all-mates
print word "Actual proportion of 'B' males: " ( ( count males with [ strategy = "B" ] ) / count males )
end
to-report b-proportion [ input_list ]
let tot length input_list
let nb length filter [ i -> i = "B" ] input_list
report nb / tot
end
I'm not 100% sure that that's what you're after- maybe you can use the rnd package to clean up the loop.
Edit in response to comment
If you modify the end of the `choose-mates like so:
...
...
; have the female's males add her to their own mates agentset
ask mates [
set mates ( turtle-set mates myself )
]
if n-max < count mates [
print "Fewer available males than mates"
]
]
end
And your go looks like:
to go
choose-mates
end
You can run setup and go as many times as you like and you should never see the printout "Fewer available males than mates":
to repeat-1000
repeat 1000 [
setup
go
]
end
I ran that a few times and never had count availa-males be less than the count of mates. However, if you add in movement without allowing the females to reset their mates agentset, you do start to see it- for example, try running this a few times:
to go
choose-mates
ask turtles [ fd 1 ]
end
Now, because the turtles are moving around, you have some cases where females held on to their mates from the previous function call and then moved into a space where there were fewer availa-males. The quick and easy fix is to have females clear their mates each time. Where you do that depends on your model goals (how often do females choose mates? Do they only forget some of their previous ones? etc), but here's a very simple way:
to go
ask turtles [ set mates ( turtle-set ) ]
choose-mates
ask turtles [ fd 1 ]
end
Now you can run that as many times as you like and shouldn't see the "Fewer available males than mates" printout.

Netlogo - Divide world equally between n agents

I'm creating an inspection model in Netlogo, and each inspector is responsible for n patches. That is, I need to divide the world in areas that are exclusive for each inspector.
I tried it with
set range (world-width * world-height / inspectors) ^ 0.5
But their range is higher than expected, and it allows one inspector to "invade" the area of other inspectors, which is not desirable.
This approach is probably way over-complicated but may do what you need- it splits the world into even vertical bands of "territory." Note that it only works properly if the world's minimum xcor is 0, and if the world-width is divisible by the number of inspectors- otherwise one inspector will have an inspection area that is different from all the others. For example, using this setup:
breed [ inspectors inspector ]
inspectors-own [ my-territory ]
to setup
ca
resize-world 0 29 0 29
create-inspectors ninspectors [
set my-territory nobody
]
split
reset-ticks
end
Make lists to store the minimum and maximum xcor values, then use those to section off patches to assign as territories to different inspectors. More explanation in comments:
to split
; get a count of the inspectors
let n count inspectors
; get section widths
let n-xcor ( max-pxcor - min-pxcor ) / n
; build lists to define min-maxes of sections
let n-min ( range min-pxcor max-pxcor n-xcor )
let n-max lput ( max-pxcor + 1 ) n-min
set n-max but-first n-max
; Foreach of the min-max pairs, set patches within
; the min-max boundary be set to the territory of one
; of the inspectors that currently has no territory
( foreach n-min n-max [
[ _min _max ] ->
set _min ceiling _min
set _max ceiling _max
let cur_inspector one-of inspectors with [ my-territory = nobody ]
ask patches with [ pxcor >= _min and pxcor < _max ] [
ask cur_inspector [
ifelse my-territory = nobody [
set my-territory myself
] [
set my-territory ( patch-set my-territory myself )
]
]
set pcolor ( [color] of cur_inspector ) - 2
]
])
; Move inspectors to their territory
ask inspectors [
setxy ( mean [pxcor] of my-territory ) ( mean [pycor] of my-territory )
show my-territory
pd
]
end
To check that it's working, you can have your inspectors wander around:
to go
ask inspectors [
face one-of neighbors with [ member? self [my-territory] of myself ]
fd 1
]
tick
end