Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

313 lines (277 sloc) 13.858 kb
from safe.impact_functions.core import (FunctionProvider,
get_hazard_layer,
get_exposure_layer,
get_question,
format_int)
from safe.storage.vector import Vector
from safe.storage.utilities import DEFAULT_ATTRIBUTE
from safe.common.utilities import ugettext as tr
from safe.common.tables import Table, TableRow
from safe.engine.interpolation import assign_hazard_values_to_exposure_data
import logging
LOGGER = logging.getLogger('InaSAFE')
class FloodBuildingImpactFunction(FunctionProvider):
"""Inundation impact on building data
:author Ole Nielsen, Kristy van Putten
# this rating below is only for testing a function, not the real one
:rating 0
:param requires category=='hazard' and \
subcategory in ['flood', 'tsunami']
:param requires category=='exposure' and \
subcategory=='structure' and \
layertype=='vector'
"""
# Function documentation
target_field = 'INUNDATED'
title = tr('Be flooded')
synopsis = tr('To assess the impacts of inundation on building footprints '
'originating from OpenStreetMap (OSM).')
actions = tr('Provide details about where critical response areas are')
# citations must be a list
citations = [tr('Hutchings, Field & Parks. Assessment of Flood impacts on '
'buildings. Impact. Vol 66(2). 2012')]
detailed_description = tr('This is an area for free form text where a'
'detailed description of the methodology used is given.')
permissible_hazard_input = tr('A raster layer where each cell represents '
'flood depth, or a vector polygon layer where each polygon represents '
'an inundated area. The following attributes are recognised '
'(in order): Flooded (True or False), FLOODPRONE (Yes or No) and '
'Affected (True or False).')
permissible_exposure_input = tr('vector polygon layer extracted from OSM '
'where each polygon represents the footprint of a building.')
limitation = tr('Lorem ipsum limitation')
def run(self, layers):
"""Flood impact to buildings (e.g. from Open Street Map)
"""
threshold = 1.0 # Flood threshold [m]
# Extract data
H = get_hazard_layer(layers) # Depth
E = get_exposure_layer(layers) # Building locations
question = get_question(H.get_name(),
E.get_name(),
self)
# Determine attribute name for hazard levels
if H.is_raster:
mode = 'grid'
hazard_attribute = 'depth'
else:
mode = 'regions'
hazard_attribute = None
# Interpolate hazard level to building locations
I = assign_hazard_values_to_exposure_data(H, E,
attribute_name=hazard_attribute)
# Extract relevant exposure data
attribute_names = I.get_attribute_names()
attributes = I.get_data()
N = len(I)
# Calculate building impact
count = 0
buildings = {}
affected_buildings = {}
for i in range(N):
if mode == 'grid':
# Get the interpolated depth
x = float(attributes[i]['depth'])
x = x >= threshold
elif mode == 'regions':
# Use interpolated polygon attribute
atts = attributes[i]
# FIXME (Ole): Need to agree whether to use one or the
# other as this can be very confusing!
# For now look for 'affected' first
if 'affected' in atts:
# E.g. from flood forecast
# Assume that building is wet if inside polygon
# as flagged by attribute Flooded
res = atts['affected']
if res is None:
x = False
else:
x = bool(res)
#if x:
# print 'Got affected', x
elif 'FLOODPRONE' in atts:
res = atts['FLOODPRONE']
if res is None:
x = False
else:
x = res.lower() == 'yes'
elif DEFAULT_ATTRIBUTE in atts:
# Check the default attribute assigned for points
# covered by a polygon
res = atts[DEFAULT_ATTRIBUTE]
if res is None:
x = False
else:
x = res
else:
# there is no flood related attribute
msg = ('No flood related attribute found in %s. '
'I was looking for either "affected", "FLOODPRONE" '
'or "inapolygon". The latter should have been '
'automatically set by call to '
'assign_hazard_values_to_exposure_data(). '
'Sorry I can\'t help more.')
raise Exception(msg)
else:
msg = (tr('Unknown hazard type %s. '
'Must be either "depth" or "grid"')
% mode)
raise Exception(msg)
# Count affected buildings by usage type if available
if 'type' in attribute_names:
usage = attributes[i]['type']
else:
usage = None
if 'amenity' in attribute_names and (usage is None or usage == 0):
usage = attributes[i]['amenity']
if 'building_t' in attribute_names and (usage is None
or usage == 0):
usage = attributes[i]['building_t']
if 'office' in attribute_names and (usage is None or usage == 0):
usage = attributes[i]['office']
if 'tourism' in attribute_names and (usage is None or usage == 0):
usage = attributes[i]['tourism']
if 'leisure' in attribute_names and (usage is None or usage == 0):
usage = attributes[i]['leisure']
if 'building' in attribute_names and (usage is None or usage == 0):
usage = attributes[i]['building']
if usage == 'yes':
usage = 'building'
#LOGGER.debug('usage ')
if usage is not None and usage != 0:
key = usage
else:
key = 'unknown'
if key not in buildings:
buildings[key] = 0
affected_buildings[key] = 0
# Count all buildings by type
buildings[key] += 1
if x is True:
# Count affected buildings by type
affected_buildings[key] += 1
# Count total affected buildings
count += 1
# Add calculated impact to existing attributes
attributes[i][self.target_field] = x
# Lump small entries and 'unknown' into 'other' category
for usage in buildings.keys():
x = buildings[usage]
if x < 25 or usage == 'unknown':
if 'other' not in buildings:
buildings['other'] = 0
affected_buildings['other'] = 0
buildings['other'] += x
affected_buildings['other'] += affected_buildings[usage]
del buildings[usage]
del affected_buildings[usage]
# Generate csv file of results
## fid = open('C:\dki_table_%s.csv' % H.get_name(), 'wb')
## fid.write('%s, %s, %s\n' % (tr('Building type'),
## tr('Temporarily closed'),
## tr('Total')))
## fid.write('%s, %i, %i\n' % (tr('All'), count, N))
# Generate simple impact report
table_body = [question,
TableRow([tr('Building type'),
tr('Number flooded'),
tr('Total')],
header=True),
TableRow([tr('All'), format_int(count), format_int(N)])]
## fid.write('%s, %s, %s\n' % (tr('Building type'),
## tr('Temporarily closed'),
## tr('Total')))
school_closed = 0
hospital_closed = 0
# Generate break down by building usage type is available
list_type_attribute = ['type',
'amenity',
'building_t',
'office',
'tourism',
'leisure',
'building']
intersect_type = set(attribute_names) & set(list_type_attribute)
if len(intersect_type) > 0:
# Make list of building types
building_list = []
for usage in buildings:
building_type = usage.replace('_', ' ')
# Lookup internationalised value if available
building_type = tr(building_type)
#==============================================================
# print ('WARNING: %s could not be translated'
# % building_type)
#==============================================================
# FIXME (Sunni) : I change affected_buildings[usage] to string
# because it will be replace with &nbsp in html
building_list.append([building_type.capitalize(),
format_int(affected_buildings[usage]),
format_int(buildings[usage])])
if building_type == 'school':
school_closed = affected_buildings[usage]
if building_type == 'hospital':
hospital_closed = affected_buildings[usage]
## fid.write('%s, %i, %i\n' % (building_type.capitalize(),
## affected_buildings[usage],
## buildings[usage]))
# Sort alphabetically
building_list.sort()
#table_body.append(TableRow([tr('Building type'),
# tr('Temporarily closed'),
# tr('Total')], header=True))
table_body.append(TableRow(tr('Breakdown by building type'),
header=True))
for row in building_list:
s = TableRow(row)
table_body.append(s)
## fid.close()
table_body.append(TableRow(tr('Action Checklist:'), header=True))
table_body.append(TableRow(tr('Are the critical facilities still '
'open?')))
table_body.append(TableRow(tr('Which structures have warning capacity '
'(eg. sirens, speakers, etc.)?')))
table_body.append(TableRow(tr('Which buildings will be evacuation '
'centres?')))
table_body.append(TableRow(tr('Where will we locate the operations '
'centre?')))
table_body.append(TableRow(tr('Where will we locate warehouse and/or '
'distribution centres?')))
if school_closed > 0:
table_body.append(TableRow(tr('Where will the students from the %s'
' closed schools go to study?') %
format_int(school_closed)))
if hospital_closed > 0:
table_body.append(TableRow(tr('Where will the patients from the %s'
' closed hospitals go for treatment '
'and how will we transport them?') %
format_int(hospital_closed)))
table_body.append(TableRow(tr('Notes'), header=True))
assumption = tr('Buildings are said to be flooded when ')
if mode == 'grid':
assumption += tr('flood levels exceed %.1f m') % threshold
else:
assumption += tr('in regions marked as affected')
table_body.append(assumption)
impact_summary = Table(table_body).toNewlineFreeString()
impact_table = impact_summary
map_title = tr('Buildings inundated')
# Create style
style_classes = [dict(label=tr('Not Flooded'), min=0, max=0,
colour='#1EFC7C', transparency=0, size=1),
dict(label=tr('Flooded'), min=1, max=1,
colour='#F31A1C', transparency=0, size=1)]
style_info = dict(target_field=self.target_field,
style_classes=style_classes)
# Create vector layer and return
V = Vector(data=attributes,
projection=I.get_projection(),
geometry=I.get_geometry(),
name=tr('Estimated buildings affected'),
keywords={'impact_summary': impact_summary,
'impact_table': impact_table,
'map_title': map_title,
'target_field': self.target_field},
style_info=style_info)
return V
Jump to Line
Something went wrong with that request. Please try again.