diff --git a/flepimop/gempyor_pkg/src/gempyor/calibrate.py b/flepimop/gempyor_pkg/src/gempyor/calibrate.py index 8d673d8d0..cfb250c96 100644 --- a/flepimop/gempyor_pkg/src/gempyor/calibrate.py +++ b/flepimop/gempyor_pkg/src/gempyor/calibrate.py @@ -1,16 +1,30 @@ +""" +Facilitates the calibration of the model using the `emcee` MCMC sampler. + +Provides CLI options for users to specify simulation parameters. + +Functions: + calibrate: Reads a configuration file for simulation settings. +""" + #!/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. @@ -113,18 +127,21 @@ # @profile_options # @profile() def calibrate( - config_filepath, - project_path, - nwalkers, - niter, - nsamples, - nthin, - ncpu, - input_run_id, - prefix, - resume, - resume_location, -): + config_filepath: str | pathlib.Path, + project_path: str, + nwalkers: int, + niter: int, + nsamples: int, + nthin: int | None, + ncpu: int, + input_run_id: int | None, + prefix: str | None, + resume: bool, + resume_location: str | None, +) -> None: + """ + Calibrate using an `emcee` sampler to initialize a model based on a config. + """ # 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..cb1c1fc88 100644 --- a/flepimop/gempyor_pkg/src/gempyor/cli.py +++ b/flepimop/gempyor_pkg/src/gempyor/cli.py @@ -27,7 +27,8 @@ ) @click.pass_context def patch(ctx: click.Context = mock_context, **kwargs) -> None: - """Merge configuration files + """ + 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 diff --git a/flepimop/gempyor_pkg/src/gempyor/compartments.py b/flepimop/gempyor_pkg/src/gempyor/compartments.py index f9c49c5f3..38b535fc0 100644 --- a/flepimop/gempyor_pkg/src/gempyor/compartments.py +++ b/flepimop/gempyor_pkg/src/gempyor/compartments.py @@ -1,10 +1,27 @@ +""" +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. +""" + +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 @@ -14,6 +31,13 @@ class Compartments: + """ + An object to handle compartment data for the model. + + Attributes: + times_set: Counter to track succesful data intialization from config. + """ + # Minimal object to be easily picklable for // runs def __init__( self, @@ -22,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: @@ -36,11 +69,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 `compartments` and `transitions`. """ self.compartments = self.parse_compartments(seir_config, compartment_config) self.transitions = self.parse_transitions(seir_config, False) @@ -50,31 +83,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 +108,20 @@ 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: + 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 +506,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, - but it ignore columns that don't exist: - :param comp_dict: - :return: + 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: + 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 +538,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[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. + 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 +713,22 @@ def get_transition_array(self): proportion_info, ) - def parse_parameters(self, parameters, parameter_names, unique_strings): + def parse_parameters( + self, parameters: np.ndarray, 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 +805,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 +854,15 @@ 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 +874,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 +922,41 @@ 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: + 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 +) -> 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: 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. + + 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 +969,25 @@ 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 +) -> Any | list[Any]: """ - 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: + 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 + 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 +1004,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 +1023,18 @@ 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. + """ 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 +1056,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() diff --git a/flepimop/gempyor_pkg/src/gempyor/inference.py b/flepimop/gempyor_pkg/src/gempyor/inference.py index 42cc98975..f5d978762 100644 --- a/flepimop/gempyor_pkg/src/gempyor/inference.py +++ b/flepimop/gempyor_pkg/src/gempyor/inference.py @@ -8,18 +8,41 @@ # This populate the namespace with four functions, with return value 0 if the # function terminated successfully +""" +Classes: + 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 +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 @@ -316,22 +339,58 @@ def autodetect_scenarios(config): class GempyorInference: + """ + 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: + 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, + prefix: str | None = None, + first_sim_index: int = 1, + stoch_traj_flag: bool = 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 + 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="", # in case the data folder is on another directory - autowrite_seir=False, + 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. + + Args: + config_filepath: Path to the config file. + 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, default is False. + """ # Config prep config.clear() config.read(user=False) @@ -562,7 +621,22 @@ 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. + + 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. + 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 @@ -748,6 +822,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. + 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: + An object that contains computed NPI outcome modifiers. + """ npi_outcomes = None if self.modinf.npi_config_outcomes: npi_outcomes = outcomes.build_outcome_modifiers( @@ -761,6 +847,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. + 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. + """ npi_seir = seir.build_npi_SEIR( modinf=self.modinf, load_ID=load_ID, @@ -774,6 +872,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. + 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. + """ param_df = None if bypass_DF is not None: param_df = bypass_DF @@ -797,6 +907,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. + 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. + """ p_draw = self.get_seir_parameters( load_ID=load_ID, sim_id2load=sim_id2load, @@ -814,6 +936,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. + load_ID: Whether to load a previous simulation's data, default is False. + 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. + """ 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 2cf4cf1c5..98dd02529 100644 --- a/flepimop/gempyor_pkg/src/gempyor/model_info.py +++ b/flepimop/gempyor_pkg/src/gempyor/model_info.py @@ -1,3 +1,18 @@ +""" +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, +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: Handles simulation time frame. + ModelInfo: Parses config file, holds model information, and manages file input/output. +""" + import datetime import logging import os @@ -24,7 +39,27 @@ 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. + + 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): + """ + 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: @@ -36,9 +71,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. + Parses config file, holds model information, and manages file input/output. + + 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_modifiers_scenario: SEIR modifier. + outcome_modifiers_scenario: Outcomes modifier. + setup_name: Name of setup (to override config, if applicable). + 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. + 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. + 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. + 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: + 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 @@ -74,6 +160,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 ce312c9a3..24e1ff8de 100644 --- a/flepimop/gempyor_pkg/src/gempyor/parameters.py +++ b/flepimop/gempyor_pkg/src/gempyor/parameters.py @@ -1,8 +1,9 @@ """ -Abstractions for interacting with the parameters configurations. +Provides abstractions for interacting with the parameters configurations. -This module contains abstractions for interacting with the parameters section of given -config files. Namely it contains the `Parameters` class. +Classes: + Parameters: + Encapsulates logic for loading, parsing, and summarizing parameter configurations. """ __all__ = ["Parameters"] @@ -53,14 +54,16 @@ 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 - config file. - ti: An initial date. - tf: A final date. + 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. - 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. Raises: ValueError: The parameter names for the SEIR model are not unique.