hpvsim 2.2.7__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hpvsim-2.2.7 → hpvsim-2.3.0}/.gitignore +3 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/CHANGELOG.md +18 -1
- {hpvsim-2.2.7/hpvsim.egg-info → hpvsim-2.3.0}/PKG-INFO +1 -1
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/analysis.py +0 -1
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/calibration.py +41 -11
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/defaults.py +1 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/interventions.py +34 -4
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/parameters.py +17 -19
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/people.py +30 -34
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/population.py +12 -1
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/sim.py +4 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/version.py +2 -2
- {hpvsim-2.2.7 → hpvsim-2.3.0/hpvsim.egg-info}/PKG-INFO +1 -1
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim.egg-info/SOURCES.txt +7 -0
- hpvsim-2.3.0/tests/baseline.json +61 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/benchmark.json +3 -3
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_dt.py +1 -1
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_multiscale.py +6 -6
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_multiscale_pars.py +2 -3
- hpvsim-2.3.0/tests/generate_v2_baselines.py +446 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_analysis.py +92 -1
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_calibration.py +11 -5
- hpvsim-2.3.0/tests/test_immunity.py +219 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_interventions.py +98 -1
- hpvsim-2.3.0/tests/test_misc.py +172 -0
- hpvsim-2.3.0/tests/test_parameters.py +74 -0
- hpvsim-2.3.0/tests/test_people.py +31 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_sim.py +40 -4
- hpvsim-2.3.0/tests/test_utils.py +367 -0
- hpvsim-2.3.0/tests/test_v2_regression.py +230 -0
- hpvsim-2.2.7/tests/baseline.json +0 -60
- {hpvsim-2.2.7 → hpvsim-2.3.0}/.github/workflows/pypi_release.yaml +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/.github/workflows/tests.yaml +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/CODE_OF_CONDUCT.md +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/LICENSE +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/MANIFEST.in +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/README.md +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/.gitignore +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/CNAME +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/README.md +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/_quarto.yml +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/_variables.yml +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/assets/favicon.ico +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/assets/starsim-logo-dark.png +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/assets/starsim-logo.png +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/assets/styles-dark.scss +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/assets/styles-light.scss +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/assets/styles.css +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/conduct.md +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/index.md +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/overview.md +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/preview +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/publish +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/quarto_utils.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/render +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/requirements.txt +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/nigeria_cancer_cases.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/nigeria_cancer_types.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/south_africa_age_pyramid.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/tut_analyzers.qmd +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/tut_calibration.qmd +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/tut_interventions.qmd +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/tut_intro.qmd +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/tut_people.qmd +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/tut_plotting.qmd +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials/tut_running.qmd +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/tutorials.md +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/docs/whats-new.md +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/examples/t05_screen_algorithms.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/__init__.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/base.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/data/__init__.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/data/downloaders.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/data/loaders.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/data/products_dx.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/data/products_tx.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/data/products_txvx.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/data/products_vx.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/data/test_downloaders.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/data/test_loaders.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/hiv.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/immunity.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/misc.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/plotting.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/regression/pars_v0.2.6.json +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/regression/pars_v0.2.9.json +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/regression/pars_v0.3.0.json +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/regression/pars_v0.3.1.json +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/run.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/settings.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim/utils.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim.egg-info/dependency_links.txt +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim.egg-info/entry_points.txt +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim.egg-info/requires.txt +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/hpvsim.egg-info/top_level.txt +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/pyproject.toml +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/setup.cfg +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/.coveragerc +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/README.md +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/benchmark_profile.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/check_coverage +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/check_hiv_data.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/hpv_test_pars.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/multiscale_concept1.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/multiscale_concept2.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/multiscale_concept3.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/multiscale_test.df +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/mysql_hpvsim_test.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/mysql_test.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/network_dx.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/plot_nathx.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/setup_mysql +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_cancer_dysp.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_hiv.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_latency.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_logistic.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_merge_scens.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_networks.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_new_progs.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_parameter_exploration.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_popgrowth.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_popscale.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_sampler.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/test_txvx.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/devtests/tut_parameter_exploration.ipynb +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/hpvsim_v1.2.2.yml +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/pytest.ini +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/requirements.txt +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/run_tests +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/simple.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_baselines.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/RSA_data.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/art_coverage_south_africa.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/australia_age_pyramid.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/hiv_incidence_south_africa.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/india_cancer_cases.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/india_cancer_deaths.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/india_cancer_types.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/india_cin_types.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/india_data.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/india_hpv_data.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/india_hpv_prevalence.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/kenya_age_pyramid.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/kenya_cancer_incidence.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/kenya_cancer_mortality.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/kenya_data.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/param_space.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/param_space_filled.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_age_pyramid.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_art_coverage_by_age_females.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_art_coverage_by_age_males.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_cancer_data_2020.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_cancer_data_hiv_2020.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_cancer_incidence_by_age_no_hiv.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_cancer_incidence_by_age_with_hiv.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_female_hiv_mortality.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_hpv_data.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_male_hiv_mortality.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_target_data.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_type_distribution_cancer.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/south_africa_type_distribution_high_grade_lesion.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/tanzania_age_pyramid.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/tanzania_data.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/test_tx_assigner.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/test_via.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data/test_via_triage.csv +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_data.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_event_schedule.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/test_run.py +0 -0
- {hpvsim-2.2.7 → hpvsim-2.3.0}/tests/update_baseline +0 -0
|
@@ -3,10 +3,27 @@ that may result in differences in model output, or are required in order
|
|
|
3
3
|
to run an old parameter set with the current version, are flagged with
|
|
4
4
|
the term "Regression information".
|
|
5
5
|
|
|
6
|
+
## Version 2.3.0 (2026-04-20)
|
|
7
|
+
|
|
8
|
+
- Fixes dt-dependent results by scaling partnership formation rates to
|
|
9
|
+
per-timestep probabilities; `layer_probs` and cross-layer defaults
|
|
10
|
+
converted to annual probabilities.
|
|
11
|
+
- *Regression information*: If workflows from v2.2.6 or earlier override default `layer_probs`, `f_cross_layer`, or `m_cross_layer` values
|
|
12
|
+
and have timesteps not equal to 1 year, then the probabilities must be converted to annual probabilities instead of per-timestep probabilities using this formula: `1 - (1 - prob) ** dt`
|
|
13
|
+
- *Regression information:* baseline model outputs change; baselines have been regenerated.
|
|
14
|
+
- Fixes `precins` flow never being incremented; removes redundant `dysplasias` flow (was an alias of `cins`).
|
|
15
|
+
- Adds test coverage for previously untested code paths.
|
|
16
|
+
- Vaccine immunity is now sterilizing (all-or-nothing) rather than leaky (per-contact). `imm_init` sets the probability of sterilizing immunity; non-sterilizing recipients get leaky protection at the `imm_init` level. Default is 0.95.
|
|
17
|
+
- Adds per-timestep transmission logging (`sim._transmission_log`) for downstream analysis of transmission chains.
|
|
18
|
+
- Calibration now supports resuming from an existing database via `keep_db=True`, running only the remaining trials.
|
|
19
|
+
- Calibration workers catch exceptions instead of crashing the entire run.
|
|
20
|
+
- Fixes `res_to_plot` indexing bug in `Calibration.plot()`.
|
|
21
|
+
- *Regression information*: vaccine efficacy will differ from previous versions due to the immunity model change.
|
|
22
|
+
|
|
6
23
|
## Version 2.2.7 (2026-04-22)
|
|
7
24
|
|
|
8
25
|
- Fix cancer treatment results always being blank: `BaseTreatment.check_eligibility` was excluding cancer patients (preventing radiation from running), `BaseTreatment.apply` was writing to CIN fields for cancer treatment, and `cum_cancer_treated` cumsum used the wrong source array
|
|
9
|
-
- *Github info* PR [
|
|
26
|
+
- *Github info* PR [94](https://github.com/starsimhub/hpvsim/pull/94), issue [91](https://github.com/starsimhub/hpvsim/issues/91)
|
|
10
27
|
|
|
11
28
|
## Version 2.2.6 (2026-04-17)
|
|
12
29
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hpvsim
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: HPVsim: Human Papillomavirus Simulator
|
|
5
5
|
Author: Robyn Stuart, Jamie Cohen, Cliff Kerr, Romesh Abeysuriya, Mariah Boudreau, Daniel Klein, Hao Hu
|
|
6
6
|
Maintainer-email: HPVsim Team <info@hpvsim.org>
|
|
@@ -742,7 +742,6 @@ class age_results(Analyzer):
|
|
|
742
742
|
mapping = {
|
|
743
743
|
'infections': ['date_exposed', 'infectious'],
|
|
744
744
|
'cin': ['date_cin', 'cin'],
|
|
745
|
-
'dysplasias': ['date_cin', 'cin'],
|
|
746
745
|
'cins': ['date_cin', 'cin'],
|
|
747
746
|
'cancers': ['date_cancerous', 'cancerous'],
|
|
748
747
|
'cancer': ['date_cancerous', 'cancerous'],
|
|
@@ -89,8 +89,10 @@ class Calibration(sc.prettyobj):
|
|
|
89
89
|
if keep_db is None: keep_db = False
|
|
90
90
|
if storage is None: storage = f'sqlite:///{db_name}'
|
|
91
91
|
if total_trials is not None: n_trials = int(np.ceil(total_trials/n_workers))
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
total_trials = int(n_trials * n_workers)
|
|
93
|
+
self.run_args = sc.objdict(n_trials=int(n_trials), n_workers=int(n_workers), total_trials=total_trials,
|
|
94
|
+
name=name, db_name=db_name, keep_db=keep_db, storage=storage,
|
|
95
|
+
rand_seed=rand_seed, sampler=sampler)
|
|
94
96
|
|
|
95
97
|
# Handle other inputs
|
|
96
98
|
self.label = label
|
|
@@ -412,7 +414,11 @@ class Calibration(sc.prettyobj):
|
|
|
412
414
|
else:
|
|
413
415
|
op.logging.set_verbosity(op.logging.ERROR)
|
|
414
416
|
study = op.load_study(storage=self.run_args.storage, study_name=self.run_args.name, sampler = self.run_args.sampler)
|
|
415
|
-
|
|
417
|
+
try:
|
|
418
|
+
output = study.optimize(self.run_trial, n_trials=self.run_args.n_trials, callbacks=None)
|
|
419
|
+
except Exception as E:
|
|
420
|
+
print(f'Worker failed with error: {E}')
|
|
421
|
+
output = None
|
|
416
422
|
return output
|
|
417
423
|
|
|
418
424
|
|
|
@@ -438,9 +444,12 @@ class Calibration(sc.prettyobj):
|
|
|
438
444
|
print('Could not delete study, skipping...')
|
|
439
445
|
print(str(E))
|
|
440
446
|
if os.path.exists(self.run_args.db_name):
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
447
|
+
try:
|
|
448
|
+
os.remove(self.run_args.db_name)
|
|
449
|
+
if self.verbose:
|
|
450
|
+
print(f'Removed existing calibration {self.run_args.db_name}')
|
|
451
|
+
except PermissionError:
|
|
452
|
+
print(f'Could not remove {self.run_args.db_name} (file in use), skipping...')
|
|
444
453
|
return
|
|
445
454
|
|
|
446
455
|
|
|
@@ -455,7 +464,8 @@ class Calibration(sc.prettyobj):
|
|
|
455
464
|
raise NotImplementedError('Implemented but does not work')
|
|
456
465
|
else:
|
|
457
466
|
sampler = None
|
|
458
|
-
output = op.create_study(storage=self.run_args.storage, study_name=self.run_args.name, sampler=sampler
|
|
467
|
+
output = op.create_study(storage=self.run_args.storage, study_name=self.run_args.name, sampler=sampler,
|
|
468
|
+
load_if_exists=self.run_args.keep_db)
|
|
459
469
|
return output
|
|
460
470
|
|
|
461
471
|
|
|
@@ -485,7 +495,23 @@ class Calibration(sc.prettyobj):
|
|
|
485
495
|
# Run the optimization
|
|
486
496
|
t0 = sc.tic()
|
|
487
497
|
self.make_study()
|
|
488
|
-
|
|
498
|
+
|
|
499
|
+
# If resuming with keep_db, check for existing trials and only run the remainder
|
|
500
|
+
if self.run_args.keep_db:
|
|
501
|
+
study = op.load_study(storage=self.run_args.storage, study_name=self.run_args.name)
|
|
502
|
+
n_existing = len([t for t in study.trials if t.state == op.trial.TrialState.COMPLETE])
|
|
503
|
+
if n_existing > 0:
|
|
504
|
+
n_remaining = max(0, self.run_args.total_trials - n_existing)
|
|
505
|
+
if n_remaining == 0:
|
|
506
|
+
print(f'Calibration already has {n_existing} completed trials, skipping workers')
|
|
507
|
+
else:
|
|
508
|
+
self.run_args.n_trials = int(np.ceil(n_remaining / self.run_args.n_workers))
|
|
509
|
+
print(f'Resuming calibration: {n_existing} trials complete, running ~{n_remaining} more')
|
|
510
|
+
self.run_workers()
|
|
511
|
+
else:
|
|
512
|
+
self.run_workers()
|
|
513
|
+
else:
|
|
514
|
+
self.run_workers()
|
|
489
515
|
study = op.load_study(storage=self.run_args.storage, study_name=self.run_args.name, sampler = self.run_args.sampler)
|
|
490
516
|
self.best_pars = sc.objdict(study.best_params)
|
|
491
517
|
self.elapsed = sc.toc(t0, output=True)
|
|
@@ -500,6 +526,7 @@ class Calibration(sc.prettyobj):
|
|
|
500
526
|
self.analyzer_results = []
|
|
501
527
|
self.sim_results = []
|
|
502
528
|
self.extra_sim_results = []
|
|
529
|
+
loaded_trials = set()
|
|
503
530
|
if load:
|
|
504
531
|
print('Loading saved results...')
|
|
505
532
|
for trial in study.trials:
|
|
@@ -510,6 +537,7 @@ class Calibration(sc.prettyobj):
|
|
|
510
537
|
self.sim_results.append(results['sim'])
|
|
511
538
|
self.analyzer_results.append(results['analyzer'])
|
|
512
539
|
self.extra_sim_results.append(results['extra_sim_results'])
|
|
540
|
+
loaded_trials.add(n)
|
|
513
541
|
if tidyup:
|
|
514
542
|
try:
|
|
515
543
|
os.remove(filename)
|
|
@@ -524,7 +552,7 @@ class Calibration(sc.prettyobj):
|
|
|
524
552
|
|
|
525
553
|
# Compare the results
|
|
526
554
|
self.initial_pars, self.par_bounds = self.sim_to_sample_pars()
|
|
527
|
-
self.parse_study(study)
|
|
555
|
+
self.parse_study(study, loaded_trials=loaded_trials)
|
|
528
556
|
|
|
529
557
|
# Tidy up
|
|
530
558
|
self.calibrated = True
|
|
@@ -534,7 +562,7 @@ class Calibration(sc.prettyobj):
|
|
|
534
562
|
return self
|
|
535
563
|
|
|
536
564
|
|
|
537
|
-
def parse_study(self, study):
|
|
565
|
+
def parse_study(self, study, loaded_trials=None):
|
|
538
566
|
'''Parse the study into a data frame -- called automatically '''
|
|
539
567
|
best = study.best_params
|
|
540
568
|
self.best_pars = best
|
|
@@ -549,6 +577,8 @@ class Calibration(sc.prettyobj):
|
|
|
549
577
|
data[key] = val
|
|
550
578
|
if data['mismatch'] is None:
|
|
551
579
|
failed_trials.append(data['index'])
|
|
580
|
+
elif loaded_trials is not None and trial.number not in loaded_trials:
|
|
581
|
+
failed_trials.append(data['index'])
|
|
552
582
|
else:
|
|
553
583
|
results.append(data)
|
|
554
584
|
print(f'Processed {n_trials} trials; {len(failed_trials)} failed')
|
|
@@ -653,7 +683,7 @@ class Calibration(sc.prettyobj):
|
|
|
653
683
|
|
|
654
684
|
# determine how many results to plot
|
|
655
685
|
if res_to_plot is not None:
|
|
656
|
-
index_to_plot = self.df.
|
|
686
|
+
index_to_plot = self.df.index[0:res_to_plot].values
|
|
657
687
|
analyzer_results = [analyzer_results[i] for i in index_to_plot]
|
|
658
688
|
sim_results = [sim_results[i] for i in index_to_plot]
|
|
659
689
|
|
|
@@ -271,6 +271,7 @@ class Flow():
|
|
|
271
271
|
|
|
272
272
|
flows = [
|
|
273
273
|
Flow('infections', color='#c78f65', label='Infections'),
|
|
274
|
+
Flow('precins', color='#c1ad71', label='Pre-CINs'),
|
|
274
275
|
Flow('cins', color='#b86113', label='CINs'),
|
|
275
276
|
Flow('cancers', color='#5f5cd2', label='Cancers'),
|
|
276
277
|
Flow('cancer_deaths', color='#000000', label='Cancer deaths', by_genotype=False),
|
|
@@ -1414,22 +1414,52 @@ class tx(Product):
|
|
|
1414
1414
|
|
|
1415
1415
|
|
|
1416
1416
|
class vx(Product):
|
|
1417
|
-
'''
|
|
1417
|
+
'''
|
|
1418
|
+
Vaccine product.
|
|
1419
|
+
|
|
1420
|
+
imm_init controls the probability that a vaccinated person gets sterilizing
|
|
1421
|
+
(all-or-nothing) immunity. People who don't get sterilizing immunity still
|
|
1422
|
+
receive leaky (per-contact) protection equal to imm_init.
|
|
1423
|
+
|
|
1424
|
+
imm_init can be:
|
|
1425
|
+
- a float (e.g. 0.95): used directly as the sterilizing probability
|
|
1426
|
+
- a dict with dist/par keys (legacy beta-distribution format): the
|
|
1427
|
+
mean of the distribution is used as the sterilizing probability
|
|
1428
|
+
'''
|
|
1418
1429
|
def __init__(self, genotype_pars=None, imm_init=None, imm_boost=None):
|
|
1419
1430
|
self.genotype_pars = genotype_pars
|
|
1420
|
-
self.imm_init = imm_init
|
|
1421
1431
|
self.imm_boost = imm_boost
|
|
1422
1432
|
self.imm_source = None # Set during immunity initialization. Warning, fragile!!!
|
|
1423
1433
|
if (imm_init is None and imm_boost is None) or (imm_init is not None and imm_boost is not None):
|
|
1424
1434
|
errormsg = 'Must provide either an initial immune effect (for first doses) or an immune boosting effect (for subsequent doses), not both/neither.'
|
|
1425
1435
|
raise ValueError(errormsg)
|
|
1426
1436
|
|
|
1437
|
+
# Convert imm_init to a float (sterilizing probability)
|
|
1438
|
+
if imm_init is not None:
|
|
1439
|
+
if isinstance(imm_init, dict):
|
|
1440
|
+
if imm_init.get('dist') == 'beta':
|
|
1441
|
+
a, b = imm_init['par1'], imm_init['par2']
|
|
1442
|
+
self.imm_init = a / (a + b)
|
|
1443
|
+
elif imm_init.get('dist') == 'beta_mean':
|
|
1444
|
+
self.imm_init = imm_init['par1']
|
|
1445
|
+
else:
|
|
1446
|
+
# Estimate the mean of an unknown distribution via Monte Carlo;
|
|
1447
|
+
# 10k samples is just for accuracy, not related to agent count
|
|
1448
|
+
self.imm_init = float(np.mean(hpu.sample(**imm_init, size=10000)))
|
|
1449
|
+
else:
|
|
1450
|
+
self.imm_init = float(imm_init)
|
|
1451
|
+
else:
|
|
1452
|
+
self.imm_init = None
|
|
1453
|
+
|
|
1427
1454
|
|
|
1428
1455
|
def administer(self, people, inds):
|
|
1429
1456
|
''' Apply the vaccine to the requested people indices. '''
|
|
1430
1457
|
inds = inds[people.alive[inds]] # Skip anyone that is dead
|
|
1431
1458
|
if self.imm_init is not None:
|
|
1432
|
-
|
|
1459
|
+
n = len(inds)
|
|
1460
|
+
sterilizing = np.random.random(n) < self.imm_init
|
|
1461
|
+
peak = np.where(sterilizing, 1.0, self.imm_init)
|
|
1462
|
+
people.peak_imm[self.imm_source, inds] = peak * people.rel_imm[inds]
|
|
1433
1463
|
elif self.imm_boost is not None:
|
|
1434
1464
|
people.peak_imm[self.imm_source, inds] *= self.imm_boost
|
|
1435
1465
|
people.t_imm_event[self.imm_source, inds] = people.t
|
|
@@ -1515,7 +1545,7 @@ def default_vx(prod_name=None):
|
|
|
1515
1545
|
dfvx = pd.read_csv(datafiles.vx) # Read in dataframe with parameters
|
|
1516
1546
|
vxprods = dict()
|
|
1517
1547
|
for name in dfvx.name.unique():
|
|
1518
|
-
vxprods[name] = vx(genotype_pars=dfvx[dfvx.name==name], imm_init=
|
|
1548
|
+
vxprods[name] = vx(genotype_pars=dfvx[dfvx.name==name], imm_init=0.95)
|
|
1519
1549
|
vxprods[name+'2'] = vx(genotype_pars=dfvx[dfvx.name==name], imm_boost=1.2) # 2nd dose
|
|
1520
1550
|
vxprods[name+'3'] = vx(genotype_pars=dfvx[dfvx.name==name], imm_boost=1.1) # 3rd dose
|
|
1521
1551
|
if prod_name is not None: return vxprods[prod_name]
|
|
@@ -73,8 +73,8 @@ def make_pars(**kwargs):
|
|
|
73
73
|
pars['add_mixing'] = None # Mixing matrix between clusters
|
|
74
74
|
pars['debut'] = dict(f=dict(dist='normal', par1=15.0, par2=2.1), # Location-specific data should be used here if possible
|
|
75
75
|
m=dict(dist='normal', par1=17.6, par2=1.8))
|
|
76
|
-
pars['f_cross_layer'] = 0.
|
|
77
|
-
pars['m_cross_layer'] = 0.
|
|
76
|
+
pars['f_cross_layer'] = 0.185 # Annual probability of females having concurrent cross-layer relationships
|
|
77
|
+
pars['m_cross_layer'] = 0.760 # Annual probability of males having concurrent cross-layer relationships
|
|
78
78
|
pars['f_partners'] = None # Distribution of preferred number of concurrent sexual partners, females
|
|
79
79
|
pars['m_partners'] = None # Distribution of preferred number of concurrent sexual partners, males
|
|
80
80
|
pars['acts'] = None # The number of sexual acts for each partnership type per year
|
|
@@ -578,16 +578,14 @@ def get_mixing(network=None):
|
|
|
578
578
|
|
|
579
579
|
layer_probs = dict(
|
|
580
580
|
m=np.array([
|
|
581
|
-
[ 0,
|
|
582
|
-
[ 0,
|
|
583
|
-
[ 0,
|
|
584
|
-
# [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] # Share of males of each age who are actively seeking marriage if underpartnered
|
|
581
|
+
[ 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75],
|
|
582
|
+
[ 0, 0, 0.0394, 0.938, 0.938, 0.938, 0.938, 0.938, 0.938, 0.938, 0.938, 0.760, 0.590, 0.344, 0.185, 0.0394], # Annual prob of females seeking marriage if underpartnered
|
|
583
|
+
[ 0, 0, 0.0394, 0.590, 0.760, 0.938, 0.938, 0.938, 0.938, 0.938, 0.938, 0.760, 0.590, 0.344, 0.185, 0.0394]] # Annual prob of males seeking marriage if underpartnered
|
|
585
584
|
),
|
|
586
585
|
c=np.array([
|
|
587
|
-
[ 0,
|
|
588
|
-
[ 0,
|
|
589
|
-
[ 0,
|
|
590
|
-
# [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] # Share of males of each age actively seeking casual relationships if underpartnered
|
|
586
|
+
[ 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75],
|
|
587
|
+
[ 0, 0, 0.590, 0.974, 0.998, 0.974, 0.870, 0.870, 0.870, 0.344, 0.0776, 0.0776, 0.0776, 0.0776, 0.0776, 0.0776], # Annual prob of females seeking casual relationships if underpartnered
|
|
588
|
+
[ 0, 0, 0.590, 0.870, 0.870, 0.870, 0.870, 0.974, 0.998, 0.974, 0.590, 0.344, 0.185, 0.0776, 0.0776, 0.0776]] # Annual prob of males seeking casual relationships if underpartnered
|
|
591
589
|
)
|
|
592
590
|
)
|
|
593
591
|
|
|
@@ -615,9 +613,9 @@ def get_mixing(network=None):
|
|
|
615
613
|
)
|
|
616
614
|
layer_probs = dict(
|
|
617
615
|
a=np.array([
|
|
618
|
-
[ 0,
|
|
619
|
-
[ 0,
|
|
620
|
-
[ 0,
|
|
616
|
+
[ 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75],
|
|
617
|
+
[ 0, 0, 0.151, 0.590, 0.974, 0.998, 0.998, 0.998, 0.996, 0.985, 0.959, 0.870, 0.870, 0.870, 0.870, 0.870], # Annual prob of females seeking partnership if underpartnered
|
|
618
|
+
[ 0, 0, 0.0394, 0.0394, 0.590, 0.974, 0.998, 0.999, 0.999, 0.999, 0.999, 0.998, 0.992, 0.974, 0.938, 0.974]] # Annual prob of males seeking partnership if underpartnered
|
|
621
619
|
))
|
|
622
620
|
|
|
623
621
|
else:
|
|
@@ -636,42 +634,42 @@ def get_vaccine_dose_pars(default=False, vaccine=None):
|
|
|
636
634
|
pars = dict(
|
|
637
635
|
|
|
638
636
|
default = dict(
|
|
639
|
-
imm_init =
|
|
637
|
+
imm_init = 0.95, # Probability of sterilizing immunity
|
|
640
638
|
doses = 1, # Number of doses for this vaccine
|
|
641
639
|
interval = None, # Interval between doses
|
|
642
640
|
imm_boost=None, # For vaccines wiht >1 dose, the factor by which each additional boost increases immunity
|
|
643
641
|
),
|
|
644
642
|
|
|
645
643
|
bivalent = dict(
|
|
646
|
-
imm_init=
|
|
644
|
+
imm_init=0.95, # Probability of sterilizing immunity
|
|
647
645
|
doses=1, # Number of doses for this vaccine
|
|
648
646
|
interval=None, # Interval between doses
|
|
649
647
|
imm_boost=None, # For vaccines wiht >1 dose, the factor by which each additional boost increases immunity
|
|
650
648
|
),
|
|
651
649
|
|
|
652
650
|
bivalent_2dose = dict(
|
|
653
|
-
imm_init=
|
|
651
|
+
imm_init=0.95, # Probability of sterilizing immunity
|
|
654
652
|
doses=2, # Number of doses for this vaccine
|
|
655
653
|
interval=0.5, # Interval between doses in years
|
|
656
654
|
imm_boost=1.2, # For vaccines wiht >1 dose, the factor by which each additional boost increases immunity
|
|
657
655
|
),
|
|
658
656
|
|
|
659
657
|
bivalent_3dose = dict(
|
|
660
|
-
imm_init=
|
|
658
|
+
imm_init=0.95, # Probability of sterilizing immunity
|
|
661
659
|
doses=3, # Number of doses for this vaccine
|
|
662
660
|
interval=[0.2, 0.5], # Interval between doses in years
|
|
663
661
|
imm_boost=[1.2, 1.1], # Factor by which each dose increases immunity
|
|
664
662
|
),
|
|
665
663
|
|
|
666
664
|
quadrivalent = dict(
|
|
667
|
-
imm_init=
|
|
665
|
+
imm_init=0.95, # Probability of sterilizing immunity
|
|
668
666
|
doses=1, # Number of doses for this vaccine
|
|
669
667
|
interval=None, # Interval between doses
|
|
670
668
|
imm_boost=None, # For vaccines wiht >1 dose, the factor by which each additional boost increases immunity
|
|
671
669
|
),
|
|
672
670
|
|
|
673
671
|
nonavalent = dict(
|
|
674
|
-
imm_init=
|
|
672
|
+
imm_init=0.95, # Probability of sterilizing immunity
|
|
675
673
|
doses=1, # Number of doses for this vaccine
|
|
676
674
|
interval=None, # Interval between doses
|
|
677
675
|
imm_boost=None, # For vaccines wiht >1 dose, the factor by which each additional boost increases immunity
|
|
@@ -458,6 +458,16 @@ class People(hpb.BasePeople):
|
|
|
458
458
|
# Initialize
|
|
459
459
|
new_pships = dict()
|
|
460
460
|
|
|
461
|
+
# Scale annual participation rates to per-timestep probabilities so that
|
|
462
|
+
# partnership formation rates are consistent regardless of dt (issue #13)
|
|
463
|
+
dt = self.dt
|
|
464
|
+
scaled_layer_probs = {lkey: lp.copy() for lkey, lp in layer_probs.items()}
|
|
465
|
+
for lp in scaled_layer_probs.values():
|
|
466
|
+
lp[1, :] = 1 - (1 - lp[1, :]) ** dt # Female participation
|
|
467
|
+
lp[2, :] = 1 - (1 - lp[2, :]) ** dt # Male participation
|
|
468
|
+
scaled_f_cross = 1 - (1 - f_cross_layer) ** dt
|
|
469
|
+
scaled_m_cross = 1 - (1 - m_cross_layer) ** dt
|
|
470
|
+
|
|
461
471
|
# Loop over layers
|
|
462
472
|
lno = 0
|
|
463
473
|
for lkey in self.layer_keys():
|
|
@@ -471,9 +481,9 @@ class People(hpb.BasePeople):
|
|
|
471
481
|
is_female=self.is_female,
|
|
472
482
|
is_active=self.is_active,
|
|
473
483
|
mixing=mixing[lkey],
|
|
474
|
-
layer_probs=
|
|
475
|
-
f_cross_layer=
|
|
476
|
-
m_cross_layer=
|
|
484
|
+
layer_probs=scaled_layer_probs[lkey],
|
|
485
|
+
f_cross_layer=scaled_f_cross,
|
|
486
|
+
m_cross_layer=scaled_m_cross,
|
|
477
487
|
durations=dur_pship[lkey],
|
|
478
488
|
acts=acts[lkey],
|
|
479
489
|
age_act_pars=age_act_pars[lkey],
|
|
@@ -942,31 +952,6 @@ class People(hpb.BasePeople):
|
|
|
942
952
|
) # These are not indices, so they scale differently
|
|
943
953
|
|
|
944
954
|
# %% Methods to make events occur (death, infection, others TBC)
|
|
945
|
-
def make_naive(self, inds):
|
|
946
|
-
"""
|
|
947
|
-
Make a set of people naive. This is used during dynamic resampling.
|
|
948
|
-
|
|
949
|
-
Args:
|
|
950
|
-
inds (array): list of people to make naive
|
|
951
|
-
"""
|
|
952
|
-
for key in self.meta.states:
|
|
953
|
-
if key in ["susceptible"]:
|
|
954
|
-
self[key][:, inds] = True
|
|
955
|
-
elif key in ["other_dead"]:
|
|
956
|
-
self[key][inds] = False
|
|
957
|
-
else:
|
|
958
|
-
self[key][:, inds] = False
|
|
959
|
-
|
|
960
|
-
# Reset immunity
|
|
961
|
-
for key in self.meta.imm_states:
|
|
962
|
-
self[key][:, inds] = 0
|
|
963
|
-
|
|
964
|
-
# Reset dates
|
|
965
|
-
for key in self.meta.dates + self.meta.durs:
|
|
966
|
-
self[key][:, inds] = np.nan
|
|
967
|
-
|
|
968
|
-
return
|
|
969
|
-
|
|
970
955
|
def infect(self, inds, g=None, layer=None):
|
|
971
956
|
"""
|
|
972
957
|
Infect people and determine their eventual outcomes.
|
|
@@ -1049,6 +1034,14 @@ class People(hpb.BasePeople):
|
|
|
1049
1034
|
f_inds = hpu.itruei(self.is_female, inds)
|
|
1050
1035
|
m_inds = hpu.itruei(self.is_male, inds)
|
|
1051
1036
|
|
|
1037
|
+
# Count new precin cases (females entering the precin state)
|
|
1038
|
+
if layer != "seed_infection" and layer != "reactivation" and len(f_inds) > 0:
|
|
1039
|
+
self.flows["precins"] += self.scale_flows(f_inds)
|
|
1040
|
+
self.genotype_flows["precins"][g] += self.scale_flows(f_inds)
|
|
1041
|
+
self.age_flows["precins"] += np.histogram(
|
|
1042
|
+
self.age[f_inds], bins=self.age_bin_edges, weights=self.scale[f_inds]
|
|
1043
|
+
)[0]
|
|
1044
|
+
|
|
1052
1045
|
# Compute disease progression for females
|
|
1053
1046
|
if len(f_inds) > 0:
|
|
1054
1047
|
gpars = self.pars["genotype_pars"][g]
|
|
@@ -1168,10 +1161,12 @@ class People(hpb.BasePeople):
|
|
|
1168
1161
|
|
|
1169
1162
|
intro = f"\nThis is the story of {uid}, a {p.age:.0f} year old {sex}."
|
|
1170
1163
|
intro += f"\n{uid} became sexually active at age {p.debut:.0f}."
|
|
1171
|
-
if not p.susceptible:
|
|
1172
|
-
|
|
1164
|
+
if not np.all(p.susceptible):
|
|
1165
|
+
dates_inf = p.date_infectious
|
|
1166
|
+
if np.any(~np.isnan(dates_inf)):
|
|
1167
|
+
earliest = np.nanmin(dates_inf)
|
|
1173
1168
|
print(
|
|
1174
|
-
f"{intro}\n{uid} contracted HPV on timestep {
|
|
1169
|
+
f"{intro}\n{uid} contracted HPV on timestep {earliest:.0f} of the simulation."
|
|
1175
1170
|
)
|
|
1176
1171
|
else:
|
|
1177
1172
|
print(f"{intro}\n{uid} did not contract HPV during the simulation.")
|
|
@@ -1196,13 +1191,14 @@ class People(hpb.BasePeople):
|
|
|
1196
1191
|
events = []
|
|
1197
1192
|
|
|
1198
1193
|
dates = {
|
|
1199
|
-
"
|
|
1194
|
+
"date_clearance": "HPV cleared",
|
|
1200
1195
|
}
|
|
1201
1196
|
|
|
1202
1197
|
for attribute, message in dates.items():
|
|
1203
1198
|
date = getattr(p, attribute)
|
|
1204
|
-
if
|
|
1205
|
-
|
|
1199
|
+
if np.any(~np.isnan(date)):
|
|
1200
|
+
earliest = np.nanmin(date)
|
|
1201
|
+
events.append((earliest, message))
|
|
1206
1202
|
|
|
1207
1203
|
if len(events):
|
|
1208
1204
|
for timestep, event in sorted(events, key=lambda x: x[0]):
|
|
@@ -110,6 +110,17 @@ def make_people(sim, popdict=None, reset=False, verbose=None, use_age_data=True,
|
|
|
110
110
|
# Create the contacts
|
|
111
111
|
lkeys = sim['acts'].keys() # TODO: consider a more robust way to do this
|
|
112
112
|
if microstructure in ['random', 'default']:
|
|
113
|
+
# Scale annual participation rates to per-timestep probabilities so
|
|
114
|
+
# that initial-network formation matches ongoing per-timestep rates
|
|
115
|
+
# (issue #13). Matches the scaling in People.create_partnerships.
|
|
116
|
+
dt = sim['dt']
|
|
117
|
+
scaled_layer_probs = {k: v.copy() for k, v in sim['layer_probs'].items()}
|
|
118
|
+
for lp in scaled_layer_probs.values():
|
|
119
|
+
lp[1, :] = 1 - (1 - lp[1, :]) ** dt
|
|
120
|
+
lp[2, :] = 1 - (1 - lp[2, :]) ** dt
|
|
121
|
+
scaled_f_cross = 1 - (1 - sim['f_cross_layer']) ** dt
|
|
122
|
+
scaled_m_cross = 1 - (1 - sim['m_cross_layer']) ** dt
|
|
123
|
+
|
|
113
124
|
contacts = dict()
|
|
114
125
|
current_partners = np.zeros((len(lkeys),n_agents))
|
|
115
126
|
lno=0
|
|
@@ -117,7 +128,7 @@ def make_people(sim, popdict=None, reset=False, verbose=None, use_age_data=True,
|
|
|
117
128
|
contacts[lkey], current_partners,_,_ = make_contacts(
|
|
118
129
|
lno=lno, tind=0, partners=partners[lno,:], current_partners=current_partners, ages=ages,
|
|
119
130
|
debuts=debuts, is_female=is_female, is_active=is_active, mixing=sim['mixing'][lkey],
|
|
120
|
-
layer_probs=
|
|
131
|
+
layer_probs=scaled_layer_probs[lkey], f_cross_layer=scaled_f_cross, m_cross_layer=scaled_m_cross,
|
|
121
132
|
durations=sim['dur_pship'][lkey], acts=sim['acts'][lkey], age_act_pars=sim['age_act_pars'][lkey],
|
|
122
133
|
cluster=cluster, add_mixing=sim['add_mixing'], **kwargs
|
|
123
134
|
)
|
|
@@ -794,6 +794,8 @@ class Sim(hpb.BaseSim):
|
|
|
794
794
|
for lkey, layer in people.contacts.items():
|
|
795
795
|
|
|
796
796
|
sus = people.susceptible.copy() # for each layer, update who's still susceptible
|
|
797
|
+
if not hasattr(self, '_transmission_log'):
|
|
798
|
+
self._transmission_log = []
|
|
797
799
|
|
|
798
800
|
# Shorten variables
|
|
799
801
|
f = layer['f']
|
|
@@ -822,6 +824,8 @@ class Sim(hpb.BaseSim):
|
|
|
822
824
|
transmissions = (np.random.random(len(betas)) < betas).nonzero()[0] # Apply probabilities to determine partnerships in which transmission occurred
|
|
823
825
|
target_inds = targets[transmissions] # Extract indices of those who got infected
|
|
824
826
|
target_inds, unique_inds = np.unique(target_inds, return_index=True) # Due to multiple partnerships, some people will be counted twice; remove them
|
|
827
|
+
source_inds = sources[transmissions[unique_inds]]
|
|
828
|
+
self._transmission_log.append((source_inds, target_inds, lkey, g))
|
|
825
829
|
people.infect(inds=target_inds, g=g, layer=lkey) # Infect people
|
|
826
830
|
|
|
827
831
|
# Determine if there are any reactivated infections on this timestep
|
|
@@ -4,6 +4,6 @@ Version and license information.
|
|
|
4
4
|
|
|
5
5
|
__all__ = ['__version__', '__versiondate__', '__license__']
|
|
6
6
|
|
|
7
|
-
__version__ = '2.
|
|
8
|
-
__versiondate__ = '2026-04-
|
|
7
|
+
__version__ = '2.3.0'
|
|
8
|
+
__versiondate__ = '2026-04-20'
|
|
9
9
|
__license__ = f'HPVsim {__version__} ({__versiondate__}) — © 2023-2026 by the Gates Foundation'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hpvsim
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: HPVsim: Human Papillomavirus Simulator
|
|
5
5
|
Author: Robyn Stuart, Jamie Cohen, Cliff Kerr, Romesh Abeysuriya, Mariah Boudreau, Daniel Klein, Hao Hu
|
|
6
6
|
Maintainer-email: HPVsim Team <info@hpvsim.org>
|
|
@@ -82,6 +82,7 @@ tests/baseline.json
|
|
|
82
82
|
tests/benchmark.json
|
|
83
83
|
tests/benchmark_profile.py
|
|
84
84
|
tests/check_coverage
|
|
85
|
+
tests/generate_v2_baselines.py
|
|
85
86
|
tests/hpvsim_v1.2.2.yml
|
|
86
87
|
tests/pytest.ini
|
|
87
88
|
tests/requirements.txt
|
|
@@ -92,9 +93,15 @@ tests/test_baselines.py
|
|
|
92
93
|
tests/test_calibration.py
|
|
93
94
|
tests/test_data.py
|
|
94
95
|
tests/test_event_schedule.py
|
|
96
|
+
tests/test_immunity.py
|
|
95
97
|
tests/test_interventions.py
|
|
98
|
+
tests/test_misc.py
|
|
99
|
+
tests/test_parameters.py
|
|
100
|
+
tests/test_people.py
|
|
96
101
|
tests/test_run.py
|
|
97
102
|
tests/test_sim.py
|
|
103
|
+
tests/test_utils.py
|
|
104
|
+
tests/test_v2_regression.py
|
|
98
105
|
tests/update_baseline
|
|
99
106
|
tests/devtests/check_hiv_data.py
|
|
100
107
|
tests/devtests/hpv_test_pars.csv
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"summary": {
|
|
3
|
+
"infections": 25397265.0,
|
|
4
|
+
"precins": 8005294.0,
|
|
5
|
+
"cins": 1208087.46875,
|
|
6
|
+
"cancers": 21194.517578125,
|
|
7
|
+
"cancer_deaths": 21194.517578125,
|
|
8
|
+
"reinfections": 19518902.5,
|
|
9
|
+
"reactivations": 0.0,
|
|
10
|
+
"n_susceptible": 586788800.0,
|
|
11
|
+
"n_infectious": 32725578.0,
|
|
12
|
+
"n_inactive": 187010.4375,
|
|
13
|
+
"n_normal": 306995072.0,
|
|
14
|
+
"n_cin": 2937310.75,
|
|
15
|
+
"n_cancerous": 187010.4375,
|
|
16
|
+
"n_infected": 32912586.0,
|
|
17
|
+
"n_abnormal": 3124321.0,
|
|
18
|
+
"n_latent": 0.0,
|
|
19
|
+
"n_precin": 12149445.0,
|
|
20
|
+
"n_screened": 2515913.5,
|
|
21
|
+
"n_cin_treated": 0.0,
|
|
22
|
+
"n_cancer_treated": 0.0,
|
|
23
|
+
"n_vaccinated": 1284138.375,
|
|
24
|
+
"n_tx_vaccinated": 11888876.0,
|
|
25
|
+
"hpv_incidence": 0.021640891066768825,
|
|
26
|
+
"cin_incidence": 0.008250109718770863,
|
|
27
|
+
"cancer_incidence": 14.207040688510245,
|
|
28
|
+
"births": 7941710.1673,
|
|
29
|
+
"other_deaths": 3009621.5,
|
|
30
|
+
"migration": 299216.7096,
|
|
31
|
+
"asr_cancer_incidence": 18.621130304934443,
|
|
32
|
+
"asr_cancer_mortality": 19.734067713347496,
|
|
33
|
+
"new_vaccinated": 99738.90625,
|
|
34
|
+
"cum_vaccinated": 1371409.9609375,
|
|
35
|
+
"new_doses": 99738.90625,
|
|
36
|
+
"cum_doses": 1408812.05078125,
|
|
37
|
+
"new_txvx_doses": 12327728.0,
|
|
38
|
+
"new_tx_vaccinated": 11900097.25,
|
|
39
|
+
"cum_txvx_doses": 12327728.0,
|
|
40
|
+
"cum_tx_vaccinated": 11900097.25,
|
|
41
|
+
"new_screens": 2580744.5,
|
|
42
|
+
"new_screened": 2515914.125,
|
|
43
|
+
"new_cin_treatments": 0.0,
|
|
44
|
+
"new_cin_treated": 0.0,
|
|
45
|
+
"new_cancer_treatments": 0.0,
|
|
46
|
+
"new_cancer_treated": 0.0,
|
|
47
|
+
"cum_screens": 2580744.5,
|
|
48
|
+
"cum_screened": 2515914.125,
|
|
49
|
+
"cum_cin_treatments": 0.0,
|
|
50
|
+
"cum_cin_treated": 0.0,
|
|
51
|
+
"cum_cancer_treatments": 0.0,
|
|
52
|
+
"cum_cancer_treated": 0.0,
|
|
53
|
+
"cancer_mortality": 14.189253574665305,
|
|
54
|
+
"n_alive": 306995072.0,
|
|
55
|
+
"cdr": 0.00980348472824997,
|
|
56
|
+
"cbr": 0.025869178015013868,
|
|
57
|
+
"hpv_prevalence": 0.10659968509201347,
|
|
58
|
+
"precin_prevalence": 0.040668902998381044,
|
|
59
|
+
"cin_prevalence": 0.019664635869021486
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"time": {
|
|
3
|
-
"initialize": 0.
|
|
4
|
-
"run": 1.
|
|
3
|
+
"initialize": 0.011,
|
|
4
|
+
"run": 1.078
|
|
5
5
|
},
|
|
6
6
|
"parameters": {
|
|
7
7
|
"n_agents": 10000,
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
"n_interventions": 7,
|
|
11
11
|
"n_analyzers": 0
|
|
12
12
|
},
|
|
13
|
-
"cpu_performance": 0.
|
|
13
|
+
"cpu_performance": 0.5786863801131209
|
|
14
14
|
}
|