Skip to content

Using the Loss Calculator

Using the Loss Calculator

This continues from an open connection to your 25.01 sample database, as in Explore Data.

# uncomment to install the packages
# !pip install matplotlib folium mapclassify geopandas
# !pip install exposurelib taxonomylib
# !pip install git+https://git.gfz-potsdam.de/globaldynamicexposure/loss-calculator@docs-patch
from exposurelib import SpatiaLiteExposure
from shapely import from_wkt
import geopandas

Set up the database for calculations

Open a new database connection for the loss calculator's own working database, then copy the 25.01 data it needs into it. db.create_tables() already creates the current entities/assets/entity_assets/taxonomies schema, so this is a straight table-for-table copy — note that sources must be copied too, since entities.source_id has a foreign key to it:

db = SpatiaLiteExposure('data/losscalculator.db')

try:
    db.connect()
    db.create_tables()
    print('attach database')
    db.connection.executescript(
        """
        ATTACH DATABASE 'data/CDMX_2501_sample.db' AS source;
        INSERT INTO taxonomies    SELECT * FROM source.taxonomies;
        INSERT INTO sources       SELECT * FROM source.sources;
        INSERT INTO entities      SELECT * FROM source.entities;
        INSERT INTO assets        SELECT * FROM source.assets;
        INSERT INTO entity_assets SELECT * FROM source.entity_assets;
        """
    )
    db.connection.commit()
    db.close()
except Exception as e:
    print("Delete existing dataset if Integrity Error - InitSpatialMetaData()")
    print(e)

Not fully verified against the loss-calculator package

Everything from here on depends on the external damagecalculator CLI and the loss-calculator package (git+https://.../loss-calculator@docs-patch). The database-copy step above has been run for real against a 25.01 sample and works. Whether the view_damage_tile_1 view (and the SQL the CLI issues internally) has itself been updated for the 25.01 entities/assets/entity_assets schema, rather than the old flat Entity/Asset/Taxonomy tables, still needs confirming by whoever maintains loss-calculator.

Calculate damage loss

!damagecalculator damage \
    -e data/losscalculator.db \
    -f data/fragility_ESRM20_various_IM.xml \
    -g data/ground_motion_field.csv \
    -t data/esrm20_exposure_vulnerability_mapping.csv \
    -S losscalculator
db = SpatiaLiteExposure('data/losscalculator.db')
db.connect()
sql_query = """
    SELECT
        quadkey,
        ST_AsText(geometry),
        no_damage_damage AS no_damage,
        slight_damage,
        moderate_damage,
        extensive_damage,
        complete_damage
    FROM view_damage_tile_1
    """

db.cursor.execute(sql_query)
res = db.cursor.fetchall()

df_dict = {
    "quadkey": [], "geometry": [], "no_damage": [],
    "slight_damage": [], "moderate_damage": [],
    "extensive_damage": [], "complete_damage": [],
}
for quadkey, geom, nd, sd, md, ed, cd in res:
    df_dict["quadkey"].append(quadkey)
    df_dict["geometry"].append(from_wkt(geom))
    df_dict["no_damage"].append(nd)
    df_dict["slight_damage"].append(sd)
    df_dict["moderate_damage"].append(md)
    df_dict["extensive_damage"].append(ed)
    df_dict["complete_damage"].append(cd)

Check results on a map

gdf = geopandas.GeoDataFrame(df_dict, crs='EPSG:4326')
gdf.iloc[:, 2:] = gdf.iloc[:, 2:].round(2)
gdf.explore('slight_damage')

Get descriptive statistics

damage_columns = ["no_damage", "slight_damage", "moderate_damage", "extensive_damage", "complete_damage"]
damage_stats = gdf[damage_columns].describe().T
damage_stats["total"] = gdf[damage_columns].sum()
damage_stats