From ce781dcee0cab3807b284e6879b7356d7cbb189f Mon Sep 17 00:00:00 2001 From: Steve Bachmeier <23350991+stevebachmeier@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:17:27 -0600 Subject: [PATCH] clean up docstrings throughout (#476) --- src/vivarium_public_health/disease/state.py | 43 ++++--- src/vivarium_public_health/mslt/delay.py | 18 ++- src/vivarium_public_health/mslt/disease.py | 49 +++++--- .../mslt/intervention.py | 21 ++-- src/vivarium_public_health/mslt/observer.py | 73 +++++++++--- src/vivarium_public_health/mslt/population.py | 17 ++- src/vivarium_public_health/plugins/parser.py | 109 +++++------------- .../population/add_new_birth_cohorts.py | 17 ++- .../population/base_population.py | 5 - .../population/data_transformations.py | 9 +- .../population/mortality.py | 6 +- src/vivarium_public_health/risks/base_risk.py | 30 +++-- .../risks/data_transformations.py | 4 +- .../risks/distributions.py | 1 - src/vivarium_public_health/risks/effect.py | 47 ++++---- .../low_birth_weight_and_short_gestation.py | 81 ++++++++----- .../treatment/scale_up.py | 16 +-- .../treatment/therapeutic_inertia.py | 4 +- 18 files changed, 291 insertions(+), 259 deletions(-) diff --git a/src/vivarium_public_health/disease/state.py b/src/vivarium_public_health/disease/state.py index be7cd63ab..0478349a4 100644 --- a/src/vivarium_public_health/disease/state.py +++ b/src/vivarium_public_health/disease/state.py @@ -103,9 +103,8 @@ def transition_side_effect(self, index: pd.Index, event_time: pd.Timestamp) -> N ---------- index An iterable of integer labels for the simulants. - event_time : pandas.Timestamp + event_time The time at which this transition occurs. - """ pop = self.population_view.get(index) pop[self.event_time_column] = event_time @@ -141,13 +140,13 @@ def add_rate_transition( The end state after the transition. get_data_functions - map from transition type to the function to pull that transition's data + Map from transition type to the function to pull that transition's data. triggered + The trigger for the transition Returns ------- - RateTransition The created transition object. """ transition = RateTransition(self, output, get_data_functions, triggered) @@ -157,7 +156,7 @@ def add_rate_transition( def add_proportion_transition( self, output: "BaseDiseaseState", - get_data_functions: Dict[str, Callable] = None, + get_data_functions: Optional[Dict[str, Callable]] = None, triggered=Trigger.NOT_TRIGGERED, ) -> ProportionTransition: """Builds a ProportionTransition from this state to the given state. @@ -166,13 +165,13 @@ def add_proportion_transition( ---------- output The end state after the transition. - get_data_functions - map from transition type to the function to pull that transition's data + Map from transition type to the function to pull that transition's data. + triggered + The trigger for the transition. Returns ------- - RateTransition The created transition object. """ if "proportion" not in get_data_functions: @@ -302,8 +301,8 @@ def __init__( allow_self_transition: bool = False, side_effect_function: Optional[Callable] = None, cause_type: str = "cause", - get_data_functions: Dict[str, Callable] = None, - cleanup_function: Callable = None, + get_data_functions: Optional[Dict[str, Callable]] = None, + cleanup_function: Optional[Callable] = None, ): """ Parameters @@ -312,14 +311,16 @@ def __init__( The name of this state. allow_self_transition Whether this state allows simulants to remain in the state for - multiple time-steps + multiple time-steps. side_effect_function A function to be called when this state is entered. cause_type The type of cause represented by this state. Either "cause" or "sequela". get_data_functions A dictionary containing a mapping to functions to retrieve data for - various state attributes + various state attributes. + cleanup_function + The cleanup function. """ super().__init__( state_id, @@ -344,7 +345,7 @@ def setup(self, builder: Builder) -> None: Parameters ---------- - builder : `engine.Builder` + builder Interface to several simulation tools. """ super().setup(builder) @@ -506,9 +507,9 @@ def next_state( ---------- index An iterable of integer labels for the simulants. - event_time: + event_time The time at which this transition occurs. - population_view: + population_view A view of the internal state of the simulation. """ eligible_index = self._filter_for_transition_eligibility(index, event_time) @@ -528,7 +529,6 @@ def compute_disability_weight(self, index: pd.Index) -> pd.Series: Returns ------- - `pandas.Series` An iterable of disability weights indexed by the provided `index`. """ disability_weight = pd.Series(0.0, index=index) @@ -555,8 +555,12 @@ def adjust_mortality_rate(self, index: pd.Index, rates_df: pd.DataFrame) -> pd.D ---------- index An iterable of integer labels for the simulants. - rates_df : `pandas.DataFrame` + rates_df + A DataFrame of mortality rates. + Returns + ------- + The modified DataFrame of mortality rates. """ rate = self.excess_mortality_rate(index, skip_post_processor=True) rates_df[self.state_id] = rate @@ -599,17 +603,18 @@ def _assign_event_time_for_prevalent_cases( infected_at = current_time - pd.to_timedelta(infected_at, unit="D") return infected_at - def _filter_for_transition_eligibility(self, index, event_time): + def _filter_for_transition_eligibility(self, index, event_time) -> pd.Index: """Filter out all simulants who haven't been in the state for the prescribed dwell time. Parameters ---------- index An iterable of integer labels for the simulants. + event_time + The time at which this transition occurs. Returns ------- - pd.Index A filtered index of the simulants. """ population = self.population_view.get(index, query='alive == "alive"') diff --git a/src/vivarium_public_health/mslt/delay.py b/src/vivarium_public_health/mslt/delay.py index baa0c14c4..3f4f5d558 100644 --- a/src/vivarium_public_health/mslt/delay.py +++ b/src/vivarium_public_health/mslt/delay.py @@ -19,8 +19,7 @@ class DelayedRisk(Component): - """ - A delayed risk represents an exposure whose impact takes time to come into + """A delayed risk represents an exposure whose impact takes time to come into effect (e.g., smoking uptake and cessation). The data required by this component are: @@ -320,8 +319,7 @@ def register_modifier(self, builder: Builder, disease: str) -> None: ######################## def on_initialize_simulants(self, pop_data: SimulantData) -> None: - """ - Define the initial distribution of the population across the bins, in + """Define the initial distribution of the population across the bins, in both the BAU and the intervention scenario. """ # Set all bins to zero, in order to create the required columns. @@ -364,7 +362,6 @@ def on_time_step_prepare(self, event: Event) -> None: - New exposures - Cessation of exposure - Increased duration of time since exposure - """ if self.clock().year == self.start_year: return @@ -540,6 +537,17 @@ def pivot_load(builder: Builder, entity_key: str) -> pd.DataFrame: Performs a long to wide conversion if dataframe has an index column named 'measure'. + Parameters + ---------- + builder + The builder object for the simulation. + entity_key + The key for the entity to be loaded. + + Returns + ------- + pd.DataFrame + The loaded data and potentially pivoted data. """ data = builder.data.load(entity_key) diff --git a/src/vivarium_public_health/mslt/disease.py b/src/vivarium_public_health/mslt/disease.py index 08db77ae3..15cff02d4 100644 --- a/src/vivarium_public_health/mslt/disease.py +++ b/src/vivarium_public_health/mslt/disease.py @@ -19,7 +19,8 @@ class AcuteDisease(Component): - """ + """This component characterises an acute disease. + An acute disease has a sufficiently short duration, relative to the time-step size, that it is not meaningful to talk about prevalence. Instead, it simply contributes an excess mortality rate, and/or a @@ -32,10 +33,18 @@ class AcuteDisease(Component): where `` is the name as provided to the constructor. - Parameters + Attributes ---------- disease The disease name (referred to as `` here). + excess_mortality + The excess mortality rate for the disease. + int_excess_mortality + The excess mortality rate for the disease in the intervention scenario. + disability_rate + The years lost due to disability (YLD) rate for the disease. + int_disability_rate + The YLD rate for the disease in the intervention scenario. """ @@ -77,16 +86,14 @@ def setup(self, builder: Builder) -> None: ################################## def mortality_adjustment(self, index, mortality_rate): - """ - Adjust the all-cause mortality rate in the intervention scenario, to + """Adjust the all-cause mortality rate in the intervention scenario, to account for any change in prevalence (relative to the BAU scenario). """ delta = self.int_excess_mortality(index) - self.excess_mortality(index) return mortality_rate + delta def disability_adjustment(self, index, yld_rate): - """ - Adjust the years lost due to disability (YLD) rate in the intervention + """Adjust the years lost due to disability (YLD) rate in the intervention scenario, to account for any change in prevalence (relative to the BAU scenario). """ @@ -106,10 +113,28 @@ class Disease(Component): where `` is the name as provided to the constructor. - Parameters + Attributes ---------- disease The disease name (referred to as `` here). + clock + The simulation clock. + start_year + The simulation start year. + simplified_equations + Whether to use simplified equations for the disease model. + incidence + The incidence rate for the disease. + incidence_intervention + The incidence rate for the disease in the intervention scenario. + remission + The remission rate for the disease. + excess_mortality + The excess mortality rate for the disease. + disability_rate + The years lost due to disability (YLD) rate for the disease. + initial_prevalence + The initial prevalence of the disease. """ @@ -231,9 +256,7 @@ def on_initialize_simulants(self, pop_data: SimulantData) -> None: self.population_view.update(pop) def on_time_step_prepare(self, event: Event) -> None: - """ - Update the disease status for both the BAU and intervention scenarios. - """ + """Update the disease status for both the BAU and intervention scenarios.""" # Do not update the disease status in the first year, the initial data # describe the disease state at the end of the year. if self.clock().year == self.start_year: @@ -356,8 +379,7 @@ def on_time_step_prepare(self, event: Event) -> None: ################################## def mortality_adjustment(self, index, mortality_rate): - """ - Adjust the all-cause mortality rate in the intervention scenario, to + """Adjust the all-cause mortality rate in the intervention scenario, to account for any change in disease prevalence (relative to the BAU scenario). """ @@ -387,8 +409,7 @@ def mortality_adjustment(self, index, mortality_rate): return mortality_rate + delta def disability_adjustment(self, index, yld_rate): - """ - Adjust the years lost due to disability (YLD) rate in the intervention + """Adjust the years lost due to disability (YLD) rate in the intervention scenario, to account for any change in disease prevalence (relative to the BAU scenario). """ diff --git a/src/vivarium_public_health/mslt/intervention.py b/src/vivarium_public_health/mslt/intervention.py index 20da83e81..e3aa05954 100644 --- a/src/vivarium_public_health/mslt/intervention.py +++ b/src/vivarium_public_health/mslt/intervention.py @@ -100,9 +100,9 @@ def adjust_rate(self, index, rates): class ModifyDiseaseIncidence(ModifyDiseaseRate): - """ - Interventions that modify a disease incidence rate, based on a PIF lookup + """Interventions that modify a disease incidence rate, based on a PIF lookup table. + """ def __init__(self, intervention: str, disease: str): @@ -110,9 +110,9 @@ def __init__(self, intervention: str, disease: str): class ModifyDiseaseMortality(ModifyDiseaseRate): - """ - Interventions that modify a disease fatality rate, based on a PIF lookup + """Interventions that modify a disease fatality rate, based on a PIF lookup table. + """ def __init__(self, intervention: str, disease: str): @@ -120,9 +120,9 @@ def __init__(self, intervention: str, disease: str): class ModifyDiseaseMorbidity(ModifyDiseaseRate): - """ - Interventions that modify a disease disability rate, based on a PIF lookup + """Interventions that modify a disease disability rate, based on a PIF lookup table. + """ def __init__(self, intervention: str, disease: str): @@ -130,10 +130,13 @@ def __init__(self, intervention: str, disease: str): class ModifyAcuteDiseaseIncidence(Component): - """ - Interventions that modify an acute disease incidence rate. - Note that this intervention will simply modify both the disability rate + """Interventions that modify an acute disease incidence rate. + + Notes + ----- + This intervention will simply modify both the disability rate and the mortality rate for the chosen acute disease. + """ ############## diff --git a/src/vivarium_public_health/mslt/observer.py b/src/vivarium_public_health/mslt/observer.py index 9614e14a1..b0b17b4c5 100644 --- a/src/vivarium_public_health/mslt/observer.py +++ b/src/vivarium_public_health/mslt/observer.py @@ -16,9 +16,8 @@ from vivarium.framework.event import Event -def output_file(config, suffix, sep="_", ext="csv"): - """ - Determine the output file name for an observer, based on the prefix +def output_file(config, suffix, sep="_", ext="csv") -> str: + """Determine the output file name for an observer, based on the prefix defined in ``config.observer.output_prefix`` and the (optional) ``config.input_data.input_draw_number``. @@ -33,6 +32,9 @@ def output_file(config, suffix, sep="_", ext="csv"): ext The output file extension. + Returns + ------- + The output file name for the observer. """ if "observer" not in config: raise ValueError("observer.output_prefix not defined") @@ -51,16 +53,22 @@ def output_file(config, suffix, sep="_", ext="csv"): class MorbidityMortality(Component): - """ - This class records the all-cause morbidity and mortality rates for each + """This class records the all-cause morbidity and mortality rates for each cohort at each year of the simulation. - Parameters + Attributes ---------- output_suffix The suffix for the CSV file in which to record the morbidity and mortality data. - + clock + The simulation clock. + tables + The tables of morbidity and mortality data. + table_cols + The columns in the tables. + output_file + The output file for the morbidity and mortality data. """ ############## @@ -148,7 +156,7 @@ def on_simulation_end(self, event: Event) -> None: # Helper methods # ################## - def calculate_LE(self, table, py_col, denom_col): + def calculate_LE(self, table, py_col, denom_col) -> pd.Series: """Calculate the life expectancy for each cohort at each time-step. Parameters @@ -162,9 +170,7 @@ def calculate_LE(self, table, py_col, denom_col): Returns ------- - The life expectancy for each table row, represented as a - pandas.Series object. - + The life expectancy for each table row. """ # Group the person-years by cohort. group_cols = ["year_of_birth", "sex"] @@ -180,17 +186,36 @@ def calculate_LE(self, table, py_col, denom_col): class Disease(Component): - """ - This class records the disease incidence rate and disease prevalence for + """This class records the disease incidence rate and disease prevalence for each cohort at each year of the simulation. - Parameters + Attributes ---------- disease The name of the chronic disease. output_suffix The suffix for the CSV file in which to record the disease data. + bau_S_col + The name of the BAU susceptible column. + bau_C_col + The name of the BAU chronic column. + int_S_col + The name of the intervention susceptible column. + int_C_col + The name of the intervention chronic column. + bau_incidence + The incidence rate for the BAU scenario. + int_incidence + The incidence rate for the intervention scenario. + tables + The tables of disease data. + table_cols + The columns in the tables. + clock + The simulation clock. + output_file + The output file for the disease data. """ @@ -286,12 +311,23 @@ def on_simulation_end(self, event: Event) -> None: class TobaccoPrevalence(Component): """This class records the prevalence of tobacco use in the population. - Parameters + Attributes ---------- output_suffix The suffix for the CSV file in which to record the prevalence data. - + config + The builder configuration object. + clock + The simulation clock. + bin_years + The number of years post-exposure to consider. + tables + The tables of tobacco prevalence data. + table_cols + The columns in the tables. + output_file + The output file for the tobacco prevalence data. """ ############## @@ -339,7 +375,7 @@ def setup(self, builder: Builder) -> None: # Setup methods # ################# - def get_bin_names(self): + def get_bin_names(self) -> list[str]: """Return the bin names for both the BAU and the intervention scenario. These names take the following forms: @@ -356,6 +392,9 @@ def get_bin_names(self): The intervention bin names take the form ``"name_intervention.X"``. + Returns + ------- + The bin names for tobacco use. """ if self.bin_years == 0: delay_bins = [str(0)] diff --git a/src/vivarium_public_health/mslt/population.py b/src/vivarium_public_health/mslt/population.py index e7619b3fe..e45a3ee36 100644 --- a/src/vivarium_public_health/mslt/population.py +++ b/src/vivarium_public_health/mslt/population.py @@ -19,8 +19,7 @@ class BasePopulation(Component): - """ - This component implements the core population demographics: age, sex, + """This component implements the core population demographics: age, sex, population size. The configuration options for this component are: @@ -113,9 +112,9 @@ def on_time_step_prepare(self, event: Event) -> None: class Mortality(Component): - """ - This component reduces the population size of each cohort over time, + """This component reduces the population size of each cohort over time, according to the all-cause mortality rate. + """ ############## @@ -156,8 +155,7 @@ def setup(self, builder: Builder) -> None: ######################## def on_time_step(self, event: Event) -> None: - """ - Calculate the number of deaths and survivors at each time-step, for + """Calculate the number of deaths and survivors at each time-step, for both the BAU and intervention scenarios. """ pop = self.population_view.get(event.index) @@ -181,10 +179,10 @@ def on_time_step(self, event: Event) -> None: class Disability(Component): - """ - This component calculates the health-adjusted life years (HALYs) for each + """This component calculates the health-adjusted life years (HALYs) for each cohort over time, according to the years lost due to disability (YLD) rate. + """ ############## @@ -219,8 +217,7 @@ def setup(self, builder: Builder) -> None: ######################## def on_time_step(self, event: Event) -> None: - """ - Calculate the HALYs for each cohort at each time-step, for both the + """Calculate the HALYs for each cohort at each time-step, for both the BAU and intervention scenarios. """ pop = self.population_view.get(event.index) diff --git a/src/vivarium_public_health/plugins/parser.py b/src/vivarium_public_health/plugins/parser.py index 57e4609c8..2c30ff1d1 100644 --- a/src/vivarium_public_health/plugins/parser.py +++ b/src/vivarium_public_health/plugins/parser.py @@ -7,6 +7,7 @@ :class:`ComponentConfigurationParser ` that can parse configurations of components specific to the Vivarium Public Health package. + """ from importlib import import_module @@ -34,34 +35,32 @@ class CausesParsingErrors(ParsingError): - """ - Error raised when there are any errors parsing a cause model configuration. - """ + """Error raised when there are any errors parsing a cause model configuration.""" def __init__(self, messages: List[str]): super().__init__("\n - " + "\n - ".join(messages)) class CausesConfigurationParser(ComponentConfigurationParser): - """ + """Parser for cause model configurations. + Component configuration parser that acts the same as the standard vivarium `ComponentConfigurationParser` but adds the additional ability to parse a configuration to create `DiseaseModel` components. These DiseaseModel configurations can either be specified directly in the configuration in a `causes` key or in external configuration files that are specified in the `external_configuration` key. + """ DEFAULT_MODEL_CONFIG = { "model_type": f"{DiseaseModel.__module__}.{DiseaseModel.__name__}", "initial_state": None, } - """ - If a cause model configuration does not specify a model type or initial - state, these default values will be used. The default model type is - `DiseaseModel` and the - default initial state is `None`. If the initial state is not specified, - the cause model must have a state named 'susceptible'. + """Default cause model configuration if it's not explicitly specified. + + If the initial state is not specified, the cause model must have a state + named 'susceptible'. """ DEFAULT_STATE_CONFIG = { @@ -72,23 +71,16 @@ class CausesConfigurationParser(ComponentConfigurationParser): "cleanup_function": None, "state_type": None, } - """ - If a state configuration does not specify cause_type, transient, - allow_self_transition, side_effect, cleanup_function, or state_type, - these default values will be used. The default cause type is 'cause', the - default transient value is False, and the default allow_self_transition - value is True. - """ + """Default state configuration if it's not explicitly specified.""" DEFAULT_TRANSITION_CONFIG = {"triggered": "NOT_TRIGGERED"} - """ - If a transition configuration does not specify a triggered value, this - default value will be used. The default triggered value is 'NOT_TRIGGERED'. + """Default triggered value. + + This value is used if the transition configuration does not explicity specify it. """ def parse_component_config(self, component_config: LayeredConfigTree) -> List[Component]: - """ - Parses the component configuration and returns a list of components. + """Parses the component configuration and returns a list of components. In particular, this method looks for an `external_configuration` key and/or a `causes` key. @@ -143,7 +135,6 @@ def parse_component_config(self, component_config: LayeredConfigTree) -> List[Co Returns ------- - List A list of initialized components. Raises @@ -188,18 +179,14 @@ def parse_component_config(self, component_config: LayeredConfigTree) -> List[Co ######################### def _add_default_config_layer(self, causes_config: LayeredConfigTree) -> None: - """ - Adds a default layer to the provided configuration that specifies - default values for the cause model configuration. + """Adds a default layer to the provided configuration. + + This default layer specifies values for the cause model configuration. Parameters ---------- causes_config A LayeredConfigTree defining the cause model configurations - - Returns - ------- - None """ default_config = {} for cause_name, cause_config in causes_config.items(): @@ -228,9 +215,7 @@ def _add_default_config_layer(self, causes_config: LayeredConfigTree) -> None: def _get_cause_model_components( self, causes_config: LayeredConfigTree ) -> List[Component]: - """ - Parses the cause model configuration and returns a list of - `DiseaseModel` components. + """Parses the cause model configuration and returns the `DiseaseModel` components. Parameters ---------- @@ -239,7 +224,6 @@ def _get_cause_model_components( Returns ------- - List[Component] A list of initialized `DiseaseModel` components """ cause_models = [] @@ -277,9 +261,7 @@ def _get_cause_model_components( def _get_state( self, state_name: str, state_config: LayeredConfigTree, cause_name: str ) -> BaseDiseaseState: - """ - Parses a state configuration and returns an initialized `BaseDiseaseState` - object. + """Parses a state configuration and returns an initialized `BaseDiseaseState` object. Parameters ---------- @@ -292,7 +274,6 @@ def _get_state( Returns ------- - BaseDiseaseState An initialized `BaseDiseaseState` object """ state_id = cause_name if state_name in ["susceptible", "recovered"] else state_name @@ -330,8 +311,7 @@ def _add_transition( sink_state: BaseDiseaseState, transition_config: LayeredConfigTree, ) -> None: - """ - Adds a transition between two states. + """Adds a transition between two states. Parameters ---------- @@ -341,10 +321,6 @@ def _add_transition( The state the transition ends at transition_config A `LayeredConfigTree` defining the transition to add - - Returns - ------- - None """ triggered = Trigger[transition_config.triggered] if "data_sources" in transition_config: @@ -372,9 +348,7 @@ def _add_transition( def _get_data_sources( self, config: LayeredConfigTree ) -> Dict[str, Callable[[Builder, Any], Any]]: - """ - Parses a data sources configuration and returns a dictionary of data - sources. + """Parses a data sources configuration and returns the data sources. Parameters ---------- @@ -383,7 +357,6 @@ def _get_data_sources( Returns ------- - Dict[str, Callable[[Builder, Any], Any]] A dictionary of data source getters """ return {name: self._get_data_source(name, config[name]) for name in config.keys()} @@ -392,9 +365,7 @@ def _get_data_sources( def _get_data_source( name: str, source: Union[str, float] ) -> Callable[[Builder, Any], Any]: - """ - Parses a data source and returns a callable that can be used to retrieve - the data. + """Parses a data source and returns a callable that can be used to retrieve the data. Parameters ---------- @@ -405,7 +376,6 @@ def _get_data_source( Returns ------- - Callable[[Builder, Any], Any] A callable that can be used to retrieve the data """ if isinstance(source, float): @@ -465,18 +435,13 @@ def _get_data_source( @staticmethod def _validate_external_configuration(external_configuration: LayeredConfigTree) -> None: - """ - Validates the external configuration. + """Validates the external configuration. Parameters ---------- external_configuration A LayeredConfigTree defining the external configuration - Returns - ------- - None - Raises ------ CausesParsingErrors @@ -504,18 +469,13 @@ def _validate_external_configuration(external_configuration: LayeredConfigTree) raise CausesParsingErrors(error_messages) def _validate_causes_config(self, causes_config: LayeredConfigTree) -> None: - """ - Validates the cause model configuration. + """Validates the cause model configuration. Parameters ---------- causes_config A LayeredConfigTree defining the cause model configurations - Returns - ------- - None - Raises ------ CausesParsingErrors @@ -530,8 +490,7 @@ def _validate_causes_config(self, causes_config: LayeredConfigTree) -> None: raise CausesParsingErrors(error_messages) def _validate_cause(self, cause_name: str, cause_config: Dict[str, Any]) -> List[str]: - """ - Validates a cause configuration and returns a list of error messages. + """Validates a cause configuration and returns a list of error messages. Parameters ---------- @@ -542,7 +501,6 @@ def _validate_cause(self, cause_name: str, cause_config: Dict[str, Any]) -> List Returns ------- - List[str] A list of error messages """ error_messages = [] @@ -607,8 +565,7 @@ def _validate_cause(self, cause_name: str, cause_config: Dict[str, Any]) -> List def _validate_state( self, cause_name: str, state_name: str, state_config: Dict[str, Any] ) -> List[str]: - """ - Validates a state configuration and returns a list of error messages. + """Validates a state configuration and returns a list of error messages. Parameters ---------- @@ -621,7 +578,6 @@ def _validate_state( Returns ------- - List[str] A list of error messages """ error_messages = [] @@ -702,8 +658,7 @@ def _validate_transition( transition_config: Dict[str, Any], states_config: Dict[str, Any], ) -> List[str]: - """ - Validates a transition configuration and returns a list of error messages. + """Validates a transition configuration and returns a list of error messages. Parameters ---------- @@ -718,7 +673,6 @@ def _validate_transition( Returns ------- - List[str] A list of error messages """ error_messages = [] @@ -803,8 +757,7 @@ def _validate_transition( def _validate_imported_type( import_path: str, cause_name: str, entity_type: str, entity_name: Optional[str] = None ) -> List[str]: - """ - Validates an imported type and returns a list of error messages. + """Validates an imported type and returns a list of error messages. Parameters ---------- @@ -820,7 +773,6 @@ def _validate_imported_type( Returns ------- - List[str] A list of error messages """ expected_type = {"model": DiseaseModel, "state": BaseDiseaseState}[entity_type] @@ -847,9 +799,7 @@ def _validate_imported_type( def _validate_data_sources( self, config: Dict[str, Any], cause_name: str, config_type: str, config_name: str ) -> List[str]: - """ - Validates the data sources in a configuration and returns a list of - error messages. + """Validates the data sources in a configuration and returns any error messages. Parameters ---------- @@ -864,7 +814,6 @@ def _validate_data_sources( Returns ------- - List[str] A list of error messages """ error_messages = [] diff --git a/src/vivarium_public_health/population/add_new_birth_cohorts.py b/src/vivarium_public_health/population/add_new_birth_cohorts.py index 42eb45d2d..e9ca043e1 100644 --- a/src/vivarium_public_health/population/add_new_birth_cohorts.py +++ b/src/vivarium_public_health/population/add_new_birth_cohorts.py @@ -81,8 +81,7 @@ class FertilityCrudeBirthRate(Component): new_births = sim_pop_size_t0 * live_births / true_pop_size * step_size - Where - + Where: sim_pop_size_t0 = the initial simulation population size live_births = annual number of live births in the true population true_pop_size = the true population size @@ -126,6 +125,7 @@ def setup(self, builder: Builder) -> None: def on_time_step(self, event: Event) -> None: """Adds new simulants every time step based on the Crude Birth Rate and an assumption that birth is a Poisson process + Parameters ---------- event @@ -151,9 +151,7 @@ def on_time_step(self, event: Event) -> None: class FertilityAgeSpecificRates(Component): - """ - A simulant-specific model for fertility and pregnancies. - """ + """A simulant-specific model for fertility and pregnancies.""" ############## # Properties # @@ -180,11 +178,11 @@ def initialization_requirements(self) -> Dict[str, List[str]]: ##################### def setup(self, builder: Builder) -> None: - """Setup the common randomness stream and - age-specific fertility lookup tables. + """Setup the common randomness stream and age-specific fertility lookup tables. + Parameters ---------- - builder : vivarium.engine.Builder + builder Framework coordination object. """ age_specific_fertility_rate = self.load_age_specific_fertility_rate_data(builder) @@ -238,9 +236,10 @@ def on_initialize_simulants(self, pop_data: SimulantData) -> None: def on_time_step(self, event: Event) -> None: """Produces new children and updates parent status on time steps. + Parameters ---------- - event : vivarium.population.PopulationEvent + event The event that triggered the function call. """ # Get a view on all living women who haven't had a child in at least nine months. diff --git a/src/vivarium_public_health/population/base_population.py b/src/vivarium_public_health/population/base_population.py index 988f9d6de..7f186798c 100644 --- a/src/vivarium_public_health/population/base_population.py +++ b/src/vivarium_public_health/population/base_population.py @@ -126,7 +126,6 @@ def on_initialize_simulants(self, pop_data: SimulantData) -> None: respectively. Here we are agnostic to the methods of entrance and exit (e.g., birth, migration, death, etc.) as these characteristics can be inferred from this column and other information about the simulant and the simulation parameters. - """ age_params = { @@ -282,7 +281,6 @@ def generate_population( Returns ------- - pandas.DataFrame Table with columns 'entrance_time' The `pandas.Timestamp` describing when the simulant entered @@ -299,7 +297,6 @@ def generate_population( The location indicating where the simulant resides. 'sex' Either 'Male' or 'Female'. The sex of the simulant. - """ simulants = pd.DataFrame( { @@ -361,7 +358,6 @@ def _assign_demography_with_initial_age( Returns ------- - pandas.DataFrame Table with same columns as `simulants` and with the additional columns 'age', 'sex', and 'location'. """ @@ -426,7 +422,6 @@ def _assign_demography_with_age_bounds( Returns ------- - pandas.DataFrame Table with same columns as `simulants` and with the additional columns 'age', 'sex', and 'location'. diff --git a/src/vivarium_public_health/population/data_transformations.py b/src/vivarium_public_health/population/data_transformations.py index d1806a3bd..768a7503a 100644 --- a/src/vivarium_public_health/population/data_transformations.py +++ b/src/vivarium_public_health/population/data_transformations.py @@ -33,7 +33,6 @@ def assign_demographic_proportions( Returns ------- - pandas.DataFrame Table with columns 'age' : Midpoint of the age group, 'age_start' : Lower bound of the age group, @@ -101,7 +100,6 @@ def rescale_binned_proportions( Returns ------- - pandas.DataFrame Table with the same columns as `pop_data` where all bins outside the range (age_start, age_end) have been discarded. If age_start and age_end don't fall cleanly on age boundaries, the bins in which they lie are clipped and @@ -174,7 +172,6 @@ def rescale_binned_proportions( def _add_edge_age_groups(pop_data: pd.DataFrame) -> pd.DataFrame: """Pads the population data with age groups that enforce constant left interpolation and interpolation to zero on the right. - """ index_cols = ["location", "year_start", "year_end", "sex"] age_cols = ["age", "age_start", "age_end"] @@ -250,7 +247,6 @@ def smooth_ages( Returns ------- - pandas.DataFrame Table with same columns as `simulants` with ages smoothed out within the age bins. """ simulants = simulants.copy() @@ -324,7 +320,7 @@ def _get_bins_and_proportions( Returns ------- - Tuple[EndpointValues, AgeValues] + A tuple of endpoints tuples and ages tuples. The `EndpointValues` tuple has values ( age at left edge of bin, age at right edge of bin, @@ -334,7 +330,6 @@ def _get_bins_and_proportions( proportion of pop in previous bin, proportion of pop in next bin, ) - """ left = float(pop_data.loc[pop_data["age"] == age.current, "age_start"].iloc[0]) right = float(pop_data.loc[pop_data["age"] == age.current, "age_end"].iloc[0]) @@ -405,7 +400,6 @@ def _construct_sampling_parameters( Returns ------- - Tuple[EndpointValues, EndpointValues, float, float] A tuple of (pdf, slope, area, cdf_inflection_point) where pdf is a tuple with values ( pdf evaluated at left bin edge, @@ -474,7 +468,6 @@ def _compute_ages( Returns ------- - Union[np.ndarray, float] Smoothed ages from one half of the age bin distribution. """ if abs(slope) < np.finfo(np.float32).eps: diff --git a/src/vivarium_public_health/population/mortality.py b/src/vivarium_public_health/population/mortality.py index fba7d24cc..76ee027e0 100644 --- a/src/vivarium_public_health/population/mortality.py +++ b/src/vivarium_public_health/population/mortality.py @@ -59,9 +59,9 @@ class Mortality(Component): - """ - This is the mortality component which models sources of mortality for a model. - THe component models all cause mortality and allows for disease models to contribute + """This is the mortality component which models of mortality in a population. + + The component models all cause mortality and allows for disease models to contribute cause specific mortality. Data used by this class should be supplied in the artifact and is configurable in the configuration to build lookup tables. For instance, let's say we want to use sex and hair color to build a lookup table for all cause mortality. diff --git a/src/vivarium_public_health/risks/base_risk.py b/src/vivarium_public_health/risks/base_risk.py index 5d442f22a..552bcd166 100644 --- a/src/vivarium_public_health/risks/base_risk.py +++ b/src/vivarium_public_health/risks/base_risk.py @@ -30,8 +30,9 @@ class Risk(Component): - """A model for a risk factor defined by either a continuous or a categorical - value. For example, + """A model for a risk factor defined by either a continuous or a categorical value. + + For example, #. high systolic blood pressure as a risk where the SBP is not dichotomized into hypotension and normal but is treated as the actual SBP @@ -138,9 +139,10 @@ def initialization_requirements(self) -> Dict[str, List[str]]: def __init__(self, risk: str): """ + Parameters ---------- - risk : + risk the type and name of a risk, specified as "type.name". Type is singular. """ super().__init__() @@ -171,8 +173,7 @@ def setup(self, builder: Builder) -> None: self.exposure = self.get_exposure_pipeline(builder) def get_distribution_type(self, builder: Builder) -> str: - """ - Get the distribution type for the risk from the configuration. + """Get the distribution type for the risk from the configuration. If the configured distribution type is not one of the supported types, it is assumed to be a data source and the data is retrieved using the @@ -180,13 +181,12 @@ def get_distribution_type(self, builder: Builder) -> str: Parameters ---------- - builder : Builder - the builder object + builder + The builder object. Returns ------- - str - the distribution type + The distribution type. """ if self.configuration is None: self.configuration = self.get_configuration(builder) @@ -207,24 +207,22 @@ def get_distribution_type(self, builder: Builder) -> str: return distribution_type def get_exposure_distribution(self, builder: Builder) -> RiskExposureDistribution: - """ - Creates and sets up the exposure distribution component for the Risk + """Creates and sets up the exposure distribution component for the Risk based on its distribution type. Parameters ---------- - builder : Builder - the builder object + builder + The builder object. Returns ------- - RiskExposureDistribution - the exposure distribution + The exposure distribution. Raises ------ NotImplementedError - if the distribution type is not supported + If the distribution type is not supported. """ try: exposure_distribution = self.exposure_distributions[self.distribution_type]( diff --git a/src/vivarium_public_health/risks/data_transformations.py b/src/vivarium_public_health/risks/data_transformations.py index 31e4203f0..2bd7c4598 100644 --- a/src/vivarium_public_health/risks/data_transformations.py +++ b/src/vivarium_public_health/risks/data_transformations.py @@ -78,7 +78,9 @@ def load_exposure_data(builder: Builder, risk: EntityString) -> pd.DataFrame: def rebin_relative_risk_data( builder, risk: EntityString, relative_risk_data: pd.DataFrame ) -> pd.DataFrame: - """When the polytomous risk is rebinned, matching relative risk needs to be rebinned. + """Rebin relative risk data if necessary. + + When the polytomous risk is rebinned, matching relative risk needs to be rebinned. After rebinning, rr for both exposed and unexposed categories should be the weighted sum of relative risk of the component categories where weights are relative proportions of exposure of those categories. For example, if cat1, cat2, cat3 are exposed categories and cat4 is unexposed with exposure [0.1,0.2,0.3,0.4], diff --git a/src/vivarium_public_health/risks/distributions.py b/src/vivarium_public_health/risks/distributions.py index 3820787be..3c83c0699 100644 --- a/src/vivarium_public_health/risks/distributions.py +++ b/src/vivarium_public_health/risks/distributions.py @@ -461,7 +461,6 @@ def clip(q): This is bound up in the GBD risk factor PAF calculation process. We'll clip the distribution tails so we don't get NaNs back from the distribution calls - """ Q_LOWER_BOUND = 0.0011 Q_UPPER_BOUND = 0.998 diff --git a/src/vivarium_public_health/risks/effect.py b/src/vivarium_public_health/risks/effect.py index 9a0048add..f0965db67 100644 --- a/src/vivarium_public_health/risks/effect.py +++ b/src/vivarium_public_health/risks/effect.py @@ -31,9 +31,12 @@ class RiskEffect(Component): """A component to model the impact of a risk factor on the target rate of - some affected entity. This component can source data either from - builder.data or from parameters supplied in the configuration. - For a risk named 'risk' that affects 'affected_risk' and 'affected_cause', + some affected entity. + + This component can source data either from builder.data or from parameters + supplied in the configuration. + + For a risk named 'risk' that affects 'affected_risk' and 'affected_cause', the configuration would look like: .. code-block:: yaml @@ -59,8 +62,7 @@ def get_name(risk: EntityString, target: TargetString) -> str: @property def configuration_defaults(self) -> Dict[str, Any]: - """ - A dictionary containing the defaults for any configurations managed by + """A dictionary containing the defaults for any configurations managed by this component. """ return { @@ -89,13 +91,14 @@ def is_exposure_categorical(self) -> bool: def __init__(self, risk: str, target: str): """ + Parameters ---------- - risk : + risk Type and name of risk factor, supplied in the form "risk_type.risk_name" where risk_type should be singular (e.g., risk_factor instead of risk_factors). - target : + target Type, name, and target rate of entity to be affected by risk factor, supplied in the form "entity_type.entity_name.measure" where entity_type should be singular (e.g., cause instead of causes). @@ -210,7 +213,9 @@ def process_categorical_data( def rebin_relative_risk_data( self, builder, relative_risk_data: pd.DataFrame ) -> pd.DataFrame: - """When the polytomous risk is rebinned, matching relative risk needs to be rebinned. + """Rebin relative risk data. + + When the polytomous risk is rebinned, matching relative risk needs to be rebinned. After rebinning, rr for both exposed and unexposed categories should be the weighted sum of relative risk of the component categories where weights are relative proportions of exposure of those categories. For example, if cat1, cat2, cat3 are exposed categories and cat4 is unexposed with exposure [0.1,0.2,0.3,0.4], @@ -320,17 +325,18 @@ def _get_risk_exposure_class(self, builder: Builder) -> Risk: class NonLogLinearRiskEffect(RiskEffect): """A component to model the impact of an exposure-parametrized risk factor on - the target rate of some affected entity. This component will - - 1) read TMRED data from the artifact and define the TMREL - 2) calculate the relative risk at TMREL by linearly interpolating over - relative risk data defined in the configuration - 3) divide relative risk data from configuration by RR at TMREL - and clip to be greater than 1 - 4) build a LookupTable which returns the exposure and RR of the left and right edges - of the RR bin containing a simulant's exposure - 5) use this LookupTable to modify the target pipeline by linearly interpolating - a simulant's RR value and multiplying it by the intended target rate + the target rate of some affected entity. + + This component: + 1) reads TMRED data from the artifact and define the TMREL + 2) calculates the relative risk at TMREL by linearly interpolating over + relative risk data defined in the configuration + 3) divides relative risk data from configuration by RR at TMREL + and clip to be greater than 1 + 4) builds a LookupTable which returns the exposure and RR of the left and right edges + of the RR bin containing a simulant's exposure + 5) uses this LookupTable to modify the target pipeline by linearly interpolating + a simulant's RR value and multiplying it by the intended target rate """ ############## @@ -339,8 +345,7 @@ class NonLogLinearRiskEffect(RiskEffect): @property def configuration_defaults(self) -> Dict[str, Any]: - """ - A dictionary containing the defaults for any configurations managed by + """A dictionary containing the defaults for any configurations managed by this component. """ return { diff --git a/src/vivarium_public_health/risks/implementations/low_birth_weight_and_short_gestation.py b/src/vivarium_public_health/risks/implementations/low_birth_weight_and_short_gestation.py index 294f9e025..5c6e1cf87 100644 --- a/src/vivarium_public_health/risks/implementations/low_birth_weight_and_short_gestation.py +++ b/src/vivarium_public_health/risks/implementations/low_birth_weight_and_short_gestation.py @@ -5,6 +5,7 @@ Low birth weight and short gestation (LBWSG) is a non-standard risk implementation that has been used in several public health models. + """ import pickle @@ -39,12 +40,16 @@ def setup(self, builder: Builder) -> None: self.category_intervals = self.get_category_intervals(builder) def get_category_intervals(self, builder: Builder) -> Dict[str, Dict[str, pd.Interval]]: - """ - Gets the intervals for each category. It is a dictionary from the string - "birth_weight" or "gestational_age" to a dictionary from the category - name to the interval - :param builder: - :return: + """Gets the intervals for each category. + + Parameters + ---------- + builder + The builder object. + + Returns + ------- + The intervals for each category. """ categories: Dict[str, str] = builder.data.load(f"{self.risk}.categories") category_intervals = { @@ -61,16 +66,19 @@ def get_category_intervals(self, builder: Builder) -> Dict[str, Dict[str, pd.Int ################## def ppf(self, propensities: pd.DataFrame) -> pd.DataFrame: - """ - Takes a DataFrame with three columns: 'categorical.propensity', - 'birth_weight.propensity', and 'gestational_age.propensity' which - contain each of those propensities for each simulant. - - Returns a DataFrame with two columns for birth-weight and gestational - age exposures. - - :param propensities: - :return: + """Calculate continuous exposures from propensities. + + Parameters + ---------- + propensities + Propensities DataFrame for each simulant with three columns: + 'categorical.propensity', 'birth_weight.propensity', and + 'gestational_age.propensity'. + + Returns + ------- + A DataFrame with two columns for birth-weight and gestational age + exposures. """ categorical_exposure = super().ppf(propensities[f"{CATEGORICAL}_propensity"]) @@ -88,10 +96,11 @@ def single_axis_ppf( self, axis: str, propensity: pd.Series, - categorical_propensity: pd.Series = None, - categorical_exposure: pd.Series = None, + categorical_propensity: Optional[pd.Series] = None, + categorical_exposure: Optional[pd.Series] = None, ) -> pd.Series: - """ + """Calculate continuous exposures from propensities for a single axis. + Takes an axis (either 'birth_weight' or 'gestational_age'), a propensity and either a categorical propensity or a categorical exposure and returns continuous exposures for that axis. @@ -101,11 +110,27 @@ def single_axis_ppf( categorical exposure parameters pipeline ("risk_factor.low_birth_weight_and_short_gestation.exposure_parameters"). - :param axis: - :param propensity: - :param categorical_propensity: - :param categorical_exposure: - :return: + Parameters + ---------- + axis + The axis for which to calculate continuous exposures ('birth_weight' + or 'gestational_age'). + propensity + The propensity for the axis. + categorical_propensity + The categorical propensity for the axis. + categorical_exposure + The categorical exposure for the axis. + + Returns + ------- + The continuous exposures for the axis. + + Raises + ------ + ValueError + If neither categorical propensity nor categorical exposure is provided + or both are provided. """ if (categorical_propensity is None) == (categorical_exposure is None): @@ -133,19 +158,15 @@ def single_axis_ppf( @staticmethod def _parse_description(axis: str, description: str) -> pd.Interval: - """ - Parses a string corresponding to a low birth weight and short gestation + """Parses a string corresponding to a low birth weight and short gestation category to an Interval. + An example of a standard description: 'Neonatal preterm and LBWSG (estimation years) - [0, 24) wks, [0, 500) g' An example of an edge case for gestational age: 'Neonatal preterm and LBWSG (estimation years) - [40, 42+] wks, [2000, 2500) g' An example of an edge case of birth weight: 'Neonatal preterm and LBWSG (estimation years) - [36, 37) wks, [4000, 9999] g' - - :param axis: - :param description: - :return: """ endpoints = { BIRTH_WEIGHT: [ diff --git a/src/vivarium_public_health/treatment/scale_up.py b/src/vivarium_public_health/treatment/scale_up.py index c0fa855be..9e60e4d6f 100644 --- a/src/vivarium_public_health/treatment/scale_up.py +++ b/src/vivarium_public_health/treatment/scale_up.py @@ -20,8 +20,7 @@ class LinearScaleUp(Component): - """ - A model for applying a linear scale-up to an intervention. + """A model for applying a linear scale-up to an intervention. This component requires input data for beginning and end dates, as well as beginning and end values. Scale-up start and end dates are by default the @@ -75,10 +74,11 @@ def configuration_key(self) -> str: def __init__(self, treatment: str): """ + Parameters ---------- - treatment : - the type and name of a treatment, specified as "type.name". Type is singular. + treatment + The type and name of a treatment, specified as "type.name". Type is singular. """ super().__init__() self.treatment = EntityString(treatment) @@ -113,8 +113,7 @@ def get_scale_up_dates(self, builder: Builder) -> Tuple[pd.Timestamp, pd.Timesta return pd.Timestamp(scale_up_config["start"]), pd.Timestamp(scale_up_config["end"]) def get_scale_up_values(self, builder: Builder) -> Tuple[LookupTable, LookupTable]: - """ - Get the values at the start and end of the scale-up period. + """Get the values at the start and end of the scale-up period. Parameters ---------- @@ -123,7 +122,6 @@ def get_scale_up_values(self, builder: Builder) -> Tuple[LookupTable, LookupTabl Returns ------- - LookupTable A tuple of lookup tables returning the values at the start and end of the scale-up period. """ @@ -172,8 +170,7 @@ def coverage_effect(self, idx: pd.Index, target: pd.Series) -> pd.Series: def get_endpoint_value_from_data( self, builder: Builder, endpoint_type: str ) -> LookupTable: - """ - Get the value at the start or end of the scale-up period from data. + """Get the value at the start or end of the scale-up period from data. Parameters ---------- @@ -185,7 +182,6 @@ def get_endpoint_value_from_data( Returns ------- - LookupTable A lookup table returning the value at the start or end of the scale-up period. """ diff --git a/src/vivarium_public_health/treatment/therapeutic_inertia.py b/src/vivarium_public_health/treatment/therapeutic_inertia.py index 66cd93138..88090cb32 100644 --- a/src/vivarium_public_health/treatment/therapeutic_inertia.py +++ b/src/vivarium_public_health/treatment/therapeutic_inertia.py @@ -17,7 +17,9 @@ class TherapeuticInertia(Component): """Expose a therapeutic inertia pipeline that defines a population-level therapeutic inertia. - This is the probability of treatment during a healthcare visit.""" + + This is the probability of treatment during a healthcare visit. + """ CONFIGURATION_DEFAULTS = { "therapeutic_inertia": {