I am building a type of 'honey-bee' model, where the bees are turtle agents and the honey is a patch specific variable. In my model, each patch is assigned a value of 'honey-here' between 1-100 based on a specific distribution.
The model starts with the bees only being able to collect honey from flowers with honey = 1, for which they then receive 1 unit of honey in return. Before the bees can 'target' flowers with honey = 2, they need to occupy (i.e. a bee on a flower) X% of the total flowers with honey = 1. For example, I might require the bees to achieve 80% occupancy, which means if there are 10 flowers total with the variable honey = 1 then the bees need to occupy 8 of those flowers before they are allowed to start looking/targeting flowers with honey = 2. As each bee individually acts, the % occupancy value will change.
I'm having performance issues for the occupancy calculation. Ideally the calculation is updated within a turtle procedure as it needs to be applied to each turtle within the loop. Here's what I currently have to find the value of the variables I need to set current % occupancy before each bee is allowed to act:
ask bees
[
;; set up variable based on ratio of number of turtles occupying target patch size against total number target patch size
;; note -- don't do this in one step to avoid divide by 0
let patch-count-current (count patches with [honey-here = bee-honey-target-size])
;; don't want number of bees, want number of unique patches
let patch-target-occupy count patches with [ (count bees-here > 0) and (honey-here = bee-honey-target-size) ]
...
Later in the code, after checking to make sure patch-count-current isn't 0, I find my % occupancy via patch-target-occupy / patch-count-current
It turns out this is a very expensive hit on my processor performance. Especially as my number of bees grows, which is exponential in my model.
Is there a better way that won't cost me so much processor for each iteration of the loop?
Thanks!
-dp
Given your response to StephenGuerin, you could manually track the counts with global variables. If there is only one bee-honey-target-size at a time, this is pretty simple. Just make a patch-count-current global and a patch-target-occupy. Then, increase them or decrease them as things change.
The Sandpile model (from the models library) uses this technique to keep track of the total amount of sand without having to iterate over the patches. Check out how the total global variable is used.
If you need to keep track of the counts for all bee-honey-target-sizes at once, you could store a list of the counts in a global variable, where the index of the list corresponds to a value of bee-honey-target-size. This is much messier unfortunately, so you would have to write helper functions for sure.
Let me know if any of this needs clarification.
Percentage occupancy is a property of the group and only needs to be calculated once per simulation step. Your performance hit is due to calculating occupancy for every bee in your simulation. The calculation for percentage occupancy for a given 'target-honey' could look like this:
to-report calc-occupancy [target-honey]
report (sum [count turtles-here] of patches with [honey-here = target-honey]) / count turtles
end
Related
Looking for a way to store a turtle length of stay in the model after they have left the model. My model runs for several months and a few thousand turtles enter, undergo process then leave the area. It's complicate model (it's a hybrid DES and ABM) so I've tried to reproduce the simple bit below.
Turtles will be created at every tick and given a random length of stay but will only be able to begin process when they move to the right area (area-name) and when their time is up they leave the area. Their time-in-system reflects the wait for the area and the length-of-stay which I want to save once they're complete. If I leave them in the model it starts to break down after a couple of months and I suspect this is because the model has too many turtles still in the system for calculation and is inefficient.
go
create turtles 2
[
set time-in-system 0
set length-of-stay ceiling ((random-normal 48 4) + ticks)]
set shape "person"
if any? area-name with [not any? turtles-here]
[move-to one-of area-name]
]
undergo-process
end
to-undergo-process
ask turtles with [shape = "person"]
[
set time-in-system time-in-system + 1
]
ask turtles-on area-name
[if ticks = length-of-stay
[set shape "dot"
move-to exit-door]
end
I can then plot and see in realtime to make sure it is working
histogram time-in-system of turtles with [shape = "dot"]
but can't seem to figure out how to store them as unique values for plotting after the model has run and I have a dataset of outcomes without keeping them alive in the model. The real-time plot isn't necessary as long as I can store the unique values after they have left
If I ask them to die then I lose the unique values in the histogram. I don't want a tally of all values but each turtle's unique value at the end of the process after they left - at the moment the only solution I have to storing them is as an agent-set that stays alive in the exit-door patch but this takes up a lot of calculation power as the model progresses for months...
There may be a really simple command for this but I've been going round in circles through the programming manual trying to find it. Any tips appreciated
You should create a list storing the values of turtles that left.
Isolating only the code that is relevant for this purpose, it would be something like:
globals [
times
]
to setup
set times (list)
end
to leave-simulation ; This being executed by turtles.
set times lput (time-in-system times)
die
end
If your program is going to run for actual months, I recommend you use the file-write command to store your data. This way the data is preserved if the program halts for any reason; it gives you much more freedom to do the analysis you want without running the full simulation again.
If you write to a .csv (comma separated value) file, you can use almost any program (excel, R, matlab, python, C# or back to netlogo) to plot a histogram.
I'm working with a NetLogo model on EV charging behaviour. All (500) agents monitor their my-charging-demand per tick and I want to find out what happens to this emergent behaviour when I change the policy intervention that is active (costs of electricity in this case). I am trying to show changes in charging characteristics such as charging-duration, charging power etc.
What is the best way to create data on the agents' my-charging-demand in time?
Right now I am plotting all their data in one graph using the following code:
ask adopters
[ create-temporary-plot-pen (word-who)
set-plot-pen-color color
plotxy ticks my-charging-demand
]
It works, but unfortunately it also made the model incredibly slow, as 500 pens are to be updated every tick. The model needs 105120 ticks before a whole year/run is completed, as each tick in the model represents 5 minutes. Therefore, speed does matter :-)
Is there a more efficient way to keep track / create data of one variable all agents have?
If I have understood this correctly, you want each agent to remember the value of its variable my-charging-demand across all time. If so, the easiest way (but I don't know if it's more efficient) is to have the list as a turtle variable. So, modify your turtles-own to add another variable:
adopters-own
[ ....
my-charging-demand
my-charging-demand-series
]
And wherever you have the code for calculating demand, add the result to the list
ask adopters
[ ...
set my-charging-demand ...
set my-charging-demand lput my-charging-demand my-charging-demand-series
...
]
I can't imagine a plot with 500 lines is readable. The plot should do something like the average of my-charging-demand or the proportion of turtles with my-charging-demand greater than some threshold.
I am trying to model a stock market. I am trying to give agents a certain kind of behaviour to base their prediction of the prices on.
So basically, every agent predicts the price of the share. In the Setup procedure, a random predicted price is assigned to each agent. As the time passes, the predicted price is supposed to be calculated as follows:
total of predicted price of the last 3 periods / 3
I don't know how to approach this issue. I tried using the last command but it does not work. I was thinking about making a sort of vector but I couldn't do so. Any leads?
This is what I have tried so far:
ask turtles [
set pre-price (pre-price + last [pre-price] of turtles + last [last [pre-price] of turtles] of turtles) / 3 ]
end
The last command does not work as I want it to work because I have tried to manually calculate the results and they don't reconcile with this command. Any idea on how to go about it?
Thank you!
This is actually a very interesting bug.
The issue is that inside your turtle call, you assume all the turtles "pre-price" is static; however, with each agent, they are assigning the variable.
I'd suggest to introduce another variable which explicitly stores the pre-prices for each tick (using a matrix/nested list)
I am struggling with trying to write this command.
Basically, what I want to do is this:
I have a collectors [own carryingcapacity], bins [own waste in bins] and warehouses [own waste_in_warehouse] as turtles.
The collectors have a maximum carrying capacity value.
I want to make the collectors check if they have carrying capacity when they find a bin, if trash in bin <= collectors max capacity, the collectors will collect, if not they'll ignore the bin.
I came up with something like this:
ask collectors
[
if any? bins with [distance myself <= 1]
[set carryingcapacity (carryingcapacity + (bins_holding_capacity of myself))]
]
Second command:
I want to make the collectors take the trash they collected to the warehouse. But this variable's value might change from one collector to another, and might vary with the quantity of bins they checked.
I want the warehouse to sum the value that it already had it on the previous days with the new daily values.
I came up with something like this as a line of command:
ask warehouses
[
if any? collectors with [distance myself <= 1]
[set waste_in_warehouse ( waste_in_warehouse + (carryingcapacity of myself))]
Thank you in advance.
Best wishes.
If I'm understanding correctly, your code for command #1 is doing the following:
ask collector agents
See if there are any bins close to a collector (but you didn't ask for this group)
increment the collector's carryingcapacity by (bins_holding_capacity) of myself (you can't use myself like this, because you aren't in a nested ask)
Step 3's logic also seems wrong, since this would be changing the collector's capacity each time, as opposed to checking if it is full.
It should be noted that by using any?, you are not also commanding that group of agents. any? only returns true or false, corresponding to whether there were agents that met the criteria or not. You need to use a second ask to command these agents.
Based on what you said, you'll need to do something like this:
ask collectors
[
ask bins with [distance myself <= 1] ;;myself refers to the collector asking
[
ifelse (waste_in_bin + [waste_in_collector] of myself) > [carryingcapacity] of myself
[;;add the waste to the collector]
[;;stop asking bins, collector is full]
]
]
These same steps should help with your second question, too.
I'm trying to implement a monitor in the user interface that displays the average value of a variable shared by a breed of turtles (turtles own). Does anyone know of a method of collecting all the values, adding them together and dividing by the quantity of turtles to get the value or know of an easier method?
If the variable that each turtle has is shell-size, for example, then:
print mean [shell-size] of turtles
will do it. It might be useful to know how to do this by hand, so that you can do other calculations if you want. Here's one way:
print (sum [shell-size] of turtles) / (count turtles)
Here's another
let total 0
ask turtles [set total total + shell-size]
print total / (count turtles)
Obviously, you'll want to replace the print statements with whatever suits your needs. For a monitor, you should be able to enter this code directly into the interface, or wrap it up in reporter and then use that in the monitor.