Converting agentset into list in NetLogo - list

I'm writing some code to vaccinate individuals in a population where flu is circulating. There are two kinds of vaccines (named HOV and HEV in the code); the HOV is already done. What I tried/wanted to do was convert the agentset of blue turtles into a list, that I could then iterate over one turtle at a time. I need to do this because the HEV condition has to give a slightly different vaccine to each blue turtle (i.e. the flu strain in each vaccine has to be slightly different). However, NetLogo is highlighting "foreach [vax-turtles]" with an error message that says "Expected a literal value."
My code is below, the "if vaccine = "HEV"" piece of code is what I need help with:
extensions [csv]
globals [strain_list_list epidemic-threshold cumulative-infections proportion-of-infection currently-infected peak-prevalence vax-strain]
turtles-own [infection-period infection-number tflu-strain immune-label ant-distance cross-immunity]
patches-own [fomite-age pflu-strain]
to setup
clear-all
setup-turtles
set strain_list_list (list t-sorted-strain-list)
print strain_list_list
reset-ticks
end
to-report t-sorted-strain-list
report map [i -> [tflu-strain] of i] sort turtles
end
to setup-turtles
create-turtles 100
ask turtles [setxy random-xcor random-ycor]
ask turtles [set color white set infection-number 0 set immune-label -999999999999 set tflu-strain -999999999999]
ask one-of turtles [set color red set infection-period 0 set infection-number 1 set immune-label 0 set tflu-strain 0]
if vaccine = "HOV" [
ifelse (one-of [1 2] = 1) [
set vax-strain (random ((2 * drift-size) + 1))]
[set vax-strain (-1 * random ((2 * drift-size) + 1))]
ask n-of prop-vax turtles with [color = white] [set color blue set immune-label vax-strain]
]
if vaccine = "HEV" [
let vax-turtles (list turtles with [color = blue])
ask n-of prop-vax turtles with [color = white] [set color blue]
foreach [vax-turtles] [
ifelse (one-of [1 2] = 1) [
set vax-strain (random ((2 * drift-size) + 1))]
[set vax-strain (-1 * random ((2 * drift-size) + 1))]
]
]
set epidemic-threshold "no"
set cumulative-infections 0
set peak-prevalence 0
end
to go
if ticks = flu-season-length [stop]
move-infecteds
move-uninfecteds
transmit
mutate
update-immunity
track-infecteds
set cumulative-infections (count turtles with [infection-period = 1] + cumulative-infections)
set proportion-of-infection (100 - (count turtles with [immune-label = -999999999999]))
set currently-infected (count turtles with [infection-period = 1])
csv:to-file "strains_each_tick.csv" strain_list_list
set strain_list_list lput t-sorted-strain-list strain_list_list
tick
end
to move-uninfecteds ;; uninfected turtles move faster than infected ones
ask turtles with [color = white or color = blue] [
right random 360
forward 5
]
end
to move-infecteds ;; infected turtles move slower than uninfected ones and always transmit infection to patches before they leave them
ask turtles with [color = red] [
if pcolor = black [
set pcolor red
set fomite-age 0
set pflu-strain tflu-strain]
right random 360
forward 3
]
end
to transmit ;; uninfected turtles are infected by fomites (red patches) with some probability. immune-labelling currently first infection
ask turtles with [color = white or color = blue and pcolor = red] [
if immune-label != pflu-strain [
set ant-distance (abs (immune-label - pflu-strain))
set cross-immunity (natural-immunity * (1 - (ant-distance / antigenic-distance-limit)))
if cross-immunity < 0 [set cross-immunity 0]
if random 100 < (((100 - cross-immunity) / 100) * probability-of-infection)
[set color red set infection-period 0 set infection-number infection-number + 1 set tflu-strain pflu-strain]
]
if immune-label = pflu-strain [
if random 100 < (((100 - natural-immunity) / 100) * probability-of-infection)
[set color red set infection-period 0 set infection-number infection-number + 1 set tflu-strain pflu-strain]
]
]
end
to mutate ;; some probability of mutation (change in strain label) when an individual receives infection from a patch
ifelse in-host [
ask turtles with [color = red] [
if random 100 < probability-of-mutation [
ifelse (one-of [1 2] = 1) [
set tflu-strain (tflu-strain + (random (drift-size + 1)))]
[set tflu-strain (tflu-strain - (random (drift-size + 1)))]
]
]
]
[ask turtles with [color = red and infection-period = 0] [
if random 100 < probability-of-mutation [
ifelse (one-of [1 2] = 1) [
set tflu-strain (tflu-strain + (random (drift-size + 1)))]
[set tflu-strain (tflu-strain - (random (drift-size + 1)))]
]
]
]
end
to update-immunity
ask turtles with [color = red and infection-period = 0] [
ifelse immune-labelling = "first-infection" [
if immune-label = -999999999999 [
set immune-label tflu-strain]]
[set immune-label tflu-strain]
]
end
to track-infecteds ;; turtles with given infection period should become uninfected
ask turtles with [color = red] [
set infection-period infection-period + 1
if infection-period = age-infection-max [
set color white set infection-period 0 set tflu-strain -999999999999
]
]
ask patches with [pcolor = red] [
set fomite-age fomite-age + 1
if fomite-age > max-fomite-persistence [
set pcolor black
]
]
end
Any advice would be greatly appreciated! Thanks

The problem is with the line
let vax-turtles (list turtles with [color = blue])
the list primitive creates a list, but not a list of turtles with [color = blue]. Rather it creates a list of its arguments, which in this case is a single angentset. You instead want a list of the agents in the agentset. The of reporter is the easiest way to get that as of always returns a list.
let vax-turtles [self] of turtles with [color = blue]
Alternatively, if you wanted the list to be sorted, you could use sort, which also always returns a list.
let vax-turtles sort turtles with [color = blue]
As for the problem you describe in the comment below, you need to ask each vax-turtle to set its own vax-strain (which I assume is a turtles-own variable). Assuming that you are using NetLogo 6.x,
if vaccine = "HEV" [
let vax-turtles [self] of turtles with [color = blue]
ask n-of prop-vax turtles with [color = white] [set color blue]
foreach [vax-turtles] [t ->
ifelse (one-of [1 2] = 1) [
ask t [set vax-strain (random ((2 * drift-size) + 1))]]
[ask t [set vax-strain (-1 * random ((2 * drift-size) + 1))]]
]
]
But if drift-size is the same for all vax-turtles, it would be pretty unlikely that, given random, JenB's solution below would give the same value for vax-strain for any two turtles, would it not?

Looking at your code, I can't see why you need to do the iteration rather than ask and it is much cleaner to stick with ask. So, try replacing:
if vaccine = "HEV" [
let vax-turtles (list turtles with [color = blue])
ask n-of prop-vax turtles with [color = white] [set color blue]
foreach [vax-turtles] [
ifelse (one-of [1 2] = 1) [
set vax-strain (random ((2 * drift-size) + 1))]
[set vax-strain (-1 * random ((2 * drift-size) + 1))]
]
]
with
if vaccine = "HEV" [
let vax-turtles turtles with [color = blue]
ask n-of prop-vax turtles with [color = white] [set color blue]
ask [vax-turtles] [
ifelse (one-of [1 2] = 1)
[ set vax-strain (random ((2 * drift-size) + 1)) ]
[ set vax-strain (-1 * random ((2 * drift-size) + 1)) ]
]
]
For that matter, I think the different values are simply different signs of the same value, so you could do:
if vaccine = "HEV" [
let vax-turtles turtles with [color = blue]
ask n-of prop-vax turtles with [color = white] [set color blue]
ask [vax-turtles] [
set vax-strain one-of [-1 1] * (random ((2 * drift-size) + 1))
]
]
Also, I am not sure if you are doing this intentionally, but you are changing the proportion to blue after creating the vax-turtles agentset. This means that the newly changed turtles will not be given a vax-strain until the next tick or whenever the code is next run. Furthermore, the code you have will assign a new vax-strain to all the blue turtles, even if they were made blue in a previous steps. If you actually want the vax-strain to be assigned once only and the turtle to change colour to show this, try:
if vaccine = "HEV" [
ask n-of prop-vax turtles with [color = white]
[ set color blue
set vax-strain one-of [-1 1] * (random ((2 * drift-size) + 1))
type "drift-size is " type drift-size type " and vax-strain is " print vax-strain ;; new line here for diagnostics
]
]
UPDATE: ask gives a new random number to each agent. You can see this by running the complete model:
turtles-own [testnum]
to setup
clear-all
create-turtles 10
[ set testnum random 5 ]
print [testnum] of turtles
end

I think
foreach sort-on [who] turtles with [color = blue]
will suffice.

Related

Netlogo: replacing matrix elements by conditioning on other rows/columns

I am working in Netlogo on a series of models making heavy use matrices. Briefly, the models include a number of state-variables for different breeds, where the state-variables are often stock-like items. As a simple example, consider the model:
extensions [ matrix ]
globals
[
]
turtles-own
[
n-items
stock-list
]
to setup
clear-all
reset-ticks
create-turtles 2
ask turtles
[
setxy random-xcor random-ycor
set n-items 10
let n-vars 3
set stock-list matrix:make-constant n-items n-vars [0] ; empty matrix
let stock-item n-values n-items [i -> i]
let stock-cost n-values n-items [ random-normal 10 2 ]
let stock-age n-values n-items [ random 50 ]
matrix:set-column stock-list 0 stock-item
matrix:set-column stock-list 1 stock-cost
matrix:set-column stock-list 2 stock-age
]
end
Here, each turtle's matrix stock-list is initialised as an empty matrix and then its columns filled in depending on the variables stock-item (id for stock), stock-cost and stock-age.
Imagine a go procedure that increments the stock age by one each time-step:
to go
ask turtles
[
let current-age matrix:get-column stock-list 1
let new-age map [x -> x + 1] current-age
matrix:set-column stock-list 2 new-age
]
tick
end
What I would like to do is an operation on stock-cost only if the age is greater than some value, e.g. 10
;; pseudo-code
for( i = 1 to I = number of items )
{
if ( stock-age[i] > 10 )
{
stock-cost[i] - 1
}
}
I know how to change the list of stock-cost conditional on its own values, using the map primitive, e.g.:
to decrease-stock-value
ask turtles
[
let current-cost matrix:get-column stock-list 1
set current-cost map [[?] -> ifelse-value (? > 10) [? - 1][?]] current-cost
matrix:set-column stock-list 1 current-cost
]
But my efforts to generalise this to using values in a different list to condition upon have failed.
Thanks for your help! Also, any insight onto whether this is a good approach to modelling state variables such as stocks would be useful.
I think I sorted it out using:
to decrease-stock-value
ask turtles
[
let current-cost matrix:get-column stock-list 1
let current-age matrix:get-column stock-list 2
let new-cost ( map [ [ a b ] ->
ifelse-value ( a > 10 ) [ b - 1 ] [ b ] ]
current-age current-cost
)
matrix:set-column stock-list 1 new-cost
]
end

Netlogo list updated in time

I'm writing up a code in Netlogo that basically should do the following:
Amongst directed links, interact and seek out their cooperative behavior (coop_b).
Store coop_b in a list variable together with the time of the interaction (reputation_now)
Every interaction, add the reputation_now to a bigger list, reputation_h (reputation history)
Now, add a time-weight to the reputation, so that the more recently had interactions weigh more in the total reputation. I do this by dividing the encounter time of an interaction by the current time tick, then multiplying that with the coop_b to retrieve a weighted reputation for each interaction. This is stored in the list reputation_h_w (historic reputations weighted). The thing is, this list should be updated every time the members interact, so that earlier additions to the list are now updated to the new time tick. My hunch is this is where my code goes in the mist (problems depicted below the code section).
My code:
to horizontal_interact
ask members [
;set random example variable for coop_b
set coop_b random-float 5 ; coop-b stands for cooperation behavior
if ticks > 0 [
ask my-out-links [ ;there are directed links between all members
set reputation_now (list [coop_b] of end2 ticks) ;list of coop_b and encounter time
set reputation_h lput reputation_now reputation_h ; history of reputations, a list of all reputation_now recorded
foreach reputation_h [ x ->
let cooperative_behavior item 0 x
let encounter_time item 1 x
let reputation_now_w (list cooperative_behavior encounter_time (encounter_time / ticks ))
]
]
]
]
end
If I test the content of reputation_h and reputation_h_w with 2 members, I get:
reputation_h is the coop_b variable of the member and the tick of encounter
links> show reputation_h
(link 1 0):
[[4.0900840358972825 1]
[0.8885953841506328 2]
[0.47017368072392984 3]]
(link 0 1): [[3.6805257472366164 1]
[3.6805257472366164 2]
[3.4201458793705326 3]]
reputation_h_w (containing the member's coop_b variable, the encounter time and the encounter time divided by the ticks):
links> show reputation_h_w
(link 0 1): [[3.6805257472366164 1 1]
[3.6805257472366164 1 0.5]
[3.6805257472366164 2 1]
[3.6805257472366164 1 0.3333333333333333]
[3.6805257472366164 2 0.6666666666666666]
[3.4201458793705326 3 1]]
(link 1 0): [[4.0900840358972825 1 1]
[4.0900840358972825 1 0.5]
[0.8885953841506328 2 1]
[4.0900840358972825 1 0.3333333333333333]
[0.8885953841506328 2 0.6666666666666666]
[0.47017368072392984 3 1]]
The problem is that reputation_h_w doesn't make sense to me - firstly there's six inputs instead of three, and secondly, the encounter time (item 1) and the encounter time/ticks (item 2) is off.
What am I doing wrong here?
Not sure where you update reputation_h_w in your code, but I'm guessing that you are not resetting it to a blank list before running your foreach loop again. So, it's lput-ing the values at the end of the list, which is not blank anymore.
Example setup:
breed [ as a ]
as-own [ coop_b ]
links-own [ reputation_now reputation_history reputation_history_w]
to setup
ca
create-as 2 [
set coop_b who + 1
setxy random-pxcor random-pycor
]
while [ any? as with [ not any? my-in-links ] ] [
ask one-of as with [ not any? my-out-links ] [
create-link-to one-of other as with [ not any? my-in-links ] [
set reputation_now []
set reputation_history []
]
]
]
reset-ticks
end
Note that here I will set reputation_history [] right before the foreach chunk runs:
to interact
if ticks > 0 [
ask links [
set reputation_now ( list [coop_b] of end2 ticks )
set reputation_history lput reputation_now reputation_history
; reset reputation history to a blank list, as you are
; recalculating the weighted value at each tick
set reputation_history_w []
foreach reputation_history [ x ->
let behavior item 0 x
let encounter_time item 1 x
let fraction encounter_time / ticks
set reputation_history_w lput (
list behavior encounter_time fraction ) reputation_history_w
]
show ( word "Current reputation: " reputation_now )
show ( word "Reputation history: " reputation_history )
show ( word "Weighted history rep list: " reputation_history_w )
]
]
tick
end
As far as why your ticks are off, I'd guess it's because you are calling tick after you run your horizontal_interact procedure. With the example above, my output looks like:
(link 0 1): "Current reputation: [2 2]"
(link 0 1): "Reputation history: [[2 1] [2 2]]"
(link 0 1): "Weighted history rep list: [[2 1 0.5] [2 2 1]]"
(link 1 0): "Current reputation: [1 2]"
(link 1 0): "Reputation history: [[1 1] [1 2]]"
(link 1 0): "Weighted history rep list: [[1 1 0.5] [1 2 1]]"
even though the ticks read 3. If you run it with tick at the start of the procedure, that might sort out your expected output.

How does one achieve a square spiral like the the Ulam spiral in Netlogo?

I spent the morning trying to find an easy function (x,y) -> n that would number the patches like this
I was not successful. Do any of Y'all have any experience or suggestions?
Here is my take on it:
patches-own [ n ]
to setup
clear-all
resize-world -4 4 -4 4 ; so it looks better, but use any size you like...
create-turtles 1 [
set heading 180
foreach n-values count patches [ ? + 1 ] [
set n ?
if [ n = 0 ] of patch-left-and-ahead 90 1 [ left 90 ]
fd 1
]
die
]
ask patches [ set plabel n ]
end
Funny you should ask I also spent the morning doing the same thing. There is a function that uses the floor function but I remembered that this is netlogo
so I made a turtle do it for me.
with this procedure
to spin
let k 1
set t t + 1
repeat 2
[
lt 90
repeat t [fd 1 ask patch-here [set n k set k k + 1]]
]
end
and this code in the start up.
crt 1 [
set heading 0
repeat 41 [spin]
die
]
and of course
patches-own [n]
to call them in n order use
foreach sort-on [n] patches ask ? [ "the stuff you want them to do" ]

NETLOGO : Give command to ONLY turtles which variable fulfill the condition - after "foreach"

users,
I am trying to give command for turtles who have various variable. My agent called consumers. Each "consumers" has different need which represent by its color ( I use 14 color-base). When the number of consumers with particular color has reached > 10, I want them to change color into white. I use code below, resulting all of consumers change color into white. Though I only need "consumers" which satisfy the condition to change into white.
to cocreate-value
let a count consumers with [ color = blue]
let b count consumers with [ color = gray]
let c count consumers with [ color = red]
let d count consumers with [ color = orange]
let e' count consumers with [ color = brown]
let f count consumers with [ color = yellow]
let g count consumers with [ color = green]
let h count consumers with [ color = lime]
let i count consumers with [ color = turquoise]
let j count consumers with [ color = cyan]
let k count consumers with [ color = sky]
let l count consumers with [ color = violet]
let m count consumers with [ color = magenta]
let n count consumers with [ color = pink]
ask consumers [set type-of-need ( list a b c d e' f g h i j k l m n ) ]
foreach type-of-need [
if ? > 10 [
let z consumers with [ ? > 10]
ask z [ set color white ]
ask consumers with [color = white] [set need? false]
]]
end
Can someone show me the solution?
Thank you
Your problem is that your list is composed of numbers (the counts for each type of consumer) rather than the type-of-need themselves. You could see this by doing a print type-of-need after you create it. Let's say it looks like [5 12 4 ...]. Then you loop through this list of numbers and eventually get to one that is larger than 10. In the example, you now have ? = 12. Then the condition for creating the agentset z will be true for all consumers.
The following code is untested, but you need to list the types rather than the counts. Try something like this:
to cocreate-value
let a count consumers with [ color = blue]
let b count consumers with [ color = gray]
ask consumers [set type-of-need ( list blue gray ) ]
foreach type-of-need [
if count consumers with [ color = ? ] > 10 [
let z consumers with [ color = ? ]
ask z [ set color white ]
ask consumers with [color = white] [set need? false]
]]
end

How to make turtles move along a list of locations in order

My objective is to have an agentset (named ships) hatch at another agentset (named ports and listed in index) containing 2 locations representing the start and end of a pathway. To go- start moving ships/ heading towards a third agentset (called waypoints and listed in index1) in their given order.
However, if a port is closer to the current waypoint than another waypoint- move to port instead. Once the ships have reached the other port, I would also like them to stop.
Currently I have the model working with only two agentsets (ships and ports) however I would like to include a third set(called waypoints) to prevent ships from hatching at all locations(ports and waypoints) and to have the ships move in a sequential order by traveling along the waypoints (like stepping stones) before reaching the beginning or the end (ports).
Here is an example of my code:
breed [ships ship]
breed [ports port]
breed [waypoints waypoint]
ships-own [target-port
current-port]
to setup
ca
let index 0
create-ports 2
[ let loc item index [ [0 -32] [32 0] ]
setxy (item 0 loc) (item 1 loc)
set index index + 1
set shape "circle"
set size 2
set color red - 1]
let index1 0
create-waypoints 2
[let loc item index1 [[12 -3] [14 -26]]
setxy (item 0 loc) (item 1 loc)
set index1 index1 + 1
set shape "circle"
set size 1
set color red - 1]
ask ports
[ let s who
hatch-ships 1
[ set current-port s
set size 1
set color red
pen-down
set pen-size 1
set target-port min-one-of ports with [ who != s] [distance myself]
set heading towards target-port
]
]
reset-ticks
end
to go
;(obey-elevation)
ask ships
[ if (distance target-port = 0)
[ let other_ports no-turtles
ask target-port [set other_ports (other ports)]
set target-port min-one-of other_ports [distance myself]
face target-port
]
ifelse (distance target-port < 1)
[ move-to target-port
]
[fd 1
]
]
tick
end
Any help would be greatly appreciated.