-
Notifications
You must be signed in to change notification settings - Fork 8
New distributions code moved down into emod-api from emodpy (Fix #50, was issue 43 in emodpy previously) #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
204d0be
fixing up distribution tests from emodpy
ckirkman-IDM 9428b2d
Fixing up IndividualProperties to properly handle a None (no IPs) con…
ckirkman-IDM 119abee
Big cleanup, removed demog templates, old dist objs, reenabling from_…
ckirkman-IDM 0ace70b
restoring migration tests after having restored demog,from_file(). Re…
ckirkman-IDM a2cb1c8
doc fixes and linting
ckirkman-IDM d080adf
Demographics.from_file() now sets implicit functions on its return ob…
ckirkman-IDM f30e770
merging from mercury
ckirkman-IDM 7125f4e
fixing minor merge error, param rename
ckirkman-IDM 7b4948a
Merge branch 'mercury' into 43
ckirkman-IDM 6eb5668
linting
ckirkman-IDM d680a0f
Simplify schema processing of interventions; add tests (#49)
kfrey-idm ae4a61e
Bump version: 2.0.36 → 2.0.37
a93ee9e
added google tag manager for analytics tracking (#53)
JSchripsema-IDM fcfa59a
removing ability to pass in unverified metadata to demographics objec…
ckirkman-IDM 3c582dd
minor file_name -> filename usage homogenization
ckirkman-IDM dbebc43
Change tracking_id to property in mkdocs.yml (#54)
JSchripsema-IDM 43703f8
adding note that susceptibility distributions are not compatible with…
ckirkman-IDM 381c0ab
adding note that susceptibility distributions are not compatible with…
ckirkman-IDM 186f242
removing e.g. usage
ckirkman-IDM c5c159b
minor doc update
ckirkman-IDM b68ae0f
distribution explanatory note
ckirkman-IDM 8ab7f4e
minor comment fix
ckirkman-IDM 71f93ac
cleanup of cruft and a touch of named parameters for clarity
ckirkman-IDM 5837553
Clean up docs (#56)
kfrey-idm 167b65c
Bump version: 2.0.37 → 2.0.38
568cb5c
demographics.to_file() indent is now optional, where None means one-l…
ckirkman-IDM 4d420d1
adding Path to demographics.to_file() type hinting
ckirkman-IDM ab49bbe
review updates
ckirkman-IDM eded5d2
changing Demgoraphics.from_file() to use 'r' reading instead of 'rb'.…
ckirkman-IDM 9028fd0
further extending Demographics.from_file() warning
ckirkman-IDM d9b7252
Updating review comments related to hiv/malaria only comment sections…
ckirkman-IDM e17b450
Setting both a simple and complex distribution for those that allow e…
ckirkman-IDM 5b4cc8f
final cleanup from review comments
ckirkman-IDM de9668c
linting
ckirkman-IDM 2e97a01
Merge branch 'main' into mercury
ckirkman-IDM dbe35d3
Merge branch 'mercury' into 43
ckirkman-IDM File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| [emodpy]: https://docs.idmod.org/projects/emodpy/en/latest/index.html | ||
| [idmtools]: https://docs.idmod.org/projects/idmtools/en/latest/index.html | ||
| [emodpy]: https://docs.idmod.org/projects/emodpy/ | ||
| [emod-api]: https://docs.idmod.org/projects/emod-api/ | ||
| [idmtools]: https://docs.idmod.org/projects/idmtools/ | ||
| [emod-generic]: https://docs.idmod.org/projects/emod-generic/en/latest/parameter-overview.html | ||
| [idmod]: https://www.idmod.org/ | ||
| [idm_pypi]: https://packages.idmod.org/ |
21 changes: 21 additions & 0 deletions
21
docs/customization/overrides/partials/integrations/analytics/custom.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| {# page partial for GTM analytics code, extends "!page.html" | ||
| #} | ||
|
|
||
| {% block extrahead %} | ||
|
|
||
| <!-- Google Tag Manager --> | ||
| <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': | ||
| new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], | ||
| j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= | ||
| 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); | ||
| })(window,document,'script','dataLayer','GTM-NK4K647');</script> | ||
| <!-- End Google Tag Manager --> | ||
|
|
||
| <!-- Google Tag Manager (noscript) --> | ||
| <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NK4K647" | ||
| height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> | ||
| <!-- End Google Tag Manager (noscript) --> | ||
|
|
||
| <meta name="google-site-verification" content="L6w2tbHp4xFTm04T0CdrrzqX_T9PH-bpQnGGYuwuAE4" /> | ||
|
|
||
| {% endblock %} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| import math | ||
| import numpy as np | ||
| import pandas as pd | ||
| import os | ||
|
|
||
| from scipy import sparse as sp | ||
| from scipy.sparse import linalg as la | ||
| from typing import Union | ||
|
|
||
| from emod_api.demographics.age_distribution import AgeDistribution | ||
| from emod_api.demographics.mortality_distribution import MortalityDistribution | ||
|
|
||
|
|
||
| def generate_equilibrium_age_distribution(birth_rate: float = 40.0, mortality_rate: float = 20.0) -> AgeDistribution: | ||
| """ | ||
| Create an AgeDistribution object representing an equilibrium for birth and mortality rates. | ||
|
|
||
| Args: | ||
| birth_rate: (float) The birth rate in units of births/year/1000-women | ||
| mortality_rate: (float) The mortality rate in units of deaths/year/1000 people | ||
|
|
||
| Returns: | ||
| an AgeDistribution object | ||
| """ | ||
| from emod_api.demographics.age_distribution import AgeDistribution | ||
|
|
||
| # convert to daily rate per person, EMOD units | ||
| birth_rate = (birth_rate / 1000) / 365 # what is actually used below | ||
| mortality_rate = (mortality_rate / 1000) / 365 # what is actually used below | ||
|
|
||
| birth_rate = math.log(1 + birth_rate) | ||
| mortality_rate = -1 * math.log(1 - mortality_rate) | ||
|
|
||
| # It is important for the age distribution computation that the age-spacing be very fine; I've used 30 days here. | ||
| # With coarse spacing, the computation in practice doesn't work as well. | ||
| age_dist_tuple = _computeAgeDist(birth_rate, [i * 30 for i in range(1200)], 1200 * [mortality_rate], 12 * [1.0]) | ||
|
|
||
| # The final demographics file, though, can use coarser binning interpolated from the finely-spaced computed distribution. | ||
| age_bins = list(range(16)) + [20 + 5 * i for i in range(14)] | ||
| cum_pop_fraction = np.interp(age_bins, [i / 365 for i in age_dist_tuple[2]], age_dist_tuple[1]).tolist() | ||
| age_bins.extend([90]) | ||
| cum_pop_fraction.extend([1.0]) | ||
| distribution = AgeDistribution(ages_years=age_bins, cumulative_population_fraction=cum_pop_fraction) | ||
| return distribution | ||
|
|
||
|
|
||
| def _computeAgeDist(bval, mvecX, mvecY, fVec, max_yr=90): | ||
| """ | ||
| Compute equilibrium age distribution given age-specific mortality and crude birth rates | ||
|
|
||
| Args: | ||
| bval: crude birth rate in births per day per person | ||
| mvecX: list of age bins in days | ||
| mvecY: List of per day mortality rate for the age bins | ||
| fVec: Seasonal forcing per month | ||
| max_yr : maximum agent age in years | ||
|
|
||
| returns EquilibPopulationGrowthRate, MonthlyAgeDist, MonthlyAgeBins | ||
| author: Kurt Frey | ||
| """ | ||
|
|
||
| bin_size = 30 | ||
| day_to_year = 365 | ||
|
|
||
| # Age brackets | ||
| avecY = np.arange(0, max_yr * day_to_year, bin_size) - 1 | ||
|
|
||
| # Mortality sampling | ||
| mvecX = [-1] + mvecX + [max_yr * day_to_year + 1] | ||
| mvecY = [mvecY[0]] + mvecY + [mvecY[-1]] | ||
| mX = np.arange(0, max_yr * day_to_year, bin_size) | ||
| mX[0] = 1 | ||
| mval = 1.0 - np.interp(mX, xp=mvecX, fp=mvecY) | ||
| r_n = mval.size | ||
|
|
||
| # Matrix construction | ||
| BmatRC = (np.zeros(r_n), np.arange(r_n)) | ||
| Bmat = sp.csr_matrix(([bval * bin_size] * r_n, BmatRC), shape=(r_n, r_n)) | ||
| Mmat = sp.spdiags(mval[:-1] ** bin_size, -1, r_n, r_n) | ||
| Dmat = Bmat + Mmat | ||
|
|
||
| # Math | ||
| (gR, popVec) = la.eigs(Dmat, k=1, sigma=1.0) | ||
| gR = np.abs(gR ** (float(day_to_year) / float(bin_size))) | ||
| popVec = np.abs(popVec) / np.sum(np.abs(popVec)) | ||
|
|
||
| # Apply seasonal forcing | ||
| mVecR = [-2.0, 30.5, 30.6, 60.5, 60.6, 91.5, 91.6, 121.5, | ||
| 121.6, 152.5, 152.6, 183.5, 183.6, 213.5, 213.6, 244.5, | ||
| 245.6, 274.5, 274.6, 305.5, 305.6, 333.5, 335.6, 364.5] | ||
| fVec = np.flipud([val for val in fVec for _ in (0, 1)]) | ||
| wfVec = np.array([np.mean(np.interp(np.mod(range(val + 1, val + 31), 365), | ||
| xp=mVecR, fp=fVec)) for val in avecY]).reshape(-1, 1) | ||
| popVec = popVec * wfVec / np.sum(popVec * wfVec) | ||
|
|
||
| # Age sampling | ||
| avecY[0] = 0 | ||
| avecX = np.clip(np.around(np.cumsum(popVec), decimals=7), 0.0, 1.0) | ||
| avecX = np.insert(avecX, 0, np.zeros(1)) | ||
|
|
||
| return gR.tolist()[0], avecX[:-1].tolist(), avecY.tolist() | ||
|
|
||
|
|
||
| def generate_mortality_over_time_from_data(data_csv: Union[str, os.PathLike], | ||
| base_year: int) -> MortalityDistribution: | ||
| """ | ||
| Generate a MortalityDistribution object from a data csv file. | ||
|
|
||
| Args: | ||
| data_csv: Path to csv file with the mortality rates by calendar year and age bucket. | ||
| base_year: The calendar year the sim is treating as the base. | ||
|
|
||
| Returns: | ||
| a MortalityDistribution object. | ||
| """ | ||
| if base_year < 0: | ||
| raise ValueError(f"User passed negative value of base_year: {base_year}.") | ||
| if base_year > 2050: | ||
| raise ValueError(f"User passed too large value of base_year: {base_year}.") | ||
|
|
||
| # Load csv. Convert rate arrays into DTK-compatiable JSON structures. | ||
| rates = [] # array of arrays, but leave that for a minute | ||
| df = pd.read_csv(data_csv) | ||
| header = df.columns | ||
| year_start = int(header[1]) # someone's going to come along with 1990.5, etc. Sigh. | ||
| year_end = int(header[-1]) | ||
| if year_end <= year_start: | ||
| raise ValueError(f"Failed check that {year_end} is greater than {year_start} in csv dataset.") | ||
| num_years = year_end - year_start + 1 | ||
| rel_years = list() | ||
| for year in range(year_start, year_start + num_years): | ||
| mort_data = list(df[str(year)]) | ||
| rel_years.append(year - base_year) | ||
|
|
||
| age_key = None | ||
| for trykey in df.keys(): | ||
| if trykey.lower().startswith("age"): | ||
| age_key = trykey | ||
| raw_age_bins = list(df[age_key]) | ||
|
|
||
| if age_key is None: | ||
| raise ValueError("Failed to find 'Age_Bin' (or similar) column in the csv dataset. Cannot process.") | ||
|
|
||
| age_bins = list() | ||
| try: | ||
| for age_bin in raw_age_bins: | ||
| left_age = float(age_bin.split("-")[0]) | ||
| age_bins.append(left_age) | ||
|
|
||
| except Exception as ex: | ||
| raise ValueError(f"Ran into error processing the values in the Age-Bin column. {ex}") | ||
|
|
||
| for idx in range(len(age_bins)): # 18 of these | ||
| # mort_data is the array of mortality rates (by year bin) for age_bin | ||
| mort_data = list(df.transpose()[idx][1:]) | ||
| rates.append(mort_data) # 28 of these, 1 for each year, eg | ||
|
|
||
| distribution = MortalityDistribution(ages_years=age_bins, mortality_rate_matrix=rates, calendar_years=rel_years) | ||
| return distribution |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.