Adding obstacles and targets from shapefile in netlogo - netlogo

I am new to NetLogo, so my apologies in advance if that question is very stupid. I would like to create an Agent-Based Model where animals move around in a complex terrain looking for water sources. Movement should be downhill, constrained by steep slopes (>25°) and targets should be lakes. I am using a real-world example from GIS data for this, and I have already managed to setup a world containing an ASCII elevation grid, a shapefile containing lines that represent slopes steeper 25degrees and a shapefile containing areas representing lakes. I have created animals (cows) and found a code line telling them to move downhill. Now, I would like to tell them
a) to avoid slopes >25° by using the slope shapefiles as obstacles and
b) to go to the lakes by using the lake shapfiles as targets
Can someone help me how to code this?
Many thanks in advance!
Here is the code I have put together so far
breed [ cows cow ]
extensions [ gis ]
patches-own [ elevation ]
globals [
slope-dataset
lake-dataset
elevation-dataset
]
to setup-terrain
clear-all
reset-ticks
set slope-dataset gis:load-dataset "FILENAME.shp" ;;extent of GIS datasets is N42.3-43.4 and W120.0-121.1
set lake-dataset gis:load-dataset "FILENAME.shp"
set elevation-dataset gis:load-dataset "FILENAME.asc"
gis:set-world-envelope gis:envelope-of slope-dataset
gis:set-world-envelope gis:envelope-of lake-dataset
gis:set-world-envelope gis:envelope-of elevation-dataset
end
to display-slopes
gis:set-drawing-color red
gis:draw slope-dataset 0.5
end
to display-lakes
gis:set-drawing-color blue
gis:draw lake-dataset 2
end
to display-elevation-in-patches
gis:apply-raster elevation-dataset elevation
let min-elevation gis:minimum-of elevation-dataset
let max-elevation gis:maximum-of elevation-dataset
ask patches
[ ; note the use of the "<= 0 or >= 0" technique to filter out
; "not a number" values, as discussed in the documentation.
if (elevation <= 0) or (elevation >= 0)
[ set pcolor scale-color black elevation min-elevation max-elevation ] ]
end
to setup-cows
set-default-shape cows "cow"
create-cows 100 [
setxy random-pxcor random-pycor
set size 1
set color white
]
end
to move
move-to patch-here ;; go to patch center
let p min-one-of neighbors [elevation]
if [elevation] of p < elevation [
face p
move-to p ;; makes cows move to the next lower elevation patch, if no lower
elevetion is present, cow doesn't move
]
end
to go
ask cows [
move
]
end

Thanks Seth, I have found the solution using the gis:intersects? primitive you suggested:
to display-slopes
ask patches gis:intersecting slope-dataset
[ set pcolor red ]
end
to go
ask cows
[fd 1
avoid-ostacles]
tick
end
to avoid-obstacles
ask cows [
if [pcolor] of patch-ahead 1 = red
[rt 90 fd 1]]
end
This way I can color the patches in red that intersect with the shapefile containing the slope vector dataset and then ask the cows to avoid and move around red colored patches.
Thanks again!

Related

Netlogo: measure mean distance between start and end patches

I am teaching myself how to create ABMs in Netlogo using the book of Railsback & Grimm 2012. I am having trouble with one book exercise which is on butterflies following "virtual" corridors. Basic idea is that butterflies go uphill for mating using the differences in height as guide. I need to calculate the width of the corridors dividing the number of patches used by the butterflies over the average distance the butterflies fly from the start patch to the end patch. I am
struggling with plotting this corridor width, which I am coding like this:
to-report corridor-width
let patches-visited count patches with [used?]
let mean-distance mean [distance start-patch] of turtles
report patches-visited / mean-distance
I then created a plot in the interface with the command:
plot corridor-width
The error message I get reads:
Division by zero. error while observer running / called by procedure
CORRIDOR-WIDTH called by plot 'Corridor width' pen 'default' update
code called by procedure SETUP called by Button 'setup'
I believe there is something wrong with the way I am coding distance start-patch but I have surfed the web and looked at several codes and I cannot spot my mistake. My whole code looks like this:
globals [ q ] ;; q is the probability that butterfly moves directly to highest patch
turtles-own [ start-patch ]
patches-own [ elevation used? ] ;; patches property of elevation and whether the patch has been used by butterfly or not.
to setup
ca
;; Let's create patches and asign them an elevation and color by using ask patches statement
ask patches
[
;; Elevation decreases linearly with distance from the center of hills. Hills are at (30,30) and
;; (120,120) coordinates. The first hill is 100 units high whereas the second one is 50
let elev1 100 - distancexy 30 30
let elev2 50 - distancexy 120 100
ifelse elev1 > elev2
[ set elevation elev1 ]
[ set elevation elev2 ]
set pcolor scale-color green elevation 0 100
set used? false
]
;; Create 50 butterflies
crt 50
ask turtles [
set size 6
;; set their initial location as their initial patch
setxy random-pxcor random-pycor
set start-patch patch-here
;; have the butterfly draw its path with the pen-down statement
pen-down
]
reset-ticks
;; Initialize the q parameter
set q 0.4
end
;; The master schedule
to go
ask turtles [ move ]
plot corridor-width
tick
if ticks >= 1000
[
let final-corridor-width corridor-width
write "Corridor width: " print final-corridor-width
;export-plot "Corridor width" (word "Corridor-width-output-for-q-" q ".csv")
stop
]
end
;; let's code the butterfly procedure of movement
to move
if elevation >=
[ elevation ] of max-one-of neighbors [ elevation ]
[ stop ]
ifelse random-float 1 < q ;; Decide whether to move to the highest sorrounding
;; patch with p=q
[ uphill elevation ] ;; move deterministically uphill
[ move-to one-of neighbors ] ;; or move randomly
set used? true
end
to-report corridor-width
let patches-visited count patches with [used?]
let mean-distance mean [distance start-patch] of turtles
report patches-visited / mean-distance
end
What happens when the mean-distance is 0?
let mean-distance mean [distance start-patch] of turtles
Essentially, in your setup, you set all the turtle's start-patch to their current patch. So, if you ask all the turtles how far away they are from their start patch, they will all tell you 0 units away.
So, [distance start-patch] of turtles is filled with a list of all 0's.
Thus, a mean of a list of all 0s is 0 causing your divide by 0 error.
Maybe in this situation, you want to report 0 instead...so
ifelse mean-distance = 0
[ report 0]
[report patches-visited / mean-distance]

set a demand and supply curve for the model tragedy of the commons in the case of an overfished pond

I am new at net logo and I want to write a model based on tragedy of the commons in the case of an overfished pond. The purpose is to find an equilibrium between fishers and fishes based on an economic model with demand and supply. If there are less fishers, more fishes will be in the pond, then after a certain time (ticks) the number of fishers increases and less fishes will be in the pond. Maybe set like a number of fishes per day that can be fished. Thus, the solution is to find a convenient number of fishers as the fishes can still reproduce. I want to have a box in the interface where I can type in a number and see what happens with the number of fishes.
I have no idea how to set this up. I hope to hear from you :)
I started with this code:
breed [fishers fisher]
breed [fishes fish]
to setup
clear-all
reset-ticks
ask patches [set pcolor blue ] ;; lake/pond in form of a rectangle in color
ask patches [ if pxcor > 8 [ set pcolor green ]]
ask patches [ if pycor > 8 [ set pcolor green ]]
ask patches [ if pycor < -8 [ set pcolor green ]]
ask patches [ if pxcor < -8 [ set pcolor green ]]
ask one-of patches with [ pcolor = blue ] [ sprout 20 [set shape "fish" set color pink set size 1.5 ]] ;; creates fishes
ask one-of patches with [ pcolor = green ] [ sprout 2 [set shape "person" set color black set size 3 ] ] ;; creates fishers
end
to go
tick
;;fishes
ask turtles with [ shape = "fish" and color = pink ]
[ right random 360 forward 1
if [pcolor] of patch-ahead 1 = green [ right 180 fd 1 ]]
;; fishers
ask turtles with [ shape = "person" and color = black]
[;right random 360 forward 1
if any? patches with [pcolor = blue]
[set heading towards one-of patches with [pcolor = blue] forward 1]
if [pcolor] of patch-ahead 1 = blue [ right 180 fd 2 ]]
ask turtles with [shape = "person" and color = black]
[if any? turtles with [shape = "fish" and color = pink] in-radius 2
[ask turtles with [shape = "fish" and color = pink] in-radius 2 [die]]]
end
Firstly, I suggest you look through existing models in the Netlogo library (Wolf-sheep-predation model may help). You roughly have the right idea in your current code, but you should look at other models to improve. You've already set your different breeds of turtles, but you should also set up their respective shapes under 'setup'. This would help you a great deal later - instead of calling for
ask turtles with [ shape = "fish"...]
you can simply
ask fishes [do sth...]
For that 'box at the interface', you can have a slider at the interface determining the number of fishers you want your run to start with. With another slider, you can set the fishing pressure in your simulated run (i.e. how many fish each fisher will catch) and I suppose you can also consider how this changes when population of fish decreases.
Finally, for a model like yours, you can observe the supply and demand trend by plotting the curves of no. of fishers over time and no. of fishes over time. Again, look at the wolf-sheep-predation model to have an idea of how to do this.
I can't give you more than this I'm afraid since I'm no pro myself but hope this helps a little. Hope someone else would be able to give you a clearer idea.

NetLogo: identification of valleys = rivers location in artificial landscape

I want to produce the artificial landscape, containing hills, slopes and valleys. So far, so good. Now, I want to place a rivers in the bottom of the valley. I thought that the easiest way will be ask turtle to move uphill/downhill by elevation as drops here: http://modelingcommons.org/browse/one_model/2352#model_tabs_browse_info
However, as my landscape is not real, my valleys are also not linears, but just the "depressions" in the terrain, and thus my river localisation is really weird looking?
Please, is there a way to create hills and valleys reflecting the real terrain in netlogo without using GIS extension? I've found great models of Erosion, Watershed and GIS gradient example, but how can I initially place my turtles to stay only in valleys?
EDIT
the GIS gradient example provide excellent problem solving of movement of all the cells over the space, and they aggregate in valleys. However, as I want to by movement of my turtle "create" the river bed on the bottom of the valley, how can I place it? maybe start at the lowest point and stop after several ticks to not to allow to get on the top of the hill? thank you !
globals [
low
high
range ]
patches-own [
altitude ]
to setup
clear-all
setup-hills
scale-patches
color-patches
end
to setup-hills
ask n-of 2 patches [
set pcolor magenta ]
ask patches [
let max_dist sqrt (world-width ^ world-width + world-height ^ world-height)
set altitude world-width - distance patch 10 10
set altitude world-width - distance min-one-of patches with [pcolor = magenta][distance myself]
]
crt 1 [ ; create a turtle, needed to identify the lowest slope
set color red
let bottom_valley min-one-of patches [altitude]
move-to bottom_valley
]
end
to scale-patches
set low [altitude] of min-one-of patches [altitude]
set high [altitude] of max-one-of patches [altitude]
set range high - low
ask patches [
set altitude altitude - low ; shift every patch down so lowest altitude is 0
set altitude altitude * 99.0 / range ; scale every patch so that the lowest is 0 and highest is 999
]
repeat 5 [
diffuse altitude 0.5 ]
end
to color-patches
ask patches [
set pcolor scale-color green altitude 0 100]
end
to create-river
ask turtles [
let p max-one-of neighbors in-radius 1 [altitude]
if [altitude] of p >= altitude [
face p
move-to p
set pcolor blue
]
]
end
You have the right general idea. I recommend checking out the "GIS Gradient" model on your landscape. You can find it in the Models Library under Code Examples/GIS. Then think how to filter patches that have a minimum number of water particles passing through it over time.
Identification of system of rivers on the landscape using GIS Gradient Example:
http://modelingcommons.org/browse/one_model/2352#model_tabs_browse_info
The whole process of identification of the river system on the complex landscape is composed by 3 subprocesses:
identify the highest points of the landscape
place here the river source (create-source)
identify patches for a downhill stream
from the highest river source, by decreasing elevetion of neighboring cells to the lowest elevation of the river valley
when turtle reaches the edge of the world, turtle dies (go-downhill)
remove top hill points (as the river does not read the summit of the hill)
the river does not start at the top of the hill, but at the highest point of the valley
the highest "river" patches from the river beds system are removed (remove-river-from-top-hill)
The number of sources depends of type of GIS data you have available. The same for the number of patches you wish to remove from the top of the hill.
;; ----------------------------------------------
;; create river
;; ----------------------------------------------
to create-source
; identify the 5 highest points of the landscape
repeat 5 [
; avoid the highest points to be close to each other
ask max-one-of patches with [ not any? turtles-here and not any? turtles in-radius 20 ] [p_elev] [
;ask patches to sporout turtles
sprout 1 [
set size 1
set color orange
]
]
]
end
to go-downhill
; stop if there is no more turtles
if not any? turtles with [color = orange]
[ stop ]
; ask turtles located on top of thehills to move downhill
ask turtles with [color = orange] [
; die when you reach the edge of the world
if ([pxcor] of patch-here = max-pxcor) or ([pycor] of patch-here = max-pycor)
or ([pxcor] of patch-here = min-pxcor) or ([pycor] of patch-here = min-pycor) [
die ]
move-to patch-here ; go to patch center
set pcolor blue ; identify the use of patch
set p min-one-of neighbors with [pcolor != blue ] [p_elev] ;; or neighbors4 with [pcolor != blue]patches in-radius 3
if p != nobody [
; move downhill if elevation of patch you are standing on is higher then one of the neighboring patches
ifelse [p_elev] of p <= p_elev
[
face p
move-to p
set pcolor blue ; identify the use of patch
]
[
;move-to min-one-of patches with [pcolor != blue] [distance myself]
move-to min-one-of patches in-radius 2 with [pcolor != blue] [p_elev]
set pcolor blue ; identify the use of patch
]
]
]
end
to remove-river-from-top-hill
; remove 5% of the blue (river) patches placed on the top of the hill
let total_blue count patches with [pcolor = blue]
repeat total_blue * 0.05 [
ask max-one-of patches with [pcolor = blue] [p_elev] [
set pcolor yellow ]
]
end
Complex river system identified:
(river bed = BLUE, removed top of the hill = YELLOW):

How to randomly remove block side in a grid?

Following on from How to control square size in a grid from square area?, I would like to randomly remove block side in a grid. Here my idea:
%% In a first time, I randomly select a white patch in the grid (figure below):
let random-patch one-of patches with [pcolor = white]
%% Then, I draw red patches to identify intersections between white roads (figure below):
ask patches with [ (pxcor mod (side + 1) = 0 ) and (pycor mod (side + 1) = 0 ) ] [set pcolor red]
%% Finally, I color in brown all white patches that are situated between two red patches and on the same side than the random patch. To identify these white patches, have I to calculate distance between the random patch and the nearest red patches and to color all white patches situated along these distances ?
Thanks in advance for your help.
An alternative way to think about your problem is in terms of finding clusters of white patches: you're picking a white patch at random, and you want to turn all the contiguous white patches to brown.
You can look at the "Patch Clusters Example" in the Code Examples section of NetLogo's model library to see one way to do this.
Here is how I would do it. Let's start by defining a grow-cluster reporter:
to-report grow-cluster [ current-cluster new-patch ]
let patches-to-add [
neighbors4 with [
pcolor = [ pcolor ] of myself and
not member? self current-cluster
]
] of new-patch
let new-cluster (patch-set current-cluster new-patch)
report ifelse-value any? patches-to-add
[ reduce grow-cluster fput new-cluster sort patches-to-add ]
[ new-cluster ]
end
The code may be hard to understand if you're not used to functional programming because it uses recursion within a call to reduce. Still, in a nutshell, it:
takes an existing patch cluster and a new patch to add to this cluster
looks for neighbors of that new patch that should also be added to the cluster, i.e., those that are the same color but not already part of the cluster
calls itself for these new patches to add so that their neighbors can be added to the cluster (and those neighbors' neighbors, etc.) until no new patches are found.
Once you have grow-cluster, you can use it to accomplish exactly what you want by seeding it with an empty cluster and the random patch that you selected:
to remove-random-side
let random-patch one-of patches with [pcolor = white]
let side grow-cluster no-patches random-patch
ask side [ set pcolor brown ]
end
Caveat: for this to work, world wrapping has to be disabled in your model settings.
Since you're making a uniform grid, you might consider just doing math on pxcor and pycor instead of taking the Patch Clusters Example approach. That approach is best suited to dealing with irregular shapes.
To set up your grid, you can just do:
ask patches [
set pcolor brown
let horizontal-street? pycor mod (side + 1) = 0
let vertical-street? pxcor mod (side + 1) = 0
if horizontal-street? or vertical-street?
[ set pcolor white ]
if horizontal-street? and vertical-street?
[ set pcolor red ]
]

To build patch clusters at large spatial scales

I used the code from How to create cluster patches that do not overlap between them to build patches as shown in the first figure below.
Here is the code :
to make-cluster
loop [
let cluster [patches in-radius (2 + random-float 2)] of one-of patches
if all? (patch-set [neighbors] of cluster) [pcolor = black] [
ask cluster [ set pcolor green ]
stop ] ]
clear-all repeat 20 [ make-cluster ]
When I use this code in a large spatial extent (i.e. 1000 x 1000 patches with patch size = 1 pixel), green patches are like circles (see the second figure below).
How can I have patches as shown in the first figure ?
Thank you very much for your help.
If your goal is to simply have heterogeneous regions (rather than specifically blocky, symmetric things), you might play around with some of the answers here: Creating a random shape (blob) of a given area in NetLogo
Frank's solution and my first solution will probably run pretty slow on that large of a world. I just added a solution that should scale to a world of your size. I've put it here too for convenience:
to make-blob [ area x y ]
let blob-maker nobody
crt 1 [ set blob-maker self setxy x y ]
let border patch-set [ patch-here ] of blob-maker
repeat area [
ask blob-maker [
ask min-one-of border [ distance myself ] [
set pcolor green
set border (patch-set border neighbors4) with [ pcolor = black ]
]
rt random 360
fd .8
]
]
ask blob-maker [ die ]
end
That said, if you like the blockiness, it's often the case that models with a large number of patches in a blocky formation can be reworked into models with a smaller number of patches that behave quite similarly. For example, one strategy is to scale down the size and movements of the turtles so that the world is still relatively large to them.