CLIMADA-project / climada_python

Python (3.8+) version of CLIMADA
GNU General Public License v3.0
311 stars 122 forks source link

Disaggregate LitPop values to custom shapes/regions #715

Closed peanutfun closed 1 year ago

peanutfun commented 1 year ago

I am using the LitPop module to create exposure data of population (fin_mode="pop") in Pakistan. The GPW dataset on Pakistan apparently reports constant values for every Admin2 region. This resolution is too coarse for my river flood impact model. Therefore, I want to use the nightlight intensity to adjust the population density on the regional level. However, LitPop disaggregates on the country-level. This means that the total population for each Admin2 region is heavily distorted if the exponent for nightlight intensity is not ~0. I want LitPop to adjust the local population density according to the nightlight intensity, while keeping the total population on the Admin2 level constant.

I would like to add an option to the LitPop.from_countries classmethod to add custom aggregation regions. This information can simply be supplied via a geopandas.GeoSeries. For fin_mode="pop", the algorithm then does not compute the total value per country, but for each geometry in the GeoSeries, and disaggregates on this level. This is similar to the current admin1 parameter, just with custom geometries.

peanutfun commented 1 year ago

I found a workaround with the current set of methods. Its only issue is that it has to execute the LitPop creation algorithm twice, which means double the runtime although both calls query the same information. Here's how it works:

from climada.entity.exposures import LitPop

shapes = [...]  # Any list of shapes for which you want the population to remain constant

# Calculate the total population for each shape
total_values = [
    LitPop.from_shape(shape, exponents=(0, 1), total_value=None).gdf["value"].sum() for shape in shapes
]

# Plug that into the actual exposure calculation
exp = LitPop.concat([
    LitPop.from_shape(shape, exponents=(1, 1), total_value=val) for val, shape in zip(total_values, shapes)
])