Module pybeepop.pybeepop
pybeepop - BeePop+ interface for Python
Classes
class PyBeePop (lib_file=None,
parameter_file=None,
weather_file=None,
residue_file=None,
verbose=False)-
Expand source code
class PyBeePop: """Python interface for the BeePop+ honey bee colony simulation model""" def __init__( self, lib_file=None, parameter_file=None, weather_file=None, residue_file=None, verbose=False, ): """Create a PyBeePop object connected to a BeePop+ shared library. Args: lib_file (str, optional): Path to the BeePop+ shared library (.dll or .so). parameters_file (str, optional): Path to a txt file of BeePop+ parameters where each line specifies parameter=value. Defaults to None. weather_file (str, optional): Path to a .csv or comma separated .txt file containing weather data. For formatting info see docs/weather_readme.txt. Defaults to None. residue_file (str, optional): Path to a .csv or comma separated .txt file containing pesticide residue data. Defaults to None. verbose (bool, optional): Print additional debugging statements? Defaults to False. Raises: FileNotFoundError: If a provided file does not exist at the specified path. NotImplementedError: If run on a platform that is not 64-bit Windows or Linux. """ self.parent = os.path.dirname(os.path.abspath(__file__)) self.platform = platform.system() self.verbose = verbose if lib_file is None: # detect OS and architecture and use pre-compiled BeePop+ if possible if self.platform == "Windows": if platform.architecture()[0] == "32bit": raise NotImplementedError( "Windows x86 (32-bit) is not supported by BeePop+. Please run on an x64 platform." ) else: lib_file = os.path.join(self.parent, "lib/beepop_win64.dll") elif self.platform == "Linux": lib_file = os.path.join(self.parent, "lib/beepop_linux.so") if self.verbose: print( """ Running in Linux mode. Trying manylinux/musllinux version. If you encounter errors, you may need to compile your own version of BeePop+ from source and pass the path to your .so file with the lib_file option. Currently, only 64-bit architecture is supported. See the pybeepop README for instructions. """ ) else: raise NotImplementedError("BeePop+ only supports Windows and Linux.") if not os.path.isfile(lib_file): raise FileNotFoundError( """ BeePop+ shared object library does not exist or is not compatible with your operating system. You may need to compile BeePop+ from source (see https://github.com/USEPA/pybeepop/blob/main/README.md for more info.) Currently, only 64-bit architecture is supported. """ ) self.lib_file = lib_file self.beepop = BeePopModel(self.lib_file, verbose=self.verbose) self.parameters = None if parameter_file is not None: self.load_parameter_file(self.parameter_file) else: self.parameter_file = None if weather_file is not None: self.load_weather(weather_file) else: self.weather_file = None if residue_file is not None: self.load_residue_file(self.residue_file) else: self.residue_file = None # self.new_features = new_features # not being used? self.output = None def set_parameters(self, parameters): """Set BeePop+ parameters based on a dictionary {parameter: value}. Args: parameters (dict): dictionary of parameteres {parameter: value}. Raises: TypeError: If parameters is not a dict. ValueError: If the parameter is not a valid BeePop+ parameter listed in the docs. """ if (parameters is not None) and (not isinstance(parameters, dict)): raise TypeError("parameters must be a named dictionary of BeePop+ parameters") self.parameters = self.beepop.set_parameters(parameters) def get_parameters(self): """Return all parameters that have been set by the user.""" return self.beepop.get_parameters() def load_weather(self, weather_file): """Load a weather file. This should be a csv or comma delimited txt file 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). Args: weather_file (_type_): Path to the weather file (csv or txt). Raises: FileNotFoundError: If the provided file does not exist at the specified path. """ if not os.path.isfile(weather_file): raise FileNotFoundError("Weather file does not exist at path: {}!".format(weather_file)) self.weather_file = weather_file self.beepop.load_weather(self.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 'paramter=value'. Args: parameter_file (_type_): Path to a txt file of BeePop+ 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 specified in the docs. """ if not os.path.isfile(parameter_file): raise FileNotFoundError( "Paramter file does not exist at path: {}!".format(parameter_file) ) self.parameter_file = parameter_file self.beepop.load_input_file(self.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 specified in scientific notation, e.g. "9.00E-08". Args: residue_file (_type_): Path to the residue .csv or .txt file. Raises: FileNotFoundError: If the provided file does not exist at the specified path. """ if not os.path.isfile(residue_file): raise FileNotFoundError("Residue file does not exist at path: {}!".format(residue_file)) self.residue_file = residue_file self.beepop.load_contam_file(self.residue_file) def run_model(self): """_summary_ Raises: RuntimeError: If the weather file has not yet been set. Returns: DataFrame: A DataFrame of the model results for the BeePop+ run. """ # check to see if parameters have been supplied if (self.parameter_file is None) and (self.parameters is None): print("No parameters have been set. Running with defualt settings.") if self.weather_file is None: raise RuntimeError("Weather must be set before running BeePop+!") self.output = self.beepop.run_beepop() 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: DataFrame or json str: A DataFrame or JSON string of the model results for the BeePop+ run. """ 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 ["Colony Size", "Adult Workers", "Capped Worker Brood", "Worker Larvae", "Worker Eggs"]. Raises: RuntimeError: If there is no output because run_model has not yet been called. Returns: Matplotlib Axes: A Matploitlib 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( "The column name {} is not a valid output column.".format( [i for (i, v) in zip(columns, invalid_cols) if v] ) ) 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.""" return self.beepop.get_errors() def get_info_log(self): """Return the BeePop+ session info log as a string for debugging.""" return self.beepop.get_info() def version(self): """Return the BeePop+ version as a string.""" version = self.beepop.get_version() return version def exit(self): """Close the connection to the BeePop+ shared library.""" self.beepop.close_library() del self.beepop return
Python interface for the BeePop+ honey bee colony simulation model
Create a PyBeePop object connected to a BeePop+ shared library.
Args
lib_file
:str
, optional- Path to the BeePop+ shared library (.dll or .so).
parameters_file
:str
, optional- Path to a txt file of BeePop+ parameters where each line specifies parameter=value. Defaults to None.
weather_file
:str
, optional- Path to a .csv or comma separated .txt file containing weather data. For formatting info see docs/weather_readme.txt. Defaults to None.
residue_file
:str
, optional- Path to a .csv or comma separated .txt file containing pesticide residue data. Defaults to None.
verbose
:bool
, optional- Print additional debugging statements? Defaults to False.
Raises
FileNotFoundError
- If a provided file does not exist at the specified path.
NotImplementedError
- If run on a platform that is not 64-bit Windows or Linux.
Methods
def exit(self)
-
Expand source code
def exit(self): """Close the connection to the BeePop+ shared library.""" self.beepop.close_library() del self.beepop return
Close the connection to the BeePop+ shared library.
def get_error_log(self)
-
Expand source code
def get_error_log(self): """Return the BeePop+ session error log as a string for debugging.""" return self.beepop.get_errors()
Return the BeePop+ session error log as a string for debugging.
def get_info_log(self)
-
Expand source code
def get_info_log(self): """Return the BeePop+ session info log as a string for debugging.""" return self.beepop.get_info()
Return the BeePop+ session info log as a string for debugging.
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: DataFrame or json str: A DataFrame or JSON string of the model results for the BeePop+ run. """ 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
DataFrame
orjson str
- A DataFrame or JSON string of the model results for the BeePop+ run.
def get_parameters(self)
-
Expand source code
def get_parameters(self): """Return all parameters that have been set by the user.""" return self.beepop.get_parameters()
Return all parameters that have been set by the user.
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 'paramter=value'. Args: parameter_file (_type_): Path to a txt file of BeePop+ 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 specified in the docs. """ if not os.path.isfile(parameter_file): raise FileNotFoundError( "Paramter file does not exist at path: {}!".format(parameter_file) ) self.parameter_file = parameter_file self.beepop.load_input_file(self.parameter_file)
Load a .txt file of parameter values to set. Each row of the file is a string with the format 'paramter=value'.
Args
parameter_file
:_type_
- Path to a txt file of BeePop+ 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 specified in the docs.
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 specified in scientific notation, e.g. "9.00E-08". Args: residue_file (_type_): Path to the residue .csv or .txt file. Raises: FileNotFoundError: If the provided file does not exist at the specified path. """ if not os.path.isfile(residue_file): raise FileNotFoundError("Residue file does not exist at path: {}!".format(residue_file)) self.residue_file = residue_file self.beepop.load_contam_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 specified in scientific notation, e.g. "9.00E-08".
Args
residue_file
:_type_
- Path to the residue .csv or .txt file.
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. This should be a csv or comma delimited txt file 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). Args: weather_file (_type_): Path to the weather file (csv or txt). Raises: FileNotFoundError: If the provided file does not exist at the specified path. """ if not os.path.isfile(weather_file): raise FileNotFoundError("Weather file does not exist at path: {}!".format(weather_file)) self.weather_file = weather_file self.beepop.load_weather(self.weather_file)
Load a weather file. This should be a csv or comma delimited txt file 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).
Args
weather_file
:_type_
- Path to the weather file (csv or txt).
Raises
FileNotFoundError
- If the provided file does not exist at the specified path.
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 ["Colony Size", "Adult Workers", "Capped Worker Brood", "Worker Larvae", "Worker Eggs"]. Raises: RuntimeError: If there is no output because run_model has not yet been called. Returns: Matplotlib Axes: A Matploitlib 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( "The column name {} is not a valid output column.".format( [i for (i, v) in zip(columns, invalid_cols) if v] ) ) 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 ["Colony Size", "Adult Workers", "Capped Worker Brood", "Worker Larvae", "Worker Eggs"].
Raises
RuntimeError
- If there is no output because run_model has not yet been called.
Returns
Matplotlib Axes
- A Matploitlib Axes object for further customization.
def run_model(self)
-
Expand source code
def run_model(self): """_summary_ Raises: RuntimeError: If the weather file has not yet been set. Returns: DataFrame: A DataFrame of the model results for the BeePop+ run. """ # check to see if parameters have been supplied if (self.parameter_file is None) and (self.parameters is None): print("No parameters have been set. Running with defualt settings.") if self.weather_file is None: raise RuntimeError("Weather must be set before running BeePop+!") self.output = self.beepop.run_beepop() return self.output
summary
Raises
RuntimeError
- If the weather file has not yet been set.
Returns
DataFrame
- A DataFrame of the model results for the BeePop+ run.
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 parameteres {parameter: value}. Raises: TypeError: If parameters is not a dict. ValueError: If the parameter is not a valid BeePop+ parameter listed in the docs. """ if (parameters is not None) and (not isinstance(parameters, dict)): raise TypeError("parameters must be a named dictionary of BeePop+ parameters") self.parameters = self.beepop.set_parameters(parameters)
Set BeePop+ parameters based on a dictionary {parameter: value}.
Args
parameters
:dict
- dictionary of parameteres {parameter: value}.
Raises
TypeError
- If parameters is not a dict.
ValueError
- If the parameter is not a valid BeePop+ parameter listed in the docs.
def version(self)
-
Expand source code
def version(self): """Return the BeePop+ version as a string.""" version = self.beepop.get_version() return version
Return the BeePop+ version as a string.