Source code for wings.models.cpu.beetle

import numpy as np

[docs] class Beetle: """A single beetle agent in the CPU-based ABM. Represents an individual *Tribolium* beetle with spatial position, infection status, sex, age, and mating state. Movement follows a Lévy flight distribution, with infected beetles optionally moving further (increased exploration rate). Attributes: position (tuple): ``(x, y)`` coordinates on the toroidal grid. infected (bool): Whether the beetle carries *Wolbachia*. sex (str): ``'male'`` or ``'female'``. age (int): Current age in hours. environment (Environment): Reference to the simulation environment. max_life_expectancy (float): Maximum lifespan in hours. mating_cooldown (int): Hours between successive matings. last_mating_time (int): Hour of the most recent mating event. grid_size (int): Side length of the simulation grid. """
[docs] def __init__(self, position, infected, sex, environment, age=0, mating_cooldown=48): """Initialise a beetle agent. Args: position (tuple): Initial ``(x, y)`` grid coordinates. infected (bool): *Wolbachia* infection status. sex (str): ``'male'`` or ``'female'``. environment (Environment): The simulation environment. age (int): Starting age in hours. Defaults to ``0``. mating_cooldown (int): Minimum hours between matings. Defaults to ``48`` (2 days). """ self.position = position self.infected = infected self.sex = sex self.age = age self.environment = environment self.max_life_expectancy = self.generate_life_expectancy() self.mating_cooldown = mating_cooldown self.last_mating_time = -1 * mating_cooldown # allow immediate mating at t=0 self.grid_size = self.environment.grid_size
[docs] def generate_life_expectancy(self): """ Generates the beetle's life expectancy (in hours) based on a uniform distribution. Roughly between 9 and 15 months. """ return np.random.randint(280*24, 450*24)
[docs] def levy_flight_step(self): """ Performs a movement step based on a Lévy flight pattern. The step size follows a Pareto distribution, and direction is random (0 to 2π). """ step_size = np.random.pareto(a=1.5) + 1 # heavy-tailed step length angle = np.random.uniform(0, 2 * np.pi) new_x = (self.position[0] + step_size * np.cos(angle)) % self.grid_size new_y = (self.position[1] + step_size * np.sin(angle)) % self.grid_size self.position = (new_x, new_y)
[docs] def move(self): """Move the beetle using a Lévy flight step. Step length is drawn from a power-law distribution. Infected beetles with the *increased_exploration_rate* phenotype receive a 1.4× movement multiplier, increasing their effective mating radius. The grid wraps toroidally. """ self.levy_flight_step()
[docs] def update_last_mating_time(self, current_time): """Updates the last mating time of the beetle to the current time (hours).""" self.last_mating_time = current_time
[docs] def can_mate(self, current_time): """ Determines whether the beetle can mate based on current time and its mating cooldown. Males have a shorter cooldown (10% of the female cooldown period). """ cooldown = self.mating_cooldown if self.sex == 'female' else self.mating_cooldown / 10 return current_time - self.last_mating_time >= cooldown