This code relates to an adaption of the NetLogo sandpile model. When the count go grains in each patch exceeds the threshold which in this case is 3, the grains are re-distributed to the surrounding neighbors. I am trying to re-distribute one grain to 4 random neighbour patches.
The code returns a run time error because patches at the edge will not have all the 8 neighbors, so when asking for 4 random neighbours it returns an errors stating can't request 4 ransom agents from 3 etc.
I am trying to find a piece of code that will resolve this problem.
****Code Below*****
to-report stabilize [animate?]
let active-patches patches with [ n > threshold ]
;; The number iterations the avalanche has gone for. Use to calculate lifetimes.
let iters 0
;; we want to count how many patches became overloaded at some point
;; during the avalanche, and also flash those patches. so as we go, we'll
;; keep adding more patches to to this initially empty set.
let avalanche-patches no-patches
while [ any? active-patches ] [
let overloaded-patches active-patches with [ n > threshold ]
if any? overloaded-patches [
set iters iters + 1
]
ask overloaded-patches [
set base-color fired-color
;; subtract 'threshold' amount from this patch
update-n -4
if animate? [ recolor ]
;; edge patches have less than four neighbors, so some sand may fall off the edge
ask n-of 4 neighbors [
update-n 1
if animate? [ recolor ]
]
]
if animate? [ display ]
;; add the current round of overloaded patches to our record of the avalanche
;; the patch-set primitive combines agentsets, removing duplicates
set avalanche-patches (patch-set avalanche-patches overloaded-patches)
;; find the set of patches which *might* be overloaded, so we will check
;; them the next time through the loop
set active-patches patch-set [ neighbors ] of overloaded-patches
]
report (list avalanche-patches iters)
end
Instead of asking 4 neighbors, ask min list 4 count neighbors:
ask n-of (min list 4 count neighbors) neighbors [
...
]
But from the model point of view, there will be different redistribution on the edge of the table, so this is not a good idea. Maybe it is better to have a wrapped world and then manually "push" the grains off the table: select 4 neighbours and call just the ones with close pxcor and pycor. The rest is off the table.
If the world is wrapped (horizontally and vertically), we can always select 4 neighbors:
let selected-neighbors n-of 4 neighbors
Among these 4 neighbors only real neighbors are on the table
set selected-neighbors selected-neighbors with [
(abs (pxcor - [ pxcor ] of myself) < 2)
and
(abs (pycor - [ pycor ] of myself) < 2)
]
ask selected-neighbors [
....
]
Related
I am trying to code for a reverse reaction in biology - I have already done that by taking inspiration from a sample code pasted below. What I don't understand is how is the association rate constant (Kb in the code) and dissociation constant (Ku in the code) are affecting the forward and backward reactions in this code. Are they affecting the speed of movement of the products after they are formed? Are they affecting the speed with which they are formed? I want the Ku to affect affinity for substrates to form a product, and Ku to affect time to dissociate for products. The product is a complex formation of two substrates.
Also, why do they multiple Kb by 2? To slow the product complex down or speed it up? It should slow down due to increase in mass.
breed [reactants reactant] ;; reactants are green, products are red breed [products product]
to setup clear-all set-default-shape reactants "molecule1" set-default-shape products "molecule2" create-reactants number
[ set color green
setxy random-xcor random-ycor ] reset-ticks end
to go ask turtles
[ rt random-float 10 - random-float 10 ;; wander around randomly
fd 1 ] ask turtles
[ ifelse (breed = reactants)
[ react-forward ] ; reactants
[ react-backward ] ; products
] tick end
to react-forward if (any? other reactants-here) and
;; multiply Kb by 2 because 2 molecules are involved
random-float 1000 < (Kb * 2)
[ ask one-of other reactants-here
[ die ]
set breed products
set color red ] end
to react-backward if (random-float 1000) < Ku
[ set breed reactants ;; change back to reactant
set color green
;; then split into two reactants
hatch 1 [ set heading random 360 ] ] end
I'm working on a smaller project and got stuck on an issue, I'm not really sure if it's possible to solve it in NetLogo but I want to give StackOverflow a go!
I got a model that divides the world into different parts and randomly add physical features (such as rivers). If a feature goes through the whole region, I want it to separate the region and make into two regions. As an example, in the picture below, I want to separate the purple region into two unique regions accordingly to the physical feature (black).
The code I used to generate the picture above, can be found below.
to setup
ca
;Setting world.
resize-world 0 19 0 19
;Creating regions.
let x 5
let y 5
let col 45
while [y <= max-pycor + 1][
while [x <= max-pxcor + 1 ][
ask patches with [pxcor < x and pxcor >= x - 5 and pycor < y and pycor >= y - 5][
set pcolor col
]
set x x + 5
set col col + 10
]
set x 5
set y y + 5
]
;Generating physical features.
ask n-of 5 patches[ sprout 1[
set pcolor black]
]
let i 0
while [ i < (max-pycor * 2 )][
ask turtles [
fd 1
set pcolor black
ifelse (random 20 <= 1)
[
rt one-of [-90 0 90]
forward 1
]
[
fd 1
set pcolor black
fd 1
set pcolor black
]
set pcolor black
set i i + 1]
]
ask turtles [die]
end
My strategy for handling this is to realize that all we really need to do is "flood" a patch out by color and tag all the found adjacent patches, then repeat for any un-tagged, non-black patches until they are all done.
NetLogo does not have a "flood" command to get all patches adjacent to a patch meeting a criteria, so we make a special reporter of our own to handle it, patches-adjacent. Then it's just easy to ask those patches-adjacent to set their region to the currently chosen region.
I don't love this code, it's a little finicky and would be prone to infinite loops if tweaked incorrectly, but it should work. I bet there is a cleaner way to do this that I'm not thinking of at the moment.
; add a variable to track the different regions
; the default value will be `0` for each patch when `clear-all` is called
patches-own [ region ]
to set-regions
let current-region 1
; only act on non-black patches that haven't yet been assigned a region
let untagged patches with [ region = 0 and pcolor != black ]
while [any? untagged] [
ask one-of untagged [
ask patches-adjacent [
set region current-region
]
]
; update the region and the untagged patches we have left to process
set current-region current-region + 1
set untagged patches with [ region = 0 and pcolor != black ]
]
; this is just to get a view of the regions to quickly see if our code worked, it can be removed
ask patches [ set plabel region ]
end
to-report patches-adjacent
report patches-adjacent-ex (patch-set self) pcolor
end
to-report patches-adjacent-ex [found pc]
let newly-found neighbors4 with [ (not member? self found) and pcolor = pc and region = 0 and pcolor != black ]
set found (patch-set found newly-found)
ask newly-found [
; use recursion to find the patches adjacent to each newly-found one
; relying on updating the `found` agentset as we go to avoid duplicates
; or looping forwarder
set found (patches-adjacent-ex found pc)
]
report found
end
I solved this by using the Patch Clusters model that can be found in the NetLogo model library.
I would like a turtle to go to the closest patches with most turtles if a threshold of a given variable is met for 5 ticks.
My code is:
to move
let count-tick 5
if var >= 9.5 [
set count-tick count-tick - 1
if count-tick = 0 [
ask turtle [
let nearest-group min-one-of (patches with [sum turtles >= 3] in-radius 3 ) [ distance myself ]
move-to nearest-group ;; go to the biggest crowd near you
ask turtle [ ;; once there do the following
set shape "star"
set color red
]
]
]
]
end
The issue I have is that a) I am unsure how to say the patch with >= 3 turtles closest to you at the given range of 3 (attempted code above) and b) how to say once there, change your shape.
Revised to keep a permanent variable to track whether the variable is high enough 5 times in a row.
turtles-own
[ count-tick
]
; wherever you create the turtles, you need to `set count-tick 5`
to move
ifelse var >= 9.5
[ set count-tick count-tick - 1 ]
[ set count-tick 5 ]
if count-tick = 0
[ let nearest-group min-one-of (patches with [count turtles >= 3] in-radius 3 ) [ distance myself ]
move-to nearest-group ;; go to the biggest crowd near you
set shape "star"
set color red
]
end
First, you are already within an ask turtles code block from the procedure calling this move procedure. So you don't need the additional ask turtles. Look up ask in the NetLogo Dictionary, it iterates through the turtles, running all the code for each turtle in turn.
Second, you need count turtles rather than sum turtles as sum is to add up values.
Note that there is no error checking in this, you may have problems if there are no patches within radius of 3 that have at least 3 turtles.
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]
to setup
ca
reset-ticks
ask patches [
set inside? (abs pycor < 10 and abs pxcor < 10)
set exit? false
ask patch 11 0 [ set pcolor lime set exit? true]
]
repeat initial-population [ ; start condition turtles with any other turtles on neighbors
ask one-of patches with [
inside? and (not any? other turtles-here) and (not any? turtles-on neighbors)] [
sprout 1 [
set color blue
set size 1
]]]
end
to go
tick
define-neighbors-radius-2
move
end
to define-neighbors-radius-2
ask turtles [
set neighbors-ahead2 patches at-points [[2 1] [2 0] [2 -1]]
set neighbors-for-y-up2 patches at-points [[2 0] [2 -1] [1 -2] [0 -2] [-1 -2]] with [inside?]
set neighbors-for-y-down2 patches at-points [[-1 2] [0 2] [1 2] [2 1] [2 0]] with [inside?]
]
end
to move
;; my intent to move turtles to exit without their neighbors are occupied by other turtles, ;;that is the 8 patches around turtles are empty until exit?
ask turtles[
ifelse inside? [
if ycor = 0 [ ;strategy to turtles with in front exit
ifelse exit? [
set heading 90
fd .5
]
[
facexy 11 0
if (not any? turtles-on neighbors) and (not any? turtles-on neighbors-ahead2) [
fd .5
]
]
]
if ycor > 0 [ ; strategy to turtles occupied "bottom-side" of inside?
facexy 11 0
if (not any? turtles-on neighbors) and (not any? turtles-on neighbors-for-y-up2) [
fd .5
]
]
if ycor < 0 [ ; strategy to turtles occupied "down-side" of inside?
facexy 11 0
if (not any? turtles-on neighbors) and (not any? turtles-on neighbors-for-y-down2) [
fd .5
]
]
]
[
set heading 90
fd .5
]
]
end
I try to move turtles to exit but not all turtles move, why?
also, turtles must go out with ycor = 0, that is obliques direction don't allow because neighbors will occupied patches aren't inside!
Can't public this question because "looks like my post is mostly code", so talk about of my life:
seriously my intent is to create a crowd in front of exit and set some rules to delay the turtles flow exit, for this I need the neighbors empty to show interaction between agents.
(also accept some suggest to set this interaction) but at the moment turtles reach exit!
thanks
One problem with this code is that have you three ifs where it appears you only want one of them to run each time, but it's possible for more than one of them to trigger. You have:
if ycor = 0 [ ...commands #1... ]
if ycor > 0 [ ...commands #2... ]
if ycor < 0 [ ...commands #3... ]
but the turtle's ycor might be changed by commands #1 or #2. So it's possible that both #1 and #2 might run, or both #2 and #3, and perhaps other combinations as well. I assume you intended that each turtle should only move once per tick, so I recommend you rewrite this as:
ifelse ycor = 0
[ ...commands #1... ]
[ ifelse ycor > 0
[ ...commands #2... ]
[ ...commands #3... ] ]
Something else that should be fixed in this code:
reset-ticks should go at the end of setup, not near the start. It tells NetLogo setup is finished.
tick should go at the end of go, not near the start. It tells NetLogo a tick has finished.
I don't know if either of these problems I've pointed out are actually causing the unintended behavior you're seeing. Perhaps the bug isn't obvious just from reading over the code. In that case, you have two possible courses of action ahead of you:
1) Back up. Throw away this broken code and go back to the last version of your model that contained only code that have you have verified to work correctly. Then try again, but this time, don't add so much new code all at once. Attempt to make a very small improvement to the code, and get that working, before moving on to the next small improvement. And so on. If at any point you get stuck, come here, show your code, and ask a specific question about it. That question should be much easier to answer than your current question. Questions of the form “Here is a big mass of code that doesn't work, help!" are very difficult to answer.
2) Press on by investigating your questions yourself. You write, “not all turtles move, why?” Perhaps someone can answer this just by reading your code; I can't (unless my first guess above is correct). In order to figure it out, I would have to run the code myself and do experiments with it. I'd do things like try running it with just a single turtle and see if that case fails; add print statements to the code, showing each the turtle's coordinates and motions, so I could try and figure out which turtle is going wrong, and exactly under what conditions; and so forth. It's like detective work, or like doing chemistry experiments in the lab.