Dear all,
I am running an ABM model with NoSpaceAgent representing sardines populations over time with three lifestages identified by the field type::Symbol and with 2 sexes (sex::Symbol).
Adults can spawn in a period of the year and I am trying to apply a weird reproduction rule (based on a previous model which was written in NetLogo); the function was letting reproducing bigger females first with the biggest male available. Males should never reproduce more than 10 times (10 different females; Engaged::Int64 < 10).
I created a MWE down here, a simplification of my simulation with comments and already my question listed, that I will report also here.
- basically all the functions working on the agents actually do not need the
Sardine
(agent) argument as I wrote them. In my simulation instead, other functions need the argumentsfunction(agent,model)
to work. This is confusing to me and I wonder if it can cause problems. especiallyadultspawn
use a loop to go through the females and males, create copies of them and the access themodel.agents[id]
to modify the features. I guess it’s not the proper way to work but I started translating a previous ABM from Netlogo which was working in this way.
2. adultspawn
can be modified work through an advanced scheduler.bytype
? From the documentation for advanced scheduling I didn’t get how, it seems to me that the scheduler would be valid for all the functions in the simulation, yet I want to use the scheduler.bytype
just for adultspawn
- I don’t understand why the
reset_engaged(Sardine, model)
version in the comment is not working.
Could you give me some advice or explanations? It would be amazing. Thank you all in advance!
using Agents
@agent Sardine NoSpaceAgent begin
type::Symbol #adult
sex::Symbol #male,female
engaged::Int64
size::Int64 #number of times the agent reproduced in 1 timestep
end
function generate_adult(N, model)
for _ in 1:N
type_agent = :adult
sex_agent = rand((:male, :female))
engaged_agent = 0
size_agent = rand(100:200)
add_agent!(Sardine, model, type_agent, sex_agent, engaged_agent, size_agent)
end
return
end
# support function to sort agents by size
function sort_agent(agent_type, sex, model, feature)
all_agents = collect(values(allagents(model)))
sorted_agents = sort(filter(agent -> (agent.type == agent_type) && (agent.sex == sex), all_agents), by=agent -> getfield(agent,Symbol(feature)), rev=true)
return sorted_agents
end
#scheduler default faster
properties = Dict(:timesteps => Int64(0))
model = ABM(Sardine; properties=properties)
generate_adult(40, model)
# stepping functions --
#increase timestep
function evolve_model(model)
model.timesteps += 1
println("timestep ", model.timesteps)
return
end
# each timestep I reset engaged and let them spawn
function sardine_step(model)
# (?.1)here Sardine argument is useless, in my complete simulation
# however I have other function tht need Sardine argument to work at each timestep.
reset_engaged(model)
adultspawn(model)
return
end
function reset_engaged(model)
for agent in allagents(model)
agent.engaged = 0
end
return
end
# (?.2) not clear why this alternative was not working
#function reset_engaged(Sardine, model)
# Sardine.engaged = 0
# return
#end
function adultspawn(model)
#sort males and females by size
sorted_female = sort_agent(:adult, :female, model, "size")
sorted_males = sort_agent(:adult, :male, model, "size")
for f in sorted_female
current_male_index = 1
#check if there are no males
if isempty(sorted_males)
println("no males available")
break
else
partner = sorted_males[current_male_index]
end
#choose the biggest male for each sorted female
if partner.engaged >= 10 #number of times reproduced
#if reproduced more than 10 times, pick the second biggest male
current_male_index += 1
if current_male_index > length(sorted_males)
println("No more males available for reproduction")
break
else
partner = sorted_males[current_male_index]
end
end
#add event of reproduction
partner.engaged += 1
f.engaged += 1
# Update the agents in the model
model.agents[partner.id].engaged = partner.engaged
model.agents[f.id].engaged = f.engaged
end
return
end
# run the model and store results
adata = [:sex, :size, :engaged]
df_agent = init_agent_dataframe(model, adata)
df_agent = run!(model, sardine_step, evolve_model,100; adata)
#takes approx 1 sec at timestep --> slooow
df_agent1 = sort!(df_agent[1], :size, rev=true)
show(df_agent1, allrows=true, allcols=true)
#seems to work but it seems slow and I would like to use a scheduler.bytype
#for adultspawn to not create copies of the agents but call the Sardine argument.
#Is it possible?