sensitivity analysis (mean of multiple simulations) in netlogo - netlogo

I have several indexes such as mean and standard deviation of variables.
After 500 ticks, the model stops.
I want to simulate this model, for instance, 100 times and plot the mean and CI of indexes.
Instead of using python or R, is there any way to do this in netlogo?

Yes, you can use BehaviorSpace to run your model 100 times, saving the results you want to a file-system file, then have a different netlogo program ( or proocedure ) read in the data and plot it. Here's a sample writing part that computes mean and standard deviation of a run of numbers and after ten ticks stops.
globals [ delist demean destd fname ]
to setup
clear-all
set fname "myfile.txt"
set delist []
reset-ticks
end
to go
if ( ticks >= 10 ) [
;; show delist
set demean mean delist;
set destd standard-deviation delist;
export-data
;;print (word "mean = " demean " stdev= " destd )
stop
]
set delist lput random 100 delist
tick
end
to export-data
if not (file-exists? fname ) [
file-open fname
file-print ( word "mean stdev" );
file-flush
file-close
]
file-open fname
file-print ( word demean " " destd )
file-flush
file-close
end
to clear-file
if (file-exists? fname ) [
file-delete fname
]
end
here's sample code reading the above myfile.txt in and plotting it.
Assume a plot widget reporting demean and destd
globals [ delist demean destd fname ]
to setup
clear-all
set fname "myfile.txt"
print " This file begins as follows:"
set delist []
ifelse (file-exists? fname ) [
file-open fname
if not file-at-end?
[ let str file-read-line
print str
]
]
[ print " expected file doesn't exits " ]
reset-ticks
end
to go
if file-at-end? [ print "Data has been all read." file-close stop]
set demean file-read
set destd file-read
print (word "mean = " demean " , std-dev = " destd )
tick
end

Related

Netlogo : calling a procedure after opening a file

Here-below is the code for opening a file, reading it and writing it into a list (inspired from another discussion) :
to setup
reset-timer
; first, we load the database file
; We check to make sure the file exists first
ifelse ( file-exists? "AT_data.txt" )
[
; We are saving the data into a list, so it only needs to be loaded once.
set AT-data []
file-open "AT_data.txt"
while [ not file-at-end? ]
[
; file-read gives variables stored in a double list
; Each iteration we append the next three-tuple to the current list: ID AT1 AT2
set AT-data sentence AT-data (list (list file-read file-read file-read))
]
user-message "File loading complete!"
file-close
;; when adding this, the procedure is running endlessly, to be checked
;; ask patches [ assign-data ]
]
[ user-message "There is no AT_data.txt file in current directory!" ]
file-close-all
print timer
end
As I wrote as a comment, when I call the next procedure [assign-data], the procedure [assign-data] runs endlessly. I setup a timer in the [assign-data] procedure and I see that it is running over and over again. When I run [assign-data] on its own, it is working appropriatly, only once.
I tried with a stop after [assign-data] but it is not working.
There must be something that I did not get yet about the use of Netlogo, do you know what it is ?
Here is the code of the assign-dataprocedure (there are 2 choices, the second is running faster)
to assign-farmers1
reset-timer
ask patches with [seed = 1] [
set death last (first (filter [current-inner-list -> (item 0 current-inner-list = ID_farm)] AT-data))
set age item 1 (first (filter [current-inner-list -> (item 0 current-inner-list = ID_farm)] AT-data))
]
print timer
end
to assign-data2
reset-timer
ask patches with [seed = 1] [
let i 1
while [i < length AT-data] [
let current-inner-list item i AT-data
ifelse (ID_farm = item 0 current-inner-list)
[ set age item 1 current-inner-list set death item 2 current-inner-list
stop]
[ set i i + 1 ]
]
]
print timer
end
-> that lead me to another question : how to stop a simulation from running endlessly ? I tried with stop in the command center but it is not working.
Thanks for you time.
HERE IS A REPRODUCIBLE EXAMPLE
(not sure if I should leave the beginning of the question)
AT_data.txt is a file made of 3 col where the first goes from 1 to 100, second and third are just random numbers.
globals [
AT-data
]
patches-own [
ID
AT1
AT2
seed
]
to setup
;; here I just create patches with different values that also appear in the list
ca
ask patches [ set seed random 10 set ID random 100
ifelse (seed = 4)
[ set pcolor orange] [set pcolor white]
]
end
to load
reset-timer
; first, we load the database file
; We check to make sure the file exists first
ifelse ( file-exists? "AT_data.txt" )
[
; We are saving the data into a list, so it only needs to be loaded once.
set AT-data []
file-open "AT_data.txt"
while [ not file-at-end? ]
[
; file-read gives variables stored in a double list
; Each iteration we append the next three-tuple to the current list: ID AT1 AT2
set AT-data sentence AT-data (list (list file-read file-read file-read))
]
user-message "File loading complete!"
file-close
;; when adding this, the procedure is running endlessly, to be checked
ask patches [ assign-data ]
stop
]
[ user-message "There is no AT_data.txt file in current directory!" ]
file-close-all
print timer
end
to assign-data
reset-timer
ask patches with [seed = 4] [
let i 1
while [i < length AT-data] [
let current-inner-list item i AT-data
ifelse (ID = item 0 current-inner-list)
[ set AT1 item 1 current-inner-list set AT2 item 2 current-inner-list
stop]
[ set i i + 1 ]
]
]
print timer
end
Are you sure the run is endless and not exponential? You ask patches to assign-data and in assign-data you use ask patches again. That means that every single patch is checking every single patch and letting the qualified patch go through the loop, which can take a while.

How can we count agents according to specific variables?

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:

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 separate values from a list using commas in netlogo?

Situation: I have a code that exports turtle coordinates according to the code below:
to path
file-open (word fileName ".csv")
file-print (word self xcor " " ycor)
file-close
end
The result is something like:
(turtle 1)[1 1 1 1 1 2] [4 4 4 2 1 5]
Question: How can I export this same list, but with its items separated by commas?
From [1 2 1 1 1] to [1,2,1,1,1], for example.
Thanks in advance
If you are trying to process this in R or something after the fact, I'd recommend potentially reporting in long format (ie, each line indicates a turtle, a tick [or similar], and the coordinates)- I find it simpler to process.
To answer your actual question- one way would be to manually collapse each list of coordinates into a string separated by commas. For example, see the toy model below.
Simple setup:
extensions [csv]
globals [ test ]
turtles-own [ xcor-list ycor-list ]
to setup
ca
crt 10 [
set xcor-list []
set ycor-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
]
]
reset-ticks
end
This reporter is what's actually doing the work of collapsing the list into a simple string for output:
to-report collapse-string-list [str-list]
report reduce word ( sentence map [ str -> word str ", " ] but-last str-list last str-list )
end
And this chunk pulls the desired turtle variables into a list of lists, calls the collapse-string-list reporter on them, then exports to a csv:
to output-coord-file
let all-turtles sort turtles
; Pull coordinates from each turtle
let who-coord-list map [
current-turtle ->
(list
[who] of current-turtle
collapse-string-list [xcor-list] of current-turtle
collapse-string-list [ycor-list] of current-turtle
)] all-turtles
; Add headers
set who-coord-list fput ["who" "x" "y"] who-coord-list
; Export
csv:to-file "toy.csv" (map [ row -> (map [i -> (word i)] row ) ] who-coord-list)
end
Output:

How to write values in files for each turtle?

How can I write values in files for each turtle ? For example, I have 100 turtles and I would like to write data specific to each turtle in 100 files. For the moment, my code writes data for all turtles in one file .txt:
to write-locations-to-file
file-open "/home/reduan/IBM/outputs.txt"
ask turtles [
file-print (word who " ; " xcor " ; " ycor " ; " color " ; " [pcolor] of patch-here "\r\n" ) ]
end
Thanks in advance for your help.
I'm not sure what it is exactly that you are having trouble with, but you can just open a different file for each turtle. In the example below, I used the who number to generate different file names, but you could use some other method, as long as all file names are unique.
to write-locations-to-files
ask turtles [
file-open (word "/home/reduan/IBM/outputs-" who ".txt")
file-print (word who " ; " xcor " ; " ycor " ; " color " ; " [pcolor] of patch-here "\r\n" )
file-close
]
end