Specification and documentation of the PWN model.
Results of model experiments can be found under https://pwn-model.github.io/PWNModel.jl
Trees are represented individually with state variables representing health state, beetle colonization and nematode infestation.
Beetles are represented in an abstract way when no nematode is involved. There is a beetle presence flag for trees, and a simple annual dispersal process based on a mass-conserving kernel.
Beetles are represented individually only where relevant for nematode dispersal:
- [TODO] Eggs, larvae and pupae in nematode-infested trees
- Adults with nematodes during maturation and ovipositioning
The model has a weekly time step.
Trees are positioned on a grid with either one large tree or multiple small trees per cell. Cell size is in the order of magnitude of 10m.
The world is divided into blocks of 1×1 km (rounded to whole tree cells; blocks at the
upper world edges may be smaller), and each block is forested with probability km2_probability.
In forested blocks, each tree cell holds a tree with probability tree_probability.
A tree is initially damaged with probability damage_prevalence (Damaged tag),
and a damaged tree is additionally colonized with probability beetle_prevalence (Colonized tag).
Time advances in weekly ticks, with ticks_per_year ticks per year.
Most submodels act once per year, at a fixed tick of the year (tick_of_year).
Infected trees become damaged (Damaged tag) ticks_to_damage ticks after infection.
At tick tick_of_infection, num_trees damaged, uninfected trees, randomly selected
from the entire world, are infected with nematodes (Infected tag, with the time of infection).
Trees with the Damaged tag are removed from the simulation with a fixed annual probability removal_probability.
Removal takes place in the same tick as background damage, right before it.
Healthy trees are damaged with a fixed annual probability damage_probability.
When damaged, the tree gets a Damaged tag.
Once per year, beetles_per_tree individual beetles emerge from each tree that is both colonized and infected.
Each beetle starts at its source tree, and gets an exponentially distributed life span with mean life_expectancy ticks,
capped at max_age ticks.
Once per year, two attraction fields on the fine grid are calculated, which guide beetle movement: one for healthy trees (maturation feeding) and one for damaged trees (egg laying).
Each tree cell density_radius that contain a tree of the same type.
The attraction of cell half_distance:
with density_weight. Thus, denser tree clusters attract beetles from farther away.
Along with the field, each cell records its source: the tree cell
Rationale: An earlier movement variant (BeetleMovementByField) moved beetles to the neighboring cell with the highest attraction.
Taking the maximum (rather than summing kernels over sources) keeps the field bounded,
without a hard radius limit, and cheap to compute (two in-place sweeps).
Further, every local maximum is a tree, so beetles cannot get trapped between trees.
Summing variants were tried, but suffered from a background level dominated by distant trees,
instability, or hard cut-offs.
With deterministic neighbor choice, any monotone transformation of the final field
(e.g. raising a summed field to a power) leaves all movement decisions unchanged.
Density must therefore enter through the seeds, before aggregation.
With
Beetles move on the fine grid, making steps_per_tick steps (days) per tick.
In each step, a beetle either feeds and targets healthy trees, or lays eggs and targets damaged trees.
For the first duration_feeding ticks after emergence, beetles always feed.
Afterwards, they feed with probability feeding_probability per step, and lay eggs otherwise.
In each step, a beetle can fly up to distance_per_step:
- In its first step after emergence, a beetle makes an undirected flight away from the tree it emerged from,
over a distance drawn uniformly between 0 and
emergence_flight_distance(but at mostdistance_per_step), in a uniformly random direction. This spreads out the beetles emerging from the same tree, which would otherwise all target the same first tree. Otherwise, a beetle on a target tree leaves it with probabilityleave_tree_probability. It then flies straight in a uniformly random direction, checking its cell after each fine cell size of distance, until it reaches a cell whose attraction source (see Tree attraction) is another tree, or the step's distance is used up. In both cases, a beetle that leaves the world dies. - A beetle that is (still) on a target tree stays there.
- Otherwise, it flies straight towards the attraction source of its cell, with the remaining distance. If the source is within reach, it lands there.
For each step that a beetle ends on a target tree, a feeding event is counted for that tree's cell.
Beetles are removed when they reach the end of their life span.
Beetle dispersal operates on a separate dispersal grid with cell size cell_size
(a multiple of the fine grid's cell size).
For each cell, the number of trees colonized by beetles is counted.
Multiplied with the fixed beetles_per_tree factor, this gives the available emerging beetles.
These are distributed to the source cell as well as the surrounding cells using an exponential,
mass-preserving (i.e., normalized) kernel, giving the arriving beetles per cell.
with half-distance kernel_half_distance (i.e. kernel_radius, rounded up to full cells.
Multiplied with the fixed trees_per_beetle,
this gives the number of colonization attempts
or, equivalently but numerically more stable:
After the Colonized flag is removed from all source trees (as beetles fly out),
this probability is applied in an independent Bernoulli trial
to each individual susceptible (damaged) tree,
adding the Colonized tag on success.
Note:
beetles_per_tree*trees_per_beetle=$R_0$ of the system.
Each tick, healthy, uninfected trees become infected based on the infection_probability