The UFZ services GitLab and Mattermost will be unavailable on Monday, July 4 from 06:00 AM to 08:00 AM due to maintenance work.

Commit 502abeff authored by Jakob Bürgermeister's avatar Jakob Bürgermeister
Browse files

Added ID to insects in order to prepare tracing their contact networks.

parent 1b665533
Pipeline #53292 passed with stage
in 3 minutes and 35 seconds
......@@ -577,6 +577,19 @@
url = {https://katalog.ub.uni-leipzig.de/Record/0-11836507X}
}
@book{the_solitary_bees,
address = {Princeton, NJ},
edition = {1st edition},
title = {The solitary bees: biology, evolution, conservation},
isbn = {978-0-691-16898-2},
shorttitle = {The solitary bees},
language = {en},
publisher = {Princeton University Press},
author = {Danforth, Bryan N.},
year = {2019},
url = {https://books.google.de/books?id=4DqNDwAAQBAJ}
}
@book{die_wildbienen_deutschlands,
title = {Die Wildbienen Deutschlands},
author = {Westrich, Paul},
......
......@@ -60,6 +60,7 @@ pub enum Activity {
impl Bumblebee {
pub fn new(
params: &Params,
id: u32,
colony_location: ColonyLocation,
species: u8,
rng: &mut Rng,
......@@ -71,6 +72,7 @@ impl Bumblebee {
let insect = Insect::new(
params,
&bumblebee_params.insect,
id,
colony_location.position,
InsectSpecies::Bumblebee(species as u8),
pollen,
......@@ -97,6 +99,7 @@ impl Bumblebee {
flowers: &mut [u64],
colonies: &mut [Colony],
rng: &mut Rng,
next_id: &mut dyn FnMut() -> u32,
contacts: &mut Contacts,
vectors: &mut Vectors,
) {
......@@ -168,6 +171,7 @@ impl Bumblebee {
flower_patches,
flowers,
rng,
next_id,
contacts,
vectors,
);
......
......@@ -72,7 +72,7 @@ During initialisation \marginpar{initialisation}, a species within the hoverfly
\begin{code}
impl Hoverfly {
pub fn new(params: &Params, position: Vector, rng: &mut Rng) -> Self {
pub fn new(params: &Params, id: u32, position: Vector, rng: &mut Rng) -> Self {
let species = params.init.hoverfly_species.sample(rng);
let hoverfly_params = &params.hoverflies[species as usize];
......@@ -82,6 +82,7 @@ impl Hoverfly {
let insect = Insect::new(
params,
&hoverfly_params.insect,
id,
position,
InsectSpecies::Hoverfly(species as u8),
pollen,
......@@ -115,6 +116,7 @@ The state update \marginpar{state update} directly manages the reproductive acti
flowers: &mut [u64],
clutches: &mut [Clutch],
rng: &mut Rng,
next_id: &mut dyn FnMut() -> u32,
contacts: &mut Contacts,
vectors: &mut Vectors,
) {
......@@ -230,6 +232,7 @@ The integration with the generic insect submodel is handled via the \inlinecode{
flower_patches,
flowers,
rng,
next_id,
contacts,
vectors,
);
......
......@@ -179,13 +179,20 @@ As entities are identified by the rank of the process they are located at and th
}
\end{code}
Each individual insect is assigned a unique identifier so that its contacts can be traced through the subworlds.
\begin{code}
let mut id = 0;
\end{code}
Hoverflies are mobile entities which perform their reproductive activities using the stationary clutch entities. Clutches are placed randomly, indexed spatially and discard if they do not support at least a single clutch of eggs in the same manner as the flower patches.
\begin{code}
let mut hoverflies = Vec::new();
for _ in 0..params.init.hoverflies {
let hoverfly = Hoverfly::new(&params, position(&mut rng), &mut rng);
let hoverfly = Hoverfly::new(&params, id, position(&mut rng), &mut rng);
id += 1;
let dest = grid.location(&hoverfly.insect.position);
......@@ -238,7 +245,8 @@ Solitary bees are mobile entities which perform their reproductive activities us
let mut solitary_bees = Vec::new();
for _ in 0..params.init.solitary_bees {
let solitary_bee = SolitaryBee::new(&params, position(&mut rng), &mut rng);
let solitary_bee = SolitaryBee::new(&params, id, position(&mut rng), &mut rng);
id += 1;
let dest = grid.location(&solitary_bee.insect.position);
......@@ -306,7 +314,9 @@ Bumblebees are mobile entities which are always associated to single colony. Hen
}
for _ in 0..colony.capacity {
let bumblebee = Bumblebee::new(&params, colony.location, colony.species, &mut rng);
let bumblebee =
Bumblebee::new(&params, id, colony.location, colony.species, &mut rng);
id += 1;
if dest == rank {
bumblebees.push(bumblebee);
......@@ -339,6 +349,18 @@ Each subworld is provided with a PRNG seeded from a cryptographically-secure RNG
}
\end{code}
The simulation is parallelized by compartmentalizing different parts of the world that only need to communicate when an insect crosses from one part to another. The number of subworlds is given by \inlinecode{size}, each is enumerated by \inlinecode{rank}. To generate mutually exclusive identifiers, each subworld first increments their identifier by their rank, and afterwards the next identifier is always incremented by size, thus for each subworld we have $\mathtt{id} \mod \mathtt{size} = \mathtt{rank}$.
\begin{code}
id += u32::from(rank);
let next_id = Box::new(move || {
let next_id = id;
id += u32::from(size);
next_id
});
\end{code}
Finally, an associative set of lists of messages used to relocate mobile entities between subworlds as explained in \autoref{process-overview} is allocated for each neighbouring process as determined by the spatial subdivision described in \autoref{grid}.
\begin{code}
......@@ -381,6 +403,7 @@ Finally, an associative set of lists of messages used to relocate mobile entitie
colonies: colonies.into(),
observers,
rng,
next_id,
observations: Default::default(),
contacts: Default::default(),
vectors: Default::default(),
......
......@@ -41,7 +41,7 @@ use queue::Queue;
use crate::{
flower_patch::{Event as FlowerPatchEvent, FlowerPatch, Location as FlowerPatchLocation},
params::{Insect as InsectParams, Params, FLOWER_PATCH_MEMORY},
pathogen::{infection_contamination, recovery, Status as PathogenStatus},
pathogen::{infection_contamination, recovery, RecoveryStatus, Status as PathogenStatus},
reduce_lifetime,
space::{reduce, Vector, WithinDistanceOfLine},
units::{Tick, Volume},
......@@ -69,6 +69,8 @@ The parameter \inlinecode{species} is also associated with each instance and is
\begin{code}
#[derive(Clone, Copy)]
pub struct Insect {
pub id: u32,
pub dies_at: Tick,
pub position: Vector,
pub movement: Vector,
pub species: Species,
......@@ -109,17 +111,22 @@ impl Insect {
pub fn new(
params: &Params,
insect_params: &InsectParams,
id: u32,
position: Vector,
species: Species,
pollen: Volume,
rng: &mut Rng,
) -> Self {
let dies_at = insect_params.life_expectancy(params, rng);
let pathogen_status = params
.init
.infection
.status(species, params, insect_params, rng);
Self {
id,
dies_at,
position,
movement: Default::default(),
species,
......@@ -147,6 +154,7 @@ The state update function \marginpar{state update} implements the state machine
flower_patches: &mut [FlowerPatch],
flowers: &mut [u64],
rng: &mut Rng,
next_id: &mut dyn FnMut() -> u32,
contacts: &mut Contacts,
vectors: &mut Vectors,
) {
......@@ -316,8 +324,21 @@ Note that the collection of nectar and pollen can also be preempted by family-sp
}
Activity::Other => (),
}
\end{code}
Each individual insect is assigned a tick at which it dies as defined in \autoref{insect-params}. This is implemented by assigning a new identifier \inlinecode{id} and tick of death \inlinecode{dies_at}. Infected individuals will not die naturally but only when they recover according to the pathogen submodel as defined in \autoref{pathogen-submodel}. This is done so that the distributions of the life expectancy and the recovery time do not interact.
recovery(&mut self.pathogen_status, tick);
\begin{code}
let just_died = match recovery(&mut self.pathogen_status, tick) {
RecoveryStatus::WillRecover => false,
RecoveryStatus::JustRecovered => true,
RecoveryStatus::Unaffected => self.dies_at <= tick,
};
if just_died {
self.id = next_id();
self.dies_at = tick + insect_params.life_expectancy(params, rng);
}
}
}
\end{code}
\ No newline at end of file
......@@ -155,6 +155,7 @@ pub struct World {
pub colonies: Box<[Colony]>,
pub observers: Vec<Observer>,
pub rng: Rng,
pub next_id: Box<dyn FnMut() -> u32>,
pub observations: Vec<Observation>,
pub contacts: Contacts,
pub vectors: Vectors,
......@@ -349,6 +350,7 @@ The invocation order between the three insect families is fixed, i.e. first the
&mut self.flowers,
&mut self.clutches,
&mut self.rng,
&mut self.next_id,
&mut self.contacts,
&mut self.vectors,
);
......@@ -418,6 +420,7 @@ Note that the entries of the \inlinecode{visited\_flowers} arrays are never disc
&mut self.flowers,
&mut self.nests,
&mut self.rng,
&mut self.next_id,
&mut self.contacts,
&mut self.vectors,
);
......@@ -452,6 +455,7 @@ Note that the entries of the \inlinecode{visited\_flowers} arrays are never disc
&mut self.flowers,
&mut self.colonies,
&mut self.rng,
&mut self.next_id,
&mut self.contacts,
&mut self.vectors,
);
......
......@@ -64,6 +64,9 @@ impl FlowerPatch {
}
\end{code}
\phantomsection
\label{insect-params}
The parameters of the insect submodel and its three specialisations describe the different insect species and families.
Mainly this is related to their foraging efforts. The exploration of the landscape is described the distance at which flower patch can be sensed \inlinecode{vision} and the capacity of the memory for depleted and ignored flower patches \inlinecode{memory} with a default value \inlinecode{FLOWER_PATCH_MEMORY} choosen large enough to avoid insects getting stuck within some part of the landscape. Their specific preferences for the various plant species are defined by an acceptance probabilities for each plant species given in \inlinecode{preferences}.
......@@ -72,11 +75,14 @@ The random walk used to represent insect flight is controlled by the pre-multipl
The foraging activity within a flower patch is controlled by the two rates \inlinecode{nectar_consumption} and \inlinecode{pollen_collection}. The former one determines the rate at which the nectar available at flower patches is depleted and thereby the rates at which individual flowers within a patch are visited. The latter one determines the rate at which the insect accumulate the amount of pollen required to engage in their reproductive activities.
The \inlinecode{life_expectancy} distribution determines how often insect identifiers are reassigned which affects resulting contact traces.
The parameters related to the pathogen submodel are the probability of infection when foraging at a contaminated flower \inlinecode{infection}, the probability of contamination of a flower when an infected insect forages there \inlinecode{contamination} and finally the exponentially distributed recovery time of an infected insect \inlinecode{recovery}.
\begin{code}
#[derive(Clone)]
pub struct Insect {
pub life_expectancy: Exp<f64>,
pub vision: Length,
pub memory: u16,
pub speed: Length,
......@@ -91,6 +97,10 @@ pub struct Insect {
}
impl Insect {
pub fn life_expectancy(&self, params: &Params, rng: &mut Rng) -> Tick {
params.tick * self.life_expectancy.sample(rng) as i64
}
pub fn recovery(&self, params: &Params, rng: &mut Rng) -> Tick {
params.tick * self.recovery.sample(rng) as i64
}
......@@ -220,6 +230,8 @@ The default set of plant species was chosen as the five most common plant specie
.into();
\end{code}
The period of adult foraging of solitary bees only lasts for a couple of weeks, for some it is only between 10 to 14 days (see page 37 from \autocite{the_solitary_bees}).
The consumption and collection rates used numbers given for bumblebees in \autocite{commercially_imported_bumble_bees} for nectar consumption and \autocite{imidacloprid_reduce_bumble_bee_pollen_foraging} for pollen collection. Due to lack of more detailed data, these values were then divided by two for solitary bees and by two again for hoverflies based on the relations of their body masses.
The amount of pollen required for a clutch of hoverfly eggs is based on the frequency of up to five eggs per day described in \autocite{biologie_der_schwebfliegen_deutschlands}. The amount of pollen a solitary bee invests into a single brood cell is sourced from \autocite{quantitative_pollen_requirements_of_solitary_bees} while the duration of building a single brood cell is taken from \autocite{components_of_nest_provisioning_behavior}.
......@@ -229,6 +241,7 @@ The parameters of the random walk used to model insect flight are based on \auto
\begin{code}
let hoverfly = Hoverfly {
insect: Insect {
life_expectancy: Exp::new(Rate::per_day(1. / 30.) * tick).unwrap(),
vision: Length::meters(2.),
memory: 128,
speed: Velocity::meters_per_second(3.) * tick,
......@@ -249,6 +262,7 @@ The parameters of the random walk used to model insect flight are based on \auto
let solitary_bee = SolitaryBee {
insect: Insect {
life_expectancy: Exp::new(Rate::per_day(1. / 30.) * tick).unwrap(),
vision: Length::meters(2.),
memory: 128,
speed: Velocity::meters_per_second(3.) * tick,
......@@ -269,6 +283,7 @@ The parameters of the random walk used to model insect flight are based on \auto
let bumblebee = Bumblebee {
insect: Insect {
life_expectancy: Exp::new(Rate::per_day(1. / 30.) * tick).unwrap(),
vision: Length::meters(2.),
memory: 128,
speed: Velocity::meters_per_second(3.) * tick,
......
......@@ -153,12 +153,24 @@ pub fn infection_contamination(
As for the decontamination of flowers, the recovery of insects is spontaneous and happens after a stochastically predetermined time span. In contrast to the DES formalism applied to the flowers, this state transition is checked every time step by the insect submodel independently of whether the insect currently visits a flower patch or not.
\begin{code}
pub fn recovery(status: &mut Status, tick: Tick) {
pub enum RecoveryStatus {
Unaffected,
WillRecover,
JustRecovered,
}
pub fn recovery(status: &mut Status, tick: Tick) -> RecoveryStatus {
match status {
Status::Infected(recovers_at) if *recovers_at <= tick => {
*status = Status::Susceptible;
Status::Infected(recovers_at) => {
if *recovers_at <= tick {
*status = Status::Susceptible;
RecoveryStatus::JustRecovered
} else {
RecoveryStatus::WillRecover
}
}
_ => (),
_ => RecoveryStatus::Unaffected,
}
}
\end{code}
......
......@@ -69,7 +69,7 @@ pub enum Activity {
\begin{code}
impl SolitaryBee {
pub fn new(params: &Params, position: Vector, rng: &mut Rng) -> Self {
pub fn new(params: &Params, id: u32, position: Vector, rng: &mut Rng) -> Self {
let species = params.init.solitary_bee_species.sample(rng);
let solitary_bee_params = &params.solitary_bees[species as usize];
......@@ -79,6 +79,7 @@ impl SolitaryBee {
let insect = Insect::new(
params,
&solitary_bee_params.insect,
id,
position,
InsectSpecies::SolitaryBee(species as u8),
pollen,
......@@ -108,6 +109,7 @@ impl SolitaryBee {
flowers: &mut [u64],
nests: &mut [Nest],
rng: &mut Rng,
next_id: &mut dyn FnMut() -> u32,
contacts: &mut Contacts,
vectors: &mut Vectors,
) {
......@@ -236,6 +238,7 @@ impl SolitaryBee {
flower_patches,
flowers,
rng,
next_id,
contacts,
vectors,
);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment