How to implement a timer for each turtle in netlogo - simulation

I am trying to implement a timer for each turtle in Netlogo
so I can take the minimum value, maximum and average time taken for each turtle.
Can anyone help

You haven't said what you actually want timed (or given any code attempt). Any time you need a turtle to remember anything from one tick to the next, you need a variable. The simplest code for a timer is to have a variable that you set to the current value of ticks when the process starts and subtract that start time from the current value of ticks when the process stops. Here is a complete model example:
turtles-own
[ start-time
time-taken
]
to setup
clear-all
create-turtles 20
[ set start-time 2 + random 10
set time-taken -1
]
reset-ticks
end
to go
let movers turtles with [time-taken = -1 and start-time <= ticks]
ask movers
[ set heading random 360
forward 1 + random 3
if random-float 1 < 0.05 [ set time-taken ticks - start-time ]
]
tick
end

And check out the new Time extension if you want your timers to use real time units (seconds, minutes, years...) and have non-integer values.
https://github.com/NetLogo/Time-Extension
Look at primitives such as time:difference-between

For example, you could do this coding that flags the turtle you want to monitor and increments the flag variable when an event occurs. You can then monitor it in the BehaviorSpace and analyses the results output in a csv file. For example, the following codes:
globals [ID]
turtles-own [special-turtle]
to create-turtle
crt 1 [
setxy min-pxcor 0
set heading 90
set special-turtle false
set ID who]
end
to go
;omitted
special-turtles
tick
end
to special-turtles
ask turtles-on patch 0 0 [set ID who]
ask max-one-of turtles [who] [set special-turtle true]
ask turtles with [special-turtle = true][set special-turtle (special-turtle + 1)]
end

I think there is something that none of the previous answers considered: the way you implement your timer depends on how you want to use the measurement.
1 - If you want to read the measurement only after the measurement is completed
The expression "after the measurement is completed" can mean both that you want to read it at some point later during the model, or maybe even just from some model's output.
The approach I'd take in this case is similar to what JenB suggested, but I believe you can put it a bit simpler because here I only use one extra turtle variable (apart from my-variable, that is there only to represent something that you already have in your model):
turtles-own [
my-variable ; This represents something you have in your model, to be used as a condition for the timer
my-timer
]
to setup
clear-all
reset-ticks
create-turtles 10
end
to go
; Here you have your normal code. When you need, just include
; 'start-timer' and 'stop-timer'. For simplicity, let's
; say you want to count how long does each turtle take
; to get from a value of 1 to a value of 5 for my-variable.
; You can just do:
ask turtles [
if (random 10 < 2) [
set my-variable (my-variable + 1)
]
if (my-variable = 1) [
start-timer
]
if (my-variable = 5) [
stop-timer
type "I am turtle " type who type " and it took me " type my-timer print " ticks."
die
]
]
tick
if (not any? turtles) [stop]
end
to start-timer
set my-timer ticks
end
to stop-timer
set my-timer (ticks - my-timer)
end
Note that most of the code is there only to make a full reproducible example, but the actual implementation only consists of my-timer, to start-timer and to stop-timer.
You can take this approach because the hypothesis here is that you will be interested in reading the measurement only after to stop-timer happened.
Otherwise, see point 2.
2 - If you want to be able to read the measurement at any moment during the simulation
In this case, you need to make the timer progress as time progresses (as opposed to point 1, where you could just take the initial and final time, and make the difference between the two).
I guess the easiest way to do this is to conditionally increment the timer every time there is a tick.
Taking the same example as before, it would be something like:
turtles-own [
my-variable ; This represents something you have in your model, to be used as a condition for the timer
timer-active?
my-timer
]
to setup
clear-all
reset-ticks
create-turtles 10 [
set timer-active? FALSE
]
end
to go
ask turtles [
if (random 10 < 2) [
set my-variable (my-variable + 1)
]
if (my-variable = 1) [
set timer-active? TRUE
]
if (my-variable = 5) [
set timer-active? FALSE
]
]
tick
ask turtles with [timer-active?] [
set my-timer (my-timer + 1)
]
if (count turtles with [my-variable < 5] = 0) [stop]
end
This way, you will be able to see at any moment what is the current value of my-timer for each turtle.

Related

Unable to generate multiple 'species' per breed in NetLogo

I'm new to NetLogo and I'm trying to create 2 sub-breeds (denoted by different shapes) within each breed for 2 breeds total (i.e. sharks and fishes). The chunks of code work as expected when ran individually, however, when running both chunks the first sub-breed of the fishes does not seem to initialise in the interface tab. For some reason the initialisation of the shark breed seems to interfere with the initiation of the fishes breed.
Any idea what i'm doing wrong? Code below.
; Create the agents
breed [sharks shark]
breed [fishes fish]
; Create the agents' variables
fishes-own
[
x0
y0
]
globals
[
species
species-f
]
to setup
; Always start with this
clear-all
reset-ticks
; Create sharks and species
create-sharks N-sharks ; N-sharks is a slider
[
set color blue
setxy random-xcor random-ycor
set species N-sharks
ask sharks
[
set shape "default"
set size 2.5
]
ask sharks with [who >= (species * (1 / 2))]
[
set shape "square"
set size 2
]
ask sharks with [who < (species * (1 / 6))]
[
set shape "star"
set size 3
]
] ; End create sharks and species
; Create fishes
create-fishes N-fishes
[
setxy random-xcor random-ycor
set x0 xcor
set y0 ycor
set species-f (N-fishes * species-ratio)
ifelse who <= species-f
[
set shape "sheep"
set size 5
]
[
set shape "cow"
set size 3
]
set color white
] ; End create fishes
end
There seem to be a number of misunderstandings about what code is run when by NetLogo, and what some pieces of code do: when you use create-turtles *number* [*commands*] (or with breeds, as in your case), commands is run once by every turtle being created (first the new turtles are created, then they run the commands in turn).
That means that every time you use ask sharks within the create-sharks' command block, every new shark will ask all other sharks to set shape and size. For example, if you create 100 sharks, instead of setting the shape and size only once you are doing it 10,000 times (100 * 100).
So you need to put all those commands out of their respective create-<breed>'s command blocks; for example:
create-sharks N-sharks [
set color blue
setxy random-xcor random-ycor
]
ask sharks [
set size 2.5
]
ask sharks with [who >= (species * (1 / 2))] [
set shape "square"
set size 2
]
ask sharks with [who < (species * (1 / 6))] [
set shape "star"
set size 3
]
This is still improvable code, but it shows how to achieve exactly the same thing by doing it once and not doing it N-sharks ^ 2 times.
A better way to do it is to bring those commands back inside the create-<breed>'s command block, but letting each agent carry out the task for itself only. That is, without using ask sharks but using ifelse, so that each shark will check its own condition:
create-sharks N-sharks [
set color blue
setxy random-xcor random-ycor
(ifelse
who >= (species * (1 / 2)) ; the first condition
[set shape "square" set size 2]
who < (species * (1 / 6)) ; the second condition
[set shape "star" set size 3]
; else
[set size 2.5])
]
All of this applies to the other breed too.
It is generally said that using who is a sign that the code should be improved, but let's not focus on this now.
You will have noticed that I omitted the part where you set species N-sharks. This is because I think there is another misunderstanding here and it is not clear to me what you wanted to do: species (such as species-f for the other breed) is a global variable. You are basically asking each of the 100 sharks (again, 100 for example) to do the same thing: set the value of a global variable to equal the value of another global variable. In this case, you are asking each shark to set species 100. This seems very unnecessary, especially considering that N-sharks is a slider used for setup and thus probably won't be changed during the simulation (which means that there is probably no need to store the current value of N-sharks as a separate global variable).
Why are you basing the repartition of your sub-breeds on the value of species? What do you want species to represent? Is it correct for it to be a separate variable from N-sharks? If yes, then it is not clear what is its point; if no, then it can be eliminated.
You need to make sure that whatever you wanted to do with N-sharks & species, and with N-fishes and species-f, is better reflected in your code.
Also because I think this is the reason why your first fish sub-breed isn't showing. First of all, what is species-ratio? It is not present in your example, but it seems to be relevant for your question. In any case, if your first fish sub-breed isn't showing, it means that there is no fish who satisfies the condition who <= species-f.
This doesn't surprise me. who numbers are progressive for turtles: if you create 15 sharks and later you create 10 fish...
... the oldest shark will have who = 0
... the youngest shark will have who = 14
... the oldest fish will have who = 15
... the youngest fish will have who = 24
As you can see in this example, there is no fish for which who <= N-fishes (where N-fishes = 10). Let alone that in your case you set species-f (N-fishes * species-ratio) and, although you didn't tell what species-ratio is, I imagine it is a value between 0 and 1 - thus making the value of species-f even smaller.
The problem is that you are using who to determine your fishes. To quote the Netlogo programming guide: "Who numbers are assigned irrespective of breeds. If you already have a frog 0, then the first mouse will be mouse 1, not mouse 0, since the who number 0 is already taken."
As such, you need to take the number of sharks into account for determining the cutoff point for your fish species
set species-f (N-fishes * species-ratio) + N-sharks - 1
One other comment I have on your code is that you use the following structure:
create-sharks N-shark [
ask sharks [...]
]
Every shark executes the entire command block of create-sharks. That means that every shark asks every shark to do something. Thus follows that every shark sets their shape to default N-shark times.
It is much more efficient to use one of the following constructions
create-sharks N-shark [...]
ask sharks [...]
or
create-sharks N-shark [
if <condition> [<reshape-self>]
]

Different results of reporters turtles/turtle x

I have created an opinion dynamics model, that works just fine. But now I wanted to see, how the opinion of all of my turtles changes. So I created the reporter "report [opinion] of turtles". When I put this in behaviorspace I get wildly jumping results that do not correspond with what I observe. If I test this with individual turtles like "report [opinion] of turtle 0", I get the smooth curve progression that I expected to see.
Does anyone know why this is happening? I would find it rather unwieldy, if I had to put every turtle individually in my behaviorspace, because I have sliding Agentsnumbers.
You can let each turtle have a list variable, at the beginning of which each turtle will record its ID. At every step, each turtle will append its opinion value.
Then you can have a global variable, which you will use as a list of lists, to which at the end of the simulation each turtle will append its own list.
In BheaviorSpace, you will only need to use one reporter (the list of lists) at the end of each experiment's run.
See below for a working example:
globals [
results
]
turtles-own [
opinion
my-list
]
to setup
clear-all
reset-ticks
set results (list)
create-turtles 3 [
set opinion random 10
set my-list list self opinion
]
end
to go
if (ticks = 5) [
ask turtles [
set results lput my-list results
]
stop
]
ask turtles [
set opinion opinion + 1
set my-list lput opinion my-list
]
tick
end
At the end of each run, the results reporter will look like:
[[(turtle 2) 3 4 5 6 7 8] [(turtle 0) 0 1 2 3 4 5] [(turtle 1) 5 6 7 8 9 10]]
Note that, this way, the lists in results will always be in random order.
If you're interested in having them ordered according to some criterion, you can do it.
The example below changes the if (ticks = 5) statement to order results according to turtles' ID, but you can just use sort on whatever characteristic you're interested in.
if (ticks = 5) [
let sorted-turtles sort turtles
foreach sorted-turtles [this-turtle -> ask this-turtle [set results lput my-list results]]
stop
]

How to extract the path taken by each turtle in the world and save it in a .csv file?

I'm still trying to extract the coordinates of the path taken by every turtle in the world. For example, I would like to know the path taken by turtle 0 was patch 00 patch 0 5 patch 0 2 and patch 1 4 and save this information in a .csv file. In this way, I would like to extract the coordinates of the path taken by all the turtles in the world. I'm thinking about creating a list that gives me this information and then saving it.
The problem is that I cannot create an empty list for each turtle created and then, before every move, add the current patch location to the lists. And finally, generate the file of this information in .csv
That is, when inspecting the turtle I don't see the list and when creating the file in .csv it is not generated. Can anyone help me with the code?
Thanks in advance
turtles-own [ mypathx mypathy mytimer]
to setup
ca
reset-ticks
crt 5
ask turtles [
setxy random-xcor random-ycor
let i [ ]
pen-down
]
end
to go
move
let n count turtles
if n = 0 and output? = true [output] ;; ouput? is an switch on interface
if n = 0 [ stop ]
tick
end
to move
ask turtles [
rt random 360
fd 1
if ticks >= 10
[
die
]
]
end
To output
file-open "test.txt"
ask turtles [
set mypathx lput pxcor mypathx
set mypathy lput pycor mypathy
let maxer length mypathx
let i 0
repeat maxer
[
file-print (word item i mypathx " " item i mypathy " " item i mytimer)
let x ( i + 1 )
]
]
file-close
end
There are a number of things to note here, so I hope I understood what you inteded to do.
First of all, note that your code goes to output only after all the turtles died (that is infact one of the conditions to go to output: if n = 0). Therefore, it is normal that there is no data to be exported: in output you ask turtles, but when output is executed all turtles already left the simulation.
However, there is also something that Filip rightly noticed in the comment to the question: it seems logical to ask turtles to save the coordinates of their journey as they move - as opposed to asking them to do so at the end of the simulation.
Based on the current code, turtles simply move in the simulation, and only at the end (e.g. when output is called) they are are asked to save their current location. It would be ideal to include a piece of code where you ask turtles, after each move, to record their location in the list.
To combine this point and the previous one, I would do something like:
to setup
clear-all
reset-ticks
create-turtles 5 [
; I talk about this piece in point 3.
]
end
to go
move
tick
end
to move
ask turtles [
right random 360
forward 1
register-coordinates
]
end
to register-coordinates
set mypathx lput pxcor mypathx
set mypathy lput pycor mypathy
set mytimer lput ticks mytimer ; This is what I assumed you want mytimer to do.
end
And here comes the other problem. You are not initiating the turtles-own variables as lists.
If you run your piece of code now, nothing happens because all turtles are dead by the time you ask them to output. But if you just remove the die command, or if you ask turtles to output before they die, you would get an error - saying that lput expected a list but got something else instead.
From the NetLogo Dictionary you can see that the list primitive is used to create a list with two values.
If you want to create a list containing any other amount of values, you have to use (list ...). This includes the case in which you want to create an empty list. To do that, I would therefore do:
create-turtles 5 [
setxy random-xcor random-ycor
set mypathx (list)
set mypathy (list)
set mytimer (list)
pen-down
]
Now, mypathx, mypathy and mytimer are legal inputs to the lput procedure.
Finally, you can include the output at the end of your simulation (note how I changed go compared to the previous code example):
to go
if ticks = 11 [
ask turtles [output]
stop
]
move
tick
end
...
to output
file-open "test.csv"
file-print (word who "," mypathx "," mypathy "," mytimer)
file-close
end
So, overall, improtant adjustments are: initiate variables as lists if you want to treat them as such; ask your turtles to save their coordinates at every step in their turtles-own list variables; only at the end, ask them to write their list variables in the output file; do not kill your turtles before you ask them to output information.
Integrating all of the above, the code would look like:
turtles-own [mypathx mypathy mytimer]
to setup
clear-all
reset-ticks
create-turtles 5 [
setxy random-xcor random-ycor
set mypathx (list)
set mypathy (list)
set mytimer (list)
pen-down
]
end
to go
if ticks = 11 [
ask turtles [output]
stop
]
move
tick
end
to move
ask turtles [
right random 360
forward 1
register-coordinates
]
end
to register-coordinates
set mypathx lput pxcor mypathx
set mypathy lput pycor mypathy
set mytimer lput ticks mytimer
end
to output
file-open "test.csv"
file-print (word who "," mypathx "," mypathy "," mytimer)
file-close
end
Final notes on the code above:
I am not sure which exact format you want your output to be, but this example code works fine in saving the lists in the .csv file - so you can take it from there and play around to make it fit your needs.
I removed the pcolor part because it seemed unnecessary for the purpose of the question.
I am not sure what you wanted i to do in setup, but it seemed unnecessary for the purpose of the question so I removed that too from my exemplar code. Be careful at how you use item: I don't know what you wanted to do, but the way you included it in your question was often giving runtime errors.
I created a .csv as per the title of the question, instead of a .txt as per the code you provided.

Netlogo turtle stops being infectious after 14 days and starts after being infected

ask turtles with [ infected? and ticks <= 14 ]
[
infect
]
this is my code, after a turtle becomes infected? he will also infect. but I want it to infect only in a 14 day period. what happens is that it infects only on the first 14 ticks and stop. What I want to do is for example, a turtle becomes infected in tick 5, then it will stop infecting in tick 19. Thank you in advance
ticks is the global time step counter so it increments from 0 (when you start the simulation with reset-ticks). What you are trying to do is have each turtle know when it became infected and then be infectious for the next 14 ticks. So you have to create a turtle variable that tracks when it becomes infected, and use that as the condition. Something like:
turtles-own
[ infected?
when-infected
]
to infect
ask turtles
[ if < whatever code you have that exposes them >
[ set infected? true ; you must have this already
set when-infected ticks
]
...
end
to ???
ask turtles with [ infected? and when-infected >= ticks - 14 ] [ infect ]
...
end
You can see that the replacement line compares the turtle's particular value of the new when-infected variable to the current value of ticks

Turtles not reseting under a conditional

I'm trying to have turtles match based on attraction parameters, however I only get either one match or one mismatch and won't count anymore turtles matching, as well as not moving the counter forward.
to new-couple
set countdown2 5
ask turtles [
;; CREATE NEW COUPLE
ifelse countdown2 <= 0
[ die ]
[ set countdown2 countdown2 - 1 ] ]
end
The code that you have provided does not have an error. Try this version of it and you will see that the new-couple code correctly reduces the countdown 5 times and then kills the rest of the turtles. So it's not producing the problem that you describe of things only happening once.
to testme
clear-all
create-turtles 10
type "Start turtles: " print count turtles
new-couple
type "End turtles: " print count turtles
end
to new-couple
let countdown2 5
ask turtles [
;; CREATE NEW COUPLE
ifelse countdown2 <= 0
[ die ]
[ set countdown2 countdown2 - 1 ] ]
end
Could you please provide more of your code. Also, an explanation of what the countdown is supposed to achieve could be useful. At the moment it basically selects the number of turtles that don't die and there are easier ways to achieve that.