Module pybeepop.pybeepop

pybeepop - BeePop+ interface for Python

Classes

class PyBeePop (engine='python',
lib_file=None,
parameter_file=None,
weather_file=None,
residue_file=None,
latitude=30.0,
verbose=False)
Expand source code
class PyBeePop:
    """
    Python interface for the BeePop+ honey bee colony simulation model.

    BeePop+ is a mechanistic model for simulating honey bee colony dynamics, designed for ecological risk assessment and research applications.
    This interface enables programmatic access to BeePop+ from Python, supporting batch simulations, sensitivity analysis, and integration with
    data analysis workflows.

    For scientific background, model structure, and example applications, see:
    Garber et al. (2022), "Simulating the Effects of Pesticides on Honey Bee (Apis mellifera L.) Colonies with BeePop+", Ecologies.
    Minucci et al. (2025), "pybeepop: A Python interface for the BeePop+ honey bee colony model," Journal of Open Research Software.

    Example usage:
        >>> from pybeepop.pybeepop import PyBeePop
        >>> model = PyBeePop(parameter_file='params.txt', weather_file='weather.csv', residue_file='residues.csv')
        >>> model.run_model()
        >>> results = model.get_output()
        >>> model.plot_output()
    """

    def __init__(
        self,
        engine="python",
        lib_file=None,
        parameter_file=None,
        weather_file=None,
        residue_file=None,
        latitude=30.0,
        verbose=False,
    ):
        """
        Initialize a PyBeePop object with choice of simulation engine.

        Args:
            engine (str, optional): Retained for backward compatibility. Only 'python'
                is accepted; the C++ engine was removed in version 0.3.0.
            lib_file (str, optional): Retained for backward compatibility. Accepted only
                as None; the C++ engine was removed in version 0.3.0.
            parameter_file (str, optional): Path to a text file of BeePop+ parameters (one per line, parameter=value). If provided,
                it is loaded after the bundled default parameter file so user values override package defaults. See
                https://doi.org/10.3390/ecologies3030022 or the documentation for valid parameters.
            weather_file (str, optional): Path to a .csv or comma-separated .txt file containing weather data, where each row denotes:
                Date (MM/DD/YY), Max Temp (C), Min Temp (C), Avg Temp (C), Windspeed (m/s), Rainfall (mm), Hours of daylight (optional).
            residue_file (str, optional): Path to a .csv or comma-separated .txt file containing pesticide residue data. Each row should specify Date (MM/DD/YYYY),
                Concentration in nectar (g A.I. / g), Concentration in pollen (g A.I. / g). Values can be in scientific notation (e.g., "9.00E-08").
            latitude (float, optional): Latitude in decimal degrees for daylight hour calculations (-90 to 90). Defaults to 30.0.
            verbose (bool, optional): If True, print additional debugging statements. Defaults to False.

        Raises:
            FileNotFoundError: If a provided file does not exist at the specified path.
            ValueError: If engine or lib_file requests the removed C++ engine, or if
                latitude is outside the valid range.

        Examples:
            >>> model = PyBeePop(weather_file='weather.csv')
            >>> results = model.run_model()

            >>> model = PyBeePop()
            >>> model.load_weather('weather.csv')
            >>> results = model.run_model()
        """
        self.verbose = verbose
        self.engine_type: str | None = None
        self.engine: BeepopEngineInterface | None = None
        self.lib_file: str | None = None  # For backward compatibility

        self._check_removed_cpp_options(engine, lib_file)

        self.engine = self._initialize_python_engine()
        self.engine_type = "python"

        # Validate and set latitude
        if not -90 <= latitude <= 90:
            raise ValueError("Latitude must be between -90 and 90 degrees")
        self.current_latitude = latitude
        self.engine.set_latitude(self.current_latitude)

        # Initialize file paths and parameters
        self.parameter_file = None
        self.weather_file = None
        self.residue_file = None
        self.parameters = {}
        self.output = None
        self.default_parameter_file = self._get_default_parameter_file()

        # Add backward compatibility alias
        self.beepop = self.engine

        # Load bundled defaults before any user-supplied parameter files.
        self._load_default_parameter_file()

        # Load files if provided
        if parameter_file is not None:
            self.load_parameter_file(parameter_file)

        if weather_file is not None:
            self.load_weather(weather_file)

        if residue_file is not None:
            self.load_residue_file(residue_file)

    def _get_default_parameter_file(self) -> str:
        """Return the packaged default parameter file path."""
        return str(Path(__file__).resolve().parent / "data" / "default_parameters.txt")

    def _load_default_parameter_file(self) -> None:
        """Load bundled default parameters without marking them as a user file."""
        self.load_parameter_file(self.default_parameter_file)
        self.parameter_file = None

    @staticmethod
    def _check_removed_cpp_options(engine, lib_file) -> None:
        """
        Reject arguments that requested the C++ engine, removed in version 0.3.0.

        Raises:
            ValueError: If engine is anything other than 'python', or lib_file is set.
        """
        if engine == "cpp":
            raise ValueError(
                "The C++ engine was removed in pybeepop+ 0.3.0. Remove the engine "
                "argument, or pass engine='python'. The Python engine requires no "
                "compiled library."
            )
        if engine != "python":
            raise ValueError(
                f"Invalid engine type: '{engine}'. 'python' is the only option."
            )
        if lib_file is not None:
            raise ValueError(
                "The lib_file argument is no longer supported. It pointed at a "
                "compiled BeePop+ library for the C++ engine, which was removed in "
                "pybeepop+ 0.3.0. Remove the argument; the Python engine needs no "
                "shared library."
            )

    def _initialize_python_engine(self) -> BeepopEngineInterface:
        """
        Initialize Python engine.

        Returns:
            PythonEngineAdapter: Initialized Python engine adapter
        """
        from .adapters import PythonEngineAdapter

        return PythonEngineAdapter(verbose=self.verbose)

    def set_parameters(self, parameters):
        """
        Set BeePop+ parameters based on a dictionary {parameter: value}.

        Args:
            parameters (dict): Dictionary of BeePop+ parameters {parameter: value}. See https://doi.org/10.3390/ecologies3030022 or the documentation for valid parameters.

        Raises:
            TypeError: If parameters is not a dict.
            ValueError: If a parameter is not a valid BeePop+ parameter.
        """
        if (parameters is not None) and (not isinstance(parameters, dict)):
            raise TypeError(
                "parameters must be a named dictionary of BeePop+ parameters"
            )
        self.parameters = self.engine.set_parameters(parameters)

    def get_parameters(self):
        """
        Return all parameters that have been set by the user.

        Returns:
            dict: Dictionary of current BeePop+ parameters.
        """
        return self.engine.get_parameters()

    def set_latitude(self, latitude):
        """
        Set the latitude for daylight hour calculations.

        Args:
            latitude (float): Latitude in decimal degrees (-90 to 90). Positive values are North, negative are South.

        Raises:
            ValueError: If latitude is outside the valid range.
        """
        if not -90 <= latitude <= 90:
            raise ValueError("Latitude must be between -90 and 90 degrees")
        self.current_latitude = latitude
        self.engine.set_latitude(latitude)

    def get_latitude(self):
        """
        Get the currently set latitude.

        Returns:
            float: Current latitude in decimal degrees.
        """
        return self.current_latitude

    def set_simulation_dates(self, start_date, end_date):
        """
        Convenience method to set simulation start and end dates. The dates can
        also be set directly as SimStart/SimEnd using the set_parameters() or
        load_parameters() methods.

        Args:
            start_date (str): Simulation start date in MM/DD/YYYY format.
            end_date (str): Simulation end date in MM/DD/YYYY format.
        """
        date_params = {"SimStart": start_date, "SimEnd": end_date}
        self.set_parameters(date_params)

        if self.verbose:
            print(f"Set simulation dates: {start_date} to {end_date}")

    def load_weather(self, weather_file):
        """
        Load a weather file. The file should be a .csv or comma-delimited .txt file where each row denotes:
        Date (MM/DD/YYYY), Max Temp (C), Min Temp (C), Avg Temp (C), Windspeed (m/s), Rainfall (mm), Hours of daylight (optional).

        Note: Loading weather may reset simulation dates (SimStart/SimEnd) to the weather file's date range.
        Any previously set parameters will be automatically re-applied after weather loading.

        Args:
            weather_file (str): Path to the weather file (csv or txt). See docs/weather_readme.txt and manuscript for format details.

        Raises:
            TypeError: If weather_file is None.
            FileNotFoundError: If the provided file does not exist at the specified path.
            OSError: If the file cannot be opened or read.
            RuntimeError: If weather file cannot be loaded.
        """
        if weather_file is None:
            raise TypeError("Cannot set weather file to None")
        if not os.path.isfile(weather_file):
            raise FileNotFoundError(
                f"Weather file does not exist at path: {weather_file}!"
            )
        self.weather_file = weather_file

        # Load weather via adapter
        success = self.engine.load_weather_file(self.weather_file)
        if not success:
            raise RuntimeError("Failed to load weather file")

    def load_parameter_file(self, parameter_file):
        """
        Load a .txt file of parameter values to set. Each row of the file is a string with the format 'parameter=value'.

        Args:
            parameter_file (str): Path to a txt file of BeePop+ parameters. See https://doi.org/10.3390/ecologies3030022 or the documentation for valid parameters.

        Raises:
            FileNotFoundError: If the provided file does not exist at the specified path.
            ValueError: If a listed parameter is not a valid BeePop+ parameter.
        """
        if not os.path.isfile(parameter_file):
            raise FileNotFoundError(
                f"Paramter file does not exist at path: {parameter_file}!"
            )
        self.parameter_file = parameter_file

        # Load parameter file via adapter
        # Note: adapter will raise ValueError for invalid parameters
        success = self.engine.load_parameter_file(self.parameter_file)
        if not success:
            raise RuntimeError("Failed to load parameter file")

    def load_residue_file(self, residue_file):
        """
        Load a .csv or comma-delimited .txt file of pesticide residues in pollen/nectar. Each row should specify Date (MM/DD/YYYY),
        Concentration in nectar (g A.I. / g), Concentration in pollen (g A.I. / g). Values can be in scientific notation (e.g., "9.00E-08").

        Args:
            residue_file (str): Path to the residue .csv or .txt file. See docs/residue_file_readme.txt and manuscript for format details.

        Raises:
            FileNotFoundError: If the provided file does not exist at the specified path.
        """
        if not os.path.isfile(residue_file):
            raise FileNotFoundError(
                f"Residue file does not exist at path: {residue_file}!"
            )
        self.residue_file = residue_file

        # Load residue file via adapter
        success = self.engine.load_residue_file(self.residue_file)
        if not success:
            raise RuntimeError("Failed to load residue file")

    def run_model(self):
        """
        Run the BeePop+ model simulation.

        Raises:
            RuntimeError: If the weather file has not yet been set.

        Returns:
            pandas.DataFrame: DataFrame of daily time series results for the BeePop+ run, including colony size, adult workers, brood, eggs, and other metrics.
        """
        # check to see if parameters have been supplied
        if (self.parameter_file is None) and (not self.parameters):
            print(
                "No user parameters have been set. Running with bundled default settings."
            )
        if self.weather_file is None:
            raise RuntimeError("Weather must be set before running BeePop+!")

        # Run via adapter
        self.output = self.engine.run_simulation()

        if self.output is None:
            raise RuntimeError("Simulation failed to produce results")

        return self.output

    def get_output(self, format="DataFrame"):
        """
        Get the output from the last BeePop+ run.

        Args:
            format (str, optional): Return results as DataFrame ('DataFrame') or JSON string ('json'). Defaults to 'DataFrame'.

        Raises:
            RuntimeError: If there is no output because run_model has not yet been called.

        Returns:
            pandas.DataFrame or str: DataFrame or JSON string of the model results. JSON output is a dictionary of lists keyed by column name.
        """
        if self.output is None:
            raise RuntimeError(
                "There are no results to plot. Please run the model first."
            )
        if format == "json":
            result = json.dumps(self.output.to_dict(orient="list"))
        else:
            result = self.output
        return result

    def plot_output(
        self,
        columns=[
            "Colony Size",
            "Adult Workers",
            "Capped Worker Brood",
            "Worker Larvae",
            "Worker Eggs",
        ],
    ):
        """
        Plot the output as a time series.

        Args:
            columns (list, optional): List of column names to plot (as strings). Defaults to key colony metrics.

        Raises:
            RuntimeError: If there is no output because run_model has not yet been called.
            IndexError: If any column name is not a valid output column.

        Returns:
            matplotlib.axes.Axes: Matplotlib Axes object for further customization.
        """
        if self.output is None:
            raise RuntimeError(
                "There are no results to plot. Please run the model first."
            )
        invalid_cols = [col not in self.output.columns for col in columns]
        if any(invalid_cols):
            raise IndexError(
                f"The column name {[i for (i, v) in zip(columns, invalid_cols) if v]} is not a valid output column."
            )
        plot = plot_timeseries(output=self.output, columns=columns)
        return plot

    def get_error_log(self):
        """
        Return the BeePop+ session error log as a string for debugging. Useful for troubleshooting.

        Returns:
            str: Error log from the BeePop+ session.
        """
        return self.engine.get_error_log()

    def get_info_log(self):
        """
        Return the BeePop+ session info log as a string for debugging..

        Returns:
            str: Info log from the BeePop+ session.
        """
        return self.engine.get_info_log()

    def version(self):
        """
        Return the BeePop+ version as a string.

        Returns:
            str: BeePop+ version string.
        """
        return self.engine.get_version()

    def exit(self):
        """
        Close the connection to the BeePop+ simulation engine and clean up resources.
        """
        if hasattr(self, "engine") and self.engine is not None:
            try:
                self.engine.cleanup()
            except Exception as e:
                if self.verbose:
                    print(f"Warning during cleanup: {e}")
            self.engine = None

    def __del__(self):
        """Destructor to ensure cleanup when object is garbage collected."""
        self.exit()

Python interface for the BeePop+ honey bee colony simulation model.

BeePop+ is a mechanistic model for simulating honey bee colony dynamics, designed for ecological risk assessment and research applications. This interface enables programmatic access to BeePop+ from Python, supporting batch simulations, sensitivity analysis, and integration with data analysis workflows.

For scientific background, model structure, and example applications, see: Garber et al. (2022), "Simulating the Effects of Pesticides on Honey Bee (Apis mellifera L.) Colonies with BeePop+", Ecologies. Minucci et al. (2025), "pybeepop: A Python interface for the BeePop+ honey bee colony model," Journal of Open Research Software.

Example usage: >>> from pybeepop.pybeepop import PyBeePop >>> model = PyBeePop(parameter_file='params.txt', weather_file='weather.csv', residue_file='residues.csv') >>> model.run_model() >>> results = model.get_output() >>> model.plot_output()

Initialize a PyBeePop object with choice of simulation engine.

Args
-----=
engine : str, optional
Retained for backward compatibility. Only 'python' is accepted; the C++ engine was removed in version 0.3.0.
lib_file : str, optional
Retained for backward compatibility. Accepted only as None; the C++ engine was removed in version 0.3.0.
parameter_file : str, optional
Path to a text file of BeePop+ parameters (one per line, parameter=value). If provided, it is loaded after the bundled default parameter file so user values override package defaults. See https://doi.org/10.3390/ecologies3030022 or the documentation for valid parameters.
weather_file : str, optional
Path to a .csv or comma-separated .txt file containing weather data, where each row denotes: Date (MM/DD/YY), Max Temp (C), Min Temp (C), Avg Temp (C), Windspeed (m/s), Rainfall (mm), Hours of daylight (optional).
residue_file : str, optional
Path to a .csv or comma-separated .txt file containing pesticide residue data. Each row should specify Date (MM/DD/YYYY), Concentration in nectar (g A.I. / g), Concentration in pollen (g A.I. / g). Values can be in scientific notation (e.g., "9.00E-08").
latitude : float, optional
Latitude in decimal degrees for daylight hour calculations (-90 to 90). Defaults to 30.0.
verbose : bool, optional
If True, print additional debugging statements. Defaults to False.
Raises
-----=
FileNotFoundError
If a provided file does not exist at the specified path.
ValueError
If engine or lib_file requests the removed C++ engine, or if latitude is outside the valid range.

Examples -----=

>>> model = PyBeePop(weather_file='weather.csv')
>>> results = model.run_model()
>>> model = PyBeePop()
>>> model.load_weather('weather.csv')
>>> results = model.run_model()

Methods

def exit(self)
Expand source code
def exit(self):
    """
    Close the connection to the BeePop+ simulation engine and clean up resources.
    """
    if hasattr(self, "engine") and self.engine is not None:
        try:
            self.engine.cleanup()
        except Exception as e:
            if self.verbose:
                print(f"Warning during cleanup: {e}")
        self.engine = None

Close the connection to the BeePop+ simulation engine and clean up resources.

def get_error_log(self)
Expand source code
def get_error_log(self):
    """
    Return the BeePop+ session error log as a string for debugging. Useful for troubleshooting.

    Returns:
        str: Error log from the BeePop+ session.
    """
    return self.engine.get_error_log()

Return the BeePop+ session error log as a string for debugging. Useful for troubleshooting.

Returns
-----=
str
Error log from the BeePop+ session.
def get_info_log(self)
Expand source code
def get_info_log(self):
    """
    Return the BeePop+ session info log as a string for debugging..

    Returns:
        str: Info log from the BeePop+ session.
    """
    return self.engine.get_info_log()

Return the BeePop+ session info log as a string for debugging..

Returns
-----=
str
Info log from the BeePop+ session.
def get_latitude(self)
Expand source code
def get_latitude(self):
    """
    Get the currently set latitude.

    Returns:
        float: Current latitude in decimal degrees.
    """
    return self.current_latitude

Get the currently set latitude.

Returns
-----=
float
Current latitude in decimal degrees.
def get_output(self, format='DataFrame')
Expand source code
def get_output(self, format="DataFrame"):
    """
    Get the output from the last BeePop+ run.

    Args:
        format (str, optional): Return results as DataFrame ('DataFrame') or JSON string ('json'). Defaults to 'DataFrame'.

    Raises:
        RuntimeError: If there is no output because run_model has not yet been called.

    Returns:
        pandas.DataFrame or str: DataFrame or JSON string of the model results. JSON output is a dictionary of lists keyed by column name.
    """
    if self.output is None:
        raise RuntimeError(
            "There are no results to plot. Please run the model first."
        )
    if format == "json":
        result = json.dumps(self.output.to_dict(orient="list"))
    else:
        result = self.output
    return result

Get the output from the last BeePop+ run.

Args
-----=
format : str, optional
Return results as DataFrame ('DataFrame') or JSON string ('json'). Defaults to 'DataFrame'.
Raises
-----=
RuntimeError
If there is no output because run_model has not yet been called.
Returns
-----=
pandas.DataFrame or str
DataFrame or JSON string of the model results. JSON output is a dictionary of lists keyed by column name.
def get_parameters(self)
Expand source code
def get_parameters(self):
    """
    Return all parameters that have been set by the user.

    Returns:
        dict: Dictionary of current BeePop+ parameters.
    """
    return self.engine.get_parameters()

Return all parameters that have been set by the user.

Returns
-----=
dict
Dictionary of current BeePop+ parameters.
def load_parameter_file(self, parameter_file)
Expand source code
def load_parameter_file(self, parameter_file):
    """
    Load a .txt file of parameter values to set. Each row of the file is a string with the format 'parameter=value'.

    Args:
        parameter_file (str): Path to a txt file of BeePop+ parameters. See https://doi.org/10.3390/ecologies3030022 or the documentation for valid parameters.

    Raises:
        FileNotFoundError: If the provided file does not exist at the specified path.
        ValueError: If a listed parameter is not a valid BeePop+ parameter.
    """
    if not os.path.isfile(parameter_file):
        raise FileNotFoundError(
            f"Paramter file does not exist at path: {parameter_file}!"
        )
    self.parameter_file = parameter_file

    # Load parameter file via adapter
    # Note: adapter will raise ValueError for invalid parameters
    success = self.engine.load_parameter_file(self.parameter_file)
    if not success:
        raise RuntimeError("Failed to load parameter file")

Load a .txt file of parameter values to set. Each row of the file is a string with the format 'parameter=value'.

Args
-----=
parameter_file : str
Path to a txt file of BeePop+ parameters. See https://doi.org/10.3390/ecologies3030022 or the documentation for valid parameters.
Raises
-----=
FileNotFoundError
If the provided file does not exist at the specified path.
ValueError
If a listed parameter is not a valid BeePop+ parameter.
def load_residue_file(self, residue_file)
Expand source code
def load_residue_file(self, residue_file):
    """
    Load a .csv or comma-delimited .txt file of pesticide residues in pollen/nectar. Each row should specify Date (MM/DD/YYYY),
    Concentration in nectar (g A.I. / g), Concentration in pollen (g A.I. / g). Values can be in scientific notation (e.g., "9.00E-08").

    Args:
        residue_file (str): Path to the residue .csv or .txt file. See docs/residue_file_readme.txt and manuscript for format details.

    Raises:
        FileNotFoundError: If the provided file does not exist at the specified path.
    """
    if not os.path.isfile(residue_file):
        raise FileNotFoundError(
            f"Residue file does not exist at path: {residue_file}!"
        )
    self.residue_file = residue_file

    # Load residue file via adapter
    success = self.engine.load_residue_file(self.residue_file)
    if not success:
        raise RuntimeError("Failed to load residue file")

Load a .csv or comma-delimited .txt file of pesticide residues in pollen/nectar. Each row should specify Date (MM/DD/YYYY), Concentration in nectar (g A.I. / g), Concentration in pollen (g A.I. / g). Values can be in scientific notation (e.g., "9.00E-08").

Args
-----=
residue_file : str
Path to the residue .csv or .txt file. See docs/residue_file_readme.txt and manuscript for format details.
Raises
-----=
FileNotFoundError
If the provided file does not exist at the specified path.
def load_weather(self, weather_file)
Expand source code
def load_weather(self, weather_file):
    """
    Load a weather file. The file should be a .csv or comma-delimited .txt file where each row denotes:
    Date (MM/DD/YYYY), Max Temp (C), Min Temp (C), Avg Temp (C), Windspeed (m/s), Rainfall (mm), Hours of daylight (optional).

    Note: Loading weather may reset simulation dates (SimStart/SimEnd) to the weather file's date range.
    Any previously set parameters will be automatically re-applied after weather loading.

    Args:
        weather_file (str): Path to the weather file (csv or txt). See docs/weather_readme.txt and manuscript for format details.

    Raises:
        TypeError: If weather_file is None.
        FileNotFoundError: If the provided file does not exist at the specified path.
        OSError: If the file cannot be opened or read.
        RuntimeError: If weather file cannot be loaded.
    """
    if weather_file is None:
        raise TypeError("Cannot set weather file to None")
    if not os.path.isfile(weather_file):
        raise FileNotFoundError(
            f"Weather file does not exist at path: {weather_file}!"
        )
    self.weather_file = weather_file

    # Load weather via adapter
    success = self.engine.load_weather_file(self.weather_file)
    if not success:
        raise RuntimeError("Failed to load weather file")

Load a weather file. The file should be a .csv or comma-delimited .txt file where each row denotes: Date (MM/DD/YYYY), Max Temp (C), Min Temp (C), Avg Temp (C), Windspeed (m/s), Rainfall (mm), Hours of daylight (optional).

Note: Loading weather may reset simulation dates (SimStart/SimEnd) to the weather file's date range. Any previously set parameters will be automatically re-applied after weather loading.

Args
-----=
weather_file : str
Path to the weather file (csv or txt). See docs/weather_readme.txt and manuscript for format details.
Raises
-----=
TypeError
If weather_file is None.
FileNotFoundError
If the provided file does not exist at the specified path.
OSError
If the file cannot be opened or read.
RuntimeError
If weather file cannot be loaded.
def plot_output(self,
columns=['Colony Size', 'Adult Workers', 'Capped Worker Brood', 'Worker Larvae', 'Worker Eggs'])
Expand source code
def plot_output(
    self,
    columns=[
        "Colony Size",
        "Adult Workers",
        "Capped Worker Brood",
        "Worker Larvae",
        "Worker Eggs",
    ],
):
    """
    Plot the output as a time series.

    Args:
        columns (list, optional): List of column names to plot (as strings). Defaults to key colony metrics.

    Raises:
        RuntimeError: If there is no output because run_model has not yet been called.
        IndexError: If any column name is not a valid output column.

    Returns:
        matplotlib.axes.Axes: Matplotlib Axes object for further customization.
    """
    if self.output is None:
        raise RuntimeError(
            "There are no results to plot. Please run the model first."
        )
    invalid_cols = [col not in self.output.columns for col in columns]
    if any(invalid_cols):
        raise IndexError(
            f"The column name {[i for (i, v) in zip(columns, invalid_cols) if v]} is not a valid output column."
        )
    plot = plot_timeseries(output=self.output, columns=columns)
    return plot

Plot the output as a time series.

Args
-----=
columns : list, optional
List of column names to plot (as strings). Defaults to key colony metrics.
Raises
-----=
RuntimeError
If there is no output because run_model has not yet been called.
IndexError
If any column name is not a valid output column.
Returns
-----=
matplotlib.axes.Axes
Matplotlib Axes object for further customization.
def run_model(self)
Expand source code
def run_model(self):
    """
    Run the BeePop+ model simulation.

    Raises:
        RuntimeError: If the weather file has not yet been set.

    Returns:
        pandas.DataFrame: DataFrame of daily time series results for the BeePop+ run, including colony size, adult workers, brood, eggs, and other metrics.
    """
    # check to see if parameters have been supplied
    if (self.parameter_file is None) and (not self.parameters):
        print(
            "No user parameters have been set. Running with bundled default settings."
        )
    if self.weather_file is None:
        raise RuntimeError("Weather must be set before running BeePop+!")

    # Run via adapter
    self.output = self.engine.run_simulation()

    if self.output is None:
        raise RuntimeError("Simulation failed to produce results")

    return self.output

Run the BeePop+ model simulation.

Raises
-----=
RuntimeError
If the weather file has not yet been set.
Returns
-----=
pandas.DataFrame
DataFrame of daily time series results for the BeePop+ run, including colony size, adult workers, brood, eggs, and other metrics.
def set_latitude(self, latitude)
Expand source code
def set_latitude(self, latitude):
    """
    Set the latitude for daylight hour calculations.

    Args:
        latitude (float): Latitude in decimal degrees (-90 to 90). Positive values are North, negative are South.

    Raises:
        ValueError: If latitude is outside the valid range.
    """
    if not -90 <= latitude <= 90:
        raise ValueError("Latitude must be between -90 and 90 degrees")
    self.current_latitude = latitude
    self.engine.set_latitude(latitude)

Set the latitude for daylight hour calculations.

Args
-----=
latitude : float
Latitude in decimal degrees (-90 to 90). Positive values are North, negative are South.
Raises
-----=
ValueError
If latitude is outside the valid range.
def set_parameters(self, parameters)
Expand source code
def set_parameters(self, parameters):
    """
    Set BeePop+ parameters based on a dictionary {parameter: value}.

    Args:
        parameters (dict): Dictionary of BeePop+ parameters {parameter: value}. See https://doi.org/10.3390/ecologies3030022 or the documentation for valid parameters.

    Raises:
        TypeError: If parameters is not a dict.
        ValueError: If a parameter is not a valid BeePop+ parameter.
    """
    if (parameters is not None) and (not isinstance(parameters, dict)):
        raise TypeError(
            "parameters must be a named dictionary of BeePop+ parameters"
        )
    self.parameters = self.engine.set_parameters(parameters)

Set BeePop+ parameters based on a dictionary {parameter: value}.

Args
-----=
parameters : dict
Dictionary of BeePop+ parameters {parameter: value}. See https://doi.org/10.3390/ecologies3030022 or the documentation for valid parameters.
Raises
-----=
TypeError
If parameters is not a dict.
ValueError
If a parameter is not a valid BeePop+ parameter.
def set_simulation_dates(self, start_date, end_date)
Expand source code
def set_simulation_dates(self, start_date, end_date):
    """
    Convenience method to set simulation start and end dates. The dates can
    also be set directly as SimStart/SimEnd using the set_parameters() or
    load_parameters() methods.

    Args:
        start_date (str): Simulation start date in MM/DD/YYYY format.
        end_date (str): Simulation end date in MM/DD/YYYY format.
    """
    date_params = {"SimStart": start_date, "SimEnd": end_date}
    self.set_parameters(date_params)

    if self.verbose:
        print(f"Set simulation dates: {start_date} to {end_date}")

Convenience method to set simulation start and end dates. The dates can also be set directly as SimStart/SimEnd using the set_parameters() or load_parameters() methods.

Args
-----=
start_date : str
Simulation start date in MM/DD/YYYY format.
end_date : str
Simulation end date in MM/DD/YYYY format.
def version(self)
Expand source code
def version(self):
    """
    Return the BeePop+ version as a string.

    Returns:
        str: BeePop+ version string.
    """
    return self.engine.get_version()

Return the BeePop+ version as a string.

Returns
-----=
str
BeePop+ version string.