Is there a way to improve the computational time when importing raster data to patches?
Here is my code. This usually takes around 20 minutes to complete. My world is 500x500. I found that using the gis:intersect? is much faster than gis:apply-coverage, if only true or false are to be considered. Cheers.
to setup-gis
set city gis:load-dataset "GSR_GIS.shp"
set LGA_nodes gis:load-dataset "LGA_nodes.shp"
set builtuparea gis:load-dataset "GSR_builtuparea.shp"
set recreationalarea gis:load-dataset "GSR_recreationalareas.shp"
set natural gis:load-dataset "GSR_natural.shp"
set reserves gis:load-dataset "GSR_reserves.shp"
set rail_network gis:load-dataset "Greater_Sydney_rail_networkt.shp"
set roads gis:load-dataset "GSR_road_network.shp"
gis:set-world-envelope gis:envelope-of city
gis:set-drawing-color white
gis:draw city 1
gis:apply-coverage city "LGA" zone
set patchesinlga (patch-set patches with [ zone > 0 ])
ask patchesinlga [
ifelse gis:intersects? builtuparea self [set builtuparea? true][set builtuparea? false]
ifelse gis:intersects? recreationalarea self [set recreationalarea? true][set recreationalarea? false]
ifelse gis:intersects? natural self [set natural? true][set natural? false]
ifelse gis:intersects? reserves self [set reserves? true][set reserves? false]
ifelse gis:intersects? roads self [set roads? true][set roads? false]
ifelse gis:intersects? rail_network self [set rail? true][set rail? false]
if gis:intersects? LGA_nodes self [sprout-LGAs 1 [set color red set shape "flag" set size 2 set LGAid [zone] of patch-here]]
]
ask patches with [zone > 0 and (round([zone] of self) / [zone] of self) != 1][set zone 0] ;; fixed the zone floating point issue
end
*Note for my edit: I've found a way to make this faster by asking only patches of interest. In my case they are patches with LGA (LGA is a zoning id), so that the patches outside of my GIS map will be excluded to run the ifelse loops, at the bottom.
But is there a way to improve this?
Some runtime results
50*50 took 23 seconds
100*100 took 79.5 seconds
400*400 took 30 minutes
I had the same problem: my code took 30+ minutes to complete and my world was only 500x700 patches. The delay was not in loading the data, but in my case, displaying the data. Looking at your code above, I believe you are experiencing a similar phenomena.
In your askpatchesinlga[] procedure, you are asking each patch to check if it intersects data. I think this is what is taking so long to execute. 2500 agents at only a second each is already about 45 minutes of processing time. To speed this up, create rasters beforehand, and load them each into netlogo. That will turn 2500 commands into 7 (ish), and should reduce your processing time accordingly.
In sum: don't ask every patch to do something if you are loading data. Do the processing first and then load in finished datasets - in your case, a built-up area raster, a rec area raster, a natural area raster, etc. Any geoprocessing toolkit should be able to make these for you.
Related
In NetLogo, I'm looking to
have turtles sprout randomly within their boundaries on an imported shapefile and
restrict their movement to these boundaries
Currently, I have them sprouting at the centroid, but quickly they spread across the map. How can I incorporate the shapefile into the turtle's movement? Ideally, they would travel slightly outside their boundary, but I'm sure that's easy to manipulate after I restrict them. The turtles need to be able to interact with eachother across borders, just not travel across the whole map.
See this image for reference:
MSOA File
A separate solution could be to restrict them within a radius of where they sprouted, but unsure of how to do that too.
I've considered:
creating different breeds, but it's much too tedious considering there must be a simpler solution
creating different colored patches and restricting their movement to their assigned-color patch, but that then limits their interaction (and again way too tedious)
What you want to do is to give patches two variables:
One that identifies which region they belong to (I assume this already exists in your code, given that you import a shapefile);
Another one that identifies the patch's own region + regions that are close enough that a turtle from the other region might move there.
I'll call the first variable region and it will be an integer, the second variable allowed and it will be a list of integers.
The idea is that turtles, each of which has its own my-region value based on where it originated from, will look at the allowed patch-variable (and not at region) to see where they can move. That way, each turtle will be able to move to any patch belonging to its own region + to those patches that are close enough to its region (according to a value that you specify, which here I called buffer-range).
This is the logic.
The code below implements it, the relevant part being to create-buffers - which I commented in-code.
Then, to go uses this new information to determine the potential patches where the turtle can move, including those outside its region but close enough (you did not share how your turtles move, but it should be easy to apply the same condition to whatever procedure you are implementing).
; Untick the 'World wraps horizontally' box in Interface > Settings.
globals [
buffer-range
]
patches-own [
region
allowed
]
turtles-own [
my-region
]
to setup
clear-all
create-regions
create-buffers
populate-world
end
to create-regions
ask patches [
ifelse (pxcor < 0)
[set region 1
set allowed (list region)
set pcolor 43]
[set region 2
set allowed (list region)
set pcolor 63]
]
end
to create-buffers
set buffer-range 3
; First, each patch targets the patches that belong to another region which is near enough according to
; the buffer value, and it also creates a local empty list that will be used by those patches.
; Then the patch ask those target patches, if any, to check if their region has not been recorded already
; as a region allowed for movement or as such a candidate. If that's the case, that region is added to
; the allowed-candidates list.
ask patches [
let target-patches (patches with [region != [region] of myself] in-radius buffer-range)
let allowed-candidates (list)
if (any? target-patches) [
ask target-patches [
if (not member? region [allowed] of myself) and (not member? region allowed-candidates) [
set allowed-candidates (lput region allowed-candidates)
]
]
]
; Now, each element of the allowed-candidates list is added to the allowed list.
foreach allowed-candidates [x -> set allowed (lput x allowed)]
]
end
to populate-world
create-turtles 10 [
setxy random-xcor random-ycor
set my-region region
set color pcolor + 2
]
end
to go
ask turtles [
move-to one-of patches with [member? [my-region] of myself allowed]
]
end
For future questions, please share what you have / what you did (check here and here)!
Ideally, you should provide an example of your problem that is like the code part of my answer: you can copy-paste it in NetLogo and you have a workable example.
Hi I am new to netlogo with no programming background,
I am trying to create a network of "neighbours" , using GIS extension ,
so far I'm using in-radius function but i am not sure if it's the one that is suitable.
since i don't understand the unit of radius in Netlogo
here's the code :
to setup
clear-drawing
clear-all
reset-ticks
; zoom to study area
resize-world 00 45 0 20
set-patch-size 20
; upload city boundries
set mosul-data gis:load-dataset"data/MosulBoundries.shp"
gis:set-world-envelope gis:envelope-of mosul-data
gis:apply-coverage mosul-data "Q_NAME_E" neighbor
to Neighbour-network
;; set 7 neighbour agents inside the city
ask turtles [
let target other turtles in-radius 1
if any? target
[ask one-of target [create-link-with myself]]
]
print count links
I want for each neighberhood neighbor each agent is linked to the 7 nearst neighbors.
my guess is that in the line if any? target something has to change , but all my attempts are useless so far.
Thank in advance
I am unclear how GIS relates to this question and you haven't provided the code for creating the agents so I can't give a complete answer. NetLogo has a coordinate system, automatically built in. Each agent has a position on that coordinate system and each patch occupies the space 1 unit by 1 unit square (centred on integer coordinates). The in-radius and distance primitives are in the distance units.
However, if all you want to do is connect to the 7 nearest turtles, you don't need any of that because NetLogo can simply find those turtles directly by finding those with the minimum distance to the asking turtle. This uses min-n-of to find the given number of turtles with the relevant minimum, and distance [myself] for the thing to minimise. The whole thing, including creating the links with the generated turtleset, can be done in a single line of code.
Here is a complete model to show you what it looks like:
to testme
clear-all
create-turtles 100 [setxy random-xcor random-ycor]
ask n-of 5 turtles
[ create-links-with min-n-of 7 other turtles [distance myself]
]
end
Sarah:
1) This helped me understand the use of 'in-radius' in NetLogo (or the unit of radius): When you use 'in-radius 1' in a patch-context, 5 patches will be selected (patch where the asking turtle is located and four neighbors, not all 8 neighboring patches).
2) Consider using 'min-one-of target [ distance myself ]' instead of 'one-of target'.
min-one-of: http://ccl.northwestern.edu/netlogo/docs/dict/min-one-of.html
distance myself: http://ccl.northwestern.edu/netlogo/docs/dict/distance.html
to Neighbour-network
; set 7 neighbour agents inside the city
ask turtles [
let target other turtles in-radius 1
let counter 0
while [ count target > 0 and counter < 8 ]
[ ask min-one-of target [ distance myself ] [
create-link-with myself
set counter counter + 1
]
]
show my-links
]
3) Consider exploring Nw extension: https://ccl.northwestern.edu/netlogo/docs/nw.html
I have a shapefile containing the location of several thousands of people. I want to import this and for each patch, I'd like to count the amount of people on this exact patch (each person is an entry in the shape file, but multiple people can be located on the exact patch depending on my world size).
I have managed to do so using the following code:
set population-here 0
let population-dataset gis:load-dataset "population_file.shp"
foreach gis:feature-list-of population-dataset [a ->
ask patches gis:intersecting a [
set population-here population-here + 1]
However, it takes several hours to load the dataset in a world of -300 to 300 pixels. Is there a faster way of counting the number of individual entries for each patch?
The population should be placed on an underlying shapefile of an area. This area is imported as following:
let area-dataset gis:load-dataset "area.shp"
ask patches [set world? false]
gis:set-world-envelope gis:envelope-of area-dataset
ask patches gis:intersecting area-dataset
[ set pcolor grey
set world? true
]
Okay, I can't test this and I'm not entirely confident in this answer as I use GIS very rarely. But I suggest you adapt the code in the GIS general examples in the NetLogo model library (see File menu). What you appear to want to do is create a turtle breed for your people, and create a person at each location where there is a person in your population dataset.
breed [people person]
patches-own [population]
to setup
< all the other stuff you have >
let population-dataset gis:load-dataset "population_file.shp"
foreach gis:feature-list-of population-dataset
[ thisFeature ->
[ let location gis:centroid-of (first (first (gis:vertex-lists-of thisFeature )))
create-people 1
[ set xcor item 0 location
set ycor item 1 location
]
]
]
ask patches [ set population count people-here ]
end
You can also import other variables from the population set (eg gender or age group) and have those variables transfer to appropriate attributes of your NetLogo people.
If you haven't found it yet, I recommend this tutorial https://simulatingcomplexity.wordpress.com/2014/08/20/turtles-in-space-integrating-gis-and-netlogo/.
Note that this assumes there is a reason why you want the people in the correct (as defined by the GIS dataset) position for your model rather than simply having some sort of population count (or density) in your GIS file and then create the people in NetLogo on the correct patch.
Using GIS, I created a road map of a city. I want turtles to appear randomly on any of the patches with the road during the setup. How would I go about doing this?
using the "n-of", "with" and "sprout" commands will get the job done.
to world ## This block will make the colors,
##you won't want to use this but it made the example reproducible
ask patches [set pcolor random 50]
end
to make_turtles
let Q 5 ##set this to the number of patches you want to spawn a turtle
ask n-of Q patches with [pcolor = 30] [sprout 1] ##tells Q number of random of patches with
##the desired character (in this case pcolor = 30)
## to sprout 1 turtle
end
you can change the with [XXX] bit to be
with [ROAD=TRUE]
if you'd like to put a reproducible example of with the owned variables it'd be easier to give you a more useful answer
patches [roads?]
turtles-own [home-patch]
to setup
setup-drivers
end
to setup-drivers
create-drivers number-of-cars [
set home-patch one-of patches with [ roads? = true]
set shape "airplane"
set color 25
set size 8
move-to home-patch
]
end
I have loaded a shapefile of certain city into Netlogo successfully using the GIS extension as shown below.
with the following code
extensions [ gis ]
globals [ countries-dataset min-map max-map]
patches-own [ mapa ]
to setup
reset-ticks
clear-turtles
clear-patches
clear-drawing
clear-all-plots
clear-output
; Note that setting the coordinate system here is optional, as
; long as all of your datasets use the same coordinate system.
; Load all of our datasets
; Load the dataset
set countries-dataset gis:load-dataset "city.shp"
gis:set-world-envelope (gis:envelope-union-of (gis:envelope-of countries-dataset))
gis:set-drawing-color green
gis:draw countries-dataset 1
reset-ticks
end
to match-cells-to-patches
cd
ct
end
to startup
setup
end
How does one create random turtles along roads only?
Do you only want turtles to be along the roads, or you also want them to move along the roads?
For the former, try gis:find-features and gis:vertex-lists-of to get all vertices in the graph, and choose a random one (this will limit the location to vertex only). If you want location to be somewhere on the straight line section, you can calculate a point between two consecutive vertices.