diff --git a/exposureinitializer/exposureinitializer.py b/exposureinitializer/exposureinitializer.py index 2295a8a0439dbd9eb930969f3922120606f9581a..66753ab8164293d77023ada78acda6bd0eb24d87 100644 --- a/exposureinitializer/exposureinitializer.py +++ b/exposureinitializer/exposureinitializer.py @@ -215,60 +215,71 @@ class ExposureInitializer: Dictionary of asset values """ - # Get all tiles within the boundary, estimate their built_area proportion and - # create the EntityReference and AssetReference datasets - # Query explanation: Subquery `A` selects all tiles and is joined with subquery `B` - # selecting the boundary, resulting in subquery `T` delivering all tiles for which the - # centroid is located within the boundary. This subquery `T` is then used twice, first - # in subquery `SumQuery` to estimate the sum of the built-area and the cross-joined - # query retrieving the built-area size per tile to compute the built-area proportion. + # Define the basic part of the queries to estimate the built-area proportion of all + # tiles within a boundary to create the EntityReference and AssetReference datasets. + # Query explanation: Subquery `SelectedTiles` selects all tiles and is joined with + # subquery `SelectedBoundary` selecting the boundary, resulting in delivering all tiles + # for which the centroid is located within the boundary. This basic part of the query is + # used twice, first to calculate the sum of the built-area and then to retrieve the + # built-area size per tile (later turned into built-area proportion). if isinstance(self.exposure_db, SpatiaLiteExposure): - where_clause = "WHERE built_area_size IS NOT NULL AND built_area_size > 0" + where_clause = "WHERE built_area_size IS NOT NULL" else: where_clause = """ - WHERE A.geometry && B.border AND built_area_size IS NOT NULL - AND built_area_size > 0 + WHERE SelectedTiles.geometry && SelectedBoundary.border + AND built_area_size IS NOT NULL """ - sql_statement = f""" - WITH T AS + basic_sql_statement = f""" + FROM ( - SELECT quadkey, built_area_size - FROM - ( - SELECT quadkey, built_area_size, country_iso_code, - {self.exposure_db.geometry_field} - FROM {self.exposure_db.tile_view} - ) AS A - INNER JOIN - ( - SELECT {self.exposure_db.geometry_field} AS border - FROM {self.exposure_db.boundary_table} - WHERE {self.exposure_db.boundary_id_field}= '{boundary_id}' - ) AS B - ON ST_Contains(B.border, ST_Centroid(A.{self.exposure_db.geometry_field})) - {where_clause} - ) - SELECT T.quadkey, T.built_area_size/SumQuery.total_sum as proportion - FROM T - CROSS JOIN + SELECT quadkey, built_area_size, {self.exposure_db.geometry_field} + FROM {self.exposure_db.tile_view} + ) AS SelectedTiles + INNER JOIN ( - SELECT SUM(T.built_area_size) as total_sum FROM T - ) AS SumQuery + SELECT {self.exposure_db.geometry_field} AS border + FROM {self.exposure_db.boundary_table} + WHERE {self.exposure_db.boundary_id_field} = '{boundary_id}' + ) AS SelectedBoundary + ON ST_Contains( + SelectedBoundary.border, + ST_Centroid(SelectedTiles.{self.exposure_db.geometry_field}) + ) + {where_clause} + """ + + # Calculate the total built area of the district + sql_statement = f""" + SELECT SUM(built_area_size) AS total_built_area + {basic_sql_statement} """ self.exposure_db.cursor.execute(sql_statement) - tiles = self.exposure_db.cursor.fetchall() - if len(tiles) == 0: + query_result = self.exposure_db.cursor.fetchone() + if query_result is None: + logger.warning(f"District {boundary_id} contains no tiles.") + return + total_built_area = query_result[0] + if total_built_area == 0: logger.warning(f"District {boundary_id} contains no tiles with built area.") return + # Retrieve all tiles with built area + sql_statement = f""" + SELECT quadkey, built_area_size + {basic_sql_statement} + """ + self.exposure_db.cursor.execute(sql_statement) + tiles = self.exposure_db.cursor.fetchall() + # Add reference entities to all tiles of the district - for quadkey, proportion in tiles: + for quadkey, built_area_size in tiles: # Check if entity exists in EntityReference and create if necessary entity_id = self.exposure_db.get_reference_entity_id(quadkey) if entity_id is None: entity_id = self.exposure_db.insert_reference_entity(quadkey, country_iso_code) # Add the respective assets by proportion of built area to `AssetReference` + proportion = built_area_size / total_built_area reference_assets = [ [ entity_id, @@ -281,7 +292,9 @@ class ExposureInitializer: ] self.exposure_db.insert_reference_assets(reference_assets) self.exposure_db.connection.commit() - logger.info(f"Assets inserted for each tile in district {boundary_id}") + logger.info( + f"{boundary_id}: {len(tiles)} assets inserted, built-area size: {total_built_area}" + ) def import_exposure(self, exposure_model_search_pattern, country_iso_code): """