I've just started a project in which I intend to simulate (among other things) the seed dispersal around trees (named zsps). Neighboring patches can already be settled or unable for seeding due to low fertility.
I wrote code that runs (at the begining of simulation) but that made the code enter into an infinite loop (I think) because some trees attempt to spread seeds but cannot find any available place.
Does anyone have a solution to escape from this trap (in case the number of places is < the number of seeds or in case there are no places at all)?
Here is the procedure I wrote :
to check-seed-dispersal
ask zsps[
let nb-seeds 0
ifelse (age > 4) [set NFemFlowers 100]
[set NFemFlowers 0]
let temp-color color
if Tot_pol > 0
[set nb-seeds round ((NFemFlowers / Tot_pol) * 6 ) ]
if (nb-seeds > 0 )[
ask patches in-radius 5 with [fertility > 8 and not any? zsps-here]
[sprout-zsps nb-seeds
[ifelse (temp-color = yellow)
[set color gray set age 0 ]
[set color red set age 0 ]
]
]
]
]
end
Related
I have a netlogo application in mind which involves multiple non interacting layers. Think floors of a building. Would I need to go to netlogo 3D or is there a suggested way to handle in regular netlogo?
This was an interesting enough question that I decided to make a simple sample.
The method I use is to have a global variable to track the number-of-floors we'll have in our building, as well as the active-floor that we are currently working with. Then all our agents, walls and workers, have a floor-num that tracks which they are on. We have a set-active-floor procedure that handles switching our currently active floor that we want to see and work with, making the patches a certain color (active-color) if they have a wall agent present and swapping which workers are hidden?. In this way, most of the magic happens in the setup-floor and set-active-floor procedures, and the real work of our model in go can be pretty typical NetLogo code asking the active-workers to do whatever we want.
While the model is running you can call set-active-floor n to any value 0 to 4 to change the current workers and walls. I also included a show-all procedure that'll un-hide all the walls and workers and let you see where they are at; you'll need to run that with the model stopped.
globals [colors active-color number-of-floors active-floor]
turtles-own [floor-num]
breed [walls wall]
breed [workers worker]
to setup
clear-all
set colors (list red blue green orange violet)
set number-of-floors 5
foreach (range 0 number-of-floors) setup-floor
reset-ticks
set-active-floor 0
end
to setup-floor [num]
set active-floor num
set active-color (item num colors)
ask patches [ set pcolor black ]
; make some random walls
create-walls (count patches * 0.2) [
set floor-num num
set hidden? true
set size 0.5
setxy random-pxcor random-pycor
set pcolor active-color
]
; only one wall per patch
ask patches [
let patch-walls floor-walls-here
let wall-count count patch-walls
if (wall-count > 1) [
ask n-of (wall-count - 1) patch-walls [ die ]
]
]
; make some workes
create-workers 10 [
set floor-num num
set hidden? true
set shape "person"
set color active-color - 2
move-to one-of patches with [pcolor != active-color]
]
end
to go
; this only "runs" the active floor, but you could run all of them
; using the same `foreach (range 0 number-of-floors) ...` code as
; in the `setup` procedure.
set-active-floor active-floor
ask active-workers [
; this code can be about the same as you'd write in a normal model...
move-to one-of patches with [pcolor != active-color]
]
tick
end
to set-active-floor [num]
set active-floor num
set active-color (item num colors)
; after the `pcolor` is set, we can use that to determine if a wall
; exists or not for an `active-worker`, we don't have to check the
; floor number at all while we do our work.
ask walls [ set hidden? true ]
ask patches [
set pcolor ifelse-value no-walls-here [ black ] [ active-color ]
]
ask workers [
set hidden? floor-num != active-floor
]
end
to-report active-workers
report workers with [floor-num = active-floor]
end
to-report floor-walls-here
report walls-here with [floor-num = active-floor]
end
to-report no-walls-here
report (count floor-walls-here = 0)
end
to show-all
foreach (range 0 number-of-floors) [ num ->
ask patches [
set pcolor ifelse-value any? walls-here [ red - 3 ] [ black ]
]
ask turtles with [floor-num = num] [
set color item num colors
set hidden? false
]
]
end
Finally, if things got much more complicated than this, I would probably choose to move to NetLogo 3D instead.
I am working on a project to model the impact of charging electric cars on the grid and modeling/simulating the driving and charging habits of the car users. I'm getting an issue in my code that unable to resolve yet.
Each location has a limited number of charging ports. For example, WORK has a total of 2 TERMINALS, so only 2 adopters can charge there simultaneously (first-come-first-serve basis). What I want to do is when 2 adopters arrive at WORK, they start charging (if required, i.e. "charging-status" = true). Any additional adopters wait until a port is available there. The adopters who finish charging should vacate the charging port for those in the wait-list, even if they don't leave.
Here's part of my effort (code) that I did:
to go
...
charge-car ; sets the charging-status based on state-of-charge.
ask adopters
[
if charging? and not marked?
[
ifelse remaining-ports != 0
[
set remaining-ports max list (remaining-ports - 1) 0
set marked? true
]
[set occupied? true]
]
if marked? and not charging?
[
set remaining-ports min list (remaining-ports + 1) terminals
set marked? false
set occupied? false
]
]
ask adopters with [charging? and marked?]
[
set color green
let battery0 battery
let charging-speed0 charging-speed
let battery1 max list 0 ( battery + charging-speed0 )
set battery min list battery1 battery-capacity
let charged min list ( battery - battery0 ) charging-speed0
set charge-demand charge-demand + charged
set soc battery / battery-capacity
set range-left battery / discharge-patch
]
tick
end
Now, the issue is this: there are multiple location on the map with charging ports. This code gives different results at some locations, even though it is the same algorithm for all locations and agents. For example, if both ports are occupied at certain locations, the "occupied?" will be true for some locations and not all of the ones with all ports engaged. I mean to say, this is showing quite a random response.
Can anyone please help me with this? Is there another way to do what I want to do? Also, please let me know if you need more info to understand my situation.
Thank you!
Edit:
This is my code for to go
to go
...
ask adopters
[
if patch-here = current-loc ; choose next target only when reached at a destination (current location)
[
choose-target
set nearest-station min-one-of patches with [location = "charging-station"][distance myself]
] ; choose target based on start time and current location
; go to target only when NOT at the arbitrary target location
if target != [0 0]
[
let dist-to-targ distance-between current-loc target
let dist-to-station distance-between current-loc nearest-station
ifelse dist-to-targ > range-left and dist-to-station < range-left
[go-to-station nearest-station]
[go-to-target]
]
if charging = "Charge Car Now"
[charge-car]
...
]
where, charge-car is
to charge-car
if patch-here = current-loc and charging-point
[
ifelse soc < 1
[
if charge-power = 1
[
set charging-speed 1 / 12
set charging-status true
]
if charge-power = 2
[
set charging-speed 6.6 / 12
set charging-status true
]
]
[
set charging-status false
set color blue
]
]
end
and go-to-target is
to go-to-target
ifelse patch-here != target
[
; move towards destination and use fuel
face target
; set marked? false
set color blue
ifelse distance target <= speed
[set speed1 0.3 * distance target] ; decrease speed as target gets nearer
[set speed1 speed]
forward speed1
set moving? true
set charging-status false
if marked?
[
set rem-term min list (rem-term + 1) terminals
type patch-here type "Updated ports" print rem-term
set marked? false
set occupied? false
]
]
[
move-to target
if target != [0 0]
[set dist-trav distance-between current-loc target]
set current-loc target
set moving? false
set dwell dwell-acq day-ind time-ind position [location] of target places ; calculate dwell time based on arrival time at target
ifelse dwell < 0
[
set dwell 288 - (ticks mod 288) ; spend rest of the time till 24:00 at that location
set dwell-flag 1
]
[set dwell-flag 0]
if current-loc = target
[
set arrival-time (ticks mod 288)
set start-time (dwell + arrival-time) mod 288
set target [0 0]
set battery battery - (discharge-patch * dist-trav) ; discharge based on distance traveled per tick
set soc battery / battery-capacity
set range-left battery / discharge-patch
if battery < 0
[set battery 0]
if soc < 0
[set soc 0]
]
]
end
where, rem-term is same as remaining-ports and charging-status is same as charging?.
I tried adding the same code in the go-to-target function, since charging-status changes there first, but that didn't show any change in the results I'm getting.
I can't see anything obviously wrong with your code. This sort of thing usually happens because you have multiple ask turtles blocks, and you work out the intention in the first block but don't do the behaviour until the second block. In your case, I can see you updating the ports count in the first block, so that doesn't directly apply.
However, I wonder if you're doing something similar with your if statements, that turtles are going through different blocks than you expect and the relevant code is missing from the extract that you pulled out. The easiest way to diagnose this type of problem is with print statements. See below for one possibility.
ask adopters
[ if charging? and not marked?
[ ifelse remaining-ports > 0
[ type patch-here print remaining-ports
set remaining-ports remaining-ports - 1
set marked? true
type patch-here type "Updated ports" print remaining-ports
]
[ set occupied? true ]
]
if marked? and not charging?
[ set remaining-ports min list (remaining-ports + 1) terminals
set marked? false
set occupied? false
]
]
Note that I also changed your code for testing/updating number of remaining ports for clarity.
On your question about lists, there is no problem adding a turtle to a list (eg set queue lput self queue) but if you want more detail than that, please ask a separate question. I strongly recommend that you do not make any attempt to introduce queues for your ports until you have the existing code working properly.
I am trying to make a turret that will fire 8 bullets in 8 directions. In the command I have, they all spawn with heading 0 how do I make them face the right direction. Each turtle should face in a multiple of 45. Just like it would with the cro command in observer context.
to fire-tacks
ask ttacks with [alive?] [
set attackSpeed attackSpeed + .5
if any? turtles with [is-bloon?] in-radius 5 and attackSpeed >= 12
[set attackSpeed 0
hatch-btacks 8 [set alive? false set is-turret? false
set size 1 set damage 1 set color black set is-dart? true set bullet-
speed 4
]]]
end
You could use range and foreach to do this (check the links for more detail on how they work). range can generate a sequence of the headings you would like, and foreach can iterate over that sequence to sprout new turtles with each heading. Have a look at this simplified example:
breed [ turrets turret ]
breed [ btacks btack ]
to setup
ca
create-turrets 1 [
setxy random-xcor random-ycor
]
reset-ticks
end
to go
ask turrets [
foreach ( range 0 360 45 ) [
new_heading ->
hatch-btacks 1 [
set heading new_heading
fd 1
]
]
]
end
I'm trying to program turtles finding jobs. They are separated in age groups.
The patches are the jobs, with two variables called "salary-here" and "hours-worked" generated randomly.
I'm trying to make my turtles (people) to stop moving (looking) when they find the patch (job) with the highest salary-here/hours-worked, but they always keep moving.
patches-own
[salary-here ; amount of salary paid in one specific job (patch)
hours-worked ; time working and leisure
reward-ratio ; ratio between salary and hours ]
turtles-own [age]
to search-job ; they can only find jobs according to age "zones"
if age = 1 [ move-to one-of patches with [ pxcor > 10 and pxcor < 40 ] ]
if age = 2 [ move-to one-of patches with [ pxcor > 40 and pxcor < 70 ] ]
if age = 3 [ move-to one-of patches with [ pxcor > 70 and pxcor < 100 ] ]
end
to go
ask turtles [ search-job ]
ask turtles [ keep-job ]
tick
end'
The idea is to: keep-job (stay in patch) if condition (reward-ratio is maximum in the surrounding area), if not, search job.
Thanks in advance for any help.
The idea is to not move a turtle if they should stay.
In your go,
ask turtles with [should-stay = false] [search-job]
I would then write a function called should-stay and insert your stay logic there.
to-report should-stay
report [reward-ratio] of patch-here >= max [reward-ration] of neighbors4
end
There are alternative ways which include storing a turtle variable that could help improve speed if performance is an issue.
From BehaviorSpace, I would like to run a model 100 times by varying two variables as follows:
["x-area" 1 ] and ["y-area" [1 1 100]].
A model is built as follows:
create landscape
add-turtles
go-simulation
By using the two variables, I would like that my 100 models run as follows:
;;; Model 1 ;;
"x-area" = 1
"y-area" = 1
clear-all
create landscape
add-turtles
go-simulation
;;; Model 2 ;;
"x-area" = 1
"y-area" = 2
add-turtles
go-simulation
;;; Model 3 ;;
"x-area" = 1
"y-area" = 3
add-turtles
go-simulation
....
;;; Model 100 ;;
"x-area" = 1
"y-area" = 100
add-turtles
go-simulation
To do this, I built 100 experiments and this method worked. Is there a faster way to run automatically 100 models without doing 100 experiments ? I tried to build 1 experiment like this
But I have this error message:
OF expected input to be a turtle agentset or patch agentset or turtle or patch but got NOBODY instead.
org.nlogo.nvm.ArgumentTypeException: OF expected input to be a turtle agentset or patch agentset or turtle or patch but got NOBODY instead.
at org.nlogo.prim._asm_proceduremovewithinpolygon_ifelse_86.perform(:4)
at org.nlogo.nvm.Context.runExclusive(Context.java:119)
at org.nlogo.nvm.ExclusiveJob.run(ExclusiveJob.java:57)
at org.nlogo.nvm.Context.runExclusiveJob(Context.java:162)
at org.nlogo.prim._asm_procedurestartsimulation_ask_69.perform(:1)
at org.nlogo.nvm.Context.stepConcurrent(Context.java:91)
at org.nlogo.nvm.ConcurrentJob.step(ConcurrentJob.java:82)
at org.nlogo.job.JobThread.org$nlogo$job$JobThread$$runPrimaryJobs(JobThread.scala:143)
at org.nlogo.job.JobThread$$anonfun$run$1.apply$mcV$sp(JobThread.scala:78)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at scala.util.control.Exception$Catch.apply(Exception.scala:88)
at org.nlogo.util.Exceptions$.handling(Exceptions.scala:41)
at org.nlogo.job.JobThread.run(JobThread.scala:75)
The problem is that my models continue to run with this error. So it is difficult to see where is the problem. Given the following message:
"at org.nlogo.prim._asm_proceduremovewithinpolygon_ifelse_86.perform(:4)" in the error message,
maybe that the problem is in the procedure "move-within-polygon".
Here is my procedure "move-within-polygon" for a given color of polygons:
if [pcolor] of patch-here = green [
set list-angles-in-green item 0 table-angles
loop [
let angle-in-green one-of list-angles-in-green
ifelse [pxcor] of (patch-right-and-ahead angle-in-green 1) = max-pxcor or [pycor] of (patch-right-and-ahead angle-in-green 1) = max-pycor [
print "die"
die
stop ]
[ ifelse (patch-right-and-ahead angle-in-green 1) != nobody and [pcolor] of (patch-right-and-ahead angle-in-green 1) = green [
print "move"
move-to patch-right-and-ahead angle-in-green 1
[ if not any? neighbors with [pcolor = green] [
print "no neighbors"
move-to patch-here
stop ] ] ] ] ]
Thanks for your help.
If a turtle ends up on the edge of the world, then patch-right-and-ahead angle-in-green 1 might point outside the world (depending on what angle-in-green is), so [pxcor] of in [pxcor] of (patch-right-and-ahead angle-in-green 1) = max-pxcor would ask for the coordinate of nobody. The same thing could happen for pycor later in the same line.
Question: Can a turtle ever get to the edge of the world in your model? It looks to me like the code that you displayed could lead to that result.
If so, then one way to prevent the error would be to replace
[pxcor] of (patch-right-and-ahead angle-in-green 1) = max-pxcor
with
xcor = max-pxcor
That's true when a turtle reaches the last column of patches. If you also want turtles to die when they're close to the edge, you could use both of these expressions in the if-else:
(xcor = max-pxcor) or ([pxcor] of (patch-right-and-ahead angle-in-green 1) = max-pxcor)
(I added parentheses simply for clarity.)
However, I wonder whether this would serve the same purpose:
xcor = max-pxcor or xcor = max-pxcor - 1
If any of these methods are right for your application, then you can obviously do the same thing for the y coordinates.
Your experiment setup appears correct to me, except that you should remove the "Stop condition" of TRUE, because if the stop condition is always true, your runs will never run the go commands even once.
The error you're getting is coming from code that you haven't shown us, so I can't help you there. You'll need to show us the code in which the error is occurring.
Also, at the time the error occurs, what are the values of x-area and y-area? And does the same error occur if you set x-area and y-area to the same values outside BehaviorSpace? If so, then the error doesn't really have anything to do with BehaviorSpace.
Finally, a note on terminology: there is only one model here, not 100, and only one experiment here, not 100. You're attempting to run one experiment on your model, and that experiment consists of 100 model runs. Using the standard terminology will help you communicate your issue clearly.