From 287eb04cd3e307e72d6ee9fed1c5a252f9fe2b6b Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Wed, 15 Jan 2025 15:11:08 -0500 Subject: [PATCH 01/15] Docstring updates (`compartments.py` is finished) --- flepimop/gempyor_pkg/src/gempyor/calibrate.py | 67 +++++- flepimop/gempyor_pkg/src/gempyor/cli.py | 3 +- .../gempyor_pkg/src/gempyor/compartments.py | 227 +++++++++++++----- 3 files changed, 228 insertions(+), 69 deletions(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/calibrate.py b/flepimop/gempyor_pkg/src/gempyor/calibrate.py index 8d673d8d0..d4d3eaa23 100644 --- a/flepimop/gempyor_pkg/src/gempyor/calibrate.py +++ b/flepimop/gempyor_pkg/src/gempyor/calibrate.py @@ -1,3 +1,27 @@ +""" +calibrate.py + +Facilitates the calibration of the model using the `emcee` MCMC sampler. +Provides CLI options for users to specify simulation paramters. + +Functions: + calibrate: Reads a configuration file for simulation settings. + +Options: + --config, -c Path to the configuration file. + --project_path, -p Path to the flepiMoP project directory. + --nwalkers, -n Number of walkers (MCMC chains) to use. Overrides value in config. + --niterations Number of MCMC iterations. Overrides value in config. + --nsamples Number of samples to retain. OVerrides value in config. + --nthin Number of samples to thin. Overrides value in config. + --j, --jobs Number of CPU cores to use for prallelization. + --id Unique ID for the run. + --prefix Prefix for output files. + --resume Flag determining whether or not to resume the current calibration. + --resume_location, -r Path to the location to resume the run from. + +""" + #!/usr/bin/env python import click from gempyor import model_info, file_paths, config, inference_parameter @@ -113,18 +137,37 @@ # @profile_options # @profile() def calibrate( - config_filepath, - project_path, - nwalkers, - niter, - nsamples, - nthin, - ncpu, - input_run_id, - prefix, - resume, - resume_location, -): + config_filepath: str, + project_path: str, + nwalkers: int, + niter: int, + nsamples: int, + nthin: int, + ncpu: int, + input_run_id: int, + prefix: str, + resume: bool, + resume_location: str, +) -> None: + """ + Calibrate using an `emcee` sampler to initialize a model based on a config. + + Args: + config_filepath: Path to the configuration file. + project_path: Path to the project directory. + nwalkers: Number of walkers (MCMC chains) to run. + niter: Number of MCMC iterations to perform. + nsamples: Number of samples to select from final MCMC chain. + nthin (optional): How often to save samples. + ncpu: Number of CPU cores to use for parallelization. + input_run_id (optional): Run ID. Will be auto-generated if not provdied. + prefix (optional): A prefix for output files. + resume: Whether or not to resume a previous calibration run. + resume_location (optional): Path to the location of the saved state to resume from. + + Returns: + None + """ # Choose a run_id if input_run_id is None: base_run_id = pathlib.Path(config_filepath).stem.replace("config_", "") diff --git a/flepimop/gempyor_pkg/src/gempyor/cli.py b/flepimop/gempyor_pkg/src/gempyor/cli.py index 529fd2638..35c3f6163 100644 --- a/flepimop/gempyor_pkg/src/gempyor/cli.py +++ b/flepimop/gempyor_pkg/src/gempyor/cli.py @@ -27,8 +27,7 @@ ) @click.pass_context def patch(ctx: click.Context = mock_context, **kwargs) -> None: - """Merge configuration files - + """ This command will merge multiple config files together by overriding the top level keys in config files. The order of the config files is important, as the last file has the highest priority and the first has the lowest. diff --git a/flepimop/gempyor_pkg/src/gempyor/compartments.py b/flepimop/gempyor_pkg/src/gempyor/compartments.py index f9c49c5f3..b7b6c9856 100644 --- a/flepimop/gempyor_pkg/src/gempyor/compartments.py +++ b/flepimop/gempyor_pkg/src/gempyor/compartments.py @@ -1,3 +1,20 @@ +""" +compartments.py + +Defines class, methods, and functions necessary to establising compartments in the model. + +Classes: + Compartments: An object to handle compartment data for the model. + +Functions: + get_list_dimension: Returns length of object passed (if a list); otherwise returns 1. + list_access_element_safe: Attempts to access something from the given object at specified index. + list_access_element: Attempts to access soemthing from the given object at specified index. + list_recursive_convert_to_string: Convert item(s) in object to str(s). + compartments: A container for subcommands related to the compartmental model. + plot: Generate a plot representing transition between compartments. + export: Export compartment data to a CSV file. +""" from functools import reduce import numpy as np @@ -9,18 +26,31 @@ from .utils import config, Timer, as_list from .shared_cli import config_files_argument, config_file_options, parse_config_files, cli +from typing import Union logger = logging.getLogger(__name__) class Compartments: + """ + An object to handle compartment data for the model. + + Arguments: + seir_config (optional): Config file for SEIR model construction information. + compartments_config (optional): Config file for compartment information. + compartments_file (optional): File to specify compartment information. + transitions_file (optional): File to specify transition information. + + Attributes: + times_set: Counter to track succesful data intialization from config. + """ # Minimal object to be easily picklable for // runs def __init__( self, - seir_config=None, - compartments_config=None, - compartments_file=None, - transitions_file=None, + seir_config = None, + compartments_config = None, + compartments_file = None, + transitions_file = None, ): self.times_set = 0 @@ -36,11 +66,11 @@ def __init__( raise ValueError("Compartments object not set, no config or file provided.") return - def constructFromConfig(self, seir_config, compartment_config): + def constructFromConfig(self, seir_config, compartment_config) -> None: """ This method is called by the constructor if the compartments are not loaded from a file. It will parse the compartments and transitions from the configuration files. - It will populate self.compartments and self.transitions. + It will populate dynamic class attributes `self.compartments` and `self.transitions`. """ self.compartments = self.parse_compartments(seir_config, compartment_config) self.transitions = self.parse_transitions(seir_config, False) @@ -50,31 +80,18 @@ def __eq__(self, other): self.compartments == other.compartments ).all().all() - def parse_compartments(self, seir_config, compartment_config): - """Parse the compartments from the configuration file: - seir_config: the configuration file for the SEIR model - compartment_config: the configuration file for the compartments - Example: if config says: - ``` - compartments: - infection_stage: ["S", "E", "I", "R"] - vaccination_stage: ["vaccinated", "unvaccinated"] - ``` - compartment_df is: - ``` - infection_stage vaccination_stage name - 0 S vaccinated S_vaccinated - 1 S unvaccinated S_unvaccinated - 2 E vaccinated E_vaccinated - 3 E unvaccinated E_unvaccinated - 4 I vaccinated I_vaccinated - 5 I unvaccinated I_unvaccinated - 6 R vaccinated R_vaccinated - 7 R unvaccinated R_unvaccinated - ``` - TODO: add tests + def parse_compartments(self, seir_config: dict, compartment_config) -> pd.DataFrame: """ + Parses compartment configurations and returns a DataFrame of compartment names. + Args: + seir_config: Configuraton information for model. + compartment_config: Configuration information for model comartments. + + Returns: + A DataFrame where each row is a unique compartment and columns + correspond to attributes of the compartments. + """ compartment_df = None for compartment_name, compartment_value in compartment_config.get().items(): tmp = pd.DataFrame({"key": 1, compartment_name: compartment_value}) @@ -88,7 +105,18 @@ def parse_compartments(self, seir_config, compartment_config): ) return compartment_df - def parse_transitions(self, seir_config, fake_config=False): + def parse_transitions(self, seir_config: dict, fake_config: bool = False) -> pd.DataFrame: + """ + Parses the transitions defined in config and returns a concatenated DataFrame. + + Args: + seir_config: Configuraton information for model. + fake_config (optional): + Flag indicating whether or not transitions provied are placeholders. + Default value is False. + Returns: + A DataFrame containing all transitions from the config. + """ rc = reduce( lambda a, b: pd.concat( [a, self.parse_single_transition(seir_config, b, fake_config)] @@ -473,10 +501,22 @@ def fromFile(self, compartments_file, transitions_file): def get_comp_idx(self, comp_dict: dict, error_info: str = "no information") -> int: """ - return the index of a compartiment given a filter. The filter has to isolate a compartiment, + Return the index of a compartiment given a filter. The filter has to isolate a compartiment, but it ignore columns that don't exist: - :param comp_dict: - :return: + + Args: + comp_dict: + A dictionary where keys are compartment names and + values are values to filter by for each column. + error_info (optional): + A message providing additional context about where the + the method was called from. Default value is "no information". + + Returns: + Index of the comaprtment that matches the filter. + + Raises: + ValueError: Filter results in more than one or zero matches. """ mask = pd.concat( [self.compartments[k] == v for k, v in comp_dict.items()], axis=1 @@ -493,7 +533,21 @@ def get_comp_idx(self, comp_dict: dict, error_info: str = "no information") -> i def get_ncomp(self) -> int: return len(self.compartments) - def get_transition_array(self): + def get_transition_array(self) -> tuple: + """ + Constructs the transition matrix for the model. + + Returns: + tuple: + - a list of unique strings from `proportion_exponent` and `rate` + - array representing transitions and corresponding compartment indices. + - array representing proportion compartment indices + - array containing start and end indices for proportions + + Raises: + ValueError: If term is not found in list of valid compartments. + ValueErrror: If any string in `rate` or `proportional_to` is an invalid candidate. + """ with Timer("SEIR.compartments"): transition_array = np.zeros( (self.transitions.shape[1], self.transitions.shape[0]), dtype="int64" @@ -654,7 +708,20 @@ def get_transition_array(self): proportion_info, ) - def parse_parameters(self, parameters, parameter_names, unique_strings): + def parse_parameters(self, parameters: list, parameter_names: list, unique_strings: list) -> np.ndarray: + """ + Parses provided parameters and stores them in NumPy arrays. + + Args: + parameters: Input parameters to be parsed. + parameter_names: List of all parameter names. + unique_strings: + List of unique values from `proportion_exponent` + and `rate` columns of transitions data. + + Returns: + Array of parsed parameters. + """ # parsed_parameters_old = self.parse_parameter_strings_to_numpy_arrays(parameters, parameter_names, unique_strings) parsed_parameters = self.parse_parameter_strings_to_numpy_arrays_v2( parameters, parameter_names, unique_strings @@ -731,11 +798,6 @@ def parse_parameter_strings_to_numpy_arrays( }, operators=["^", "*", "/", "+", "-"], ): - """This is called recursusively for each operator. It parse the string according to the first operators - parameters: array with the value of each parameter - parameter_names: list of string with all defined parameters under parameters (not unique parameters, really parameters) - string""" - if ( not operators ): # empty list means all have been tried. Usually there just remains one string in string_list at that time. @@ -785,7 +847,14 @@ def parse_parameter_strings_to_numpy_arrays( return rc - def get_compartments_explicitDF(self): + def get_compartments_explicitDF(self) -> pd.DataFrame: + """ + Returns a copy of the compartments information DataFrame. + All columns receive a 'mc_' prefix. + + Returns: + A copy of the compartments DataFrame. + """ df: pd.DataFrame = self.compartments.copy( deep=True ) # .melt(id_vars='name', var_name='meta_compartment', value_name='sub_compartment') @@ -797,10 +866,6 @@ def get_compartments_explicitDF(self): def plot( self, output_file="transition_graph", source_filters=[], destination_filters=[] ): - """ - if source_filters is [["age0to17"], ["OMICRON", "WILD"]], it means filter all transitions that have - as source age0to17 AND (OMICRON OR WILD). - """ import graphviz from functools import reduce, partial @@ -849,13 +914,39 @@ def filter_func(lst, this_filter=[]): src.render(output_file) -def get_list_dimension(thing): +def get_list_dimension(thing: any) -> int: + """ + Returns the dimension of a given object. + + Args: + thing: Object whose dimension needs to be determined. + + Returns: + int: Length of the object if a list, otherwise 1. + """ if type(thing) == list: return len(thing) return 1 -def list_access_element_safe(thing, idx, dimension=None, encapsulate_as_list=False): +def list_access_element_safe(thing: any, idx: int, dimension=None, encapsulate_as_list=False) -> Union[any, list]: + """ + Attempts to access an element from the given object `thing` at the specified index `idx`. + + Args: + thing: Object to be accessed from. + idx: Index of object you would like to access. + dimension (optional): Dimension or shape of the object. + encapsulate_as_list (optional): If `True`, the accessed element will be returned as a list. + + Raises: + Exception: If `thing` is not iterable or `idx ` is out of range. + + Returns: + Item at `idx` if `thing` is list, or + element itself if `thing` is not a list. + Returned item will be a list if `encapsulate_as_list` is `True`. + """ try: return list_access_element(thing, idx, dimension, encapsulate_as_list) except Exception as e: @@ -868,11 +959,19 @@ def list_access_element_safe(thing, idx, dimension=None, encapsulate_as_list=Fal ) -def list_access_element(thing, idx, dimension=None, encapsulate_as_list=False): +def list_access_element(thing: any, idx: int, dimension=None, encapsulate_as_list=False) -> Union[any, list]: """ - This function is used to access elements in a list or a single element. - if list, it will return the element at index idx. - if not list, it will return the element itself, for any idx. + Access an element from a list or return the input itself if not a list. + If input `thing` is a list, the function will return the element at the specified index (`idx`). + If input `thing` is not a list, the function will return the element itself, regardless of the + `idx` value. + + Args: + + Returns: + Item at `idx` if `thing` is list, or + element itself if `thing` is not a list. + Returned item will be a list if `encapsulate_as_list` is `True`. """ if not dimension is None: if dimension == 1: @@ -889,7 +988,17 @@ def list_access_element(thing, idx, dimension=None, encapsulate_as_list=False): return rc -def list_recursive_convert_to_string(thing): +def list_recursive_convert_to_string(thing: any) -> str: + """ + Return given object as a str, + or recursively convert elements of given list to strs. + + Args: + thing: Object to be converted to a str or series of strs. + + Returns: + Value(s) in `thing` as str(s). + """ if type(thing) == list: return [list_recursive_convert_to_string(x) for x in thing] return str(thing) @@ -898,14 +1007,20 @@ def list_recursive_convert_to_string(thing): @cli.group() @pass_context def compartments(ctx: Context): - """Commands for working with FlepiMoP compartments""" + """ + Add commands for working with FlepiMoP compartments. + A container for subcommands `plot` and `export`. + Commands in this container will require context about the compartmental model. + """ pass @compartments.command(params=[config_files_argument] + list(config_file_options.values())) @pass_context def plot(ctx: Context, **kwargs): - """Plot compartments""" + """ + Command to generate a plot representing transitions between compartments. + """ parse_config_files(config, ctx, **kwargs) assert config["compartments"].exists() assert config["seir"].exists() @@ -927,7 +1042,9 @@ def plot(ctx: Context, **kwargs): @compartments.command(params=[config_files_argument] + list(config_file_options.values())) @pass_context def export(ctx: Context, **kwargs): - """Export compartments""" + """ + Export compartment information to a CSV file. + """ parse_config_files(config, ctx, **kwargs) assert config["compartments"].exists() assert config["seir"].exists() From 3ee75146163776979f5f2210637e9be0a9f9cfc1 Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Wed, 22 Jan 2025 14:26:23 -0500 Subject: [PATCH 02/15] Updating docstring in `inference.py`, `model_info.py`, `parameters.py` --- flepimop/gempyor_pkg/src/gempyor/inference.py | 160 ++++++++++++++++-- .../gempyor_pkg/src/gempyor/model_info.py | 87 +++++++++- .../gempyor_pkg/src/gempyor/parameters.py | 46 +++-- 3 files changed, 269 insertions(+), 24 deletions(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/inference.py b/flepimop/gempyor_pkg/src/gempyor/inference.py index 8fb6ed900..184c3eaf4 100644 --- a/flepimop/gempyor_pkg/src/gempyor/inference.py +++ b/flepimop/gempyor_pkg/src/gempyor/inference.py @@ -8,6 +8,29 @@ # This populate the namespace with four functions, with return value 0 if the # function terminated successfully +""" +inference.py + +Class: + GempyorInference: + Encapsulates the process of simulation. Provides functionality for parameter + inference, SEIR model execution, outcome computation, and inference optimization. + +Functions: + simulation_atomic: + Runs a SEIR simulation (generates and reduces parameters, executes SEIR + processes, computes outcomes, handles NPIs and seeding data). + get_static_arguments: Get the static arguments for the log likelihood function. + autodetect_senarios: Auto-detect the scenarios provided in config. + paramred_parallel: + Initializes a `GempyorInference` object with a configuration file, + reads specified NPI file, and computes reduced SEIR model specifications + based on this info. Returns the reduced parameters. + paramred_parallel_config: + Initializes a `GempyorInference` object with a configuration file, + retreives SEIR model specifications and NPIs, and computes reduced + parameters based on this info. Returns the reduced parameters. +""" from concurrent.futures import ProcessPoolExecutor import copy @@ -316,22 +339,58 @@ def autodetect_scenarios(config): class GempyorInference: + """ + Encapsulates the process of simulation. Provides functionality for parameter + inference, SEIR model execution, outcome computation, and inference optimization. + + Attributes: + seir_modifiers_scenario: + outcome_modifiers_scenario: + modinf: A `ModelInfo` object. + already_built: Flag to determine if necessary objects have been built. + autowrite_seir: Flag to automatically write SEIR data after simulation. + static_sim_arguments: Dictionary containing static simulation arguments. + do_inference: Flag to determine if model should be run with inference. + silent: Flag indicating whether to supress output messaging. + save: Flag indicating whether simulation results should be saved. + """ def __init__( self, config_filepath, - run_id="test_run_id", - prefix=None, - first_sim_index=1, - stoch_traj_flag=False, - rng_seed=None, - nslots=1, - inference_filename_prefix="", # usually for {global or chimeric}/{intermediate or final} - inference_filepath_suffix="", # usually for the slot_id - out_run_id=None, # if out_run_id is different from in_run_id, fill this - out_prefix=None, # if out_prefix is different from in_prefix, fill this - path_prefix="", # in case the data folder is on another directory - autowrite_seir=False, + run_id = "test_run_id", + prefix: str = None, + first_sim_index: int = 1, + stoch_traj_flag: bool = False, + rng_seed = None, + nslots: int = 1, + inference_filename_prefix: str = "", # usually for {global or chimeric}/{intermediate or final} + inference_filepath_suffix: str = "", # usually for the slot_id + out_run_id = None, # if out_run_id is different from in_run_id, fill this + out_prefix = None, # if out_prefix is different from in_prefix, fill this + path_prefix: str = "", # in case the data folder is on another directory + autowrite_seir: bool = False, ): + """ + Initializes the `GempyorInference` object by loading config, setting + up the model, and configuring inference parameters. + + Non-optinal Arg: + config_filepath: Path to the config file. + + Optional Args: + run_id: ID of the run. + prefix: Prefix for files. + first_sim_index: Index of first simulation, default is 1. + stoch_traj_flag: Whether to run the model stochastically, default is False. + rng_seed: Number of slots for parallel computation. + nslots: Number of slots, default is 1. + inference_filename_prefix: Prefix for inference-related file paths. + inference_filepath_suffix: Suffix for inference-related file paths. + out_run_id: ID for run output. + out_prefix: Prefix for file paths to output. + path_prefix: Prefix for paths to files (in case data folder is in another directory) + autowrite_seir: Flag to automatically write SEIR data after simulation, defaul is False. + """ # Config prep config.clear() config.read(user=False) @@ -563,6 +622,21 @@ def one_simulation( sim_id2load: int = None, parallel=False, ): + """ + Method to oversee inference simulation. + You can optionally load previous simulation data as well. + + Args: + sim_id2write: ID of the simulation to be written. + load_ID: Wether to load a previous simulation's data, default is False. + sim_id2load: ID of simulation to be loaded, default is None. + parallel: Whether to run simulation in parallel chains, default is False. + + Returns: 0 + + Raises: + ValueError: If `load_ID` is True and `sim_id2load` is not provided. + """ sim_id2write = int(sim_id2write) self.lastsim_sim_id2write = sim_id2write self.lastsim_loadID = load_ID @@ -751,6 +825,18 @@ def plot_transition_graph( def get_outcome_npi( self, load_ID=False, sim_id2load=None, bypass_DF=None, bypass_FN=None ): + """ + Builds the non-pharmaceutical intervention outcome modifiers. + + Args: + load_ID: Whether to load a previous simulation's data, default is False. + sim_id2load: ID of simulation to be loaded, default is None. + bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. + bypass_FN: An alternative function to use during outcome modifier construction, default is None. + + Returns: + npi_outcomes: An object that contains computed NPI outcome modifiers. + """ npi_outcomes = None if self.modinf.npi_config_outcomes: npi_outcomes = outcomes.build_outcome_modifiers( @@ -764,6 +850,18 @@ def get_outcome_npi( return npi_outcomes def get_seir_npi(self, load_ID=False, sim_id2load=None, bypass_DF=None, bypass_FN=None): + """ + Builds the SEIR non-pharmaceutical interventions information. + + Args: + load_ID: Whether to load a previous simulation's data, default is False. + sim_id2load: ID of simulation to be loaded, default is None. + bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. + bypass_FN: An alternative function to use during outcome modifier construction, default is None. + + Returns: + npi_seir: An object that contains NPI parameters for the SEIR model. + """ npi_seir = seir.build_npi_SEIR( modinf=self.modinf, load_ID=load_ID, @@ -777,6 +875,18 @@ def get_seir_npi(self, load_ID=False, sim_id2load=None, bypass_DF=None, bypass_F def get_seir_parameters( self, load_ID=False, sim_id2load=None, bypass_DF=None, bypass_FN=None ): + """ + Generates SEIR model parameters. + + Args: + load_ID: Whether to load a previous simulation's data, default is False. + sim_id2load: ID of simulation to be loaded, default is None. + bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. + bypass_FN: An alternative function to use during outcome modifier construction, default is None. + + Returns: + p_draw: An array containing the drawn model parameters. + """ param_df = None if bypass_DF is not None: param_df = bypass_DF @@ -800,6 +910,18 @@ def get_seir_parameters( def get_seir_parametersDF( self, load_ID=False, sim_id2load=None, bypass_DF=None, bypass_FN=None ): + """ + Retreive SEIR parameters and return them as a pd.DataFrame. + + Args: + load_ID: Whether to load a previous simulation's data, default is False. + sim_id2load: ID of simulation to be loaded, default is None. + bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. + bypass_FN: An alternative function to use during outcome modifier construction, default is None. + + Returns: + A pd.DatyaFrame containing the SEIR model parameters. + """ p_draw = self.get_seir_parameters( load_ID=load_ID, sim_id2load=sim_id2load, @@ -817,6 +939,20 @@ def get_seir_parameter_reduced( bypass_DF=None, bypass_FN=None, ): + """ + Retreives and reduces SEIR model parameters and returns them as a pd.DataFrame. + + Args: + npi_seir: A dictionary of NPI parameters. + p_draw: An array containing drawn model parameters, default is None. + load_ID: Whether to load a previous simulation's data, default is False. + sim_id2load: ID of simulation to be loaded, default is None. + bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. + bypass_FN: An alternative function to use during outcome modifier construction, default is None. + + Returns: + A pd.DataFrame containing reduced SEIR model parameters. + """ if p_draw is None: p_draw = self.get_seir_parameters( load_ID=load_ID, diff --git a/flepimop/gempyor_pkg/src/gempyor/model_info.py b/flepimop/gempyor_pkg/src/gempyor/model_info.py index 2c0f88efa..5a72820d2 100644 --- a/flepimop/gempyor_pkg/src/gempyor/model_info.py +++ b/flepimop/gempyor_pkg/src/gempyor/model_info.py @@ -1,3 +1,18 @@ +""" +model_info.py + +Defines the `ModelInfo` class (and associated methods), used for setting up and +managing the configuration of a simulation. The primary focuses of a `ModelInfo` object +are parsing and validating config details (including time frames, subpop info, +model parameters, outcomes) and file handling for input and output data. +This submodule is intended to serve as a foundational part of flepiMoP's +infrastructure for conducting simulations and storing results. + +Classes: + TimeSetup: + ModelInfo: +""" + import pandas as pd import datetime, os, logging, pathlib, confuse from . import ( @@ -15,6 +30,23 @@ class TimeSetup: + """ + Handles the simulation time frame based on config info. + + `TimeSetup` reads the start and end dates from the config, validates the time frame, + and calculates the number of days in the simulation. It also establishes a + pd.DatetimeIndex for the entire simulation period. + + Args: + config: A config object. + + + Attributes: + ti (datetime.date): Start date of simulation. + tf (datetime.date): End date of simulation. + n_days (int): Total number of days in the simulation time frame. + dates (pd.DatetimeIndex): A sequence of dates spanning the simulation time frame (inclusive of the start and end dates). + """ def __init__(self, config: confuse.ConfigView): self.ti = config["start_date"].as_date() self.tf = config["end_date"].as_date() @@ -27,9 +59,60 @@ def __init__(self, config: confuse.ConfigView): class ModelInfo: - # TODO: update this documentation add explaination about the construction of ModelInfo """ - Parse config and hold some results, with main config sections. + Parse config file and manage file input/output. + + Non-optional Arg: + config: Config object. + Optional Args: + nslots: Number of slots for MCMC (default is 1). + write_csv: Whether to write results to CSV files (default is False). + write_parquet: Whether to write results to parquet files (default is False). ** + first_sim_index : Index of first simulation (default is 1). + stoch_traj_flag: Whether to run the model stochastically (default is False). ** + seir_modifiers_scenario: SEIR modifier. + outcome_modifiers_scenario: Outcomes modifier. + setup_name: Name of setup (to override config, if applicable). + path_prefix: Prefix to paths where simulation data files are stored. + in_run_id: ID for input run (generated if not specified). + out_run_id: ID for outputr run (generated if not specified). + in_prefix: Path prefix for input directory. + out_prefix: Path prefix for output directory. + inference_filename_prefix: Path prefix for inference files directory. + inference_filepath_suffix: Path suffix for inference files directory. + config_filepath: Path to configuration file. + All optional args are inherited as attributes. + + Additional Attributes: + time_setup: `TimeSetup` object (start/end dates of simulation, as pd.DatetimeIndex). + ti: Initial time (time start). + tf: Final time (fime finish). + n_days: Number of days in simulation. + dates: pd.DatetimeIndex sequence of dates that span simulation. + subpop_struct: `SubpopulationStructure` object (info about subpops). + nsubpops: Number of subpopulations in simulation. + subpop_pop: NumPy array containing population of each subpop. + mobility: Matrix with values representing movement of people between subpops. + seir_config: SEIR configuration info, if relevant for simulation. + seir_modifiers_library: Modifiers for SEIR model, if relevant for simulation. + seeding_config: Seeding config, if relevant. + parameters: `Parameter` object containing information about parameters. + seeding: Seeding configuration information, if relevant. + initial_conditions: Initial condition information for simulation. + npi_config_seir: Non-pharmaceutical intervention configurations for SEIR, if relevant. + compartments: `Compartments` object contianing information about compartments. + outcomes_config: Outcomes configurations, if relevant. + npi_config_outcomes: Non-pharmaceutical intervention outcome configurations, if relevant. + + Raises: + ValueError: + If provided configuration information is incompatible with expectations. + ValueError: + If non-existent sections are referenced. + NotImplementedError: + If an unimplemented feature is referenced. + + Config sections: ``` subpop_setup # Always required compartments # Required if running seir diff --git a/flepimop/gempyor_pkg/src/gempyor/parameters.py b/flepimop/gempyor_pkg/src/gempyor/parameters.py index 7ab0de151..55d39c107 100644 --- a/flepimop/gempyor_pkg/src/gempyor/parameters.py +++ b/flepimop/gempyor_pkg/src/gempyor/parameters.py @@ -1,8 +1,12 @@ """ -Abstractions for interacting with the parameters configurations. +parameters.py -This module contains abstractions for interacting with the parameters section of given -config files. Namely it contains the `Parameters` class. +Provides abstractions for interacting with the parameters configurations. + +Classes: + Parameters: + Encapsulates logic for loading, parsing, and + summarizing parameter configurations. """ __all__ = ["Parameters"] @@ -28,7 +32,15 @@ class Parameters: """ Encapsulates logic for loading, parsing, and summarizing parameter configurations. - + Parameters can be defined or drawn from distributions. + + Args: + parameter_config: Configuration information (in a confuse.ConfigView) for parameters. + ti: Initial time of simulation (time start). + tf: Final time of simulation (time finish). + subpop_names: Names of all subpopulations. + path_prefix: Pathway prefix to directory with + Attributes: npar: The number of parameters contained within the given configuration. pconfig: A view subsetting to the parameters section of a given config file. @@ -39,6 +51,8 @@ class Parameters: attribute. stacked_modifier_method: A mapping of modifier method to the parameters to which that modifier method is relevant for. + + Raises: """ def __init__( @@ -52,16 +66,28 @@ def __init__( ): """ Initialize a `Parameters` instance from a parameter config view. + Encapsulates logic for loading, parsing, and summarizing parameter configurations. + Parameters can be defined or drawn from distributions. Args: - parameter_config: A view subsetting to the parameters section of a given + parameter_config: A confuse.ConfigView subsetting the parameters section of a given config file. - ti: An initial date. - tf: A final date. + ti: An initial date for simulation. + tf: A final date for simulation. subpop_names: A list of subpopulation names. - path_prefix: A file path prefix to use when reading in parameter values from - a dataframe like file. - + path_prefix: A file path prefix to directory containing parameter values. + + Attributes: + pconfig: confuse.ConfigView of parameter configuration information. + pnames: A list of parameter names. + npar: Number of parameters. + pdata: A dictionary containing a processed and reformatted view of the `pconfig` + attribute. + pnames2pindex: A map of parameter names to their location in the `pnames` + attribute. + stacked_modifier_method: A map of modifier methods to the parameters which + that modifier method is relevant for. + Raises: ValueError: The parameter names for the SEIR model are not unique. ValueError: The dataframe file found for a given parameter contains an From 572f8f7fa4f5f9969c6f96c3e7b33cbeaacc3016 Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Wed, 22 Jan 2025 14:28:06 -0500 Subject: [PATCH 03/15] Linting with `black` --- flepimop/gempyor_pkg/src/gempyor/calibrate.py | 6 +- .../gempyor_pkg/src/gempyor/compartments.py | 92 ++++++++++--------- flepimop/gempyor_pkg/src/gempyor/inference.py | 49 +++++----- .../gempyor_pkg/src/gempyor/model_info.py | 35 +++---- .../gempyor_pkg/src/gempyor/parameters.py | 10 +- 5 files changed, 102 insertions(+), 90 deletions(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/calibrate.py b/flepimop/gempyor_pkg/src/gempyor/calibrate.py index d4d3eaa23..37271a931 100644 --- a/flepimop/gempyor_pkg/src/gempyor/calibrate.py +++ b/flepimop/gempyor_pkg/src/gempyor/calibrate.py @@ -150,7 +150,7 @@ def calibrate( resume_location: str, ) -> None: """ - Calibrate using an `emcee` sampler to initialize a model based on a config. + Calibrate using an `emcee` sampler to initialize a model based on a config. Args: config_filepath: Path to the configuration file. @@ -158,13 +158,13 @@ def calibrate( nwalkers: Number of walkers (MCMC chains) to run. niter: Number of MCMC iterations to perform. nsamples: Number of samples to select from final MCMC chain. - nthin (optional): How often to save samples. + nthin (optional): How often to save samples. ncpu: Number of CPU cores to use for parallelization. input_run_id (optional): Run ID. Will be auto-generated if not provdied. prefix (optional): A prefix for output files. resume: Whether or not to resume a previous calibration run. resume_location (optional): Path to the location of the saved state to resume from. - + Returns: None """ diff --git a/flepimop/gempyor_pkg/src/gempyor/compartments.py b/flepimop/gempyor_pkg/src/gempyor/compartments.py index b7b6c9856..bf48c8d03 100644 --- a/flepimop/gempyor_pkg/src/gempyor/compartments.py +++ b/flepimop/gempyor_pkg/src/gempyor/compartments.py @@ -15,6 +15,7 @@ plot: Generate a plot representing transition between compartments. export: Export compartment data to a CSV file. """ + from functools import reduce import numpy as np @@ -33,10 +34,10 @@ class Compartments: """ - An object to handle compartment data for the model. + An object to handle compartment data for the model. Arguments: - seir_config (optional): Config file for SEIR model construction information. + seir_config (optional): Config file for SEIR model construction information. compartments_config (optional): Config file for compartment information. compartments_file (optional): File to specify compartment information. transitions_file (optional): File to specify transition information. @@ -44,13 +45,14 @@ class Compartments: Attributes: times_set: Counter to track succesful data intialization from config. """ + # Minimal object to be easily picklable for // runs def __init__( self, - seir_config = None, - compartments_config = None, - compartments_file = None, - transitions_file = None, + seir_config=None, + compartments_config=None, + compartments_file=None, + transitions_file=None, ): self.times_set = 0 @@ -70,7 +72,7 @@ def constructFromConfig(self, seir_config, compartment_config) -> None: """ This method is called by the constructor if the compartments are not loaded from a file. It will parse the compartments and transitions from the configuration files. - It will populate dynamic class attributes `self.compartments` and `self.transitions`. + It will populate dynamic class attributes `self.compartments` and `self.transitions`. """ self.compartments = self.parse_compartments(seir_config, compartment_config) self.transitions = self.parse_transitions(seir_config, False) @@ -89,7 +91,7 @@ def parse_compartments(self, seir_config: dict, compartment_config) -> pd.DataFr compartment_config: Configuration information for model comartments. Returns: - A DataFrame where each row is a unique compartment and columns + A DataFrame where each row is a unique compartment and columns correspond to attributes of the compartments. """ compartment_df = None @@ -105,13 +107,15 @@ def parse_compartments(self, seir_config: dict, compartment_config) -> pd.DataFr ) return compartment_df - def parse_transitions(self, seir_config: dict, fake_config: bool = False) -> pd.DataFrame: + def parse_transitions( + self, seir_config: dict, fake_config: bool = False + ) -> pd.DataFrame: """ Parses the transitions defined in config and returns a concatenated DataFrame. Args: seir_config: Configuraton information for model. - fake_config (optional): + fake_config (optional): Flag indicating whether or not transitions provied are placeholders. Default value is False. Returns: @@ -503,18 +507,18 @@ def get_comp_idx(self, comp_dict: dict, error_info: str = "no information") -> i """ Return the index of a compartiment given a filter. The filter has to isolate a compartiment, but it ignore columns that don't exist: - + Args: - comp_dict: - A dictionary where keys are compartment names and + comp_dict: + A dictionary where keys are compartment names and values are values to filter by for each column. - error_info (optional): - A message providing additional context about where the - the method was called from. Default value is "no information". - + error_info (optional): + A message providing additional context about where the + the method was called from. Default value is "no information". + Returns: Index of the comaprtment that matches the filter. - + Raises: ValueError: Filter results in more than one or zero matches. """ @@ -535,14 +539,14 @@ def get_ncomp(self) -> int: def get_transition_array(self) -> tuple: """ - Constructs the transition matrix for the model. + Constructs the transition matrix for the model. Returns: tuple: - a list of unique strings from `proportion_exponent` and `rate` - array representing transitions and corresponding compartment indices. - array representing proportion compartment indices - - array containing start and end indices for proportions + - array containing start and end indices for proportions Raises: ValueError: If term is not found in list of valid compartments. @@ -708,17 +712,19 @@ def get_transition_array(self) -> tuple: proportion_info, ) - def parse_parameters(self, parameters: list, parameter_names: list, unique_strings: list) -> np.ndarray: + def parse_parameters( + self, parameters: list, parameter_names: list, unique_strings: list + ) -> np.ndarray: """ Parses provided parameters and stores them in NumPy arrays. Args: parameters: Input parameters to be parsed. parameter_names: List of all parameter names. - unique_strings: - List of unique values from `proportion_exponent` + unique_strings: + List of unique values from `proportion_exponent` and `rate` columns of transitions data. - + Returns: Array of parsed parameters. """ @@ -850,7 +856,7 @@ def parse_parameter_strings_to_numpy_arrays( def get_compartments_explicitDF(self) -> pd.DataFrame: """ Returns a copy of the compartments information DataFrame. - All columns receive a 'mc_' prefix. + All columns receive a 'mc_' prefix. Returns: A copy of the compartments DataFrame. @@ -916,11 +922,11 @@ def filter_func(lst, this_filter=[]): def get_list_dimension(thing: any) -> int: """ - Returns the dimension of a given object. - + Returns the dimension of a given object. + Args: thing: Object whose dimension needs to be determined. - + Returns: int: Length of the object if a list, otherwise 1. """ @@ -929,19 +935,21 @@ def get_list_dimension(thing: any) -> int: return 1 -def list_access_element_safe(thing: any, idx: int, dimension=None, encapsulate_as_list=False) -> Union[any, list]: +def list_access_element_safe( + thing: any, idx: int, dimension=None, encapsulate_as_list=False +) -> Union[any, list]: """ Attempts to access an element from the given object `thing` at the specified index `idx`. - + Args: thing: Object to be accessed from. - idx: Index of object you would like to access. + idx: Index of object you would like to access. dimension (optional): Dimension or shape of the object. encapsulate_as_list (optional): If `True`, the accessed element will be returned as a list. - + Raises: Exception: If `thing` is not iterable or `idx ` is out of range. - + Returns: Item at `idx` if `thing` is list, or element itself if `thing` is not a list. @@ -959,12 +967,14 @@ def list_access_element_safe(thing: any, idx: int, dimension=None, encapsulate_a ) -def list_access_element(thing: any, idx: int, dimension=None, encapsulate_as_list=False) -> Union[any, list]: +def list_access_element( + thing: any, idx: int, dimension=None, encapsulate_as_list=False +) -> Union[any, list]: """ Access an element from a list or return the input itself if not a list. If input `thing` is a list, the function will return the element at the specified index (`idx`). - If input `thing` is not a list, the function will return the element itself, regardless of the - `idx` value. + If input `thing` is not a list, the function will return the element itself, regardless of the + `idx` value. Args: @@ -990,14 +1000,14 @@ def list_access_element(thing: any, idx: int, dimension=None, encapsulate_as_lis def list_recursive_convert_to_string(thing: any) -> str: """ - Return given object as a str, + Return given object as a str, or recursively convert elements of given list to strs. Args: thing: Object to be converted to a str or series of strs. - + Returns: - Value(s) in `thing` as str(s). + Value(s) in `thing` as str(s). """ if type(thing) == list: return [list_recursive_convert_to_string(x) for x in thing] @@ -1009,8 +1019,8 @@ def list_recursive_convert_to_string(thing: any) -> str: def compartments(ctx: Context): """ Add commands for working with FlepiMoP compartments. - A container for subcommands `plot` and `export`. - Commands in this container will require context about the compartmental model. + A container for subcommands `plot` and `export`. + Commands in this container will require context about the compartmental model. """ pass diff --git a/flepimop/gempyor_pkg/src/gempyor/inference.py b/flepimop/gempyor_pkg/src/gempyor/inference.py index 184c3eaf4..2a78bd91a 100644 --- a/flepimop/gempyor_pkg/src/gempyor/inference.py +++ b/flepimop/gempyor_pkg/src/gempyor/inference.py @@ -342,10 +342,10 @@ class GempyorInference: """ Encapsulates the process of simulation. Provides functionality for parameter inference, SEIR model execution, outcome computation, and inference optimization. - + Attributes: seir_modifiers_scenario: - outcome_modifiers_scenario: + outcome_modifiers_scenario: modinf: A `ModelInfo` object. already_built: Flag to determine if necessary objects have been built. autowrite_seir: Flag to automatically write SEIR data after simulation. @@ -354,19 +354,20 @@ class GempyorInference: silent: Flag indicating whether to supress output messaging. save: Flag indicating whether simulation results should be saved. """ + def __init__( self, config_filepath, - run_id = "test_run_id", + run_id="test_run_id", prefix: str = None, first_sim_index: int = 1, stoch_traj_flag: bool = False, - rng_seed = None, + rng_seed=None, nslots: int = 1, inference_filename_prefix: str = "", # usually for {global or chimeric}/{intermediate or final} inference_filepath_suffix: str = "", # usually for the slot_id - out_run_id = None, # if out_run_id is different from in_run_id, fill this - out_prefix = None, # if out_prefix is different from in_prefix, fill this + out_run_id=None, # if out_run_id is different from in_run_id, fill this + out_prefix=None, # if out_prefix is different from in_prefix, fill this path_prefix: str = "", # in case the data folder is on another directory autowrite_seir: bool = False, ): @@ -378,8 +379,8 @@ def __init__( config_filepath: Path to the config file. Optional Args: - run_id: ID of the run. - prefix: Prefix for files. + run_id: ID of the run. + prefix: Prefix for files. first_sim_index: Index of first simulation, default is 1. stoch_traj_flag: Whether to run the model stochastically, default is False. rng_seed: Number of slots for parallel computation. @@ -624,7 +625,7 @@ def one_simulation( ): """ Method to oversee inference simulation. - You can optionally load previous simulation data as well. + You can optionally load previous simulation data as well. Args: sim_id2write: ID of the simulation to be written. @@ -831,11 +832,11 @@ def get_outcome_npi( Args: load_ID: Whether to load a previous simulation's data, default is False. sim_id2load: ID of simulation to be loaded, default is None. - bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. - bypass_FN: An alternative function to use during outcome modifier construction, default is None. + bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. + bypass_FN: An alternative function to use during outcome modifier construction, default is None. Returns: - npi_outcomes: An object that contains computed NPI outcome modifiers. + npi_outcomes: An object that contains computed NPI outcome modifiers. """ npi_outcomes = None if self.modinf.npi_config_outcomes: @@ -851,16 +852,16 @@ def get_outcome_npi( def get_seir_npi(self, load_ID=False, sim_id2load=None, bypass_DF=None, bypass_FN=None): """ - Builds the SEIR non-pharmaceutical interventions information. + Builds the SEIR non-pharmaceutical interventions information. Args: load_ID: Whether to load a previous simulation's data, default is False. sim_id2load: ID of simulation to be loaded, default is None. - bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. - bypass_FN: An alternative function to use during outcome modifier construction, default is None. - + bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. + bypass_FN: An alternative function to use during outcome modifier construction, default is None. + Returns: - npi_seir: An object that contains NPI parameters for the SEIR model. + npi_seir: An object that contains NPI parameters for the SEIR model. """ npi_seir = seir.build_npi_SEIR( modinf=self.modinf, @@ -881,8 +882,8 @@ def get_seir_parameters( Args: load_ID: Whether to load a previous simulation's data, default is False. sim_id2load: ID of simulation to be loaded, default is None. - bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. - bypass_FN: An alternative function to use during outcome modifier construction, default is None. + bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. + bypass_FN: An alternative function to use during outcome modifier construction, default is None. Returns: p_draw: An array containing the drawn model parameters. @@ -919,7 +920,7 @@ def get_seir_parametersDF( bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. bypass_FN: An alternative function to use during outcome modifier construction, default is None. - Returns: + Returns: A pd.DatyaFrame containing the SEIR model parameters. """ p_draw = self.get_seir_parameters( @@ -940,18 +941,18 @@ def get_seir_parameter_reduced( bypass_FN=None, ): """ - Retreives and reduces SEIR model parameters and returns them as a pd.DataFrame. + Retreives and reduces SEIR model parameters and returns them as a pd.DataFrame. Args: npi_seir: A dictionary of NPI parameters. - p_draw: An array containing drawn model parameters, default is None. + p_draw: An array containing drawn model parameters, default is None. load_ID: Whether to load a previous simulation's data, default is False. sim_id2load: ID of simulation to be loaded, default is None. bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. bypass_FN: An alternative function to use during outcome modifier construction, default is None. - + Returns: - A pd.DataFrame containing reduced SEIR model parameters. + A pd.DataFrame containing reduced SEIR model parameters. """ if p_draw is None: p_draw = self.get_seir_parameters( diff --git a/flepimop/gempyor_pkg/src/gempyor/model_info.py b/flepimop/gempyor_pkg/src/gempyor/model_info.py index 5a72820d2..246995f90 100644 --- a/flepimop/gempyor_pkg/src/gempyor/model_info.py +++ b/flepimop/gempyor_pkg/src/gempyor/model_info.py @@ -33,8 +33,8 @@ class TimeSetup: """ Handles the simulation time frame based on config info. - `TimeSetup` reads the start and end dates from the config, validates the time frame, - and calculates the number of days in the simulation. It also establishes a + `TimeSetup` reads the start and end dates from the config, validates the time frame, + and calculates the number of days in the simulation. It also establishes a pd.DatetimeIndex for the entire simulation period. Args: @@ -47,6 +47,7 @@ class TimeSetup: n_days (int): Total number of days in the simulation time frame. dates (pd.DatetimeIndex): A sequence of dates spanning the simulation time frame (inclusive of the start and end dates). """ + def __init__(self, config: confuse.ConfigView): self.ti = config["start_date"].as_date() self.tf = config["end_date"].as_date() @@ -60,27 +61,27 @@ def __init__(self, config: confuse.ConfigView): class ModelInfo: """ - Parse config file and manage file input/output. + Parse config file and manage file input/output. Non-optional Arg: config: Config object. Optional Args: - nslots: Number of slots for MCMC (default is 1). - write_csv: Whether to write results to CSV files (default is False). + nslots: Number of slots for MCMC (default is 1). + write_csv: Whether to write results to CSV files (default is False). write_parquet: Whether to write results to parquet files (default is False). ** - first_sim_index : Index of first simulation (default is 1). + first_sim_index : Index of first simulation (default is 1). stoch_traj_flag: Whether to run the model stochastically (default is False). ** - seir_modifiers_scenario: SEIR modifier. - outcome_modifiers_scenario: Outcomes modifier. - setup_name: Name of setup (to override config, if applicable). - path_prefix: Prefix to paths where simulation data files are stored. + seir_modifiers_scenario: SEIR modifier. + outcome_modifiers_scenario: Outcomes modifier. + setup_name: Name of setup (to override config, if applicable). + path_prefix: Prefix to paths where simulation data files are stored. in_run_id: ID for input run (generated if not specified). out_run_id: ID for outputr run (generated if not specified). - in_prefix: Path prefix for input directory. - out_prefix: Path prefix for output directory. - inference_filename_prefix: Path prefix for inference files directory. - inference_filepath_suffix: Path suffix for inference files directory. - config_filepath: Path to configuration file. + in_prefix: Path prefix for input directory. + out_prefix: Path prefix for output directory. + inference_filename_prefix: Path prefix for inference files directory. + inference_filepath_suffix: Path suffix for inference files directory. + config_filepath: Path to configuration file. All optional args are inherited as attributes. Additional Attributes: @@ -88,7 +89,7 @@ class ModelInfo: ti: Initial time (time start). tf: Final time (fime finish). n_days: Number of days in simulation. - dates: pd.DatetimeIndex sequence of dates that span simulation. + dates: pd.DatetimeIndex sequence of dates that span simulation. subpop_struct: `SubpopulationStructure` object (info about subpops). nsubpops: Number of subpopulations in simulation. subpop_pop: NumPy array containing population of each subpop. @@ -108,7 +109,7 @@ class ModelInfo: ValueError: If provided configuration information is incompatible with expectations. ValueError: - If non-existent sections are referenced. + If non-existent sections are referenced. NotImplementedError: If an unimplemented feature is referenced. diff --git a/flepimop/gempyor_pkg/src/gempyor/parameters.py b/flepimop/gempyor_pkg/src/gempyor/parameters.py index 55d39c107..4b190e657 100644 --- a/flepimop/gempyor_pkg/src/gempyor/parameters.py +++ b/flepimop/gempyor_pkg/src/gempyor/parameters.py @@ -37,10 +37,10 @@ class Parameters: Args: parameter_config: Configuration information (in a confuse.ConfigView) for parameters. ti: Initial time of simulation (time start). - tf: Final time of simulation (time finish). + tf: Final time of simulation (time finish). subpop_names: Names of all subpopulations. - path_prefix: Pathway prefix to directory with - + path_prefix: Pathway prefix to directory with + Attributes: npar: The number of parameters contained within the given configuration. pconfig: A view subsetting to the parameters section of a given config file. @@ -72,7 +72,7 @@ def __init__( Args: parameter_config: A confuse.ConfigView subsetting the parameters section of a given config file. - ti: An initial date for simulation. + ti: An initial date for simulation. tf: A final date for simulation. subpop_names: A list of subpopulation names. path_prefix: A file path prefix to directory containing parameter values. @@ -87,7 +87,7 @@ def __init__( attribute. stacked_modifier_method: A map of modifier methods to the parameters which that modifier method is relevant for. - + Raises: ValueError: The parameter names for the SEIR model are not unique. ValueError: The dataframe file found for a given parameter contains an From b680cb82f861a3788f8992f87d14f73fcb72e6cd Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Wed, 22 Jan 2025 15:00:59 -0500 Subject: [PATCH 04/15] Documentation update in `model_info` --- flepimop/gempyor_pkg/src/gempyor/model_info.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/model_info.py b/flepimop/gempyor_pkg/src/gempyor/model_info.py index 246995f90..95b2691cb 100644 --- a/flepimop/gempyor_pkg/src/gempyor/model_info.py +++ b/flepimop/gempyor_pkg/src/gempyor/model_info.py @@ -9,8 +9,8 @@ infrastructure for conducting simulations and storing results. Classes: - TimeSetup: - ModelInfo: + TimeSetup: Handles simulation time frame. + ModelInfo: Parses config file, holds model information, and manages file input/output. """ import pandas as pd @@ -61,7 +61,7 @@ def __init__(self, config: confuse.ConfigView): class ModelInfo: """ - Parse config file and manage file input/output. + Parses config file, holds model information, and manages file input/output. Non-optional Arg: config: Config object. From ab85156eb8e1d3235b1feaf647f026713089f799 Mon Sep 17 00:00:00 2001 From: Emily Przykucki <100221052+emprzy@users.noreply.github.com> Date: Fri, 24 Jan 2025 09:19:07 -0500 Subject: [PATCH 05/15] Changing a data type hint in `compartments.py` --- flepimop/gempyor_pkg/src/gempyor/compartments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/compartments.py b/flepimop/gempyor_pkg/src/gempyor/compartments.py index bf48c8d03..a4ddc20f6 100644 --- a/flepimop/gempyor_pkg/src/gempyor/compartments.py +++ b/flepimop/gempyor_pkg/src/gempyor/compartments.py @@ -713,7 +713,7 @@ def get_transition_array(self) -> tuple: ) def parse_parameters( - self, parameters: list, parameter_names: list, unique_strings: list + self, parameters: np.ndarray, parameter_names: list, unique_strings: list ) -> np.ndarray: """ Parses provided parameters and stores them in NumPy arrays. From 2b777c58854d1db3aab56c53ce56e88373578d3a Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Fri, 24 Jan 2025 14:26:46 -0500 Subject: [PATCH 06/15] Implementing suggestions from @TimothyWillard review --- flepimop/gempyor_pkg/src/gempyor/calibrate.py | 31 +++----- flepimop/gempyor_pkg/src/gempyor/cli.py | 2 + .../gempyor_pkg/src/gempyor/compartments.py | 64 +++++++++-------- flepimop/gempyor_pkg/src/gempyor/inference.py | 62 ++++++++-------- .../gempyor_pkg/src/gempyor/model_info.py | 72 ++++++++++++------- .../gempyor_pkg/src/gempyor/parameters.py | 27 +------ 6 files changed, 122 insertions(+), 136 deletions(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/calibrate.py b/flepimop/gempyor_pkg/src/gempyor/calibrate.py index 37271a931..7e571ce07 100644 --- a/flepimop/gempyor_pkg/src/gempyor/calibrate.py +++ b/flepimop/gempyor_pkg/src/gempyor/calibrate.py @@ -1,25 +1,10 @@ """ -calibrate.py - Facilitates the calibration of the model using the `emcee` MCMC sampler. Provides CLI options for users to specify simulation paramters. Functions: calibrate: Reads a configuration file for simulation settings. -Options: - --config, -c Path to the configuration file. - --project_path, -p Path to the flepiMoP project directory. - --nwalkers, -n Number of walkers (MCMC chains) to use. Overrides value in config. - --niterations Number of MCMC iterations. Overrides value in config. - --nsamples Number of samples to retain. OVerrides value in config. - --nthin Number of samples to thin. Overrides value in config. - --j, --jobs Number of CPU cores to use for prallelization. - --id Unique ID for the run. - --prefix Prefix for output files. - --resume Flag determining whether or not to resume the current calibration. - --resume_location, -r Path to the location to resume the run from. - """ #!/usr/bin/env python @@ -142,12 +127,12 @@ def calibrate( nwalkers: int, niter: int, nsamples: int, - nthin: int, + nthin: int | None, ncpu: int, - input_run_id: int, - prefix: str, + input_run_id: int | None, + prefix: str | None, resume: bool, - resume_location: str, + resume_location: str | None, ) -> None: """ Calibrate using an `emcee` sampler to initialize a model based on a config. @@ -158,12 +143,12 @@ def calibrate( nwalkers: Number of walkers (MCMC chains) to run. niter: Number of MCMC iterations to perform. nsamples: Number of samples to select from final MCMC chain. - nthin (optional): How often to save samples. + nthin: How often to save samples. ncpu: Number of CPU cores to use for parallelization. - input_run_id (optional): Run ID. Will be auto-generated if not provdied. - prefix (optional): A prefix for output files. + input_run_id: Run ID. Will be auto-generated if not provdied. + prefix: A prefix for output files. resume: Whether or not to resume a previous calibration run. - resume_location (optional): Path to the location of the saved state to resume from. + resume_location: Path to the location of the saved state to resume from. Returns: None diff --git a/flepimop/gempyor_pkg/src/gempyor/cli.py b/flepimop/gempyor_pkg/src/gempyor/cli.py index 35c3f6163..cb1c1fc88 100644 --- a/flepimop/gempyor_pkg/src/gempyor/cli.py +++ b/flepimop/gempyor_pkg/src/gempyor/cli.py @@ -28,6 +28,8 @@ @click.pass_context def patch(ctx: click.Context = mock_context, **kwargs) -> None: """ + Merge configuration files. + This command will merge multiple config files together by overriding the top level keys in config files. The order of the config files is important, as the last file has the highest priority and the first has the lowest. diff --git a/flepimop/gempyor_pkg/src/gempyor/compartments.py b/flepimop/gempyor_pkg/src/gempyor/compartments.py index bf48c8d03..ad490f7ff 100644 --- a/flepimop/gempyor_pkg/src/gempyor/compartments.py +++ b/flepimop/gempyor_pkg/src/gempyor/compartments.py @@ -1,6 +1,4 @@ """ -compartments.py - Defines class, methods, and functions necessary to establising compartments in the model. Classes: @@ -27,7 +25,7 @@ from .utils import config, Timer, as_list from .shared_cli import config_files_argument, config_file_options, parse_config_files, cli -from typing import Union +from typing import Any logger = logging.getLogger(__name__) @@ -36,12 +34,6 @@ class Compartments: """ An object to handle compartment data for the model. - Arguments: - seir_config (optional): Config file for SEIR model construction information. - compartments_config (optional): Config file for compartment information. - compartments_file (optional): File to specify compartment information. - transitions_file (optional): File to specify transition information. - Attributes: times_set: Counter to track succesful data intialization from config. """ @@ -54,6 +46,15 @@ def __init__( compartments_file=None, transitions_file=None, ): + """ + Initializes a `Compartments` object. + + Args: + seir_config: Config file for SEIR model construction information. + compartments_config: Config file for compartment information. + compartments_file: File to specify compartment information. + transitions_file: File to specify transition information. + """ self.times_set = 0 ## Something like this is needed for check script: @@ -115,7 +116,7 @@ def parse_transitions( Args: seir_config: Configuraton information for model. - fake_config (optional): + fake_config: Flag indicating whether or not transitions provied are placeholders. Default value is False. Returns: @@ -505,14 +506,14 @@ def fromFile(self, compartments_file, transitions_file): def get_comp_idx(self, comp_dict: dict, error_info: str = "no information") -> int: """ - Return the index of a compartiment given a filter. The filter has to isolate a compartiment, - but it ignore columns that don't exist: + Return the index of a compartiment given a filter. The filter has to isolate a compartment, + but it ignores columns that don't exist: Args: comp_dict: A dictionary where keys are compartment names and values are values to filter by for each column. - error_info (optional): + error_info: A message providing additional context about where the the method was called from. Default value is "no information". @@ -542,11 +543,11 @@ def get_transition_array(self) -> tuple: Constructs the transition matrix for the model. Returns: - tuple: - - a list of unique strings from `proportion_exponent` and `rate` - - array representing transitions and corresponding compartment indices. - - array representing proportion compartment indices - - array containing start and end indices for proportions + tuple[list[str], np.ndarray, np.ndarray, np.ndarray]: + - unique_strings: unique strings from `proportion_exponent` and `rate` + - transition_array: array representing transitions and corresponding compartment indices. + - proportion_array: array representing proportion compartment indices + - proportion_info: array containing start and end indices for proportions Raises: ValueError: If term is not found in list of valid compartments. @@ -855,8 +856,7 @@ def parse_parameter_strings_to_numpy_arrays( def get_compartments_explicitDF(self) -> pd.DataFrame: """ - Returns a copy of the compartments information DataFrame. - All columns receive a 'mc_' prefix. + Returns a copy of the compartments information DataFrame; all columns receive a 'mc_' prefix. Returns: A copy of the compartments DataFrame. @@ -920,7 +920,7 @@ def filter_func(lst, this_filter=[]): src.render(output_file) -def get_list_dimension(thing: any) -> int: +def get_list_dimension(thing: Any) -> int: """ Returns the dimension of a given object. @@ -928,7 +928,7 @@ def get_list_dimension(thing: any) -> int: thing: Object whose dimension needs to be determined. Returns: - int: Length of the object if a list, otherwise 1. + Length of the object if a list, otherwise 1. """ if type(thing) == list: return len(thing) @@ -936,16 +936,16 @@ def get_list_dimension(thing: any) -> int: def list_access_element_safe( - thing: any, idx: int, dimension=None, encapsulate_as_list=False -) -> Union[any, list]: + thing: Any, idx: int, dimension=None, encapsulate_as_list=False +) -> Any | list[Any]: """ Attempts to access an element from the given object `thing` at the specified index `idx`. Args: thing: Object to be accessed from. idx: Index of object you would like to access. - dimension (optional): Dimension or shape of the object. - encapsulate_as_list (optional): If `True`, the accessed element will be returned as a list. + dimension: Dimension or shape of the object. + encapsulate_as_list: If `True`, the accessed element will be returned as a list. Default is False. Raises: Exception: If `thing` is not iterable or `idx ` is out of range. @@ -968,8 +968,8 @@ def list_access_element_safe( def list_access_element( - thing: any, idx: int, dimension=None, encapsulate_as_list=False -) -> Union[any, list]: + thing: Any, idx: int, dimension=None, encapsulate_as_list=False +) -> Any | list[Any]: """ Access an element from a list or return the input itself if not a list. If input `thing` is a list, the function will return the element at the specified index (`idx`). @@ -977,6 +977,10 @@ def list_access_element( `idx` value. Args: + thing: Object to be accessed from. + idx: Index of object you would like to access. + dimension: Dimension or shape of the object. + encapsulate_as_list: If `True`, the accessed element will be returned as a list. Default is False. Returns: Item at `idx` if `thing` is list, or @@ -998,7 +1002,7 @@ def list_access_element( return rc -def list_recursive_convert_to_string(thing: any) -> str: +def list_recursive_convert_to_string(thing: Any) -> str: """ Return given object as a str, or recursively convert elements of given list to strs. @@ -1019,8 +1023,6 @@ def list_recursive_convert_to_string(thing: any) -> str: def compartments(ctx: Context): """ Add commands for working with FlepiMoP compartments. - A container for subcommands `plot` and `export`. - Commands in this container will require context about the compartmental model. """ pass diff --git a/flepimop/gempyor_pkg/src/gempyor/inference.py b/flepimop/gempyor_pkg/src/gempyor/inference.py index fefe30cc1..55c19712c 100644 --- a/flepimop/gempyor_pkg/src/gempyor/inference.py +++ b/flepimop/gempyor_pkg/src/gempyor/inference.py @@ -9,9 +9,7 @@ # function terminated successfully """ -inference.py - -Class: +Classes: GempyorInference: Encapsulates the process of simulation. Provides functionality for parameter inference, SEIR model execution, outcome computation, and inference optimization. @@ -47,6 +45,7 @@ from . import seir, model_info from . import outcomes, file_paths from .utils import config, Timer, read_df, as_list +from typing import Literal logging.basicConfig(level=os.environ.get("FLEPI_LOGLEVEL", "INFO").upper()) @@ -340,8 +339,10 @@ def autodetect_scenarios(config): class GempyorInference: """ - Encapsulates the process of simulation. Provides functionality for parameter - inference, SEIR model execution, outcome computation, and inference optimization. + Class to encapsulate the process of inference simulation. + + Provides functionality for parameter inference, SEIR model execution, + outcome computation, and inference optimization. Attributes: seir_modifiers_scenario: @@ -359,7 +360,7 @@ def __init__( self, config_filepath, run_id="test_run_id", - prefix: str = None, + prefix: str | None = None, first_sim_index: int = 1, stoch_traj_flag: bool = False, rng_seed=None, @@ -372,13 +373,10 @@ def __init__( autowrite_seir: bool = False, ): """ - Initializes the `GempyorInference` object by loading config, setting - up the model, and configuring inference parameters. + Initializes the `GempyorInference` object by loading config, setting up the model, and configuring inference parameters. - Non-optinal Arg: + Args: config_filepath: Path to the config file. - - Optional Args: run_id: ID of the run. prefix: Prefix for files. first_sim_index: Index of first simulation, default is 1. @@ -390,7 +388,7 @@ def __init__( out_run_id: ID for run output. out_prefix: Prefix for file paths to output. path_prefix: Prefix for paths to files (in case data folder is in another directory) - autowrite_seir: Flag to automatically write SEIR data after simulation, defaul is False. + autowrite_seir: Flag to automatically write SEIR data after simulation, default is False. """ # Config prep config.clear() @@ -622,7 +620,7 @@ def one_simulation( load_ID: bool = False, sim_id2load: int = None, parallel=False, - ): + ) -> Literal[0]: """ Method to oversee inference simulation. You can optionally load previous simulation data as well. @@ -630,7 +628,7 @@ def one_simulation( Args: sim_id2write: ID of the simulation to be written. load_ID: Wether to load a previous simulation's data, default is False. - sim_id2load: ID of simulation to be loaded, default is None. + sim_id2load: ID of simulation to be loaded. parallel: Whether to run simulation in parallel chains, default is False. Returns: 0 @@ -827,13 +825,13 @@ def get_outcome_npi( Builds the non-pharmaceutical intervention outcome modifiers. Args: - load_ID: Whether to load a previous simulation's data, default is False. - sim_id2load: ID of simulation to be loaded, default is None. - bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. - bypass_FN: An alternative function to use during outcome modifier construction, default is None. + load_ID: Whether to load a previous simulation's data. + sim_id2load: ID of simulation to be loaded. + bypass_DF: An alternative data frame to use during outcome modifier construction. + bypass_FN: An alternative function to use during outcome modifier construction. Returns: - npi_outcomes: An object that contains computed NPI outcome modifiers. + An object that contains computed NPI outcome modifiers. """ npi_outcomes = None if self.modinf.npi_config_outcomes: @@ -853,9 +851,9 @@ def get_seir_npi(self, load_ID=False, sim_id2load=None, bypass_DF=None, bypass_F Args: load_ID: Whether to load a previous simulation's data, default is False. - sim_id2load: ID of simulation to be loaded, default is None. - bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. - bypass_FN: An alternative function to use during outcome modifier construction, default is None. + sim_id2load: ID of simulation to be loaded. + bypass_DF: An alternative data frame to use during outcome modifier construction. + bypass_FN: An alternative function to use during outcome modifier construction. Returns: npi_seir: An object that contains NPI parameters for the SEIR model. @@ -878,9 +876,9 @@ def get_seir_parameters( Args: load_ID: Whether to load a previous simulation's data, default is False. - sim_id2load: ID of simulation to be loaded, default is None. - bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. - bypass_FN: An alternative function to use during outcome modifier construction, default is None. + sim_id2load: ID of simulation to be loaded. + bypass_DF: An alternative data frame to use during outcome modifier construction. + bypass_FN: An alternative function to use during outcome modifier construction. Returns: p_draw: An array containing the drawn model parameters. @@ -913,9 +911,9 @@ def get_seir_parametersDF( Args: load_ID: Whether to load a previous simulation's data, default is False. - sim_id2load: ID of simulation to be loaded, default is None. - bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. - bypass_FN: An alternative function to use during outcome modifier construction, default is None. + sim_id2load: ID of simulation to be loaded. + bypass_DF: An alternative data frame to use during outcome modifier construction. + bypass_FN: An alternative function to use during outcome modifier construction. Returns: A pd.DatyaFrame containing the SEIR model parameters. @@ -942,11 +940,11 @@ def get_seir_parameter_reduced( Args: npi_seir: A dictionary of NPI parameters. - p_draw: An array containing drawn model parameters, default is None. + p_draw: An array containing drawn model parameters. load_ID: Whether to load a previous simulation's data, default is False. - sim_id2load: ID of simulation to be loaded, default is None. - bypass_DF: An alternative data frame to use during outcome modifier construction, default is None. - bypass_FN: An alternative function to use during outcome modifier construction, default is None. + sim_id2load: ID of simulation to be loaded. + bypass_DF: An alternative data frame to use during outcome modifier construction. + bypass_FN: An alternative function to use during outcome modifier construction. Returns: A pd.DataFrame containing reduced SEIR model parameters. diff --git a/flepimop/gempyor_pkg/src/gempyor/model_info.py b/flepimop/gempyor_pkg/src/gempyor/model_info.py index 022d5a5e9..656902207 100644 --- a/flepimop/gempyor_pkg/src/gempyor/model_info.py +++ b/flepimop/gempyor_pkg/src/gempyor/model_info.py @@ -1,6 +1,4 @@ """ -model_info.py - Defines the `ModelInfo` class (and associated methods), used for setting up and managing the configuration of a simulation. The primary focuses of a `ModelInfo` object are parsing and validating config details (including time frames, subpop info, @@ -46,10 +44,6 @@ class TimeSetup: and calculates the number of days in the simulation. It also establishes a pd.DatetimeIndex for the entire simulation period. - Args: - config: A config object. - - Attributes: ti (datetime.date): Start date of simulation. tf (datetime.date): End date of simulation. @@ -58,6 +52,12 @@ class TimeSetup: """ def __init__(self, config: confuse.ConfigView): + """ + Initializes a `TimeSetup` object. + + Args: + config: A configuration confuse.ConfigView object. + """ self.ti = config["start_date"].as_date() self.tf = config["end_date"].as_date() if self.tf <= self.ti: @@ -72,28 +72,15 @@ class ModelInfo: """ Parses config file, holds model information, and manages file input/output. - Non-optional Arg: - config: Config object. - Optional Args: - nslots: Number of slots for MCMC (default is 1). + Attributes: + nslots: Number of slots for MCMC. write_csv: Whether to write results to CSV files (default is False). - write_parquet: Whether to write results to parquet files (default is False). ** - first_sim_index : Index of first simulation (default is 1). - stoch_traj_flag: Whether to run the model stochastically (default is False). ** - seir_modifiers_scenario: SEIR modifier. + write_parquet: Whether to write results to parquet files (default is False) + first_sim_index: Index of first simulation (default is 1). + stoch_traj_flag: Whether to run the model stochastically (default is False). + seir_modifiers_scenario: seir_modifiers_scenario: SEIR modifier. outcome_modifiers_scenario: Outcomes modifier. setup_name: Name of setup (to override config, if applicable). - path_prefix: Prefix to paths where simulation data files are stored. - in_run_id: ID for input run (generated if not specified). - out_run_id: ID for outputr run (generated if not specified). - in_prefix: Path prefix for input directory. - out_prefix: Path prefix for output directory. - inference_filename_prefix: Path prefix for inference files directory. - inference_filepath_suffix: Path suffix for inference files directory. - config_filepath: Path to configuration file. - All optional args are inherited as attributes. - - Additional Attributes: time_setup: `TimeSetup` object (start/end dates of simulation, as pd.DatetimeIndex). ti: Initial time (time start). tf: Final time (fime finish). @@ -103,8 +90,11 @@ class ModelInfo: nsubpops: Number of subpopulations in simulation. subpop_pop: NumPy array containing population of each subpop. mobility: Matrix with values representing movement of people between subpops. + path_prefix: Prefix to paths where simulation data files are stored. seir_config: SEIR configuration info, if relevant for simulation. seir_modifiers_library: Modifiers for SEIR model, if relevant for simulation. + parameters_config: Parameter information from config. + initial_conditions_config: Initial conditions information from config. seeding_config: Seeding config, if relevant. parameters: `Parameter` object containing information about parameters. seeding: Seeding configuration information, if relevant. @@ -113,6 +103,16 @@ class ModelInfo: compartments: `Compartments` object contianing information about compartments. outcomes_config: Outcomes configurations, if relevant. npi_config_outcomes: Non-pharmaceutical intervention outcome configurations, if relevant. + outcome_modifiers_library: Outcome modifiers, pulled from config. + in_run_id: ID for input run (generated if not specified). + out_run_id: ID for outputr run (generated if not specified). + in_prefix: Path prefix for input directory. + out_prefix: Path prefix for output directory. + inference_filename_prefix: Path prefix for inference files directory. + inference_filepath_suffix: Path suffix for inference files directory. + timestamp: Current datetime. + extension: File extensions. + config_filepath: Path to configuration file. Raises: ValueError: @@ -158,6 +158,28 @@ def __init__( setup_name=None, # override config setup_name config_filepath="", ): + """ + Initializes a `ModelInfo` object. + + Args: + config: Config object. + nslots: Number of slots for MCMC (default is 1). + write_csv: Whether to write results to CSV files (default is False). + write_parquet: Whether to write results to parquet files (default is False). + first_sim_index : Index of first simulation (default is 1). + stoch_traj_flag: Whether to run the model stochastically (default is False). + seir_modifiers_scenario: SEIR modifier. + outcome_modifiers_scenario: Outcomes modifier. + setup_name: Name of setup (to override config, if applicable). + path_prefix: Prefix to paths where simulation data files are stored. + in_run_id: ID for input run (generated if not specified). + out_run_id: ID for outputr run (generated if not specified). + in_prefix: Path prefix for input directory. + out_prefix: Path prefix for output directory. + inference_filename_prefix: Path prefix for inference files directory. + inference_filepath_suffix: Path suffix for inference files directory. + config_filepath: Path to configuration file. + """ self.nslots = nslots self.write_csv = write_csv self.write_parquet = write_parquet diff --git a/flepimop/gempyor_pkg/src/gempyor/parameters.py b/flepimop/gempyor_pkg/src/gempyor/parameters.py index 958bae5f5..cfa81d030 100644 --- a/flepimop/gempyor_pkg/src/gempyor/parameters.py +++ b/flepimop/gempyor_pkg/src/gempyor/parameters.py @@ -1,12 +1,9 @@ """ -parameters.py - Provides abstractions for interacting with the parameters configurations. Classes: Parameters: - Encapsulates logic for loading, parsing, and - summarizing parameter configurations. + Encapsulates logic for loading, parsing, and summarizing parameter configurations. """ __all__ = ["Parameters"] @@ -32,14 +29,6 @@ class Parameters: """ Encapsulates logic for loading, parsing, and summarizing parameter configurations. - Parameters can be defined or drawn from distributions. - - Args: - parameter_config: Configuration information (in a confuse.ConfigView) for parameters. - ti: Initial time of simulation (time start). - tf: Final time of simulation (time finish). - subpop_names: Names of all subpopulations. - path_prefix: Pathway prefix to directory with Attributes: npar: The number of parameters contained within the given configuration. @@ -51,8 +40,6 @@ class Parameters: attribute. stacked_modifier_method: A mapping of modifier method to the parameters to which that modifier method is relevant for. - - Raises: """ def __init__( @@ -66,6 +53,7 @@ def __init__( ): """ Initialize a `Parameters` instance from a parameter config view. + Encapsulates logic for loading, parsing, and summarizing parameter configurations. Parameters can be defined or drawn from distributions. @@ -77,17 +65,6 @@ def __init__( subpop_names: A list of subpopulation names. path_prefix: A file path prefix to directory containing parameter values. - Attributes: - pconfig: confuse.ConfigView of parameter configuration information. - pnames: A list of parameter names. - npar: Number of parameters. - pdata: A dictionary containing a processed and reformatted view of the `pconfig` - attribute. - pnames2pindex: A map of parameter names to their location in the `pnames` - attribute. - stacked_modifier_method: A map of modifier methods to the parameters which - that modifier method is relevant for. - Raises: ValueError: The parameter names for the SEIR model are not unique. ValueError: The dataframe file found for a given parameter contains an From 5ad4b06b05548b4a72cc8e6bfd727c60d1f8f097 Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Thu, 30 Jan 2025 12:49:54 -0500 Subject: [PATCH 07/15] Updating weird formatting on a CLI command --- flepimop/gempyor_pkg/src/gempyor/calibrate.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/calibrate.py b/flepimop/gempyor_pkg/src/gempyor/calibrate.py index 7e571ce07..ce96e31fe 100644 --- a/flepimop/gempyor_pkg/src/gempyor/calibrate.py +++ b/flepimop/gempyor_pkg/src/gempyor/calibrate.py @@ -4,7 +4,6 @@ Functions: calibrate: Reads a configuration file for simulation settings. - """ #!/usr/bin/env python @@ -136,22 +135,6 @@ def calibrate( ) -> None: """ Calibrate using an `emcee` sampler to initialize a model based on a config. - - Args: - config_filepath: Path to the configuration file. - project_path: Path to the project directory. - nwalkers: Number of walkers (MCMC chains) to run. - niter: Number of MCMC iterations to perform. - nsamples: Number of samples to select from final MCMC chain. - nthin: How often to save samples. - ncpu: Number of CPU cores to use for parallelization. - input_run_id: Run ID. Will be auto-generated if not provdied. - prefix: A prefix for output files. - resume: Whether or not to resume a previous calibration run. - resume_location: Path to the location of the saved state to resume from. - - Returns: - None """ # Choose a run_id if input_run_id is None: From 2301fe18ee552c620341de34959ef6bcc9ca2990 Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Fri, 31 Jan 2025 11:30:49 -0500 Subject: [PATCH 08/15] Update calibrate.py --- flepimop/gempyor_pkg/src/gempyor/calibrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/calibrate.py b/flepimop/gempyor_pkg/src/gempyor/calibrate.py index ce96e31fe..1e826e3e4 100644 --- a/flepimop/gempyor_pkg/src/gempyor/calibrate.py +++ b/flepimop/gempyor_pkg/src/gempyor/calibrate.py @@ -121,7 +121,7 @@ # @profile_options # @profile() def calibrate( - config_filepath: str, + config_filepath: str | pathlib.Path, project_path: str, nwalkers: int, niter: int, From 2a2589009bb4925c79f5eb7054a79d39a93f5ab6 Mon Sep 17 00:00:00 2001 From: Emily Przykucki <100221052+emprzy@users.noreply.github.com> Date: Fri, 31 Jan 2025 12:25:49 -0500 Subject: [PATCH 09/15] Update flepimop/gempyor_pkg/src/gempyor/parameters.py Co-authored-by: Carl A. B. Pearson --- flepimop/gempyor_pkg/src/gempyor/parameters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/parameters.py b/flepimop/gempyor_pkg/src/gempyor/parameters.py index cfa81d030..bdd1897b6 100644 --- a/flepimop/gempyor_pkg/src/gempyor/parameters.py +++ b/flepimop/gempyor_pkg/src/gempyor/parameters.py @@ -58,7 +58,7 @@ def __init__( Parameters can be defined or drawn from distributions. Args: - parameter_config: A confuse.ConfigView subsetting the parameters section of a given + parameter_config: A view of the overall configuration object focused on the parameters section of a given config file. ti: An initial date for simulation. tf: A final date for simulation. From e3f553d308739c9090549dc6c8c33158d0037d05 Mon Sep 17 00:00:00 2001 From: Emily Przykucki <100221052+emprzy@users.noreply.github.com> Date: Fri, 31 Jan 2025 12:40:28 -0500 Subject: [PATCH 10/15] Update flepimop/gempyor_pkg/src/gempyor/compartments.py Co-authored-by: Timothy Willard <9395586+TimothyWillard@users.noreply.github.com> --- flepimop/gempyor_pkg/src/gempyor/compartments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/compartments.py b/flepimop/gempyor_pkg/src/gempyor/compartments.py index c9ba5ce41..d1a1fe3c7 100644 --- a/flepimop/gempyor_pkg/src/gempyor/compartments.py +++ b/flepimop/gempyor_pkg/src/gempyor/compartments.py @@ -73,7 +73,7 @@ def constructFromConfig(self, seir_config, compartment_config) -> None: """ This method is called by the constructor if the compartments are not loaded from a file. It will parse the compartments and transitions from the configuration files. - It will populate dynamic class attributes `self.compartments` and `self.transitions`. + It will populate dynamic class attributes `compartments` and `transitions`. """ self.compartments = self.parse_compartments(seir_config, compartment_config) self.transitions = self.parse_transitions(seir_config, False) From 9b7905910672c44e229db5d3b724dfdf2854b2e2 Mon Sep 17 00:00:00 2001 From: Emily Przykucki <100221052+emprzy@users.noreply.github.com> Date: Fri, 31 Jan 2025 12:40:55 -0500 Subject: [PATCH 11/15] Update flepimop/gempyor_pkg/src/gempyor/calibrate.py Co-authored-by: Timothy Willard <9395586+TimothyWillard@users.noreply.github.com> --- flepimop/gempyor_pkg/src/gempyor/calibrate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/calibrate.py b/flepimop/gempyor_pkg/src/gempyor/calibrate.py index 1e826e3e4..19e92cc87 100644 --- a/flepimop/gempyor_pkg/src/gempyor/calibrate.py +++ b/flepimop/gempyor_pkg/src/gempyor/calibrate.py @@ -1,6 +1,7 @@ """ Facilitates the calibration of the model using the `emcee` MCMC sampler. -Provides CLI options for users to specify simulation paramters. + +Provides CLI options for users to specify simulation parameters. Functions: calibrate: Reads a configuration file for simulation settings. From 89b685fbc5b3517375b0d25f7cbae8665e13ea7e Mon Sep 17 00:00:00 2001 From: Emily Przykucki <100221052+emprzy@users.noreply.github.com> Date: Fri, 31 Jan 2025 12:41:41 -0500 Subject: [PATCH 12/15] Update flepimop/gempyor_pkg/src/gempyor/compartments.py Co-authored-by: Timothy Willard <9395586+TimothyWillard@users.noreply.github.com> --- flepimop/gempyor_pkg/src/gempyor/compartments.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/compartments.py b/flepimop/gempyor_pkg/src/gempyor/compartments.py index d1a1fe3c7..2eff4d387 100644 --- a/flepimop/gempyor_pkg/src/gempyor/compartments.py +++ b/flepimop/gempyor_pkg/src/gempyor/compartments.py @@ -856,7 +856,9 @@ def parse_parameter_strings_to_numpy_arrays( def get_compartments_explicitDF(self) -> pd.DataFrame: """ - Returns a copy of the compartments information DataFrame; all columns receive a 'mc_' prefix. + Returns a copy of the compartments information DataFrame. + + All columns receive a 'mc_' prefix. Returns: A copy of the compartments DataFrame. From 10ea5878de1bc35afb80f763adc5f3626478e9f2 Mon Sep 17 00:00:00 2001 From: Emily Przykucki <100221052+emprzy@users.noreply.github.com> Date: Fri, 31 Jan 2025 12:45:03 -0500 Subject: [PATCH 13/15] Update flepimop/gempyor_pkg/src/gempyor/model_info.py Co-authored-by: Timothy Willard <9395586+TimothyWillard@users.noreply.github.com> --- flepimop/gempyor_pkg/src/gempyor/model_info.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flepimop/gempyor_pkg/src/gempyor/model_info.py b/flepimop/gempyor_pkg/src/gempyor/model_info.py index 656902207..98dd02529 100644 --- a/flepimop/gempyor_pkg/src/gempyor/model_info.py +++ b/flepimop/gempyor_pkg/src/gempyor/model_info.py @@ -1,4 +1,6 @@ """ +Abstractions for interacting with models as a monolithic object. + Defines the `ModelInfo` class (and associated methods), used for setting up and managing the configuration of a simulation. The primary focuses of a `ModelInfo` object are parsing and validating config details (including time frames, subpop info, From fd5ad0698b5776bce3130ffd779d4843c0f54b14 Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Fri, 31 Jan 2025 13:14:59 -0500 Subject: [PATCH 14/15] Making import statements PEP8 compliant --- flepimop/gempyor_pkg/src/gempyor/calibrate.py | 17 +++++++++++------ .../gempyor_pkg/src/gempyor/compartments.py | 4 ++-- flepimop/gempyor_pkg/src/gempyor/inference.py | 11 ++++++----- flepimop/gempyor_pkg/src/gempyor/parameters.py | 4 ++-- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/calibrate.py b/flepimop/gempyor_pkg/src/gempyor/calibrate.py index 19e92cc87..cfb250c96 100644 --- a/flepimop/gempyor_pkg/src/gempyor/calibrate.py +++ b/flepimop/gempyor_pkg/src/gempyor/calibrate.py @@ -8,18 +8,23 @@ """ #!/usr/bin/env python +import os +import shutil +import copy +import pathlib +import multiprocessing + import click +import emcee +import numpy as np + +import gempyor from gempyor import model_info, file_paths, config, inference_parameter from gempyor.inference import GempyorInference from gempyor.utils import config, as_list -import gempyor -import numpy as np -import os, shutil, copy -import emcee -import pathlib -import multiprocessing import gempyor.postprocess_inference + # from .profile import profile_options # disable operations using the MKL linear algebra. diff --git a/flepimop/gempyor_pkg/src/gempyor/compartments.py b/flepimop/gempyor_pkg/src/gempyor/compartments.py index 2eff4d387..38b535fc0 100644 --- a/flepimop/gempyor_pkg/src/gempyor/compartments.py +++ b/flepimop/gempyor_pkg/src/gempyor/compartments.py @@ -14,18 +14,18 @@ export: Export compartment data to a CSV file. """ +import logging from functools import reduce +from typing import Any import numpy as np import pandas as pd import pyarrow as pa import pyarrow.parquet as pq -import logging from click import pass_context, Context from .utils import config, Timer, as_list from .shared_cli import config_files_argument, config_file_options, parse_config_files, cli -from typing import Any logger = logging.getLogger(__name__) diff --git a/flepimop/gempyor_pkg/src/gempyor/inference.py b/flepimop/gempyor_pkg/src/gempyor/inference.py index 55c19712c..f5d978762 100644 --- a/flepimop/gempyor_pkg/src/gempyor/inference.py +++ b/flepimop/gempyor_pkg/src/gempyor/inference.py @@ -30,22 +30,23 @@ parameters based on this info. Returns the reduced parameters. """ -from concurrent.futures import ProcessPoolExecutor -import copy +import os import logging +import copy import multiprocessing as mp -import os +from concurrent.futures import ProcessPoolExecutor -import numba as nb import numpy as np import pandas as pd import pyarrow.parquet as pq import xarray as xr +import numba as nb + +from typing import Literal from . import seir, model_info from . import outcomes, file_paths from .utils import config, Timer, read_df, as_list -from typing import Literal logging.basicConfig(level=os.environ.get("FLEPI_LOGLEVEL", "INFO").upper()) diff --git a/flepimop/gempyor_pkg/src/gempyor/parameters.py b/flepimop/gempyor_pkg/src/gempyor/parameters.py index bdd1897b6..1eb8323a4 100644 --- a/flepimop/gempyor_pkg/src/gempyor/parameters.py +++ b/flepimop/gempyor_pkg/src/gempyor/parameters.py @@ -58,8 +58,8 @@ def __init__( Parameters can be defined or drawn from distributions. Args: - parameter_config: A view of the overall configuration object focused on the parameters section of a given - config file. + parameter_config: A view of the overall configuration object focused on the parameters + section of a given config file. ti: An initial date for simulation. tf: A final date for simulation. subpop_names: A list of subpopulation names. From 588e926f56f3cff899f35ec88eca8439ee8133ae Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Fri, 31 Jan 2025 14:41:03 -0500 Subject: [PATCH 15/15] Linting with `black` --- flepimop/gempyor_pkg/src/gempyor/parameters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flepimop/gempyor_pkg/src/gempyor/parameters.py b/flepimop/gempyor_pkg/src/gempyor/parameters.py index 1eb8323a4..24e1ff8de 100644 --- a/flepimop/gempyor_pkg/src/gempyor/parameters.py +++ b/flepimop/gempyor_pkg/src/gempyor/parameters.py @@ -58,7 +58,7 @@ def __init__( Parameters can be defined or drawn from distributions. Args: - parameter_config: A view of the overall configuration object focused on the parameters + parameter_config: A view of the overall configuration object focused on the parameters section of a given config file. ti: An initial date for simulation. tf: A final date for simulation.