How to loop in NetLogo? - netlogo

I have the following problem. I need to loop through the code. However, it doesn't work.
Contextualizing the problem: I have 3 files (in .asc) that represent data referring to 3 ages of the turtles (age 2, age 4 and age 8). I would like if the user puts the value 1 in num-user, it would only do the simulation with only one file (L_2) that would represent [ "2" ] ; if the user puts the value 2 in num-user, he would do the simulation with the files (L_2 and L_4) that would represent [ "2" "4" ] and finally, if the user puts the value 3 in num-use, it would simulate the files (L_2 , L_4 and L_8) that would represent [ "2" "4" "8" ]. The problem is that the loop is not working and gives various errors. Like:
Extension exception: ascii file ./L_8.asc not found or Can't find element 3 of the list [2 4 8], which is only of length 3 or go runs more than 3 simulations.
I was unable to attach the .ascii files here in the question. But if anyone can look at the code and identify the error I would be very grateful. I can't use BehaviouSpace to solve the situation, I need this loop in the code.
Thanks in advance!
extensions [ gis ]
globals [ num turtle-ages num-ages files random-seeds num-user repetitions ]
to setup
ca
set random-seeds 1
random-seed random-seeds
set num 0
set turtle-ages [ "2" "4" "8" ]
set num-ages item num turtle-ages
setup-asc
setup-turtles
reset-ticks
end
to setup-2
clear
random-seed random-seeds
set num-ages item num turtle-ages
setup-asc
setup-turtles
reset-ticks
end
to setup-turtles
ask n-of 5 patches [ sprout 1 ]
end
to clear
set files 0
clear-ticks
clear-turtles
end
to setup-asc
let number1 num-ages
set files gis:load-dataset ( word "./L_" number1 ".asc" ) ;; this loads a one raster file. There are 3 files in the folder with the names: (L_2.asc ; L_4.asc and L_8.asc
end
to go
move
tick
let n count turtles
if n = 0 or ticks = 10
[
set random-seeds random-seeds + 1
set repetitions 1
if random-seeds = repetitions + 1
[
set random-seeds 1
set num num + 1
;; if the user puts the value 1 in num-user, it would only do the simulation with only one file (L_2) that would represent [ "2" ]
;;; if the user puts the value 2 in num-user, he would do the simulation with the files (L_2 and L_4) that would represent [ "2" "4" ]
;;;; and finally, if the user puts the value 3 in num-use, it would simulate the files (L_2 , L_4 and L_8) that would represent [ "2" "4" "8" ]
set num-user 1 ;;
if num = num-user [ stop ]
]
setup-2
]
end
to move
ask turtles [
right random 360
fd 1
if ticks = 5 [ die ]
]
end

Whenever possible, I'd suggest paring down your code to a MRE to a) make sure that users here can run your code (without your files, for example, this is not really viable) and b) to see if reframing your question / goals in simpler terms would help get things working- at least that's what works for me!
I think that you might find foreach useful here as a way to loop through your desired simulations instead of manually tracking the number of iterations. For this example, assuming num-user is a numeric input widget on the interface, the setup below will determine which of the ages to process:
globals [ ages-to-run ]
to base-setup
ca
; Determine how many simulations to run, based on user input into
; 'num-user' numerical input widget on the interface
ifelse num-user < 1 or num-user > 3 [
print "Incorrect number of simulations indicated"
] [
let possible-sims [ "2" "4" "8" ]
set ages-to-run sublist possible-sims 0 num-user
]
reset-ticks
end
After running the above, the ages-to-run variable will contain ["2"], ["2" "4"], or ["2" "4" "8"]. Next, you can iterate over those desired ages to run your simulations (a little more detail in comments):
to run-simulations
if ages-to-run = 0 [
print "Simulation setup not complete"
]
foreach ages-to-run [
; This is the loop proper where each "age" is iterated.
; All of your simulation calls (manual variable resetting,
; etc) should all go within this loop.
current-age ->
print word "Running simulations for age: " current-age
let file-to-load ( word "./L_" current-age ".asc" )
print file-to-load
clear-turtles
ask n-of 5 patches [
sprout 1 [
pd
set color runresult current-age + 55
]
]
repeat 20 [
ask turtles [
rt random 60 - 30
fd 1
]
tick
]
print ( word "Simulations complete for age: " current-age "\n" )
]
end
Running that code above with 3 entered into num-user will run a simulation for each age (different colors indicate different runs):
So to run simulations proper, all your per-age code should go within that foreach loop indicated above- and be careful, as you were in your question, to not reset global variables.

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 to access the first turtle of a code sequence in NetLogo 6.2?

I have the following doubts:
I have several individuals of 9 turtle codes.
The turtle codes are: R1M1 R2M1 R3M1 R1M2 R2M2 R3M2 R1M3 R2M3 R3M3. And I have 10 individuals of each code.
As the code is structured in a loop sequence and the order that the code exits in the result exported in .csv, I would like to ask the first individual of the first code (R1M1) to print the output header. But, I'm only getting it using one-of, and then the header often doesn't come out in the first line of the output. And I don't know how I can access the first turtle from the R1M1 code. Does anyone have any ideas?
What I thought of is calling turtle 0 which has the code R1M1. But, I still don't know how to do this in NetLogo.
OBS.: I tried to use only turtle 0, but in the other codes, too, there is turtle 0 and then the header appears.
Thanks in advance
let n count turtles with [ profiles-code = "R1M1" ]
if n > 0
[
ask one-of turtles with [ profiles-code = "R1M1" ]
[
prepare-header-output;; CALL A PROCEDURE
]
]
An example of how the header is coming out (has 3 individuals from each of the 9 codes)
I would use a flag / semaphore variable to indicate if a header is needed. You'll need to adapt the below if you have your turtles outputting the data, but hopefully this will get you pointed in the right direction- more details in comments:
globals [ need-headers? ]
turtles-own [ class ]
to setup
ca
random-seed 1
set need-headers? true
if file-exists? "test_output.csv" [ file-delete "test_output.csv" ]
crt 10 [
set class item random 5 "ABCDE"
]
reset-ticks
end
to go
if count turtles < 1 [ stop ]
ask turtles [
if random-float 1 < 0.25 [ die ]
]
; Toy output example
file-open "test_output.csv"
foreach range length "ABCDE" [ i ->
; Output headers if needed
if need-headers? [
file-print "turtle-type, count, ticks"
; Change the need-headers? to false so this step will only happen once
set need-headers? false
]
let ltr item i "ABCDE"
let n-type count turtles with [ class = ltr ]
file-print ( word ltr "," n-type "," ticks )
]
file-close
tick
end
Output here looks something like:
but if I don't change need-headers? to false, it looks like:

Counting turtles after a chunk of code has executed

In my model currently, I have a monitor on the Interface that counts the total number of turtles (deer in my case) every tick. Is it possible to have another monitor that counts the number of deer after a certain line of code is executed? For example, here's a snippet of code:
to catch-fawns-source
let fawn-hunting-rate (fawn-harvest-rate-source)
if any? fawns-on source-patches
[ ask fawns-on source-patches [
if random-float 1.0001 < (fawn-hunting-rate)
[ set harvest (harvest + 1)
set fawn-harvest (fawn-harvest + 1)
set source-harvest (source-harvest + 1)
die ] ]
]
end
In this case, this is where I have fawns being harvested. This code is the same for my male and female adult and juvenile deer. So is there a way I could track my population specifically after that snippet of code (and the other identical ones for the juveniles and adults) is executed?
I'm not sure if I would need any sort of Netlogo extension (if there are any applicable to this) or if I could somehow add in another global variable and lines of code that accomplishes this task.
Thanks for all of your help as always!
I think you can get away with another global variable that you just update however often you want. For a very simple example, consider this setup:
globals [ most-recent-pop-check ]
to setup
ca
crt 10
set most-recent-pop-check count turtles
reset-ticks
end
Here, most-recent-pop-check will only be updated when needed, then you can just set a monitor to display that variable. In this example, the value will only change every 25 ticks- see comments for more detail:
to go
ask turtles [
; Turtles may die
if random-float 1 < 0.25 [
die
]
; Throw in some density-dependence to control population size
if random-float 1 < ( 0.5 * ( 1 - ( count turtles / 500 ) ) ) [
hatch random 2 + 1
]
]
; If the ticks are not 0, and if the remainder after dividing
; the ticks by 0 is 0, update the most-recent-pop-check
; variable to reflect the current turtle population.
if ticks != 0 and ticks mod 25 = 0 [
set most-recent-pop-check count turtles
]
tick
end
Of course, in your case rather than having the update occur based on the number of ticks, just have it occur whenever you run the code chunk you're after.

Perspective based ranking?

I have a program where each peer has their own ranking system of other peers, what is the best way to implement this is NetLogo?
Normally, I would solve this with a 2D list:
[[turtle 1, score], [turtle 2, score], ...]
But this seems very troubling in NetLogo. This is my code for creating and modifying a 2D list:
to test
clear-all
crt 10
;Create a list of turtles
let agents-list [self] of turtles
;Create empty list, which will be the top level of the TwoD list
let TwoD-list []
;Populate the TwoD-list: [[turtle 0, 0], [turtle 1, 0], ...]
foreach agents-list [
set TwoD-list (lput (list ? 0) TwoD-list)
]
show TwoD-list
repeat 5 [
;Change a value in the TwoD-list
let rand-index random (length TwoD-list) ;select a random index
;The next line is what makes it a huge headache, basically you have to select a list at the top level to replace, and then select the list at the lower level to replace it.
;This entire line of code is just adding one to an element
set TwoD-list (replace-item rand-index TwoD-list (replace-item 1 (item rand-index TwoD-list) (item 1 (item rand-index TwoD-list) + 1)))
show TwoD-list
]
end
What else can I do? Or is there a better way to implement this method?
If you want to model relations between agents, NetLogo has the perfect thing for that: links!
Having each turtle assign a score to all other turtles can be quite naturally expressed as:
directed-link-breed [ rankings ranking ]
rankings-own [ score ]
to setup
clear-all
create-turtles 10
ask turtles [ create-rankings-to other turtles ]
; increment 5 random rankings by one:
ask n-of 5 rankings [ set score score + 1 ]
; display the rankings of each turtle:
ask turtles [ show [ (word end2 " " score) ] of my-out-rankings ]
end
If you don't want the links to show up in the view, you can hide them with:
ask links [ set hidden? true ]

Controlling lives of turtles in NetLogo

For a project, I'm developping a simulation in NetLogo dealing with rabies diseases in dogs and humans. I have some turtles-humans with dogs that can be vaccinated or not. At the beginning I create a dog with rabie and, in according to the fase (1 or 2) of the disease, it can spread the disease to other dogs with a probability. At the end the dog can die either for paralysis (if a probability is higher than 75%) or for other complications. Here's the code:
http://pastebin.com/esR75G3T
In the end you can see that a dog not dying for paralysis will die after some days (between 4 or 6). In other words when the days_infected are equal to end-life.
To check if everything is ok at the beginning I tried to set that NONE of the dog is vaccinated so everyone is supposed to get the disease. In fact when the dog is in phase 2 it will bite anyone. The problem is that if I delete the last line of the code, everything works and some dogs die of paralysis and the other remain alive. If I enable also the last line to let the other dogs die too, nothing works...no dog is infected. why?
This is not a problem with your code: this is a problem with the dynamics of your model. What's happening is that your initial sick dog dies before actually infecting another dog. This is why removing the if (days_infected = end-life) [die] "fixes" the problem.
When I tried your model with a huge population (e.g., 5000 people) so that encounters are more frequent, the infection does spread. You could also increase the probability of infection, or increase the duration of the "furious" phase, I guess.
Another unrelated suggestion, if I may: you should have distinct persons and dogs breeds. Trying to cram everything inside regular turtles makes your code much more complicated than it should be. The way I would approach this would be to create a link from the person to her dog, and then use tie so that the dog is automatically moved when you move the person.
Edit:
OK, here is a version of your code slightly modified to use breeds:
globals [
total_dogs_infected
total_dogs
dead_humans
dead_dogs
]
breed [ persons person ]
persons-own [
sick?
]
breed [ dogs dog ]
dogs-own [
sick?
vaccinated?
rabies_phase
days_infected
end-incubator
end-furious
end-life
]
to setup
clear-all
initialize-globals
setup-turtles
reset-ticks
end
to initialize-globals
set dead_humans 0
set dead_dogs 0
set total_dogs_infected 0
end
to setup-turtles
set-default-shape persons "person"
set-default-shape dogs "wolf"
create-persons people [
setxy random-xcor random-ycor
set size 1.5
set sick? false
ifelse random 100 < 43 [
set color green
hatch-dogs 1 [
set color brown
set heading 115 fd 1
create-link-from myself [ tie ]
set days_infected 0
set vaccinated? (random 100 > %_not_vaccinated)
if not vaccinated? [ set color orange ]
]
]
[
set color blue ;umano sano senza cane
]
]
set total_dogs count dogs
ask one-of dogs [ get_sick ]
end
to get_sick
set sick? true
set color white
set rabies_phase 1
set end-incubator 14 + random 57
set end-furious (end-incubator + random 5)
set end-life (end-furious + 4 + random 2)
set total_dogs_infected total_dogs_infected + 1
end
to go
move
infect
get-older-sick-dog
tick
end
to move
ask persons [
rt random 180
lt random 180
fd 1
]
end
to infect
ask dogs with [ sick? ] [
if (rabies_phase = 1 and (random 100) <= 2) or rabies_phase = 2 [
ask other dogs-here with [ not sick? and not vaccinated? ] [ get_sick ]
]
]
end
to get-older-sick-dog
ask dogs with [ sick? ] [
set days_infected days_infected + 1
;the incubator phase ends after at least 14 days + random(57) and then we have phase 2 (furious)
if (days_infected = end-incubator) [ set rabies_phase 2 ]
;when the main furious phase finishes we have 75% of probability that a secondary furious phase continues for other 4 - 6 days until death ;or we have a probability of 25% that the disease end in paralysis with a fast death
if (days_infected = end-furious and (random 100 > 75)) [
set dead_dogs dead_dogs + 1
die
]
if (days_infected = end-life) [
die
]
]
end
; These last reporters are not used,
; they just illustrate how to get the
; dog from the owner or vice-versa:
to-report my-dog ; person reporter
report one-of out-link-neighbors
end
to-report has-dog? ; person reporter
report any? out-link-neighbors
end
to-report my-owner ; dog reporter
report one-of in-link-neighbors
end
Not only does it simplify some expressions (e.g., ask dogs with [ sick? ] instead of ask turtles with [ has_dog? and sick_dog? ]), it opens up all sorts of possibilities: a dog could run away from its owner, the owner could die without the dog dying, an owner could have two dogs, etc.