def run(self, layers=None): """Classified hazard impact to buildings (e.g. from Open Street Map). :param layers: List of layers expected to contain. * hazard: Classified Hazard layer * exposure: Vector layer of structure data on the same grid as hazard """ self.validate() self.prepare(layers) # The 3 classes low_t = self.parameters['low_hazard_class'] medium_t = self.parameters['medium_hazard_class'] high_t = self.parameters['high_hazard_class'] # Extract data hazard = self.hazard # Classified Hazard exposure = self.exposure # Building locations # Determine attribute name for hazard levels if hazard.is_raster: hazard_attribute = 'level' else: hazard_attribute = None interpolated_result = assign_hazard_values_to_exposure_data( hazard, exposure, attribute_name=hazard_attribute, mode='constant') # Extract relevant exposure data attribute_names = interpolated_result.get_attribute_names() attributes = interpolated_result.get_data() buildings_total = len(interpolated_result) # Calculate building impact self.buildings = {} self.affected_buildings = OrderedDict([(tr('High Hazard Class'), {}), (tr('Medium Hazard Class'), {}), (tr('Low Hazard Class'), {})]) for i in range(buildings_total): usage = get_osm_building_usage(attribute_names, attributes[i]) if usage is None or usage == 0: usage = 'unknown' if usage not in self.buildings: self.buildings[usage] = 0 for category in self.affected_buildings.keys(): self.affected_buildings[category][usage] = OrderedDict([ (tr('Buildings Affected'), 0) ]) # Count all buildings by type self.buildings[usage] += 1 attributes[i][self.target_field] = 0 attributes[i][self.affected_field] = 0 level = float(attributes[i]['level']) level = float(numpy_round(level)) if level == high_t: impact_level = tr('High Hazard Class') elif level == medium_t: impact_level = tr('Medium Hazard Class') elif level == low_t: impact_level = tr('Low Hazard Class') else: continue # Add calculated impact to existing attributes attributes[i][self.target_field] = { tr('High Hazard Class'): 3, tr('Medium Hazard Class'): 2, tr('Low Hazard Class'): 1 }[impact_level] attributes[i][self.affected_field] = 1 # Count affected buildings by type self.affected_buildings[impact_level][usage][tr( 'Buildings Affected')] += 1 # Consolidate the small building usage groups < 25 to other self._consolidate_to_other() # Create style style_classes = [ dict(label=tr('High'), value=3, colour='#F31A1C', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Medium'), value=2, colour='#F4A442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Low'), value=1, colour='#EBF442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Not Affected'), value=None, colour='#1EFC7C', transparency=0, size=2, border_color='#969696', border_width=0.2) ] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_table = impact_summary = self.generate_html_report() # For printing map purpose map_title = tr('Buildings affected') legend_units = tr('(Low, Medium, High)') legend_title = tr('Structure inundated status') # Create vector layer and return vector_layer = Vector(data=attributes, projection=exposure.get_projection(), geometry=exposure.get_geometry(), name=tr('Estimated buildings affected'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.affected_field, 'map_title': map_title, 'legend_units': legend_units, 'legend_title': legend_title, 'buildings_total': buildings_total, 'buildings_affected': self.total_affected_buildings }, style_info=style_info) self._impact = vector_layer return vector_layer
def run(self): """Classified hazard impact to buildings (e.g. from Open Street Map). """ self.validate() self.prepare() # Value from layer's keywords # Try to get the value from keyword, if not exist, it will not fail, # but use the old get_osm_building_usage try: structure_class_field = self.exposure.keyword( 'structure_class_field') except KeywordNotFoundError: structure_class_field = None # The 3 classes categorical_hazards = self.parameters['Categorical hazards'].value low_t = categorical_hazards[0].value medium_t = categorical_hazards[1].value high_t = categorical_hazards[2].value # Determine attribute name for hazard levels if self.hazard.layer.is_raster: hazard_attribute = 'level' else: hazard_attribute = None interpolated_result = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=hazard_attribute, mode='constant') # Extract relevant exposure data attribute_names = interpolated_result.get_attribute_names() attributes = interpolated_result.get_data() buildings_total = len(interpolated_result) # Calculate building impact self.buildings = {} self.affected_buildings = OrderedDict([ (tr('High Hazard Class'), {}), (tr('Medium Hazard Class'), {}), (tr('Low Hazard Class'), {}) ]) for i in range(buildings_total): if (structure_class_field and structure_class_field in attribute_names): usage = attributes[i][structure_class_field] else: usage = get_osm_building_usage(attribute_names, attributes[i]) if usage is None or usage == 0: usage = 'unknown' if usage not in self.buildings: self.buildings[usage] = 0 for category in self.affected_buildings.keys(): self.affected_buildings[category][usage] = OrderedDict([ (tr('Buildings Affected'), 0)]) # Count all buildings by type self.buildings[usage] += 1 attributes[i][self.target_field] = 0 attributes[i][self.affected_field] = 0 level = float(attributes[i]['level']) level = float(numpy_round(level)) if level == high_t: impact_level = tr('High Hazard Class') elif level == medium_t: impact_level = tr('Medium Hazard Class') elif level == low_t: impact_level = tr('Low Hazard Class') else: continue # Add calculated impact to existing attributes attributes[i][self.target_field] = { tr('High Hazard Class'): 3, tr('Medium Hazard Class'): 2, tr('Low Hazard Class'): 1 }[impact_level] attributes[i][self.affected_field] = 1 # Count affected buildings by type self.affected_buildings[impact_level][usage][ tr('Buildings Affected')] += 1 # Consolidate the small building usage groups < 25 to other self._consolidate_to_other() # Create style style_classes = [dict(label=tr('High'), value=3, colour='#F31A1C', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Medium'), value=2, colour='#F4A442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Low'), value=1, colour='#EBF442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Not Affected'), value=None, colour='#1EFC7C', transparency=0, size=2, border_color='#969696', border_width=0.2)] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_table = impact_summary = self.html_report() # For printing map purpose map_title = tr('Buildings affected') legend_title = tr('Structure inundated status') legend_units = tr('(Low, Medium, High)') # Create vector layer and return vector_layer = Vector( data=attributes, projection=self.exposure.layer.get_projection(), geometry=self.exposure.layer.get_geometry(), name=tr('Estimated buildings affected'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.affected_field, 'map_title': map_title, 'legend_units': legend_units, 'legend_title': legend_title, 'buildings_total': buildings_total, 'buildings_affected': self.total_affected_buildings}, style_info=style_info) self._impact = vector_layer return vector_layer
def run(self): """Classified hazard impact to buildings (e.g. from Open Street Map). """ self.validate() self.prepare() self.provenance.append_step( 'Calculating Step', 'Impact function is calculating the impact.') # Value from layer's keywords # Try to get the value from keyword, if not exist, it will not fail, # but use the old get_osm_building_usage try: structure_class_field = self.exposure.keyword( 'structure_class_field') except KeywordNotFoundError: structure_class_field = None # The 3 classes categorical_hazards = self.parameters['Categorical hazards'].value low_t = categorical_hazards[0].value medium_t = categorical_hazards[1].value high_t = categorical_hazards[2].value # Determine attribute name for hazard levels if self.hazard.layer.is_raster: hazard_attribute = 'level' else: hazard_attribute = None interpolated_result = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=hazard_attribute, mode='constant') # Extract relevant exposure data attribute_names = interpolated_result.get_attribute_names() attributes = interpolated_result.get_data() buildings_total = len(interpolated_result) # Calculate building impact self.buildings = {} self.affected_buildings = OrderedDict([(tr('High Hazard Class'), {}), (tr('Medium Hazard Class'), {}), (tr('Low Hazard Class'), {})]) for i in range(buildings_total): if (structure_class_field and structure_class_field in attribute_names): usage = attributes[i][structure_class_field] else: usage = get_osm_building_usage(attribute_names, attributes[i]) if usage is None or usage == 0: usage = 'unknown' if usage not in self.buildings: self.buildings[usage] = 0 for category in self.affected_buildings.keys(): self.affected_buildings[category][usage] = OrderedDict([ (tr('Buildings Affected'), 0) ]) # Count all buildings by type self.buildings[usage] += 1 attributes[i][self.target_field] = 0 attributes[i][self.affected_field] = 0 level = float(attributes[i]['level']) level = float(numpy_round(level)) if level == high_t: impact_level = tr('High Hazard Class') elif level == medium_t: impact_level = tr('Medium Hazard Class') elif level == low_t: impact_level = tr('Low Hazard Class') else: continue # Add calculated impact to existing attributes attributes[i][self.target_field] = { tr('High Hazard Class'): 3, tr('Medium Hazard Class'): 2, tr('Low Hazard Class'): 1 }[impact_level] attributes[i][self.affected_field] = 1 # Count affected buildings by type self.affected_buildings[impact_level][usage][tr( 'Buildings Affected')] += 1 # Consolidate the small building usage groups < 25 to other # Building threshold #2468 postprocessors = self.parameters['postprocessors'] building_postprocessors = postprocessors['BuildingType'][0] self.building_report_threshold = building_postprocessors.value[0].value self._consolidate_to_other() # Create style style_classes = [ dict(label=tr('High'), value=3, colour='#F31A1C', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Medium'), value=2, colour='#F4A442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Low'), value=1, colour='#EBF442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Not Affected'), value=None, colour='#1EFC7C', transparency=0, size=2, border_color='#969696', border_width=0.2) ] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_table = impact_summary = self.html_report() # For printing map purpose map_title = tr('Buildings affected') legend_title = tr('Structure inundated status') legend_units = tr('(Low, Medium, High)') extra_keywords = { 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.affected_field, 'map_title': map_title, 'legend_units': legend_units, 'legend_title': legend_title, 'buildings_total': buildings_total, 'buildings_affected': self.total_affected_buildings } self.set_if_provenance() impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return vector_layer = Vector(data=attributes, projection=self.exposure.layer.get_projection(), geometry=self.exposure.layer.get_geometry(), name=tr('Estimated buildings affected'), keywords=impact_layer_keywords, style_info=style_info) self._impact = vector_layer return vector_layer
def run(self, layers): """Classified hazard impact to buildings (e.g. from Open Street Map). :param layers: List of layers expected to contain. * hazard: Classified Hazard layer * exposure: Vector layer of structure data on the same grid as hazard """ # The 3 classes low_t = self.parameters['low_hazard_class'] medium_t = self.parameters['medium_hazard_class'] high_t = self.parameters['high_hazard_class'] # Extract data hazard = get_hazard_layer(layers) # Classified Hazard exposure = get_exposure_layer(layers) # Building locations question = get_question(hazard.get_name(), exposure.get_name(), self) # Determine attribute name for hazard levels if hazard.is_raster: hazard_attribute = 'level' else: hazard_attribute = None interpolated_result = assign_hazard_values_to_exposure_data( hazard, exposure, attribute_name=hazard_attribute, mode='constant') # Extract relevant exposure data attribute_names = interpolated_result.get_attribute_names() attributes = interpolated_result.get_data() N = len(interpolated_result) # Calculate building impact count = 0 count1 = 0 count2 = 0 count3 = 0 buildings = {} affected_buildings = {} for i in range(N): # Get class value val = float(attributes[i]['level']) # FIXME it would be good if the affected were words not numbers # FIXME need to read hazard layer and see class or keyword val = float(numpy_round(val)) if val == high_t: count3 += 1 elif val == medium_t: count2 += 1 elif val == low_t: count1 += 1 else: count += 1 # Count affected buildings by usage type if available if 'type' in attribute_names: usage = attributes[i]['type'] elif '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' 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 val is True: # Count affected buildings by type affected_buildings[key] += 1 # Add calculated impact to existing attributes if val == high_t: attributes[i][self.target_field] = 3 attributes[i][self.affected_field] = 1 elif val == medium_t: attributes[i][self.target_field] = 2 attributes[i][self.affected_field] = 1 elif val == low_t: attributes[i][self.target_field] = 1 attributes[i][self.affected_field] = 1 else: attributes[i][self.target_field] = 0 attributes[i][self.affected_field] = 0 # Lump small entries and 'unknown' into 'other' category for usage in buildings.keys(): val = buildings[usage] if val < 25 or usage == 'unknown': if 'other' not in buildings: buildings['other'] = 0 affected_buildings['other'] = 0 buildings['other'] += val affected_buildings['other'] += affected_buildings[usage] del buildings[usage] del affected_buildings[usage] # Generate impact summary table_body = [ question, TableRow([tr('Hazard Level'), tr('Number of Buildings')], header=True), TableRow([tr('High Hazard Class'), format_int(count3)]), TableRow([tr('Medium Hazard Class'), format_int(count2)]), TableRow([tr('Low Hazard Class'), format_int(count1)]), TableRow([ tr('Total Buildings Affected'), format_int(count1 + count2 + count3) ], header=True), TableRow([tr('Buildings Not Affected'), format_int(count)], header=True), TableRow( [tr('All Buildings'), format_int(N)], header=True) ] school_closed = 0 hospital_closed = 0 # Generate break down by building usage type is available list_type_attribute = [ 'TYPE', '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) 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] # Sort alphabetically building_list.sort() table_body.append( TableRow(tr('Breakdown by building type'), header=True)) for row in building_list: s = TableRow(row) table_body.append(s) 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)) table_body.append( tr('Map shows buildings affected in' ' low, medium and high hazard class areas.')) # Result impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary # Create style style_classes = [ dict(label=tr('High'), value=3, colour='#F31A1C', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Medium'), value=2, colour='#F4A442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Low'), value=1, colour='#EBF442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Not Affected'), value=None, colour='#1EFC7C', transparency=0, size=2, border_color='#969696', border_width=0.2) ] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') # For printing map purpose map_title = tr('Buildings affected') legend_units = tr('(Low, Medium, High)') legend_title = tr('Structure inundated status') # Create vector layer and return vector_layer = Vector(data=attributes, projection=exposure.get_projection(), geometry=exposure.get_geometry(), name=tr('Estimated buildings affected'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.affected_field, 'map_title': map_title, 'legend_units': legend_units, 'legend_title': legend_title, 'buildings_total': N, 'buildings_affected': count1 + count2 + count3 }, style_info=style_info) return vector_layer
def run(self): """Classified hazard impact to buildings (e.g. from Open Street Map). """ # Value from layer's keywords structure_class_field = self.exposure.keyword("structure_class_field") try: exposure_value_mapping = self.exposure.keyword("value_mapping") except KeywordNotFoundError: # Generic IF, the keyword might not be defined base.py exposure_value_mapping = {} self.hazard_class_mapping = self.hazard.keyword("value_map") keys = [x["key"] for x in generic_raster_hazard_classes["classes"]] names = [x["name"] for x in generic_raster_hazard_classes["classes"]] classes = OrderedDict() for i in range(len(keys)): classes[keys[i]] = names[i] # Determine attribute name for hazard class hazard_class_attribute = get_non_conflicting_attribute_name( "haz_class", [x.keys() for x in self.exposure.layer.data][0] ) interpolated_result = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=hazard_class_attribute, mode="constant" ) # Extract relevant exposure data attributes = interpolated_result.get_data() # Number of building in the interpolated layer buildings_total = len(interpolated_result) # Inverse the order from low to high self.init_report_var(classes.values()[::-1]) for i in range(buildings_total): # Get the usage of the building usage = attributes[i][structure_class_field] usage = main_type(usage, exposure_value_mapping) # Initialize value as Not affected attributes[i][self.target_field] = tr("Not affected") attributes[i][self.affected_field] = 0 # Get the hazard level of the building level = float(attributes[i][hazard_class_attribute]) level = float(numpy_round(level)) # Find the class according the building's level for k, v in self.hazard_class_mapping.items(): if level in v: impact_class = classes[k] # Set the impact level attributes[i][self.target_field] = impact_class # Set to affected attributes[i][self.affected_field] = 1 break # Count affected buildings by type self.classify_feature(attributes[i][self.target_field], usage, bool(attributes[i][self.affected_field])) self.reorder_dictionaries() # Create style # Low, Medium and High are translated in the attribute table. # "Not affected" is not translated in the attribute table. style_classes = [ dict( label=tr("Not Affected"), value="Not affected", colour="#1EFC7C", transparency=0, size=2, border_color="#969696", border_width=0.2, ), dict( label=tr("Low"), value=tr("Low hazard zone"), colour="#EBF442", transparency=0, size=2, border_color="#969696", border_width=0.2, ), dict( label=tr("Medium"), value=tr("Medium hazard zone"), colour="#F4A442", transparency=0, size=2, border_color="#969696", border_width=0.2, ), dict( label=tr("High"), value=tr("High hazard zone"), colour="#F31A1C", transparency=0, size=2, border_color="#969696", border_width=0.2, ), ] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type="categorizedSymbol") LOGGER.debug("target field : " + self.target_field) impact_data = self.generate_data() extra_keywords = { "target_field": self.affected_field, "map_title": self.map_title(), "legend_units": self.metadata().key("legend_units"), "legend_title": self.metadata().key("legend_title"), "buildings_total": buildings_total, "buildings_affected": self.total_affected_buildings, } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create impact layer and return impact_layer = Vector( data=attributes, projection=self.exposure.layer.get_projection(), geometry=self.exposure.layer.get_geometry(), name=self.map_title(), keywords=impact_layer_keywords, style_info=style_info, ) impact_layer.impact_data = impact_data self._impact = impact_layer return impact_layer
def run(self, layers): """Classified hazard impact to buildings (e.g. from Open Street Map). :param layers: List of layers expected to contain. * hazard: Classified Hazard layer * exposure: Vector layer of structure data on the same grid as hazard """ # The 3 classes low_t = self.parameters['low_hazard_class'] medium_t = self.parameters['medium_hazard_class'] high_t = self.parameters['high_hazard_class'] # Extract data hazard = get_hazard_layer(layers) # Classified Hazard exposure = get_exposure_layer(layers) # Building locations question = get_question(hazard.get_name(), exposure.get_name(), self) # Determine attribute name for hazard levels if hazard.is_raster: hazard_attribute = 'level' else: hazard_attribute = None interpolated_result = assign_hazard_values_to_exposure_data( hazard, exposure, attribute_name=hazard_attribute, mode='constant') # Extract relevant exposure data attribute_names = interpolated_result.get_attribute_names() attributes = interpolated_result.get_data() N = len(interpolated_result) # Calculate building impact count = 0 count1 = 0 count2 = 0 count3 = 0 buildings = {} affected_buildings = {} for i in range(N): # Get class value val = float(attributes[i]['level']) # FIXME it would be good if the affected were words not numbers # FIXME need to read hazard layer and see class or keyword val = float(numpy_round(val)) if val == high_t: count3 += 1 elif val == medium_t: count2 += 1 elif val == low_t: count1 += 1 else: count += 1 # Count affected buildings by usage type if available if 'type' in attribute_names: usage = attributes[i]['type'] elif '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' 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 val is True: # Count affected buildings by type affected_buildings[key] += 1 # Add calculated impact to existing attributes if val == high_t: attributes[i][self.target_field] = 3 attributes[i][self.affected_field] = 1 elif val == medium_t: attributes[i][self.target_field] = 2 attributes[i][self.affected_field] = 1 elif val == low_t: attributes[i][self.target_field] = 1 attributes[i][self.affected_field] = 1 else: attributes[i][self.target_field] = 0 attributes[i][self.affected_field] = 0 # Lump small entries and 'unknown' into 'other' category for usage in buildings.keys(): val = buildings[usage] if val < 25 or usage == 'unknown': if 'other' not in buildings: buildings['other'] = 0 affected_buildings['other'] = 0 buildings['other'] += val affected_buildings['other'] += affected_buildings[usage] del buildings[usage] del affected_buildings[usage] # Generate impact summary table_body = [question, TableRow([tr('Hazard Level'), tr('Number of Buildings')], header=True), TableRow([tr('High Hazard Class'), format_int(count3)]), TableRow([tr('Medium Hazard Class'), format_int(count2)]), TableRow([tr('Low Hazard Class'), format_int(count1)]), TableRow([tr('Total Buildings Affected'), format_int(count1 + count2 + count3)], header=True), TableRow([tr('Buildings Not Affected'), format_int(count)], header=True), TableRow([tr('All Buildings'), format_int(N)], header=True)] school_closed = 0 hospital_closed = 0 # Generate break down by building usage type is available list_type_attribute = [ 'TYPE', '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) 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] # Sort alphabetically building_list.sort() table_body.append(TableRow(tr('Breakdown by building type'), header=True)) for row in building_list: s = TableRow(row) table_body.append(s) 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)) table_body.append(tr('Map shows buildings affected in' ' low, medium and high hazard class areas.')) # Result impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary # Create style style_classes = [dict(label=tr('High'), value=3, colour='#F31A1C', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Medium'), value=2, colour='#F4A442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Low'), value=1, colour='#EBF442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Not Affected'), value=None, colour='#1EFC7C', transparency=0, size=2, border_color='#969696', border_width=0.2)] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') # For printing map purpose map_title = tr('Buildings affected') legend_units = tr('(Low, Medium, High)') legend_title = tr('Structure inundated status') # Create vector layer and return vector_layer = Vector( data=attributes, projection=exposure.get_projection(), geometry=exposure.get_geometry(), name=tr('Estimated buildings affected'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.affected_field, 'map_title': map_title, 'legend_units': legend_units, 'legend_title': legend_title, 'buildings_total': N, 'buildings_affected': count1 + count2 + count3}, style_info=style_info) return vector_layer
def run(self): """Classified hazard impact to buildings (e.g. from Open Street Map). """ # Value from layer's keywords structure_class_field = self.exposure.keyword('structure_class_field') try: exposure_value_mapping = self.exposure.keyword('value_mapping') except KeywordNotFoundError: # Generic IF, the keyword might not be defined base.py exposure_value_mapping = {} self.hazard_class_mapping = self.hazard.keyword('value_map') keys = [x['key'] for x in generic_raster_hazard_classes['classes']] names = [x['name'] for x in generic_raster_hazard_classes['classes']] classes = OrderedDict() for i in range(len(keys)): classes[keys[i]] = names[i] # Determine attribute name for hazard class hazard_class_attribute = get_non_conflicting_attribute_name( 'haz_class', [x.keys() for x in self.exposure.layer.data][0]) interpolated_result = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=hazard_class_attribute, mode='constant') # Extract relevant exposure data attributes = interpolated_result.get_data() # Number of building in the interpolated layer buildings_total = len(interpolated_result) # Inverse the order from low to high self.init_report_var(classes.values()[::-1]) for i in range(buildings_total): # Get the usage of the building usage = attributes[i][structure_class_field] usage = main_type(usage, exposure_value_mapping) # Initialize value as Not affected attributes[i][self.target_field] = tr('Not affected') attributes[i][self.affected_field] = 0 # Get the hazard level of the building level = float(attributes[i][hazard_class_attribute]) level = float(numpy_round(level)) # Find the class according the building's level for k, v in self.hazard_class_mapping.items(): if level in v: impact_class = classes[k] # Set the impact level attributes[i][self.target_field] = impact_class # Set to affected attributes[i][self.affected_field] = 1 break # Count affected buildings by type self.classify_feature(attributes[i][self.target_field], usage, bool(attributes[i][self.affected_field])) self.reorder_dictionaries() # Create style # Low, Medium and High are translated in the attribute table. # "Not affected" is not translated in the attribute table. style_classes = [ dict(label=tr('Not Affected'), value='Not affected', colour='#1EFC7C', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Low'), value=tr('Low hazard zone'), colour='#EBF442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Medium'), value=tr('Medium hazard zone'), colour='#F4A442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('High'), value=tr('High hazard zone'), colour='#F31A1C', transparency=0, size=2, border_color='#969696', border_width=0.2), ] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') LOGGER.debug('target field : ' + self.target_field) impact_data = self.generate_data() extra_keywords = { 'target_field': self.affected_field, 'map_title': self.map_title(), 'legend_units': self.metadata().key('legend_units'), 'legend_title': self.metadata().key('legend_title'), 'buildings_total': buildings_total, 'buildings_affected': self.total_affected_buildings } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create impact layer and return impact_layer = Vector(data=attributes, projection=self.exposure.layer.get_projection(), geometry=self.exposure.layer.get_geometry(), name=self.map_title(), keywords=impact_layer_keywords, style_info=style_info) impact_layer.impact_data = impact_data self._impact = impact_layer return impact_layer
def run(self): """Classified hazard impact to buildings (e.g. from Open Street Map). """ # Value from layer's keywords structure_class_field = self.exposure.keyword('structure_class_field') try: exposure_value_mapping = self.exposure.keyword('value_mapping') except KeywordNotFoundError: # Generic IF, the keyword might not be defined base.py exposure_value_mapping = {} # The 3 classes categorical_hazards = self.parameters['Categorical hazards'].value low_t = categorical_hazards[0].value medium_t = categorical_hazards[1].value high_t = categorical_hazards[2].value # Determine attribute name for hazard levels if self.hazard.layer.is_raster: hazard_attribute = 'level' else: hazard_attribute = None interpolated_result = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=hazard_attribute, mode='constant') # Extract relevant exposure data attributes = interpolated_result.get_data() buildings_total = len(interpolated_result) hazard_classes = [ tr('Low Hazard Class'), tr('Medium Hazard Class'), tr('High Hazard Class') ] self.init_report_var(hazard_classes) for i in range(buildings_total): usage = attributes[i][structure_class_field] usage = main_type(usage, exposure_value_mapping) # Count all buildings by type attributes[i][self.target_field] = 0 attributes[i][self.affected_field] = 0 level = float(attributes[i]['level']) level = float(numpy_round(level)) if level == high_t: impact_level = tr('High Hazard Class') elif level == medium_t: impact_level = tr('Medium Hazard Class') elif level == low_t: impact_level = tr('Low Hazard Class') else: continue # Add calculated impact to existing attributes attributes[i][self.target_field] = { tr('High Hazard Class'): 3, tr('Medium Hazard Class'): 2, tr('Low Hazard Class'): 1 }[impact_level] attributes[i][self.affected_field] = 1 # Count affected buildings by type self.classify_feature(impact_level, usage, True) self.reorder_dictionaries() # Consolidate the small building usage groups < 25 to other # Building threshold #2468 postprocessors = self.parameters['postprocessors'] building_postprocessors = postprocessors['BuildingType'][0] self.building_report_threshold = building_postprocessors.value[0].value self._consolidate_to_other() # Create style style_classes = [ dict( label=tr('Not Affected'), value=None, colour='#1EFC7C', transparency=0, size=2, border_color='#969696', border_width=0.2), dict( label=tr('Low'), value=1, colour='#EBF442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict( label=tr('Medium'), value=2, colour='#F4A442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict( label=tr('High'), value=3, colour='#F31A1C', transparency=0, size=2, border_color='#969696', border_width=0.2), ] style_info = dict( target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_data = self.generate_data() extra_keywords = { 'target_field': self.affected_field, 'map_title': self.metadata().key('map_title'), 'legend_units': self.metadata().key('legend_units'), 'legend_title': self.metadata().key('legend_title'), 'buildings_total': buildings_total, 'buildings_affected': self.total_affected_buildings } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create impact layer and return impact_layer = Vector( data=attributes, projection=self.exposure.layer.get_projection(), geometry=self.exposure.layer.get_geometry(), name=self.metadata().key('layer_name'), keywords=impact_layer_keywords, style_info=style_info) impact_layer.impact_data = impact_data self._impact = impact_layer return impact_layer
def run(self): """Classified hazard impact to buildings (e.g. from Open Street Map). """ self.validate() self.prepare() self.provenance.append_step("Calculating Step", "Impact function is calculating the impact.") # Value from layer's keywords # Try to get the value from keyword, if not exist, it will not fail, # but use the old get_osm_building_usage try: structure_class_field = self.exposure.keyword("structure_class_field") except KeywordNotFoundError: structure_class_field = None # The 3 classes categorical_hazards = self.parameters["Categorical hazards"].value low_t = categorical_hazards[0].value medium_t = categorical_hazards[1].value high_t = categorical_hazards[2].value # Determine attribute name for hazard levels if self.hazard.layer.is_raster: hazard_attribute = "level" else: hazard_attribute = None interpolated_result = assign_hazard_values_to_exposure_data( self.hazard.layer, self.exposure.layer, attribute_name=hazard_attribute, mode="constant" ) # Extract relevant exposure data attribute_names = interpolated_result.get_attribute_names() attributes = interpolated_result.get_data() buildings_total = len(interpolated_result) # Calculate building impact self.buildings = {} self.affected_buildings = OrderedDict( [(tr("High Hazard Class"), {}), (tr("Medium Hazard Class"), {}), (tr("Low Hazard Class"), {})] ) for i in range(buildings_total): if structure_class_field and structure_class_field in attribute_names: usage = attributes[i][structure_class_field] else: usage = get_osm_building_usage(attribute_names, attributes[i]) if usage is None or usage == 0: usage = "unknown" if usage not in self.buildings: self.buildings[usage] = 0 for category in self.affected_buildings.keys(): self.affected_buildings[category][usage] = OrderedDict([(tr("Buildings Affected"), 0)]) # Count all buildings by type self.buildings[usage] += 1 attributes[i][self.target_field] = 0 attributes[i][self.affected_field] = 0 level = float(attributes[i]["level"]) level = float(numpy_round(level)) if level == high_t: impact_level = tr("High Hazard Class") elif level == medium_t: impact_level = tr("Medium Hazard Class") elif level == low_t: impact_level = tr("Low Hazard Class") else: continue # Add calculated impact to existing attributes attributes[i][self.target_field] = { tr("High Hazard Class"): 3, tr("Medium Hazard Class"): 2, tr("Low Hazard Class"): 1, }[impact_level] attributes[i][self.affected_field] = 1 # Count affected buildings by type self.affected_buildings[impact_level][usage][tr("Buildings Affected")] += 1 # Consolidate the small building usage groups < 25 to other # Building threshold #2468 postprocessors = self.parameters["postprocessors"] building_postprocessors = postprocessors["BuildingType"][0] self.building_report_threshold = building_postprocessors.value[0].value self._consolidate_to_other() # Create style style_classes = [ dict( label=tr("High"), value=3, colour="#F31A1C", transparency=0, size=2, border_color="#969696", border_width=0.2, ), dict( label=tr("Medium"), value=2, colour="#F4A442", transparency=0, size=2, border_color="#969696", border_width=0.2, ), dict( label=tr("Low"), value=1, colour="#EBF442", transparency=0, size=2, border_color="#969696", border_width=0.2, ), dict( label=tr("Not Affected"), value=None, colour="#1EFC7C", transparency=0, size=2, border_color="#969696", border_width=0.2, ), ] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type="categorizedSymbol") impact_table = impact_summary = self.html_report() # For printing map purpose map_title = tr("Buildings affected") legend_title = tr("Structure inundated status") legend_units = tr("(Low, Medium, High)") extra_keywords = { "impact_summary": impact_summary, "impact_table": impact_table, "target_field": self.affected_field, "map_title": map_title, "legend_units": legend_units, "legend_title": legend_title, "buildings_total": buildings_total, "buildings_affected": self.total_affected_buildings, } self.set_if_provenance() impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return vector_layer = Vector( data=attributes, projection=self.exposure.layer.get_projection(), geometry=self.exposure.layer.get_geometry(), name=tr("Estimated buildings affected"), keywords=impact_layer_keywords, style_info=style_info, ) self._impact = vector_layer return vector_layer
def run(self, layers=None): """Classified hazard impact to buildings (e.g. from Open Street Map). :param layers: List of layers expected to contain. * hazard: Classified Hazard layer * exposure: Vector layer of structure data on the same grid as hazard """ self.validate() self.prepare(layers) # The 3 classes low_t = self.parameters['low_hazard_class'] medium_t = self.parameters['medium_hazard_class'] high_t = self.parameters['high_hazard_class'] # Extract data hazard = self.hazard # Classified Hazard exposure = self.exposure # Building locations # Determine attribute name for hazard levels if hazard.is_raster: hazard_attribute = 'level' else: hazard_attribute = None interpolated_result = assign_hazard_values_to_exposure_data( hazard, exposure, attribute_name=hazard_attribute, mode='constant') # Extract relevant exposure data attribute_names = interpolated_result.get_attribute_names() attributes = interpolated_result.get_data() buildings_total = len(interpolated_result) # Calculate building impact self.buildings = {} self.affected_buildings = OrderedDict([ (tr('High Hazard Class'), {}), (tr('Medium Hazard Class'), {}), (tr('Low Hazard Class'), {}) ]) for i in range(buildings_total): usage = get_osm_building_usage(attribute_names, attributes[i]) if usage is None or usage == 0: usage = 'unknown' if usage not in self.buildings: self.buildings[usage] = 0 for category in self.affected_buildings.keys(): self.affected_buildings[category][usage] = OrderedDict([ (tr('Buildings Affected'), 0)]) # Count all buildings by type self.buildings[usage] += 1 attributes[i][self.target_field] = 0 attributes[i][self.affected_field] = 0 level = float(attributes[i]['level']) level = float(numpy_round(level)) if level == high_t: impact_level = tr('High Hazard Class') elif level == medium_t: impact_level = tr('Medium Hazard Class') elif level == low_t: impact_level = tr('Low Hazard Class') else: continue # Add calculated impact to existing attributes attributes[i][self.target_field] = { tr('High Hazard Class'): 3, tr('Medium Hazard Class'): 2, tr('Low Hazard Class'): 1 }[impact_level] attributes[i][self.affected_field] = 1 # Count affected buildings by type self.affected_buildings[impact_level][usage][ tr('Buildings Affected')] += 1 # Consolidate the small building usage groups < 25 to other self._consolidate_to_other() # Create style style_classes = [dict(label=tr('High'), value=3, colour='#F31A1C', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Medium'), value=2, colour='#F4A442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Low'), value=1, colour='#EBF442', transparency=0, size=2, border_color='#969696', border_width=0.2), dict(label=tr('Not Affected'), value=None, colour='#1EFC7C', transparency=0, size=2, border_color='#969696', border_width=0.2)] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_table = impact_summary = self.generate_html_report() # For printing map purpose map_title = tr('Buildings affected') legend_units = tr('(Low, Medium, High)') legend_title = tr('Structure inundated status') # Create vector layer and return vector_layer = Vector( data=attributes, projection=exposure.get_projection(), geometry=exposure.get_geometry(), name=tr('Estimated buildings affected'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.affected_field, 'map_title': map_title, 'legend_units': legend_units, 'legend_title': legend_title, 'buildings_total': buildings_total, 'buildings_affected': self.total_affected_buildings}, style_info=style_info) self._impact = vector_layer return vector_layer