I am making a NetLogo model. Each agent has a list of 5 integers (agent-list). On each tick, turtles create link with one other turtle, and share with each other their list.
turtles-own [ agent-list ]
.
.
.
ask turtles [
create-link-with one-of other turtles
set agent-list lput agent-list of link-neighbors agent-list
]
I know the code above doesn't work, how should I fix it?
The simplest way to combine the lists as you've described would probably be sentence:
turtles-own [ agent-list ]
to setup
ca
crt 3 [
set agent-list map [random 10] range 5
]
reset-ticks
end
to link-and-share
ask turtles [
let target one-of other turtles
create-link-with target
set agent-list sentence agent-list [agent-list] of target
show agent-list
]
end
However, you'll have do do some tweaking depending on what you're actually looking to do since that means that turtles linking later in the procedure are likely to pull the agent-list of turtles that have already modified their own agent-list. So, if turtle 0 grabs the agent-list of turtle 1, then later turtle 4 grabs the agent-list of turtle 0, turtle 4 would have an agent-list of 15 integers, not 10, similar to the output below:
(turtle 1): [6 1 5 4 7 3 9 8 1 1]
(turtle 0): [9 0 3 3 5 3 9 8 1 1]
(turtle 2): [3 9 8 1 1 9 0 3 3 5 3 9 8 1 1]
Related
I have a problem with accelerating a code in NetLogo. I tried a few things and they didn't work. The problem is in the "setup-patches" procedure that refers to the creation of turtles (please, see the code).
I have a map (I use the GIS extension, but to be a replicable example I didn't use it here) with 7 classes (which in the code is called habitatcover). 6 habitatcover have vegetation and therefore is used by turtles (mobile agent) and 1 class has no vegetation and therefore is not used by turtles (habitatcover 7). Turtles can born in the 6 types of habitatcover that have vegetation and their combinations result in 63 items (please, see the variable in the code called ValidHabs).
Also, I have 3 types of metabolism and 3 types of reproduction, which results in 9 combinations, that is, 9 types of turtles.
For each ValidHabs item (which has a total of 63 items) 50 individuals of each of the 9 types of turtles are born. Therefore, for item 0 of ValidHabs which is [1] 450 individuals will be born (= 9 * 50) it executes all the procedures and goes to the next item in the ValidHabs list until it goes through all the items in this list.
The problem is that as the world is 1000x1000 and 450 turtles are born per list item (which has 63 items in total), using GIS, as well, I have several maps to perform these procedures, in addition to having minimum 15 repetitions per map (using BehaviourSpace) takes a lot of time do execute one map (almost 5 days per map). I've already tried to make modifications to speed it up and haven't had much success. I know the problem is in the "setup-patches" procedure, but I'm not quite sure how to solve it. Can anybody help me?
Thanks in advance!
The code below:
globals
[
RandomSeeds
HotPatchSet
ValidHabs
ValidHabsItem
CurrentHotPatchSet
]
turtles-own
[
turtle-profiles-habitat
energy-reproduction
turtle-metabolism
turtle-profiles-code
turtle-profiles-reproduction-code
turtle-profiles-metabolism-code
turtle-profiles-habitat-code
]
patches-own
[
habitatcover
]
to setup
clear-all
set RandomSeeds 1
random-seed RandomSeeds
resize-world 999 * 0 ( 999 * 1 ) ( 999 * -1 ) 999 * 0 ;; defines the edge size of the world and location of origin: corner top left. The world is 1000x1000
read-legal-habs ;; create list of valid habitats for each turtle profile
set ValidHabsItem 0
setup-layers
setup-patches
reset-ticks
end
to read-legal-habs ;; create list of valid habitats for each turtle profile
set ValidHabs [[1] [2] [3] [4] [5] [6] [1 2] [1 3] [1 4] [1 5] [1 6] [2 3] [2 4] [2 5] [2 6] [3 4] [3 5] [3 6] [4 5] [4 6] [5 6] [1 2 3] [1 2 4] [1 2 5] [1 2 6] [1 3 4] [1 3 5] [1 3 6] [1 4 5] [1 4 6] [1 5 6] [2 3 4] [2 3 5] [2 3 6] [2 4 5] [2 4 6] [2 5 6] [3 4 5] [3 4 6] [3 5 6] [4 5 6] [1 2 3 4] [1 2 3 5] [1 2 3 6] [1 2 4 5] [1 2 4 6] [1 2 5 6] [1 3 4 5] [1 3 4 6] [1 3 5 6] [1 4 5 6] [2 3 4 5] [2 3 4 6] [2 3 5 6] [2 4 5 6] [3 4 5 6] [1 2 3 4 5] [1 2 3 4 6] [1 2 3 5 6] [1 2 4 5 6] [1 3 4 5 6] [2 3 4 5 6] [1 2 3 4 5 6]]
end
to setup-layers ;; the original code I use GIS. And depending on how the class distributions (habitatcover) are on the map, it takes longer to create the turtles
let pcolors [ ]
set pcolors [ 25 65 23 53 105 10 2 ]
ask patches
[
set pcolor item ( random 7 ) pcolors
]
ask patches
[
if pcolor = 25 [ set habitatcover 1 ]
if pcolor = 65 [ set habitatcover 2 ]
if pcolor = 23 [ set habitatcover 3 ]
if pcolor = 53 [ set habitatcover 4 ]
if pcolor = 105 [ set habitatcover 5 ]
if pcolor = 10 [ set habitatcover 6 ]
if pcolor = 2 [ set habitatcover 7 ]
]
end
to setup-patches
let list1 ( list 2 4 8 ) ;; metabolism types
let list2 ( list 10 15 20 ) ;; reproduction types
let n0 count turtles
set HotPatchSet patches with [ ( habitatcover != 7 ) ] ;; referring to all 6 habitatcovers that have some type of vegetation removing habitatcover 7 that has no vegetation
set CurrentHotPatchSet HotPatchSet with [ habitatcover = one-of item ValidHabsItem ValidHabs ] ;; CurrentHotPatchSet will be the HotPatchSet with the current habitatcover ;; ValidHabsItem is the item that goes from 0 to 62 since there are 63 habitacover combinations (see the list ValidHabs has 63 items)
let s ( length list1 ) * ( length list2 ) * 50 ;; 50 individuals per profile = 3 * 3 * 50 = 450 turtles
while [ n0 < s ]
[
(
foreach list1
[
this-metabolism ->
foreach list2
[
this-reproduction ->
let c count CurrentHotPatchSet
if c = 0 [ stop ]
ask one-of CurrentHotPatchSet
[
sprout 1
[
set turtle-profiles-habitat item ValidHabsItem ValidHabs ;; I need the ValidHabsItem and turtle-profiles-habitat, because in the "go" procedure I'm calling each item (ValidHabsItem) from the ValidHabs list to execute all the procedures
set turtle-metabolism this-metabolism
set energy-reproduction this-reproduction
setup-turtles
]
set CurrentHotPatchSet CurrentHotPatchSet with [ not any? turtles in-radius 3 ] ;; each turtle must be a minimum distance of 3 patches and can't have more than one turtle in each patch
]
]
]
)
set n0 count turtles
]
end
to setup-turtles
set turtle-profiles-habitat-code reduce_list turtle-profiles-habitat
(
ifelse
turtle-metabolism = 2 [ set turtle-profiles-metabolism-code "_M1" ]
turtle-metabolism = 4 [ set turtle-profiles-metabolism-code "_M2" ]
turtle-metabolism = 6 [ set turtle-profiles-metabolism-code "_M3" ]
)
(
ifelse
energy-reproduction = 5 [ set turtle-profiles-reproduction-code "_R1" ]
energy-reproduction = 10 [ set turtle-profiles-reproduction-code "_R2" ]
energy-reproduction = 15 [ set turtle-profiles-reproduction-code "_R3" ]
)
set turtle-profiles-code ( word turtle-profiles-habitat-code turtle-profiles-reproduction-code turtle-profiles-metabolism-code )
end
to-report reduce_list [ a_list ]
report read-from-string word reduce word a_list ""
end
Opening note: In no way I am assuming that my suggestions are exhaustive, as other people might see other things to improve.
I intend this question to be exclusively on code, i.e. assuming that it is not addressing non-code options such as computer cluster etc.
Eliminate the time needed to upload GIS data
Importing GIS data in NetLogo is a lengthy process. You can get rid of this process by using export-world and import-world (see here and here). These commands will let you export to a file the current state of your NetLogo world, and then import into NetLogo that state from the file. You can perform the export once when the GIS data has been loaded (so that the GIS information is stored in patches) and store the file somewhere: this means that you won't need to upload GIS data again but will only need to perform import-world.
My personal suggestion is that you create a separate NetLogo file to do this: only in this separate file you will have the GIS extension's procedures and the export-world command. In the file with your main model, you will only have the import-world part.
Of course you will need to create a new/different file for each new/different set of GIS files you use.
Reduce the amount of times you need to perform import-world
Your model is quite big, so it might be the case that import-world too takes some time. You can adjust your code such that, when using BeahviorSpace, you will only have to run import-world once.
See here for some previous discussion.
The idea is that in your setup, instead of using clear-all (which would also clear all of that imported data which is stored inside patches), you manually clear everything apart from patches (i.e. you use clear-globals, clear-ticks, clear-turtles, clear-drawing, clear-all-plots and clear-output). This will allow you to check if the data has already been imported: if not, then it means that this is the first run and you need to use import-world; if yes, it means that patches already have that information stored and thus import-world needs not to be performed.
I don't know if in your model the patch variables coming from GIS (i.e. coming from import-world) might be changed during the simulation. If this is the case, it means that you need to store the initial state of these variables as a special patch variable, which will be used to reset the initial state when you do not use import-world.
Some code will make all of this clearer. For example, in case the GIS information imported through import-world is stored as a vegetation patch variable, you can create an initial-vegetation variable for this purpose:
patches-own [
initial-vegetation
vegetation
]
to setup
clear-globals
clear-ticks
clear-turtles
clear-drawing
clear-all-plots
clear-output
ifelse (all? patches [initial-vegetation = 0])
[import-world "initial-state.csv"]
[ask patches [set vegetation initial-vegetation]]
end
Otherwise, if in your model the variable of interest can never be changed (following my example: if vegetation never changes during the simulation...) things are even simpler:
patches-own [
vegetation
]
to setup
clear-globals
clear-ticks
clear-turtles
clear-drawing
clear-all-plots
clear-output
ifelse (all? patches [initial-vegetation = 0])
[import-world "initial-state.csv"]
[]
end
Looking at your setup-patches procedure, I don't see any code that is obviously inefficient.
(probably set n0 n0 + 1 would be faster than set n0 count turtles - but this is just for the sake of noting it, as it surely has a negligible effect).
Possible unintended aspects in your code? (1)
ValidHabsItem is used twice but it is never set to anything different than zero. In setup there is set ValidHabsItem 0 (anyway note that this is superflous, as zero is the default value), and the value of ValidHabsItem is never changed. I don't know if this is used in some other way in the full version of your code (e.g. if the value of ValidHabsItem iterates from 0 to 62) but note that, looking exclusively at the code in your question, this means that item ValidHabsItem ValidHabs is always [1]. Which in turn, looking at the two instances where you use it in setup-patches, means that:
The statement:
set CurrentHotPatchSet HotPatchSet with [habitatcover = one-of item ValidHabsItem ValidHabs]
is equivalent to:
set CurrentHotPatchSet HotPatchSet with [habitatcover = 1]
The statement:
set turtle-profiles-habitat item ValidHabsItem ValidHabs
is equivalent to:
set turtle-profiles-habitat [1]
Overall this means that, by using the code in your question, turtles will only be born on orange patches (those with habitatcover = 1) and they will only have turtle-profiles-habitat = [1]. Is this intended? Is it not? I am not sure, but it looks peculiar enough for me to point it out.
Possible unintended aspects in your code? (2)
Let's imagine that ValidHabsItem is not constantly 0 but it goes from 0 to 62, with the effect that item ValidHabsItem ValidHabs is always a different list containing a varying number of numbers.
What do you want your code to do when you write:
set CurrentHotPatchSet HotPatchSet with [habitatcover = one-of item ValidHabsItem ValidHabs]
?
If you want to check that habitatcover of patches is one of the values in the current list of habitats, then this is not what your code is doing.
Let's take an example: the current list being represented by item ValidHabsItem ValidHabs is [2 4 5].
The one-of item ValidHabsItem ValidHabs statement is literally one of [2 4 5]. Given that one-of is a random reporter, let's say that in this occasion it extracts the value of 4. This means that your:
set CurrentHotPatchSet HotPatchSet with [habitatcover = one-of item ValidHabsItem ValidHabs]
is
set CurrentHotPatchSet HotPatchSet with [habitatcover = 4]
even if item ValidHabsItem ValidHabs = [2 4 5]; with the result that all patches having habitatcover = 2 or habitatcover = 5 will be excluded.
If it is correct to say that this is not what you wanted, it means that what you are looking for is the member? reporter (see here):
set CurrentHotPatchSet HotPatchSet with [member? (habitatcover) (item ValidHabsItem ValidHabs)]
In the example where item ValidHabsItem ValidHabs = [2 4 5], the code above will set CurrentHotPatchSet as every patch having habitatcover as either 2, 4 or 5.
I'm trying to solve a problem of speed in creating turtles in the NetLogo world.
I have a model that has a world with a size of 600X600. I, too, have 31 turtle profiles (each turtle can only born in a specific habitatcover type or habitatcover set (see ValidHabs variable in the code). In the code, too, there are 2 variables that are metabolism with 2 levels (list1 in the code) and reproduction with 2 levels (list2 in the code). Also, I would like to have at least 200 turtles born in the world or more in this world.
The problem is that it is taking a long time for turtles to be born in the world. Have I already created a switch called Display? to speed up the creation of the turtles. I also set it to faster speed and it still takes a long time to create the turtles.
Does anyone know how I can speed up the creation of turtles based on my code?
I don't know what else to do to speed up the code... I appreciate any kind of help :)
Thanks in advance
The code below:
globals [ ValidHabs ValidHabsItem HotPatchSet CurrentHotPatchSet ]
patches-own [ habitatcover ]
turtles-own [ turtle-profiles-habitat metabolism reproduction all-code code-metabolism code-reproduction ]
to setup
clear-all
random-seed 1
;; ValidHabs are the habitat profiles of the turtles are all combinations of 5 types of habitatcover without repetition
set ValidHabs [[1] [2] [3] [4] [5] [1 2] [1 3] [1 4] [1 5] [2 3] [2 4] [2 5] [3 4] [3 5] [4 5] [1 2 3] [1 2 4] [1 2 5] [1 3 4] [1 3 5] [1 4 5] [2 3 4] [2 3 5] [2 4 5] [3 4 5] [1 2 3 4] [1 2 3 5] [1 2 4 5] [1 3 4 5] [2 3 4 5] [1 2 3 4 5]]
ifelse ( Display? = true ) [ display ] [ no-display ] ;; display is a switch in interface
resize-world 599 * 0 ( 599 * 1 ) ( 599 * -1 ) 599 * 0 ;; the world is 600X600 in size
setup-world
setup-patches
reset-ticks
print ( word "That setup took " timer " seconds" )
end
to setup-world
let pcolors []
set pcolors [ 25 65 23 53 105 10 ]
ask patches [
set pcolor item (random 5) pcolors
]
ask patches [
if pcolor = 25 [ set habitatcover 1 ]
if pcolor = 65 [ set habitatcover 2 ]
if pcolor = 23 [ set habitatcover 3 ]
if pcolor = 53 [ set habitatcover 4 ]
if pcolor = 105 [ set habitatcover 5 ]
if pcolor = 10 [ set habitatcover 6 ]
]
end
to setup-patches
set-patch-size 0.6 ;; view patch size
set HotPatchSet patches with [ ( habitatcover != 6 ) ]
let list1 ( list 2 4 )
let list2 ( list 5 10 )
let n0 count turtles
set CurrentHotPatchSet HotPatchSet with [ habitatcover = one-of item ValidHabsItem ValidHabs ]
while [ n0 < ( length list1 ) * ( length list2 ) * 200 ] ;; I want 200 ou more turtles in the word. Here I put 200
[
(
foreach list1
[
this-metabolism ->
foreach list2
[
this-reproduction ->
let c count CurrentHotPatchSet
if c = 0 [ stop ]
ask one-of CurrentHotPatchSet
[
sprout 1
[
set turtle-profiles-habitat item ValidHabsItem ValidHabs
set metabolism this-metabolism
set reproduction this-reproduction
setup-turtles who
]
set CurrentHotPatchSet CurrentHotPatchSet with [ not any? turtles in-radius 2 ]
]
]
]
)
set n0 count turtles
]
end
to setup-turtles [ whichTurtle? ]
set color black
ask turtle who [
(
ifelse
metabolism = 2 [set code-metabolism "M1"]
metabolism = 4 [set code-metabolism "M2"]
)
(
ifelse
reproduction = 5 [set code-reproduction "R1"]
reproduction = 10 [set code-reproduction "R2"]
)
set all-code ( word code-metabolism code-reproduction )
]
end
I'm afraid I did not look for the particular problems in your code, but there is general advice on speeding up models here:
http://jasss.soc.surrey.ac.uk/20/1/3.html
with updates here:
http://www.railsback-grimm-abm-book.com/jasss-models/
I'm pretty sure that some of the advice applies to your code.
I would like to quantify how many times each turtle has passed each patch in the world. Do you know how I can get this information from NetLogo? I was able to find out how many times the turtle visited the patches, but not how many times it went to each specific patch. For example: turtle 0 visited patch (0, 0) 2 times and patch (0, 1) 4 times. But,Turtle 2 visited patch (0 0) 3 times and patch (0, 1) 3 times and so on.
But, the following error appears: Element 287 of list [0] could not be found, which is only 1.
error while patch 7 22 running ITEM
called by (anonymous command: [ id -> let item id turtle-visits set turtle-visits replace-item id turtle-visits current-num-visits + 1 ])
called by procedure GO
called by 'go' button
Can someone help me?
globals [ edge-size ]
patches-own [ turtle-visits ]
to setup
ca
let num-turtles 1
set edge-size 29
resize-world 0 edge-size 0 edge-size
let pcolors []
set pcolors [ 85 95 ]
ask patches [
set turtle-visits n-values num-turtles [0]
set pcolor item (random 2) pcolors
]
reset-ticks
end
to go
ask turtles [
rt random 360
fd 1
]
end
The problem is, that you initialize the list of turtle-visits with the number of turtles per patch, i.e num-turtles:
set turtle-visits n-values num-turtles [0]
If you replace num-turtles with count turtles, since you want a value for every turtle in the world, it should work:
set turtle-visits n-values count turtles [0]
I have a NetLogo model in which agents retrieve multiple lists of variables from other agents. The order in which these lists are returned is crucial, because variables in each list are associated with each other. However, I believe lists are returned from other agents in a random order each time. For example, take the following simplified test case:
turtles-own [testlist1 testlist2 testlist3 testlist4]
to setup
random-seed 1
clear-all
create-turtles 5
ask turtles [
create-links-with other turtles
set testlist1 []
set testlist2 []
set testlist3 []
set testlist4 []
set testlist1 lput [who] of self testlist1
set testlist2 lput [who] of self testlist2] ;identical to testlist1
end
to go
ask turtles[
set testlist3 reduce sentence [testlist1] of link-neighbors
show testlist3
set testlist4 reduce sentence [testlist2] of link-neighbors
show testlist4]
end
For my use case, values in testlist3 and testlist4 should be in the same order, but their orders differ at random. Output:
(turtle 2): [0 3 1 4]
(turtle 2): [3 4 1 0]
(turtle 3): [4 1 0 2]
(turtle 3): [1 0 2 4]
(turtle 0): [4 2 3 1]
(turtle 0): [3 4 2 1]
(turtle 1): [0 4 2 3]
(turtle 1): [4 2 3 0]
(turtle 4): [0 2 1 3]
(turtle 4): [0 3 2 1]
My question: What is the best way to return multiple lists (such as testlist and testlist2 above) from an agent-set in the same order in a given procedure?
Replacing link-neighbors with turtle-set sort link-neighbors doesn't work, because after converting the sorted list back to an agent-set, the agents in the agent-set are called in a random order. If at all possible, I'd prefer not to have to refactor the entire model from lists to matrices using the matrix extension.
You were on the right track with the idea of turning your agentset to a list. The only part missing was using map instead of turning it back into a turtle set and then using of again:
to go
ask turtles[
set testlist3 reduce sentence map [ t -> [ testlist1 ] of t ] sort link-neighbors
show testlist3
set testlist4 reduce sentence map [ t -> [ testlist2 ] of t ] sort link-neighbors
show testlist4
]
end
See this answer for a bit more detail about the parallel between list operations and agentset operations.
I'm currently do my project about path planning.
So the step of my plans are like this:
Click "setup" to arrange all the coordinate
Click "start" to create the moving turtles
Click "go" to make the moving turtle going to nearest coordinate (label with "x")
Which mean, at step 4, the moving turtle already calculate it's distance with every coordinate.
Here I attach the interface and the coding
to setup
clear-all
set-default-shape turtles "x"
create-turtles 9
ask turtles[set color red]
ask turtle 0[setxy 0 15]
ask turtle 1[setxy 4 15]
ask turtle 2[setxy -4 15]
ask turtle 3[setxy 0 12]
ask turtle 4[setxy 4 12]
ask turtle 5[setxy -4 12]
ask turtle 6[setxy 0 9]
ask turtle 7[setxy 4 9]
ask turtle 8[setxy -4 9]
end
to start
set-default-shape turtles "airplane"
create-turtles 1
ask turtle 9[setxy 0 -15]
end
Don't forget that distance depends on your topology.
to setup
clear-all
let targets [
[0 15] [4 15] [-4 15]
[0 12] [4 12] [-4 12]
[0 9] [4 9] [-4 9]
]
foreach targets [xy -> ask patch item 0 xy item 1 xy [
sprout 1 [set shape "x" set color red]
]
]
create-turtles 1 [ set shape "airplane" setxy 0 -15]
end
EDIT: If you treat all other turtles as eligible targets, then once you move turtle 9 to a target it will stay there. If you do not want that, you say that a turtle in the same location is not eligible:
to move
ask turtle 9 [move-to min-one-of eligibles [distance myself]]
end
to-report eligibles
report turtles with [0 < distance myself]
end