Thank you for reading this, any advice gratefully received :)
I have a switch (a panic button) when turned on all Agents values are changed and a countdown (global var) initiated. When countdown reaches 1 all Agent values are re-set and panic is over.
Problem is that panic is never over!! Via a monitor I can see my countdown is not going 10,9,8 etc (as expected) but 10,-9181,-198187 etc (random number, always negative).
I must be missing something really simple! My procedures (called from go):
to start-panic
ask generals
[ if panic = true and countdown = 10
[ set fear fear + 1
set probability probability + 1
set canchat? true
set conversation 10
set countdown countdown - 1 ] ]
end
to continue-panic
ask generals
[ if panic = true
[ set countdown countdown - 1 ] ]
end
to stop-panic
ask generals
[ if panic = true and countdown = 1
[ set panic false
set fear fear - 1
set probability probability - 1
set canchat? false
set conversation 5
set countdown 10 ] ]
end
Thank you Seth. Your reply made me think about contexts.
I discovered i was calling the continue-panic procedure as:
ask turtles [ continue-panic ]
whereas the correct logic is
if panic [ continue-panic ]
This countdown works fine now, panic is over (both mine and agents)
You have set countdown countdown - 1 inside ask generals, so every general decrements the countdown. But you only wanted it decremented once.
Taking start-panic for an example, I think you intended logic more like:
to start-panic
if panic and countdown = 10 [
ask generals
[ set fear fear + 1
set probability probability + 1
set canchat? true
set conversation 10 ]
set countdown countdown - 1 ]
end
Related
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.
I was able to include the recovery or die but now I'm having trouble getting the standard deviation and of the turtles that died. I think I got the standard deviation but can't get the mean
if random-float 1 < recover-or-die [
set epi-state recovered-code
set color green
ifelse random-float 1 < 0.90[
]
]
]
I tried this for the mean and it kept saying "Expected Command"
Your problem is ifelse recovery-prob < 0.1 = true. I don't know what your recovery-prob is set to, but this line is always true or always false. What you probably want to do (and what is in your comment) is:
ask turtles with [epi-state = infectious-code]
[ ifelse random-float 1 < recovery-prob
[ set epi-state recovered-code
set color green
]
[ die
]
]
Note that you don't need to actually have the = true part.
If you have recover-prob set to 0.05 (for example), the condition is true for all turtles and they all recover. If it's set to 0.2 (for example), it is false for all turtles and they all die.
This block still has a logic problem I think. The way you have it written, any infectious turtle will either recover or die immediately. What about the turtles who stay infectious for more than one tick?
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
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.
I have the following code where I hatch a new agent,
to t-of-slowdown [ es-poi ]
if we-look > 0 [
set we-look (we-look - 1)
if (we-look <= 0) [
if es-poi and (not any? events-here) [
hatch-events 1 [
set color green
set size 5
set is-poi? true
set new-poi true
let m [[ end2 ] of cur-link] of myself
move-to m ]
set events-x ([who] of events-here)
show events-x
set we-poi-var va-geometric (1 / 1500) + we-ticks poi
set sera-poi false
]
set impregna true
set color red
set seguir true
set we-look random-normal 120 20 ;time to watch an event
]
]
end
which is run in a turtle context (walkers breed)
A walker is moving by a 'link' (another procedure which calls this one), and when a counter is <0,
this code generates a new event (events breed) and places it in the same place where the walker is (cur-link is the current walker link).
After that, the walker must get the id number of the new event
set events-x ([who] of events-here)
The problem here is that variable events-x get an empty list []. The next time the walker passes by the same event it does get the number-id of the event.
Something must be wrong but I can not guess what it is.
I would appreciate very much if someone could take a look and point me some help.
Regards
You could:
let child-who -1
hatch-events 1 [
...
set child-who who
...
]
set events-x child-who
Or:
hatch-events 1 [
...
let child-who who
ask myself [ set events-x my-who ]
...
]
Both of these are a bit clunky, sadly. The second one avoids needing to initialize child-who to a meaningless value, but it requires using myself, a primitive that is likely to mystify the reader.
You could avoid both problems with:
let parent self
hatch-events 1 [
...
let child-who who
ask parent [ set events-x child-who ]
...
]
(But note that using who numbers at all, for anything, is rarely the best and most idiomatic solution to any problem. It's almost always better to store a reference to the turtle itself.)