diff --git a/README.rst b/README.rst index 8af511b..4580e5c 100644 --- a/README.rst +++ b/README.rst @@ -21,27 +21,7 @@ your operating system at the following places: Once you have all three installed, you should open up your normal shell (if you're on linux or OSX) or the ``git bash`` shell if you're on windows. You'll then make an environment, clone this repository, then install -all necessary requirements as follows:: - - :~$ conda create --name=vivarium_sodium_reduction python=3.11 - ...conda will download python and base dependencies... - :~$ conda activate vivarium_sodium_reduction - (vivarium_sodium_reduction) :~$ git clone https://github.com/ihmeuw/vivarium_sodium_reduction.git - ...git will copy the repository from github and place it in your current directory... - (vivarium_sodium_reduction) :~$ cd vivarium_sodium_reduction - (vivarium_sodium_reduction) :~$ pip install -e . - ...pip will install vivarium and other requirements... - -Supported Python versions: 3.9, 3.10, 3.11 - -Note the ``-e`` flag that follows pip install. This will install the python -package in-place, which is important for making the model specifications later. - -To install requirements from a provided requirements.txt (e.g. installing an -archived repository with the exact same requirements it was run with), replace -`pip install -e .` with the following:: - - (vivarium_sodium_reduction) :~$ pip install -r requirements.txt +all necessary requirements with `source evironment.sh`. Cloning the repository should take a fair bit of time as git must fetch the data artifact associated with the demo (several GB of data) from the @@ -50,16 +30,7 @@ you are likely only retrieving the checksum file that github holds onto, and your simulations will fail.** If you are only retrieving checksum files you can explicitly pull the data by executing ``git-lfs pull``. -Vivarium uses the Hierarchical Data Format (HDF) as the backing storage -for the data artifacts that supply data to the simulation. You may not have -the needed libraries on your system to interact with these files, and this is -not something that can be specified and installed with the rest of the package's -dependencies via ``pip``. If you encounter HDF5-related errors, you should -install hdf tooling from within your environment like so:: - - (vivarium_sodium_reduction) :~$ conda install hdf5 - -The ``(vivarium_sodium_reduction)`` that precedes your shell prompt will probably show +The ``(vivarium_sodium_reduction_simulation)`` that precedes your shell prompt will probably show up by default, though it may not. It's just a visual reminder that you are installing and running things in an isolated programming environment so it doesn't conflict with other source code and libraries on your @@ -123,12 +94,7 @@ step. For more ways to run simulations, see the tutorials at https://vivarium.readthedocs.io/en/latest/tutorials/running_a_simulation/index.html and https://vivarium.readthedocs.io/en/latest/tutorials/exploration.html -To run multiple simulations in parallel, you can use the `psimulate` command, which you can install with:: - - (vivarium_sodium_reduction) :~$ pip install vivarium_cluster_tools - (vivarium_sodium_reduction) :~$ conda install redis - -Then you can run simulations in parallel on IHME's cluster:: +To run multiple simulations in parallel, you can use the `psimulate` command:: - (vivarium_sodium_reduction) :~$ - psimulate run -o /mnt/share/homes/abie/vivarium_results/sodium_usa/ -P proj_simscience src/vivarium_sodium_reduction/model_specifications/model_spec.yaml src/vivarium_sodium_reduction/model_specifications/branches/scenarios.yaml + psimulate run -vvv -m 10 -P proj_simscience src/vivarium_sodium_reduction/model_specifications/model_spec.yaml sr +c/vivarium_sodium_reduction/model_specifications/branches/scenarios.yaml diff --git a/src/vivarium_sodium_reduction/components/interventions.py b/src/vivarium_sodium_reduction/components/interventions.py index fb252cb..706f4e5 100644 --- a/src/vivarium_sodium_reduction/components/interventions.py +++ b/src/vivarium_sodium_reduction/components/interventions.py @@ -37,7 +37,7 @@ def setup(self, builder: Builder) -> None: self.population_view = builder.population.get_view(["age"]) builder.value.register_value_modifier( - self.target, modifier=self.adjust_exposure, requires_columns=["age"] + f'{self.target}.exposure', modifier=self.adjust_exposure, requires_columns=["age"] ) def adjust_exposure(self, index: pd.Index, exposure: pd.Series) -> pd.Series: diff --git a/src/vivarium_sodium_reduction/components/risks.py b/src/vivarium_sodium_reduction/components/risks.py index a65c0f0..9a32cfc 100644 --- a/src/vivarium_sodium_reduction/components/risks.py +++ b/src/vivarium_sodium_reduction/components/risks.py @@ -16,7 +16,6 @@ ) from vivarium_public_health.utilities import EntityString - class DropValueRisk(Risk): def __init__(self, risk: str): super().__init__(risk) @@ -60,133 +59,6 @@ def post_processor(exposure, _): return post_processor - -class CorrelatedRisk(DropValueRisk): - """A risk that can be correlated with another risk. - - TODO: document strategy used in this component in more detail, - Abie had an AI adapt it from https://github.com/ihmeuw/vivarium_nih_us_cvd""" - - @property - def columns_created(self) -> List[str]: - return [] - - @property - def columns_required(self) -> Optional[List[str]]: - return [self.propensity_column_name] - - @property - def initialization_requirements(self) -> Dict[str, List[str]]: - return { - "requires_columns": [], - "requires_values": [], - "requires_streams": [], - } - - def on_initialize_simulants(self, pop_data: SimulantData) -> None: - pass - - def on_time_step_prepare(self, event: Event) -> None: - pass - - -class ThresholdRisk(Component): - """A component that generates a risk based on a threshold of another risk.""" - - def __init__(self, risk: str, threshold: str): - super().__init__() - self.risk = EntityString(risk) - self.threshold = float(threshold) - self.exposure_pipeline_name = f"{self.risk.name}.threshold_exposure" - - def setup(self, builder: Builder) -> None: - self.continuous_exposure = builder.value.get_value(self.risk.exposure_pipeline_name) - self.threshold_exposure = builder.value.register_value_producer( - self.exposure_pipeline_name, - source=self.continuous_exposure - ) - - def get_exposure_threshold_value(self, value): - - return np.where(value <= self.threshold, 'cat1', 'cat2') - - - -class RiskCorrelation(Component): - """A component that generates a specified correlation between two risk exposures.""" - - @property - def columns_created(self) -> List[str]: - return self.propensity_column_names + self.exposure_column_names - - @property - def columns_required(self) -> Optional[List[str]]: - return ["age"] - - @property - def initialization_requirements(self) -> Dict[str, List[str]]: - return {"requires_columns": ["age"] + self.ensemble_propensities} - - def __init__(self, risk1: str, risk2: str, correlation: str): - super().__init__() - correlated_risks = [risk1, risk2] - correlation_matrix = np.array([[1, float(correlation)], [float(correlation), 1]]) - self.correlated_risks = [EntityString(risk) for risk in correlated_risks] - self.correlation_matrix = correlation_matrix - self.propensity_column_names = [ - f"{risk.name}_propensity" for risk in self.correlated_risks - ] - self.exposure_column_names = [ - f"{risk.name}_exposure" for risk in self.correlated_risks - ] - self.ensemble_propensities = [ - f"ensemble_propensity_" + risk - for risk in self.correlated_risks - if risk_factors[risk.name].distribution == "ensemble" - ] - - def setup(self, builder: Builder) -> None: - self.distributions = { - risk: builder.components.get_component(risk).exposure_distribution - for risk in self.correlated_risks - } - self.exposures = { - risk: builder.value.get_value(f"{risk.name}.exposure") - for risk in self.correlated_risks - } - self.input_draw = builder.configuration.input_data.input_draw_number - self.random_seed = builder.configuration.randomness.random_seed - - def on_initialize_simulants(self, pop_data: SimulantData) -> None: - pop = self.population_view.subview(["age"]).get(pop_data.index) - propensities = pd.DataFrame(index=pop.index) - - np.random.seed(get_hash(f"{self.input_draw}_{self.random_seed}")) - probit_propensity = np.random.multivariate_normal( - mean=[0] * len(self.correlated_risks), cov=self.correlation_matrix, size=len(pop) - ) - correlated_propensities = scipy.stats.norm().cdf(probit_propensity) - propensities[self.propensity_column_names] = correlated_propensities - - def get_exposure_from_propensity(propensity_col: pd.Series) -> pd.Series: - risk = propensity_col.name.replace("_propensity", "") - exposure_values = self.distributions["risk_factor." + risk].ppf(propensity_col) - return pd.Series(exposure_values) - - exposures = propensities.apply(get_exposure_from_propensity) - exposures.columns = [ - col.replace("_propensity", "_exposure") for col in propensities.columns - ] - - self.population_view.update(pd.concat([propensities, exposures], axis=1)) - - def on_time_step_prepare(self, event: Event) -> None: - for risk in self.exposures: - exposure_values = self.exposures[risk](event.index) - exposure_col = pd.Series(exposure_values, name=f"{risk.name}_exposure") - self.population_view.update(exposure_col) - - class SodiumSBPEffect(Component): @property def name(self): @@ -198,7 +70,7 @@ def setup(self, builder: Builder): builder.value.register_value_modifier( "high_systolic_blood_pressure.drop_value", - modifier=self.sodium_effect_on_sbp, + modifier=self.sodium_effect_on_sbp_drop, requires_columns=["age", "sex"], requires_values=[ "diet_high_in_sodium.exposure", @@ -206,14 +78,13 @@ def setup(self, builder: Builder): ], ) - def sodium_effect_on_sbp(self, index, sbp_drop_value): + def sodium_effect_on_sbp_drop(self, index, sbp_drop_value): sodium_exposure = self.sodium_exposure(index) sodium_exposure_raw = self.sodium_exposure_raw(index) # FIXME: this should go in the constants.py file mmHg_per_g_sodium = 5.8/6.0 # 5.8 (2.5, 9.2) mmHg decrease per 6g/day sodium decrease - sbp_increase = pd.Series(0, index=index) sodium_drop = sodium_exposure_raw - sodium_exposure sbp_drop_due_to_sodium_drop = sodium_drop * mmHg_per_g_sodium diff --git a/src/vivarium_sodium_reduction/model_specifications/branches/scenarios.yaml b/src/vivarium_sodium_reduction/model_specifications/branches/scenarios.yaml index 0329c54..2f40cf4 100644 --- a/src/vivarium_sodium_reduction/model_specifications/branches/scenarios.yaml +++ b/src/vivarium_sodium_reduction/model_specifications/branches/scenarios.yaml @@ -1,5 +1,5 @@ -input_draw_count: 5 -random_seed_count: 30 +input_draw_count: 1 +random_seed_count: 1 branches: - relative_shift_intervention_on_diet_high_in_sodium: diff --git a/src/vivarium_sodium_reduction/model_specifications/model_spec.yaml b/src/vivarium_sodium_reduction/model_specifications/model_spec.yaml index 497d56a..1c013cb 100644 --- a/src/vivarium_sodium_reduction/model_specifications/model_spec.yaml +++ b/src/vivarium_sodium_reduction/model_specifications/model_spec.yaml @@ -32,9 +32,8 @@ components: 'cause.stomach_cancer.incidence_rate') vivarium_sodium_reduction.components: risks: - - CorrelatedRisk('risk_factor.high_systolic_blood_pressure') - - CorrelatedRisk('risk_factor.diet_high_in_sodium') - - RiskCorrelation('risk_factor.high_systolic_blood_pressure', 'risk_factor.diet_high_in_sodium', '0.0') + - DropValueRisk('risk_factor.high_systolic_blood_pressure') + - DropValueRisk('risk_factor.diet_high_in_sodium') - SodiumSBPEffect() interventions: - RelativeShiftIntervention('diet_high_in_sodium') @@ -61,12 +60,12 @@ configuration: day: 31 step_size: 168 # 28*6 (approximately 6 months, in days) population: - population_size: 100_000 + population_size: 10_000 initialization_age_min: 0 initialization_age_max: 100 relative_shift_intervention_on_diet_high_in_sodium: - shift_factor: 0.85 + shift_factor: 2.0 age_start: 0 age_end: 125