import pandas as pd
import numpy as np
import json
import os
#from emod_api.demographics.Demographics import Demographics, Node, from_csv
import emod_api.demographics.Demographics as Demog
[docs]class TBHIVDemographics(Demog.Demographics):
"""
This class is derived from emod_api.demographics' Demographics class so that we can set
certain defaults for TBHIV in construction. Keen observers will note thatt SetDefaultProperties
does not look like a TBHIV-specific function. But as we add other disease types the
generatlizations and speicfics will become clearer. The architectural point is solid.
"""
def __init__(self, pop=None, nodes=None, idref="Gridded world grump2.5arcmin", base_file=None):
# if nodes are specified pop not used
if nodes is None:
nodes = [ Demog.Node( pop=pop, lat=0, lon=0, forced_id=1 ) ]
super().__init__( nodes, idref=idref )
super().SetDefaultNodeAttributes()
self.SetHIVCoInfectionDistribution()
self.SetHIVTBCoInfectionMortalityDistribution()
self.SetHeteroRiskUniformDist( 1.0, 1.0 ) # Uniform from 1 to 1 is a way of saying 1. emod-api doesnot
[docs] def SetHIVCoInfectionDistribution( self ):
"""
Insert some notion of a default HIVCoInfection distribution.
"""
default_hivco = { "HIVCoinfectionDistribution":
{
"NumDistributionAxes": 3,
"AxisNames": [ "gender", "time", "age" ],
"AxisUnits": [ "male =0, female=1", "years", "years" ],
"AxisScaleFactors": [ 1, 365, 365 ],
"NumPopulationGroups": [ 2, 3, 4 ],
"PopulationGroups":
[
[ 0, 1 ],
[ 0, 50, 100],
[ 0, 15, 35, 50]
],
"ResultUnits": "Probability of HIV infection per repetition of HIV Outbreak",
"ResultScaleFactor": 0.019199999999999998,
"ResultValues":
[
[
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]
],
[
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]
]
]
}
}
self.raw['Defaults']['IndividualAttributes'].update(
default_hivco
)
[docs] def SetHIVTBCoInfectionMortalityDistribution( self ):
"""
Insert some notion of a default HIVTBCoInfection Mortality distribution.
"""
default_setting = {
"HIVTBCoinfMortalityDistribution": {
"AxisNames": [
"age",
"year"
],
"AxisScaleFactors": [
365,
1
],
"AxisUnits": [
"years",
"years"
],
"NumDistributionAxes": 2,
"NumPopulationGroups": [
2,
1
],
"PopulationGroups": [
[
0,
15
],
[
0
]
],
"ResultScaleFactor": 2.739726027397e-06,
"ResultUnits": "annual deaths per 1000 individuals",
"ResultValues": [
[
14
],
[
14
]
]
}
}
self.raw['Defaults']['IndividualAttributes'].update(
default_setting
)
#
# 'STATIC' instantiator functions that are really module functions
#
[docs]def fromBasicNode(lat=0, lon=0, pop=1e6, name=1, forced_id=1, implicit_config_fns = None ):
"""
This function creates a single-node TBHIVDemographics instance from the params you give it.
"""
new_nodes = [ Demog.Node(lat=lat, lon=lon, pop=pop, name=name, forced_id=forced_id) ]
return TBHIVDemographics(pop=pop, nodes=new_nodes )
[docs]def from_template_node(lat=0, lon=0, pop=1e6, name=1, forced_id=1 ):
"""
Create a single-node :py:class:`~emodpy_tbhiv.demographics.TBHIVDemographics`
instance from the parameters you supply.
Args:
lat: Latitude of the centroid of the node to create.
lon: Longitude of the centroid of the node to create.
pop: Human population of the node.
name: The name of the node. This may be a characteristic of the
node, such as "rural" or "urban", or an identifying integer.
forced_id: The node ID for the single node.
Returns:
A :py:class:`~emodpy_tbhiv.demographics.TBHIVDemographics` instance.
"""
return fromBasicNode( lat, lon, pop, name, forced_id )
[docs]def fromData( pop=1e6, filename_male=None, filename_female=None ):
# User variables where to start extrapolation (ie before HIV epidemic) and how far to look back
# All in years unless noted otherwise
extrap_point = 1980
look_back = 20
time_horizon = 2100
now_ish = 1980
look_back_from_now_ish = 20
interval_for_fitting_regression = [1970, 1980]
predict_horizons = 2050
# This is all you need to use here (Note you prob want to override the default on extrapolation
myob = TBHIVDemographics( pop )
if filename_male and filename_female:
myob.infer_natural_mortality( filename_male, filename_female, interval_for_fitting_regression)
else:
print( "Natural mortality data not provided." )
#myob.generate_file( name='Output_demog.json' )
return myob
[docs]def from_csv(pop_file, res=30/3600, id_ref="from_csv", filename_male=None, filename_female=None):
"""
Create a multi-node :py:class:`~emodpy_tbhiv.demographics.TBHIVDemographics`
instance from a CSV file describing a population.
Args:
pop_file: The path to the csv file to ingest.
res: Resolution.
id_ref: A string to identify the file, needs to match other input files.
filename_male: Path to male mortality csv.
filename_female: Path to female mortality csv.
Returns:
A :py:class:`~emodpy_tbhiv.demographics.TBHIVDemographics` instance
"""
if os.path.exists( pop_file ) == False:
raise ValueError( f"Can't find input data file {pop_file}" )
generic_demog = Demog.from_csv( pop_file, res, id_ref )
nodes = generic_demog._nodes
demog = TBHIVDemographics(nodes=nodes, idref=id_ref)
if filename_male and filename_female:
interval_for_fitting_regression = [1970, 1980]
demog.infer_natural_mortality( filename_male, filename_female, interval_for_fitting_regression)
else:
print( "Natural mortality data not provided." )
return demog
[docs]def from_params(tot_pop=1e6, num_nodes=100, frac_rural=0.3, id_ref="from_params", filename_male=None, filename_female=None):
"""
Create a multi-node :py:class:`~emodpy_tbhiv.demographics.TBHIVDemographics`
instance as a synthetic population based on a few parameters.
Args:
tot_pop: The total human population in the node.
num_nodes: The number of nodes to create.
frac_rural: The fraction of the population that is rural.
id_ref: Method describing how the latitude and longitude values are created
for each of the nodes in a simulation. "Gridded world" values use a grid
overlaid across the globe at some arcsec resolution. You may also generate
the grid using another tool or coordinate system. For more information,
see :ref:`emod-tbhiv:demo-metadata`.
filename_male: Path to male mortality csv.
filename_female: Path to female mortality csv.
Returns:
A :py:class:`~emodpy_tbhiv.demographics.TBHIVDemographics` instance.
"""
generic_demog = Demog.from_params(tot_pop, num_nodes, frac_rural, id_ref)
nodes = generic_demog.nodes
demog = TBHIVDemographics(nodes=nodes, idref=id_ref )
if filename_male and filename_female:
interval_for_fitting_regression = [1970, 1980]
demog.infer_natural_mortality(filename_male, filename_female, interval_for_fitting_regression)
else:
print( "Natural mortality data not provided." )
return demog