Module pybeepop.beepop.epadata

BeePop+ EPA Pesticide Data Management Module.

This module contains classes for managing pesticide active ingredient (AI) data including toxicity parameters, consumption rates, and environmental fate characteristics. This data drives pesticide exposure and mortality calculations throughout the simulation.Different life stages have varying sensitivity to pesticide exposure based on physiological differences and exposure pathways.

Classes

AIItem: Individual active ingredient with toxicity and fate parameters EPAData: EPA pesticide database manager with consumption and exposure data

Classes

class AIItem (name: str = '')
Expand source code
class AIItem:
    """Not currently being used? Only supported one AI at a time,
    directly setting class variables in EPAData"""

    def __init__(self, name: str = ""):
        self.name = name
        self.adult_slope = 0.0
        self.adult_ld50 = 0.0
        self.adult_slope_contact = 0.0
        self.adult_ld50_contact = 0.0
        self.larva_slope = 0.0
        self.larva_ld50 = 0.0
        self.kow = 0.0
        self.koc = 0.0
        self.half_life = 0.0
        self.contact_factor = 0.0

Not currently being used? Only supported one AI at a time, directly setting class variables in EPAData

class EPAData
Expand source code
class EPAData:
    """EPA pesticide database manager with active ingredient and consumption data.

    Manages pesticide data including active ingredient toxicity
    parameters, bee consumption rates by life stage, and foraging behavior data.
    Provides centralized access to pesticide exposure and effects parameters
    used throughout the simulation.

    Integrates toxicity data with consumption patterns to calculate realistic
    pesticide exposure doses for different bee castes and life stages. Supports
    both oral and contact exposure routes (contact for foliar application mode only).

    """

    def __init__(self):
        self.ai_items: List[AIItem] = []
        self.current_ai: Optional[AIItem] = None

        # Currently selected AI attributes (matching C++ m_AI_* naming)
        self.m_AI_Name = ""
        self.m_AI_AdultSlope = 0.0
        self.m_AI_AdultLD50 = 0.0
        self.m_AI_AdultSlope_Contact = 0.0  # foliar application only
        self.m_AI_AdultLD50_Contact = 0.0  # foliar application only
        self.m_AI_LarvaSlope = 0.0
        self.m_AI_LarvaLD50 = 0.0
        self.m_AI_KOW = 0.0  # soil application only
        self.m_AI_KOC = 0.0  # soil application only
        self.m_AI_HalfLife = 0.0
        self.m_AI_ContactFactor = 0.0  # foliar application only

        # Consumption (match C++ m_C_* naming exactly)
        self.m_C_L4_Pollen = 0.0
        self.m_C_L4_Nectar = 0.0
        self.m_C_L5_Pollen = 0.0
        self.m_C_L5_Nectar = 0.0
        self.m_C_LD_Pollen = 0.0
        self.m_C_LD_Nectar = 0.0
        self.m_C_A13_Pollen = 0.0
        self.m_C_A13_Nectar = 0.0
        self.m_C_A410_Pollen = 0.0
        self.m_C_A410_Nectar = 0.0
        self.m_C_A1120_Pollen = 0.0
        self.m_C_A1120_Nectar = 0.0
        self.m_C_AD_Pollen = 0.0
        self.m_C_AD_Nectar = 0.0
        self.m_C_Forager_Pollen = 0.0
        self.m_C_Forager_Nectar = 0.0

        # Incoming (match C++ m_I_* naming exactly)
        self.m_I_PollenTrips = 0
        self.m_I_NectarTrips = 0
        self.m_I_PercentNectarForagers = 0.0
        self.m_I_PollenLoad = 0.0
        self.m_I_NectarLoad = 0.0

        # Current dosages (matching C++ m_D_* naming)
        self.m_D_L4 = 0.0  # Current dosage for larvae 4 days old
        self.m_D_L5 = 0.0  # Current dosage for larvae 5 days old
        self.m_D_LD = 0.0  # Current dosage for larvae drone
        self.m_D_A13 = 0.0  # Current dosage for adult workers 1-3 days old
        self.m_D_A410 = 0.0  # Current dosage for adult workers 4-10 days old
        self.m_D_A1120 = 0.0  # Current dosage for adult workers 11-20 days old
        self.m_D_AD = 0.0  # Current dosage for adult drones
        self.m_D_C_Foragers = 0.0  # Current contact dosage for foragers
        self.m_D_D_Foragers = 0.0  # Current diet dosage for foragers

        # Maximum doses seen so far for each life stage
        self.m_D_L4_Max = 0.0
        self.m_D_L5_Max = 0.0
        self.m_D_LD_Max = 0.0
        self.m_D_A13_Max = 0.0
        self.m_D_A410_Max = 0.0
        self.m_D_A1120_Max = 0.0
        self.m_D_AD_Max = 0.0
        self.m_D_C_Foragers_Max = 0.0
        self.m_D_D_Foragers_Max = 0.0

        # Exposure (match C++ naming exactly)
        self.m_FoliarEnabled = False
        self.m_SoilEnabled = False
        self.m_SeedEnabled = False
        self.m_E_AppRate = 0.0
        self.m_E_SoilTheta = 0.0
        self.m_E_SoilP = 0.0
        self.m_E_SoilFoc = 0.0
        self.m_E_SoilConcentration = 0.0
        self.m_E_SeedConcentration = 0.0
        self.m_FoliarAppDate = datetime.now()
        self.m_FoliarForageBegin = datetime.now()
        self.m_FoliarForageEnd = datetime.now()
        self.m_SoilForageBegin = datetime.now()
        self.m_SoilForageEnd = datetime.now()
        self.m_SeedForageBegin = datetime.now()
        self.m_SeedForageEnd = datetime.now()

        # Nectar/Pollen Bypass File Processing (match C++ naming exactly)
        self.m_NecPolFileEnabled = False
        self.m_NecPolFileName = ""

    def add_ai_item(self, item: AIItem):
        self.ai_items.append(item)

    def remove_ai_item(self, name: str) -> bool:
        for i, item in enumerate(self.ai_items):
            if item.name == name:
                del self.ai_items[i]
                return True
        return False

    def get_ai_item(self, name: str) -> Optional[AIItem]:
        for item in self.ai_items:
            if item.name == name:
                return item
        return None

    def set_current_ai_item(self, item: AIItem):
        self.current_ai = item

    def get_ai_item_count(self) -> int:
        return len(self.ai_items)

    def dose_response(self, dose: float, ld50: float, slope: float) -> float:
        """
        Replicates the C++ DoseResponse logic:
        - Converts dose from grams to micrograms
        - Assumes LD50 is already in micrograms/bee (as per C++ comment)
        - Validates input
        - Returns proportion killed
        """
        dose *= 1_000_000.0  # Convert grams to micrograms
        # LD50 is assumed to already be in micrograms/bee (per C++ comment)
        valid = (dose > ld50 * 0.05) and (ld50 > 0) and (slope >= 0) and (slope < 20)
        if not valid:
            return 0.0
        return 1.0 / (1.0 + (dose / ld50) ** (-slope))

EPA pesticide database manager with active ingredient and consumption data.

Manages pesticide data including active ingredient toxicity parameters, bee consumption rates by life stage, and foraging behavior data. Provides centralized access to pesticide exposure and effects parameters used throughout the simulation.

Integrates toxicity data with consumption patterns to calculate realistic pesticide exposure doses for different bee castes and life stages. Supports both oral and contact exposure routes (contact for foliar application mode only).

Methods

def add_ai_item(self,
item: AIItem)
Expand source code
def add_ai_item(self, item: AIItem):
    self.ai_items.append(item)
def dose_response(self, dose: float, ld50: float, slope: float) ‑> float
Expand source code
def dose_response(self, dose: float, ld50: float, slope: float) -> float:
    """
    Replicates the C++ DoseResponse logic:
    - Converts dose from grams to micrograms
    - Assumes LD50 is already in micrograms/bee (as per C++ comment)
    - Validates input
    - Returns proportion killed
    """
    dose *= 1_000_000.0  # Convert grams to micrograms
    # LD50 is assumed to already be in micrograms/bee (per C++ comment)
    valid = (dose > ld50 * 0.05) and (ld50 > 0) and (slope >= 0) and (slope < 20)
    if not valid:
        return 0.0
    return 1.0 / (1.0 + (dose / ld50) ** (-slope))

Replicates the C++ DoseResponse logic: - Converts dose from grams to micrograms - Assumes LD50 is already in micrograms/bee (as per C++ comment) - Validates input - Returns proportion killed

def get_ai_item(self, name: str) ‑> AIItem | None
Expand source code
def get_ai_item(self, name: str) -> Optional[AIItem]:
    for item in self.ai_items:
        if item.name == name:
            return item
    return None
def get_ai_item_count(self) ‑> int
Expand source code
def get_ai_item_count(self) -> int:
    return len(self.ai_items)
def remove_ai_item(self, name: str) ‑> bool
Expand source code
def remove_ai_item(self, name: str) -> bool:
    for i, item in enumerate(self.ai_items):
        if item.name == name:
            del self.ai_items[i]
            return True
    return False
def set_current_ai_item(self,
item: AIItem)
Expand source code
def set_current_ai_item(self, item: AIItem):
    self.current_ai = item