def prepare(self, layers): """Prepare this impact function for running the analysis. This method should normally be called in your concrete class's run method before it attempts to do any real processing. This method will do any needed house keeping such as: * checking that the exposure and hazard layers sufficiently overlap (post 3.1) * clipping or subselecting features from both layers such that only features / coverage within the actual analysis extent will be analysed (post 3.1) * raising errors if any untenable condition exists e.g. extent has no valid CRS. (post 3.1) We suggest to overload this method in your concrete class implementation so that it includes any impact function specific checks too. ..note: For 3.1, we will still do those preprocessing in analysis class. We will just need to check if the function_type is 'qgis2.0', it needs to have the extent set. :param layers: List of layers (hazard and exposure). This is necessary now, until we streamline the preprocess in the base class and remove unnecessary routines in analysis, impact_calculator, impact_calculator_thread, and calculate_safe_impact module. :type layers: list # """ if layers is not None: self.hazard = get_hazard_layer(layers) self.exposure = get_exposure_layer(layers)
def run(layers): """Risk plugin for earthquake school damage """ # Extract data H = get_hazard_layer(layers) # Ground shaking E = get_exposure_layer(layers) # Building locations # Interpolate hazard level to building locations H = assign_hazard_values_to_exposure_data(H, E, attribute_name='MMI') # Extract relevant numerical data coordinates = E.get_geometry() shaking = H.get_data() # Calculate building damage building_damage = [] for i in range(len(shaking)): x = float(shaking[i]['MMI']) if x < 6.0 or (x != x): # x != x -> check for nan pre python 2.6 value = 0.0 else: value = (0.692 * (x**4) - 15.82 * (x**3) + 135.0 * (x**2) - 509.0 * x + 714.4) building_damage.append({'DAMAGE': value, 'MMI': x}) # Create new layer and return V = Vector(data=building_damage, projection=E.get_projection(), geometry=coordinates) return V
def run(layers): """Risk plugin for volcano population impact Input layers: List of layers expected to contain H: Raster layer of volcanic hazard level P: Raster layer of population data on the same grid as H """ # Identify hazard and exposure layers # Volcanic hazard level [0-1] volcanic_hazard_level = get_hazard_layer(layers) population = get_exposure_layer(layers) # Density [people/area] # Extract data as numeric arrays V = volcanic_hazard_level.get_data(nan=0.0) # Population density P = population.get_data(nan=0.0, scaling=True) # Calculate impact as population exposed to depths > threshold I = numpy.where(V > 2.0 / 3, P, 0) # Generate text with result for this study number_of_people_affected = numpy.nansum(I.flat) impact_summary = ('%i people affected by volcanic hazard level greater' ' than 0.667' % number_of_people_affected) # Create raster object and return R = Raster(I, projection=volcanic_hazard_level.get_projection(), geotransform=volcanic_hazard_level.get_geotransform(), name='People affected', keywords={'impact_summary': impact_summary}) return R
def run(layers): """Risk plugin for earthquake fatalities Input layers: List of layers expected to contain H: Raster layer of flood depth P: Raster layer of population data on the same grid as H """ threshold = 1 # Load above which people are regarded affected [kg/m2] # Identify hazard and exposure layers inundation = get_hazard_layer(layers) # Tephra load [kg/m2] population = get_exposure_layer(layers) # Density [people/km^2] # Extract data as numeric arrays D = inundation.get_data(nan=0.0) # Depth P = population.get_data(nan=0.0, scaling=True) # Population density # Calculate impact as population exposed to depths > threshold I = numpy.where(D > threshold, P, 0) # Generate text with result for this study number_of_people_affected = numpy.nansum(I.flat) impact_summary = ('%i people affected by ash levels greater ' 'than %i kg/m^2' % (number_of_people_affected, threshold)) # Create raster object and return R = Raster(I, projection=inundation.get_projection(), geotransform=inundation.get_geotransform(), name='People affected', keywords={'impact_summary': impact_summary}) return R
def run(layers): """Risk plugin for earthquake school damage """ # Extract data H = get_hazard_layer(layers) # Ground shaking E = get_exposure_layer(layers) # Building locations # Interpolate hazard level to building locations H = assign_hazard_values_to_exposure_data(H, E, attribute_name='MMI') # Extract relevant numerical data coordinates = E.get_geometry() shaking = H.get_data() # Calculate building damage building_damage = [] for i in range(len(shaking)): x = float(shaking[i]['MMI']) if x < 6.0 or (x != x): # x != x -> check for nan pre python 2.6 value = 0.0 else: value = (0.692 * (x ** 4) - 15.82 * (x ** 3) + 135.0 * (x ** 2) - 509.0 * x + 714.4) building_damage.append({'DAMAGE': value, 'MMI': x}) # Create new layer and return V = Vector(data=building_damage, projection=E.get_projection(), geometry=coordinates) return V
def run(self, layers): """Risk plugin for tsunami population """ thresholds = [0.2, 0.3, 0.5, 0.8, 1.0] # threshold = 1 # Depth above which people are regarded affected [m] # Identify hazard and exposure layers inundation = get_hazard_layer(layers) # Tsunami inundation [m] population = get_exposure_layer(layers) # Population density # Extract data as numeric arrays D = inundation.get_data(nan=0.0) # Depth P = population.get_data(nan=0.0, scaling=True) # Population density # Calculate impact as population exposed to depths > 1m I_map = numpy.where(D > thresholds[-1], P, 0) # Generate text with result for this study number_of_people_affected = numpy.nansum(I_map.flat) # Do breakdown # Create report impact_summary = ('<table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></th>' ' <tr></tr>' % ('Ambang batas', 'Jumlah orang terdampak')) counts = [] for i, threshold in enumerate(thresholds): I = numpy.where(D > threshold, P, 0) counts.append(numpy.nansum(I.flat)) impact_summary += ' <tr><td>%s m</td><td>%i</td></tr>' % ( threshold, counts[i]) impact_summary += '</table>' # Create raster object and return R = Raster(I_map, projection=inundation.get_projection(), geotransform=inundation.get_geotransform(), name='People affected by more than 1m of inundation', keywords={'impact_summary': impact_summary}) return R
def run(self, layers): """Risk plugin for tsunami population """ thresholds = [0.2, 0.3, 0.5, 0.8, 1.0] #threshold = 1 # Depth above which people are regarded affected [m] # Identify hazard and exposure layers inundation = get_hazard_layer(layers) # Tsunami inundation [m] population = get_exposure_layer(layers) # Population density # Extract data as numeric arrays D = inundation.get_data(nan=0.0) # Depth P = population.get_data(nan=0.0, scaling=True) # Population density # Calculate impact as population exposed to depths > 1m I_map = numpy.where(D > thresholds[-1], P, 0) # Generate text with result for this study number_of_people_affected = numpy.nansum(I_map.flat) # Do breakdown # Create report impact_summary = ('<table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></th>' ' <tr></tr>' % ('Ambang batas', 'Jumlah orang terdampak')) counts = [] for i, threshold in enumerate(thresholds): I = numpy.where(D > threshold, P, 0) counts.append(numpy.nansum(I.flat)) impact_summary += ' <tr><td>%s m</td><td>%i</td></tr>' % ( threshold, counts[i]) impact_summary += '</table>' # Create raster object and return R = Raster(I_map, projection=inundation.get_projection(), geotransform=inundation.get_geotransform(), name='People affected by more than 1m of inundation', keywords={'impact_summary': impact_summary}) return R
def run(layers, teta=14.05, beta=0.17): # zeta=2.15): """Risk plugin for earthquake fatalities Input H: Numerical array of hazard data E: Numerical array of exposure data """ # Suppress warnings about invalid value in multiply and divide zero # http://comments.gmane.org/gmane.comp.python.numeric.general/43218 # http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html old_numpy_setting = numpy.seterr(invalid='ignore') numpy.seterr(divide='ignore') # Identify input layers intensity = get_hazard_layer(layers) population = get_exposure_layer(layers) # Extract data H = intensity.get_data(nan=0) P = population.get_data(nan=0) # Calculate impact logHazard = 1 / beta * numpy.log(H / teta) # Convert array to be standard floats expected by cdf arrayout = numpy.array([[float(value) for value in row] for row in logHazard]) x = arrayout * P F = normal_cdf(x) numpy.seterr(**old_numpy_setting) # Create new layer and return R = Raster(F, projection=population.get_projection(), geotransform=population.get_geotransform(), name='Estimated fatalities') return R
def run(layers, teta=14.05, beta=0.17, zeta=2.15): """Risk plugin for earthquake fatalities Input H: Numerical array of hazard data E: Numerical array of exposure data """ # Suppress warnings about invalid value in multiply and divide zero # http://comments.gmane.org/gmane.comp.python.numeric.general/43218 # http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html old_numpy_setting = numpy.seterr(invalid='ignore') numpy.seterr(divide='ignore') # Identify input layers intensity = get_hazard_layer(layers) population = get_exposure_layer(layers) # Extract data H = intensity.get_data(nan=0) P = population.get_data(nan=0) # Calculate impact logHazard = 1 / beta * numpy.log(H / teta) # Convert array to be standard floats expected by cdf arrayout = numpy.array([[float(value) for value in row] for row in logHazard]) x = arrayout * P F = cdf(x) numpy.seterr(**old_numpy_setting) # Create new layer and return R = Raster(F, projection=population.get_projection(), geotransform=population.get_geotransform(), name='Estimated fatalities') return R
def run(layers): """Risk plugin for earthquake school damage """ # Extract data H = get_hazard_layer(layers) # Ground shaking E = get_exposure_layer(layers) # Building locations # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() shaking = H.get_data() # Calculate building damage building_damage = [] for i in range(len(shaking)): x = float(shaking[i].values()[0]) if x < 6.0 or (x != x): # x != x -> check for nan pre python 2.6 value = 0.0 else: print x value = (0.692 * (x ** 4) - 15.82 * (x ** 3) + 135.0 * (x ** 2) - 509.0 * x + 714.4) building_damage.append({'DAMAGE': value, 'MMI': x}) # FIXME (Ole): Need helper to generate new layer using # correct spatial reference # (i.e. sensibly wrap the following lines) projection = E.get_projection() V = Vector(data=building_damage, projection=E.get_projection(), geometry=coordinates) return V
def run(layers): """Risk plugin for earthquake school damage """ # Extract data H = get_hazard_layer(layers) # Ground shaking E = get_exposure_layer(layers) # Building locations # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() shaking = H.get_data() # Calculate building damage building_damage = [] for i in range(len(shaking)): x = float(shaking[i].values()[0]) if x < 6.0 or (x != x): # x != x -> check for nan pre python 2.6 value = 0.0 else: print x value = (0.692 * (x**4) - 15.82 * (x**3) + 135.0 * (x**2) - 509.0 * x + 714.4) building_damage.append({'DAMAGE': value, 'MMI': x}) # FIXME (Ole): Need helper to generate new layer using # correct spatial reference # (i.e. sensibly wrap the following lines) projection = E.get_projection() V = Vector(data=building_damage, projection=E.get_projection(), geometry=coordinates) return V
def run(self, layers): """Indonesian Earthquake Fatality Model Input layers: List of layers expected to contain H: Raster layer of MMI ground shaking P: Raster layer of population density """ # Establish model coefficients x = self.parameters['x'] y = self.parameters['y'] # Define percentages of people being displaced at each mmi level displacement_rate = self.parameters['displacement_rate'] # Tolerance for transparency tolerance = self.parameters['tolerance'] # Extract input layers intensity = get_hazard_layer(layers) population = get_exposure_layer(layers) question = get_question(intensity.get_name(), population.get_name(), self) # Extract data grids H = intensity.get_data() # Ground Shaking P = population.get_data(scaling=True) # Population Density # Calculate population affected by each MMI level # FIXME (Ole): this range is 2-9. Should 10 be included? mmi_range = range(2, 10) number_of_exposed = {} number_of_displaced = {} number_of_fatalities = {} # Calculate fatality rates for observed Intensity values (H # based on ITB power model R = numpy.zeros(H.shape) for mmi in mmi_range: # Identify cells where MMI is in class i mask = (H > mmi - 0.5) * (H <= mmi + 0.5) # Count population affected by this shake level I = numpy.where(mask, P, 0) # Calculate expected number of fatalities per level fatality_rate = numpy.power(10.0, x * mmi - y) F = fatality_rate * I # Calculate expected number of displaced people per level try: D = displacement_rate[mmi] * I except KeyError, e: msg = 'mmi = %i, I = %s, Error msg: %s' % (mmi, str(I), str(e)) raise InaSAFEError(msg) # Adjust displaced people to disregard fatalities. # Set to zero if there are more fatalities than displaced. D = numpy.where(D > F, D - F, 0) # Sum up numbers for map R += D # Displaced # Generate text with result for this study # This is what is used in the real time system exposure table number_of_exposed[mmi] = numpy.nansum(I.flat) number_of_displaced[mmi] = numpy.nansum(D.flat) number_of_fatalities[mmi] = numpy.nansum(F.flat)
def run(self, layers): """Risk plugin for flood population evacuation Input layers: List of layers expected to contain my_hazard: Raster layer of flood depth my_exposure: Raster layer of population data on the same grid as my_hazard Counts number of people exposed to flood levels exceeding specified threshold. Return Map of population exposed to flood levels exceeding the threshold Table with number of people evacuated and supplies required """ # Identify hazard and exposure layers my_hazard = get_hazard_layer(layers) # Flood inundation [m] my_exposure = get_exposure_layer(layers) question = get_question(my_hazard.get_name(), my_exposure.get_name(), self) # Determine depths above which people are regarded affected [m] # Use thresholds from inundation layer if specified thresholds = self.parameters['thresholds [m]'] verify(isinstance(thresholds, list), 'Expected thresholds to be a list. Got %s' % str(thresholds)) # Extract data as numeric arrays D = my_hazard.get_data(nan=0.0) # Depth # Calculate impact as population exposed to depths > max threshold P = my_exposure.get_data(nan=0.0, scaling=True) # Calculate impact to intermediate thresholds counts = [] # merely initialize my_impact = None for i, lo in enumerate(thresholds): if i == len(thresholds) - 1: # The last threshold my_impact = M = numpy.where(D >= lo, P, 0) else: # Intermediate thresholds hi = thresholds[i + 1] M = numpy.where((D >= lo) * (D < hi), P, 0) # Count val = int(numpy.sum(M)) # Don't show digits less than a 1000 val = round_thousand(val) counts.append(val) # Count totals evacuated = counts[-1] total = int(numpy.sum(P)) # Don't show digits less than a 1000 total = round_thousand(total) # Calculate estimated minimum needs # The default value of each logistic is based on BNPB Perka 7/2008 # minimum bantuan minimum_needs = self.parameters['minimum needs'] tot_needs = evacuated_population_weekly_needs(evacuated, minimum_needs) # Generate impact report for the pdf map # noinspection PyListCreation table_body = [ question, TableRow([(tr('People in %.1f m of water') % thresholds[-1]), '%s%s' % (format_int(evacuated), ( '*' if evacuated >= 1000 else ''))], header=True), TableRow(tr('* Number is rounded to the nearest 1000'), header=False), TableRow(tr('Map shows population density needing evacuation')), TableRow(tr('Table below shows the weekly minium needs for all ' 'evacuated people')), TableRow([tr('Needs per week'), tr('Total')], header=True), [tr('Rice [kg]'), format_int(tot_needs['rice'])], [tr('Drinking Water [l]'), format_int(tot_needs['drinking_water'])], [tr('Clean Water [l]'), format_int(tot_needs['water'])], [tr('Family Kits'), format_int(tot_needs['family_kits'])], [tr('Toilets'), format_int(tot_needs['toilets'])]] table_body.append(TableRow(tr('Action Checklist:'), header=True)) table_body.append(TableRow(tr('How will warnings be disseminated?'))) table_body.append(TableRow(tr('How will we reach stranded people?'))) table_body.append(TableRow(tr('Do we have enough relief items?'))) table_body.append(TableRow(tr('If yes, where are they located and how ' 'will we distribute them?'))) table_body.append(TableRow(tr( 'If no, where can we obtain additional relief items from and how ' 'will we transport them to here?'))) # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Total population: %s') % format_int(total), tr('People need evacuation if flood levels exceed %(eps).1f m') % {'eps': thresholds[-1]}, tr('Minimum needs are defined in BNPB regulation 7/2008'), tr('All values are rounded up to the nearest integer in order to ' 'avoid representing human lives as fractionals.')]) if len(counts) > 1: table_body.append(TableRow(tr('Detailed breakdown'), header=True)) for i, val in enumerate(counts[:-1]): s = (tr('People in %(lo).1f m to %(hi).1f m of water: %(val)i') % {'lo': thresholds[i], 'hi': thresholds[i + 1], 'val': format_int(val)}) table_body.append(TableRow(s, header=False)) # Result impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary # check for zero impact if numpy.nanmax(my_impact) == 0 == numpy.nanmin(my_impact): table_body = [ question, TableRow([(tr('People in %.1f m of water') % thresholds[-1]), '%s' % format_int(evacuated)], header=True)] my_message = Table(table_body).toNewlineFreeString() raise ZeroImpactException(my_message) # Create style colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] classes = create_classes(my_impact.flat[:], len(colours)) interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() if i == 1: label = create_label(interval_classes[i], 'Low') elif i == 4: label = create_label(interval_classes[i], 'Medium') elif i == 7: label = create_label(interval_classes[i], 'High') else: label = create_label(interval_classes[i]) style_class['label'] = label style_class['quantity'] = classes[i] if i == 0: transparency = 100 else: transparency = 0 style_class['transparency'] = transparency style_class['colour'] = colours[i] style_classes.append(style_class) style_info = dict(target_field=None, style_classes=style_classes, style_type='rasterStyle') # For printing map purpose map_title = tr('People in need of evacuation') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) legend_units = tr('(people per cell)') legend_title = tr('Population density') # Create raster object and return R = Raster(my_impact, projection=my_hazard.get_projection(), geotransform=my_hazard.get_geotransform(), name=tr('Population which %s') % ( get_function_title(self).lower()), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title}, style_info=style_info) return R
def run(self, layers): """Risk plugin for flood population evacuation. :param layers: List of layers expected to contain * hazard_layer : Vector polygon layer of flood depth * exposure_layer : Raster layer of population data on the same grid as hazard_layer Counts number of people exposed to areas identified as flood prone :returns: Map of population exposed to flooding Table with number of people evacuated and supplies required. :rtype: tuple """ # Identify hazard and exposure layers hazard_layer = get_hazard_layer(layers) # Flood inundation exposure_layer = get_exposure_layer(layers) question = get_question(hazard_layer.get_name(), exposure_layer.get_name(), self) # Check that hazard is polygon type if not hazard_layer.is_vector: message = ('Input hazard %s was not a vector layer as expected ' % hazard_layer.get_name()) raise Exception(message) message = ( 'Input hazard must be a polygon layer. I got %s with layer type ' '%s' % (hazard_layer.get_name(), hazard_layer.get_geometry_name())) if not hazard_layer.is_polygon_data: raise Exception(message) # Run interpolation function for polygon2raster P = assign_hazard_values_to_exposure_data(hazard_layer, exposure_layer, attribute_name='population') # Initialise attributes of output dataset with all attributes # from input polygon and a population count of zero new_attributes = hazard_layer.get_data() category_title = 'affected' # FIXME: Should come from keywords deprecated_category_title = 'FLOODPRONE' categories = {} for attr in new_attributes: attr[self.target_field] = 0 try: cat = attr[category_title] except KeyError: try: cat = attr['FLOODPRONE'] categories[cat] = 0 except KeyError: pass # Count affected population per polygon, per category and total affected_population = 0 for attr in P.get_data(): affected = False if 'affected' in attr: res = attr['affected'] if res is None: x = False else: x = bool(res) affected = x elif 'FLOODPRONE' in attr: # If there isn't an 'affected' attribute, res = attr['FLOODPRONE'] if res is not None: affected = res.lower() == 'yes' elif 'Affected' in attr: # Check the default attribute assigned for points # covered by a polygon res = attr['Affected'] if res is None: x = False else: x = res affected = x else: # assume that every polygon is affected (see #816) affected = True # there is no flood related attribute # message = ('No flood related attribute found in %s. ' # 'I was looking for either "Flooded", "FLOODPRONE" ' # 'or "Affected". The latter should have been ' # 'automatically set by call to ' # 'assign_hazard_values_to_exposure_data(). ' # 'Sorry I can\'t help more.') # raise Exception(message) if affected: # Get population at this location pop = float(attr['population']) # Update population count for associated polygon poly_id = attr['polygon_id'] new_attributes[poly_id][self.target_field] += pop # Update population count for each category if len(categories) > 0: try: cat = new_attributes[poly_id][category_title] except KeyError: cat = new_attributes[poly_id][ deprecated_category_title] categories[cat] += pop # Update total affected_population += pop # Estimate number of people in need of evacuation evacuated = (affected_population * self.parameters['evacuation_percentage'] / 100.0) affected_population, rounding = population_rounding_full( affected_population) total = int(numpy.sum(exposure_layer.get_data(nan=0, scaling=False))) # Don't show digits less than a 1000 total = population_rounding(total) evacuated, rounding_evacuated = population_rounding_full(evacuated) minimum_needs = [ parameter.serialize() for parameter in self.parameters['minimum needs'] ] # Generate impact report for the pdf map table_body = [ question, TableRow([ tr('People affected'), '%s*' % (format_int(int(affected_population))) ], header=True), TableRow([ TableCell(tr('* Number is rounded up to the nearest %s') % (rounding), col_span=2) ]), TableRow([ tr('People needing evacuation'), '%s*' % (format_int(int(evacuated))) ], header=True), TableRow([ TableCell(tr('* Number is rounded up to the nearest %s') % (rounding_evacuated), col_span=2) ]), TableRow([ tr('Evacuation threshold'), '%s%%' % format_int(self.parameters['evacuation_percentage']) ], header=True), TableRow( tr('Map shows the number of people affected in each flood prone ' 'area')), TableRow( tr('Table below shows the weekly minimum needs for all ' 'evacuated people')) ] total_needs = evacuated_population_needs(evacuated, minimum_needs) for frequency, needs in total_needs.items(): table_body.append( TableRow([ tr('Needs should be provided %s' % frequency), tr('Total') ], header=True)) for resource in needs: table_body.append( TableRow([ tr(resource['table name']), format_int(resource['amount']) ])) impact_table = Table(table_body).toNewlineFreeString() table_body.append(TableRow(tr('Action Checklist:'), header=True)) table_body.append(TableRow(tr('How will warnings be disseminated?'))) table_body.append(TableRow(tr('How will we reach stranded people?'))) table_body.append(TableRow(tr('Do we have enough relief items?'))) table_body.append( TableRow( tr('If yes, where are they located and how will we distribute ' 'them?'))) table_body.append( TableRow( tr('If no, where can we obtain additional relief items from and ' 'how will we transport them to here?'))) # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Total population: %s') % format_int(total), tr('People need evacuation if in the area identified as ' '"Flood Prone"'), tr('Minimum needs are defined in BNPB regulation 7/2008') ]) impact_summary = Table(table_body).toNewlineFreeString() # Create style # Define classes for legend for flooded population counts colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] population_counts = [x['population'] for x in new_attributes] classes = create_classes(population_counts, len(colours)) interval_classes = humanize_class(classes) # Define style info for output polygons showing population counts style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class['label'] = create_label(interval_classes[i]) if i == 0: transparency = 0 style_class['min'] = 0 else: transparency = 0 style_class['min'] = classes[i - 1] style_class['transparency'] = transparency style_class['colour'] = colours[i] style_class['max'] = classes[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='graduatedSymbol') # For printing map purpose map_title = tr('People affected by flood prone areas') legend_notes = tr('Thousand separator is represented by \'.\'') legend_units = tr('(people per polygon)') legend_title = tr('Population Count') # Create vector layer and return vector_layer = Vector(data=new_attributes, projection=hazard_layer.get_projection(), geometry=hazard_layer.get_geometry(), name=tr('People affected by flood prone areas'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title, 'affected_population': affected_population, 'total_population': total, 'total_needs': total_needs }, style_info=style_info) return vector_layer
def run(self, layers): """Impact plugin for hazard impact """ # Extract data H = get_hazard_layer(layers) # Value E = get_exposure_layer(layers) # Building locations question = get_question(H.get_name(), E.get_name(), self) # Interpolate hazard level to building locations H = assign_hazard_values_to_exposure_data(H, E, attribute_name='hazard_lev', mode='constant') # Extract relevant numerical data coordinates = H.get_geometry() category = H.get_data() N = len(category) # List attributes to carry forward to result layer #attributes = E.get_attribute_names() # Calculate building impact according to guidelines count2 = 0 count1 = 0 count0 = 0 building_impact = [] for i in range(N): # Get category value val = float(category[i]['hazard_lev']) # Classify buildings according to value ## if val >= 2.0 / 3: ## affected = 2 ## count2 += 1 ## elif 1.0 / 3 <= val < 2.0 / 3: ## affected = 1 ## count1 += 1 ## else: ## affected = 0 ## count0 += 1 ## FIXME it would be good if the affected were words not numbers ## FIXME need to read hazard layer and see category or keyword if val == 3: affected = 3 count2 += 1 elif val == 2: affected = 2 count1 += 1 elif val == 1: affected = 1 count0 += 1 else: affected = 'None' # Collect depth and calculated damage result_dict = {self.target_field: affected, 'CATEGORY': val} # Record result for this feature building_impact.append(result_dict) # Create impact report # Generate impact summary table_body = [question, TableRow([tr('Category'), tr('Affected')], header=True), TableRow([tr('High'), format_int(count2)]), TableRow([tr('Medium'), format_int(count1)]), TableRow([tr('Low'), format_int(count0)]), TableRow([tr('All'), format_int(N)])] table_body.append(TableRow(tr('Notes'), header=True)) table_body.append(tr('Categorised hazard has only 3' ' classes, high, medium and low.')) impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary map_title = tr('Categorised hazard impact on buildings') #FIXME it would be great to do categorized rather than grduated # Create style style_classes = [dict(label=tr('Low'), min=1, max=1, colour='#1EFC7C', transparency=0, size=1), dict(label=tr('Medium'), min=2, max=2, colour='#FFA500', transparency=0, size=1), dict(label=tr('High'), min=3, max=3, colour='#F31A1C', transparency=0, size=1)] style_info = dict(target_field=self.target_field, style_classes=style_classes) # Create vector layer and return name = 'Buildings Affected' V = Vector(data=building_impact, projection=E.get_projection(), geometry=coordinates, geometry_type=E.geometry_type, keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'target_field': self.target_field, 'statistics_type': self.statistics_type, 'statistics_classes': self.statistics_classes}, name=name, style_info=style_info) return V
def run(self, layers): """Risk plugin for earthquake school damage """ # Extract data H = get_hazard_layer(layers) # Ground shaking E = get_exposure_layer(layers) # Building locations keywords = E.get_keywords() if 'datatype' in keywords: datatype = keywords['datatype'] if datatype.lower() == 'osm': # Map from OSM attributes to the guideline classes (URM and RM) E = osm2bnpb(E, target_attribute=self.vclass_tag) elif datatype.lower() == 'sigab': # Map from SIGAB attributes to the guideline classes # (URM and RM) E = sigab2bnpb(E) else: E = unspecific2bnpb(E, target_attribute=self.vclass_tag) else: E = unspecific2bnpb(E, target_attribute=self.vclass_tag) # Interpolate hazard level to building locations H = assign_hazard_values_to_exposure_data(H, E, attribute_name='MMI') # Extract relevant numerical data coordinates = E.get_geometry() shaking = H.get_data() N = len(shaking) # List attributes to carry forward to result layer attributes = E.get_attribute_names() # Calculate building damage count3 = 0 count2 = 0 count1 = 0 count_unknown = 0 building_damage = [] for i in range(N): mmi = float(shaking[i]['MMI']) building_class = E.get_data(self.vclass_tag, i) lo, hi = damage_parameters[building_class] if numpy.isnan(mmi): # If we don't know the shake level assign Not-a-Number damage = numpy.nan count_unknown += 1 elif mmi < lo: damage = 1 # Low count1 += 1 elif lo <= mmi < hi: damage = 2 # Medium count2 += 1 elif mmi >= hi: damage = 3 # High count3 += 1 else: msg = 'Undefined shakelevel %s' % str(mmi) raise Exception(msg) # Collect shake level and calculated damage result_dict = {self.target_field: damage, 'MMI': mmi} # Carry all orginal attributes forward for key in attributes: result_dict[key] = E.get_data(key, i) # Record result for this feature building_damage.append(result_dict) # Create report impact_summary = ('<table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></th>' ' <tr></tr>' ' <tr><td>%s:</td><td>%s</td></tr>' ' <tr><td>%s (10-25%%):</td><td>%s</td></tr>' ' <tr><td>%s (25-50%%):</td><td>%s</td></tr>' ' <tr><td>%s (50-100%%):</td><td>%s</td></tr>' % (tr('Buildings'), tr('Total'), tr('All'), format_int(N), tr('Low damage'), format_int(count1), tr('Medium damage'), format_int(count2), tr('High damage'), format_int(count3))) impact_summary += (' <tr><td>%s (NaN):</td><td>%s</td></tr>' % ('Unknown', format_int(count_unknown))) impact_summary += '</table>' # Create style style_classes = [dict(label=tr('Low damage'), min=0.5, max=1.5, colour='#fecc5c', transparency=0), dict(label=tr('Medium damage'), min=1.5, max=2.5, colour='#fd8d3c', transparency=0), dict(label=tr('High damage'), min=2.5, max=3.5, colour='#f31a1c', transparency=0)] style_info = dict(target_field=self.target_field, style_classes=style_classes) # Create vector layer and return V = Vector(data=building_damage, projection=E.get_projection(), geometry=coordinates, name='Estimated damage level', keywords={'impact_summary': impact_summary}, style_info=style_info) return V
def run(layers): """Risk plugin for tsunami building damage """ # Extract data H = get_hazard_layer(layers) # Ground shaking E = get_exposure_layer(layers) # Building locations # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() inundation = H.get_data() # Calculate N = len(H) impact = [] for i in range(N): #------------------- # Extract parameters #------------------- depth = float(inundation[i].values()[0]) shore_distance = E.get_data('SHORE_DIST', i) # FIXME: Get rid of the type casting when # issue #66 is done number_of_people_in_building = int(E.get_data('NEXIS_PEOP', i)) wall_type = E.get_data('WALL_TYPE', i) contents_value = E.get_data('CONT_VALUE', i) structure_value = E.get_data('STR_VALUE', i) #------------------------ # Compute people affected #------------------------ if 0.01 < depth < 1.0: people_affected = number_of_people_in_building else: people_affected = 0 if depth >= 1.0: people_severely_affected = number_of_people_in_building else: people_severely_affected = 0 #---------------------------------------- # Compute impact on buldings and contents #---------------------------------------- depth_floor = depth - 0.3 # Adjust for floor height if depth_floor >= 0.0: buildings_inundated = 1 else: buildings_inundated = 0 if depth_floor < 0.0: structural_damage = contents_damage = 0.0 else: # Water is deep enough to cause damage if wall_type in struct_damage_curve: curve = struct_damage_curve[wall_type] else: # Establish default for unknown wall type curve = struct_damage_curve['Brick veneer'] structural_damage = curve(depth_floor) contents_damage = contents_damage_curve(depth_floor) #--------------- # Compute losses #--------------- structural_loss = structural_damage * structure_value contents_loss = contents_damage * contents_value #------- # Return #------- impact.append({ 'NEXIS_PEOP': number_of_people_in_building, 'PEOPLE_AFFECTED': people_affected, 'PEOPLE_SEV_AFFECTED': people_severely_affected, 'STRUCT_INUNDATED': buildings_inundated, 'STRUCT_DAMAGE_fraction': structural_damage, 'CONTENTS_DAMAGE_fraction': contents_damage, 'STRUCT_LOSS_AUD': structural_loss, 'CONTENTS_LOSS_AUD': contents_loss, 'DEPTH': depth }) # FIXME (Ole): Need helper to generate new layer using # correct spatial reference # (i.e. sensibly wrap the following lines) V = Vector(data=impact, projection=E.get_projection(), geometry=coordinates, name='Estimated tsunami impact') return V
def run(self, layers): """Plugin for impact of population as derived by categorised hazard Input layers: List of layers expected to contain my_hazard: Raster layer of categorised hazard my_exposure: Raster layer of population data Counts number of people exposed to each category of the hazard Return Map of population exposed to high category Table with number of people in each category """ # The 3 category high_t = 1 medium_t = 0.66 low_t = 0.34 # Identify hazard and exposure layers my_hazard = get_hazard_layer(layers) # Categorised Hazard my_exposure = get_exposure_layer(layers) # Population Raster question = get_question(my_hazard.get_name(), my_exposure.get_name(), self) # Extract data as numeric arrays C = my_hazard.get_data(nan=0.0) # Category # Calculate impact as population exposed to each category P = my_exposure.get_data(nan=0.0, scaling=True) H = numpy.where(C == high_t, P, 0) M = numpy.where(C > medium_t, P, 0) L = numpy.where(C < low_t, P, 0) # Count totals total = int(numpy.sum(P)) high = int(numpy.sum(H)) medium = int(numpy.sum(M)) - int(numpy.sum(H)) low = int(numpy.sum(L)) - int(numpy.sum(M)) total_impact = high + medium + low # Don't show digits less than a 1000 total = round_thousand(total) total_impact = round_thousand(total_impact) high = round_thousand(high) medium = round_thousand(medium) low = round_thousand(low) # Generate impact report for the pdf map table_body = [ question, TableRow([tr('People impacted '), '%s' % format_int(total_impact)], header=True), TableRow( [tr('People in high hazard area '), '%s' % format_int(high)], header=True), TableRow([ tr('People in medium hazard area '), '%s' % format_int(medium) ], header=True), TableRow([tr('People in low hazard area'), '%s' % format_int(low)], header=True) ] impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Map shows population density in high or medium ' 'hazard area'), tr('Total population: %s') % format_int(total) ]) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('People in high hazard areas') # Generate 8 equidistant classes across the range of flooded population # 8 is the number of classes in the predefined flood population style # as imported # noinspection PyTypeChecker classes = numpy.linspace(numpy.nanmin(M.flat[:]), numpy.nanmax(M.flat[:]), 8) # Modify labels in existing flood style to show quantities style_classes = style_info['style_classes'] style_classes[1]['label'] = tr('Low [%i people/cell]') % classes[1] style_classes[4]['label'] = tr('Medium [%i people/cell]') % classes[4] style_classes[7]['label'] = tr('High [%i people/cell]') % classes[7] style_info['legend_title'] = tr('Population Density') # Create raster object and return R = Raster(M, projection=my_hazard.get_projection(), geotransform=my_hazard.get_geotransform(), name=tr('Population which %s') % (get_function_title(self).lower()), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title }, style_info=style_info) return R
def run(self, layers): """Plugin for impact of population as derived by categorised hazard. :param layers: List of layers expected to contain * hazard_layer: Raster layer of categorised hazard * exposure_layer: Raster layer of population data Counts number of people exposed to each category of the hazard :returns: Map of population exposed to high category Table with number of people in each category """ # The 3 category high_t = self.parameters['Categorical thresholds'][2] medium_t = self.parameters['Categorical thresholds'][1] low_t = self.parameters['Categorical thresholds'][0] # Identify hazard and exposure layers hazard_layer = get_hazard_layer(layers) # Categorised Hazard exposure_layer = get_exposure_layer(layers) # Population Raster question = get_question(hazard_layer.get_name(), exposure_layer.get_name(), self) # Extract data as numeric arrays C = hazard_layer.get_data(nan=0.0) # Category # Calculate impact as population exposed to each category P = exposure_layer.get_data(nan=0.0, scaling=True) H = numpy.where(C <= high_t, P, 0) M = numpy.where(C < medium_t, P, 0) L = numpy.where(C < low_t, P, 0) # Count totals total = int(numpy.sum(P)) high = int(numpy.sum(H)) - int(numpy.sum(M)) medium = int(numpy.sum(M)) - int(numpy.sum(L)) low = int(numpy.sum(L)) total_impact = high + medium + low # Don't show digits less than a 1000 total = population_rounding(total) total_impact = population_rounding(total_impact) high = population_rounding(high) medium = population_rounding(medium) low = population_rounding(low) minimum_needs = [ parameter.serialize() for parameter in self.parameters['minimum needs'] ] # Generate impact report for the pdf map table_body = [ question, TableRow([tr('People impacted '), '%s' % format_int(total_impact)], header=True), TableRow( [tr('People in high hazard area '), '%s' % format_int(high)], header=True), TableRow([ tr('People in medium hazard area '), '%s' % format_int(medium) ], header=True), TableRow([tr('People in low hazard area'), '%s' % format_int(low)], header=True) ] impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Map shows population count in high or medium hazard area'), tr('Total population: %s') % format_int(total), TableRow( tr('Table below shows the minimum needs for all ' 'affected people')) ]) total_needs = evacuated_population_needs(total_impact, minimum_needs) for frequency, needs in total_needs.items(): table_body.append( TableRow([ tr('Needs should be provided %s' % frequency), tr('Total') ], header=True)) for resource in needs: table_body.append( TableRow([ tr(resource['table name']), format_int(resource['amount']) ])) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('People in high hazard areas') # Generate 8 equidistant classes across the range of flooded population # 8 is the number of classes in the predefined flood population style # as imported # noinspection PyTypeChecker classes = numpy.linspace(numpy.nanmin(M.flat[:]), numpy.nanmax(M.flat[:]), 8) # Modify labels in existing flood style to show quantities style_classes = style_info['style_classes'] style_classes[1]['label'] = tr('Low [%i people/cell]') % classes[1] style_classes[4]['label'] = tr('Medium [%i people/cell]') % classes[4] style_classes[7]['label'] = tr('High [%i people/cell]') % classes[7] style_info['legend_title'] = tr('Population Count') # Create raster object and return raster_layer = Raster(M, projection=hazard_layer.get_projection(), geotransform=hazard_layer.get_geotransform(), name=tr('Population which %s') % (get_function_title(self).lower()), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'total_needs': total_needs }, style_info=style_info) return raster_layer
def run(self, layers): """Risk plugin for volcano hazard on building/structure Input layers: List of layers expected to contain my_hazard: Hazard layer of volcano my_exposure: Vector layer of structure data on the same grid as my_hazard Counts number of building exposed to each volcano hazard zones. Return Map of building exposed to volcanic hazard zones Table with number of buildings affected """ # Identify hazard and exposure layers my_hazard = get_hazard_layer(layers) # Volcano hazard layer my_exposure = get_exposure_layer(layers) is_point_data = False question = get_question(my_hazard.get_name(), my_exposure.get_name(), self) # Input checks if not my_hazard.is_vector: msg = ('Input hazard %s was not a vector layer as expected ' % my_hazard.get_name()) raise Exception(msg) msg = ('Input hazard must be a polygon or point layer. I got %s ' 'with layer type %s' % (my_hazard.get_name(), my_hazard.get_geometry_name())) if not (my_hazard.is_polygon_data or my_hazard.is_point_data): raise Exception(msg) if my_hazard.is_point_data: # Use concentric circles radii = self.parameters['distances [km]'] is_point_data = True centers = my_hazard.get_geometry() attributes = my_hazard.get_data() rad_m = [x * 1000 for x in radii] # Convert to meters Z = make_circular_polygon(centers, rad_m, attributes=attributes) # To check category_title = 'Radius' my_hazard = Z category_names = rad_m name_attribute = 'NAME' # As in e.g. the Smithsonian dataset else: # Use hazard map category_title = 'KRB' # FIXME (Ole): Change to English and use translation system category_names = ['Kawasan Rawan Bencana III', 'Kawasan Rawan Bencana II', 'Kawasan Rawan Bencana I'] name_attribute = 'GUNUNG' # As in e.g. BNPB hazard map # Get names of volcanos considered if name_attribute in my_hazard.get_attribute_names(): D = {} for att in my_hazard.get_data(): # Run through all polygons and get unique names D[att[name_attribute]] = None volcano_names = '' for name in D: volcano_names += '%s, ' % name volcano_names = volcano_names[:-2] # Strip trailing ', ' else: volcano_names = tr('Not specified in data') if not category_title in my_hazard.get_attribute_names(): msg = ('Hazard data %s did not contain expected ' 'attribute %s ' % (my_hazard.get_name(), category_title)) raise InaSAFEError(msg) # Run interpolation function for polygon2raster P = assign_hazard_values_to_exposure_data(my_hazard, my_exposure) # Initialise attributes of output dataset with all attributes # from input polygon and a building count of zero new_attributes = my_hazard.get_data() categories = {} for attr in new_attributes: attr[self.target_field] = 0 cat = attr[category_title] categories[cat] = 0 # Count impacted building per polygon and total for attr in P.get_data(): # Update building count for associated polygon poly_id = attr['polygon_id'] if poly_id is not None: new_attributes[poly_id][self.target_field] += 1 # Update building count for each category cat = new_attributes[poly_id][category_title] categories[cat] += 1 # Count totals total = len(my_exposure) # Generate simple impact report blank_cell = '' table_body = [question, TableRow([tr('Volcanos considered'), '%s' % volcano_names, blank_cell], header=True), TableRow([tr('Distance [km]'), tr('Total'), tr('Cumulative')], header=True)] cum = 0 for name in category_names: # prevent key error count = categories.get(name, 0) cum += count if is_point_data: name = int(name) / 1000 table_body.append(TableRow([name, format_int(count), format_int(cum)])) table_body.append(TableRow(tr('Map shows buildings affected in ' 'each of volcano hazard polygons.'))) impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([TableRow(tr('Notes'), header=True), tr('Total number of buildings %s in the viewable ' 'area') % format_int(total), tr('Only buildings available in OpenStreetMap ' 'are considered.')]) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('Buildings affected by volcanic hazard zone') # Create style colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] building_counts = [x[self.target_field] for x in new_attributes] classes = create_classes(building_counts, len(colours)) interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class['label'] = create_label(interval_classes[i]) if i == 0: transparency = 100 style_class['min'] = 0 else: transparency = 30 style_class['min'] = classes[i - 1] style_class['transparency'] = transparency style_class['colour'] = colours[i] style_class['max'] = classes[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='graduatedSymbol') # For printing map purpose map_title = tr('Building affected by volcanic hazard zone') legend_notes = tr('Thousand separator is represented by \'.\'') legend_units = tr('(building)') legend_title = tr('Building count') # Create vector layer and return V = Vector(data=new_attributes, projection=my_hazard.get_projection(), geometry=my_hazard.get_geometry(as_geometry_objects=True), name=tr('Buildings affected by volcanic hazard zone'), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title}, style_info=style_info) return V
def run(self, layers): """Indonesian Earthquake Fatality Model Input: :param layers: List of layers expected to contain, my_hazard: Raster layer of MMI ground shaking my_exposure: Raster layer of population density """ displacement_rate = self.parameters['displacement_rate'] # Tolerance for transparency tolerance = self.parameters['tolerance'] # Extract input layers intensity = get_hazard_layer(layers) population = get_exposure_layer(layers) question = get_question(intensity.get_name(), population.get_name(), self) # Extract data grids my_hazard = intensity.get_data() # Ground Shaking my_exposure = population.get_data(scaling=True) # Population Density # Calculate population affected by each MMI level # FIXME (Ole): this range is 2-9. Should 10 be included? mmi_range = self.parameters['mmi_range'] number_of_exposed = {} number_of_displaced = {} number_of_fatalities = {} # Calculate fatality rates for observed Intensity values (my_hazard # based on ITB power model R = numpy.zeros(my_hazard.shape) for mmi in mmi_range: # Identify cells where MMI is in class i and # count population affected by this shake level I = numpy.where((my_hazard > mmi - self.parameters['step']) * (my_hazard <= mmi + self.parameters['step']), my_exposure, 0) # Calculate expected number of fatalities per level fatality_rate = self.fatality_rate(mmi) F = fatality_rate * I # Calculate expected number of displaced people per level try: D = displacement_rate[mmi] * I except KeyError, e: msg = 'mmi = %i, I = %s, Error msg: %s' % (mmi, str(I), str(e)) # noinspection PyExceptionInherit raise InaSAFEError(msg) # Adjust displaced people to disregard fatalities. # Set to zero if there are more fatalities than displaced. D = numpy.where(D > F, D - F, 0) # Sum up numbers for map R += D # Displaced # Generate text with result for this study # This is what is used in the real time system exposure table number_of_exposed[mmi] = numpy.nansum(I.flat) number_of_displaced[mmi] = numpy.nansum(D.flat) # noinspection PyUnresolvedReferences number_of_fatalities[mmi] = numpy.nansum(F.flat)
def run(self, layers): """Experimental impact function. Input layers: List of layers expected to contain H: Polygon layer of inundation areas E: Vector layer of roads """ target_field = self.parameters['target_field'] road_type_field = self.parameters['road_type_field'] threshold_min = self.parameters['min threshold [m]'] threshold_max = self.parameters['max threshold [m]'] if threshold_min > threshold_max: message = tr('''The minimal threshold is greater then the maximal specified threshold. Please check the values.''') raise GetDataError(message) # Extract data H = get_hazard_layer(layers) # Flood E = get_exposure_layer(layers) # Roads question = get_question(H.get_name(), E.get_name(), self) H = H.get_layer() E = E.get_layer() # Get necessary width and height of raster height = (self.extent[3] - self.extent[1]) / H.rasterUnitsPerPixelY() height = int(height) width = (self.extent[2] - self.extent[0]) / H.rasterUnitsPerPixelX() width = int(width) # Align raster extent and self.extent raster_extent = H.dataProvider().extent() xmin = raster_extent.xMinimum() xmax = raster_extent.xMaximum() ymin = raster_extent.yMinimum() ymax = raster_extent.yMaximum() x_delta = (xmax - xmin) / H.width() x = xmin for i in range(H.width()): if abs(x - self.extent[0]) < x_delta: # We have found the aligned raster boundary break x += x_delta _ = i y_delta = (ymax - ymin) / H.height() y = ymin for i in range(H.width()): if abs(y - self.extent[1]) < y_delta: # We have found the aligned raster boundary break y += y_delta clip_extent = [x, y, x + width * x_delta, y + height * y_delta] # Clip and polygonize small_raster = clip_raster(H, width, height, QgsRectangle(*clip_extent)) flooded_polygon = polygonize(small_raster, threshold_min, threshold_max) # Filter geometry and data using the extent extent = QgsRectangle(*self.extent) request = QgsFeatureRequest() request.setFilterRect(extent) if flooded_polygon is None: message = tr('''There are no objects in the hazard layer with "value">'%s'. Please check the value or use other extent.''' % (threshold_min, )) raise GetDataError(message) # Clip exposure by the extent extent_as_polygon = QgsGeometry().fromRect(extent) line_layer = clip_by_polygon(E, extent_as_polygon) # Find inundated roads, mark them line_layer = split_by_polygon(line_layer, flooded_polygon, request, mark_value=(target_field, 1)) # Find inundated roads, mark them # line_layer = split_by_polygon( # E, # flooded_polygon, # request, # mark_value=(target_field, 1)) target_field_index = line_layer.dataProvider().\ fieldNameIndex(target_field) # Generate simple impact report epsg = get_utm_epsg(self.extent[0], self.extent[1]) output_crs = QgsCoordinateReferenceSystem(epsg) transform = QgsCoordinateTransform(E.crs(), output_crs) road_len = flooded_len = 0 # Length of roads roads_by_type = dict() # Length of flooded roads by types roads_data = line_layer.getFeatures() road_type_field_index = line_layer.fieldNameIndex(road_type_field) for road in roads_data: attributes = road.attributes() road_type = attributes[road_type_field_index] if road_type.__class__.__name__ == 'QPyNullVariant': road_type = tr('Other') geom = road.geometry() geom.transform(transform) length = geom.length() road_len += length if road_type not in roads_by_type: roads_by_type[road_type] = {'flooded': 0, 'total': 0} roads_by_type[road_type]['total'] += length if attributes[target_field_index] == 1: flooded_len += length roads_by_type[road_type]['flooded'] += length table_body = [ question, TableRow([ tr('Road Type'), tr('Flooded in the threshold (m)'), tr('Total (m)') ], header=True), TableRow([tr('All'), int(flooded_len), int(road_len)]) ] table_body.append(TableRow(tr('Breakdown by road type'), header=True)) for t, v in roads_by_type.iteritems(): table_body.append(TableRow([t, int(v['flooded']), int(v['total'])])) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('Roads inundated') style_classes = [ dict(label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=0.5), dict(label=tr('Inundated'), value=1, colour='#F31A1C', transparency=0, size=0.5) ] style_info = dict(target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') # Convert QgsVectorLayer to inasafe layer and return it line_layer = Vector(data=line_layer, name=tr('Flooded roads'), keywords={ 'impact_summary': impact_summary, 'map_title': map_title, 'target_field': target_field }, style_info=style_info) return line_layer
def run(self, layers): """Flood impact to buildings (e.g. from Open Street Map). """ threshold = self.parameters['threshold [m]'] # Flood threshold [m] verify(isinstance(threshold, float), 'Expected thresholds to be a float. Got %s' % str(threshold)) # 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) 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'] 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 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 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)]) ] 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)) 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) # Result impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary # Create style style_classes = [ dict(label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=1), dict(label=tr('Inundated'), value=1, colour='#F31A1C', transparency=0, size=1) ] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') # For printing map purpose map_title = tr('Buildings inundated') legend_units = tr('(inundated or not inundated)') legend_title = tr('Structure inundated status') # 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, 'target_field': self.target_field, 'map_title': map_title, 'legend_units': legend_units, 'legend_title': legend_title }, style_info=style_info) return V
def run(self, layers): """Risk plugin for flood population evacuation Input layers: List of layers expected to contain H: Raster layer of volcano depth P: Raster layer of population data on the same grid as H Counts number of people exposed to flood levels exceeding specified threshold. Return Map of population exposed to flood levels exceeding the threshold Table with number of people evacuated and supplies required """ # Identify hazard and exposure layers H = get_hazard_layer(layers) # Flood inundation E = get_exposure_layer(layers) question = get_question(H.get_name(), E.get_name(), self) # Input checks if not H.is_vector: msg = ('Input hazard %s was not a vector layer as expected ' % H.get_name()) raise Exception(msg) msg = ('Input hazard must be a polygon or point layer. ' 'I got %s with layer ' 'type %s' % (H.get_name(), H.get_geometry_name())) if not (H.is_polygon_data or H.is_point_data): raise Exception(msg) if H.is_point_data: # Use concentric circles radii = self.parameters['R [km]'] centers = H.get_geometry() attributes = H.get_data() rad_m = [x * 1000 for x in radii] # Convert to meters H = make_circular_polygon(centers, rad_m, attributes=attributes) #H.write_to_file('Evac_zones_%s.shp' % str(radii)) # To check category_title = 'Radius' category_header = tr('Distance [km]') category_names = radii name_attribute = 'NAME' # As in e.g. the Smithsonian dataset else: # Use hazard map category_title = 'KRB' category_header = tr('Category') # FIXME (Ole): Change to English and use translation system category_names = [ 'Kawasan Rawan Bencana III', 'Kawasan Rawan Bencana II', 'Kawasan Rawan Bencana I' ] name_attribute = 'GUNUNG' # As in e.g. BNPB hazard map attributes = H.get_data() # Get names of volcanos considered if name_attribute in H.get_attribute_names(): D = {} for att in H.get_data(): # Run through all polygons and get unique names D[att[name_attribute]] = None volcano_names = '' for name in D: volcano_names += '%s, ' % name volcano_names = volcano_names[:-2] # Strip trailing ', ' else: volcano_names = tr('Not specified in data') if not category_title in H.get_attribute_names(): msg = ('Hazard data %s did not contain expected ' 'attribute %s ' % (H.get_name(), category_title)) raise InaSAFEError(msg) # Run interpolation function for polygon2raster P = assign_hazard_values_to_exposure_data(H, E, attribute_name='population') # Initialise attributes of output dataset with all attributes # from input polygon and a population count of zero new_attributes = H.get_data() categories = {} for attr in new_attributes: attr[self.target_field] = 0 cat = attr[category_title] categories[cat] = 0 # Count affected population per polygon and total evacuated = 0 for attr in P.get_data(): # Get population at this location pop = float(attr['population']) # Update population count for associated polygon poly_id = attr['polygon_id'] new_attributes[poly_id][self.target_field] += pop # Update population count for each category cat = new_attributes[poly_id][category_title] categories[cat] += pop # Count totals total = int(numpy.sum(E.get_data(nan=0))) # Don't show digits less than a 1000 if total > 1000: total = total // 1000 * 1000 # Count number and cumulative for each zone cum = 0 pops = {} cums = {} for name in category_names: if category_title == 'Radius': key = name * 1000 # Convert to meters else: key = name pop = int(categories[key]) if pop > 1000: pop = pop // 1000 * 1000 cum += pop if cum > 1000: cum = cum // 1000 * 1000 pops[name] = pop cums[name] = cum # Use final accumulation as total number needing evac evacuated = cum # Calculate estimated needs based on BNPB Perka # 7/2008 minimum bantuan # FIXME (Ole): Refactor into one function to be shared rice = int(evacuated * 2.8) drinking_water = int(evacuated * 17.5) water = int(evacuated * 67) family_kits = int(evacuated / 5) toilets = int(evacuated / 20) # Generate impact report for the pdf map blank_cell = '' table_body = [ question, TableRow( [tr('Volcanos considered'), '%s' % volcano_names, blank_cell], header=True), TableRow([ tr('People needing evacuation'), '%s' % format_int(evacuated), blank_cell ], header=True), TableRow( [category_header, tr('Total'), tr('Cumulative')], header=True) ] for name in category_names: table_body.append( TableRow( [name, format_int(pops[name]), format_int(cums[name])])) table_body.extend([ TableRow( tr('Map shows population affected in ' 'each of volcano hazard polygons.')), TableRow([tr('Needs per week'), tr('Total'), blank_cell], header=True), [tr('Rice [kg]'), format_int(rice), blank_cell], [tr('Drinking Water [l]'), format_int(drinking_water), blank_cell], [tr('Clean Water [l]'), format_int(water), blank_cell], [tr('Family Kits'), format_int(family_kits), blank_cell], [tr('Toilets'), format_int(toilets), blank_cell] ]) impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Total population %s in the viewable area') % format_int(total), tr('People need evacuation if they are within the ' 'volcanic hazard zones.') ]) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('People affected by volcanic hazard zone') # Define classes for legend for flooded population counts colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] population_counts = [x[self.target_field] for x in new_attributes] cls = [0] + numpy.linspace(1, max(population_counts), len(colours)).tolist() # Define style info for output polygons showing population counts style_classes = [] for i, colour in enumerate(colours): lo = cls[i] hi = cls[i + 1] if i == 0: label = tr('0') else: label = tr('%i - %i') % (lo, hi) entry = dict(label=label, colour=colour, min=lo, max=hi, transparency=50, size=1) style_classes.append(entry) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, legend_title=tr('Population Count')) # Create vector layer and return V = Vector(data=new_attributes, projection=H.get_projection(), geometry=H.get_geometry(as_geometry_objects=True), name=tr('Population affected by volcanic hazard zone'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'target_field': self.target_field }, style_info=style_info) return V
def run(self, layers): """Risk plugin for volcano hazard on building/structure Input layers: List of layers expected to contain my_hazard: Hazard layer of volcano my_exposure: Vector layer of structure data on the same grid as my_hazard Counts number of building exposed to each volcano hazard zones. Return Map of building exposed to volcanic hazard zones Table with number of buildings affected """ # Identify hazard and exposure layers my_hazard = get_hazard_layer(layers) # Volcano hazard layer my_exposure = get_exposure_layer(layers) is_point_data = False question = get_question(my_hazard.get_name(), my_exposure.get_name(), self) # Input checks if not my_hazard.is_vector: msg = ('Input hazard %s was not a vector layer as expected ' % my_hazard.get_name()) raise Exception(msg) msg = ('Input hazard must be a polygon or point layer. I got %s ' 'with layer type %s' % (my_hazard.get_name(), my_hazard.get_geometry_name())) if not (my_hazard.is_polygon_data or my_hazard.is_point_data): raise Exception(msg) if my_hazard.is_point_data: # Use concentric circles radii = self.parameters['distances [km]'] is_point_data = True centers = my_hazard.get_geometry() attributes = my_hazard.get_data() rad_m = [x * 1000 for x in radii] # Convert to meters Z = make_circular_polygon(centers, rad_m, attributes=attributes) # To check category_title = 'Radius' my_hazard = Z category_names = rad_m name_attribute = 'NAME' # As in e.g. the Smithsonian dataset else: # Use hazard map category_title = 'KRB' # FIXME (Ole): Change to English and use translation system category_names = [ 'Kawasan Rawan Bencana III', 'Kawasan Rawan Bencana II', 'Kawasan Rawan Bencana I' ] name_attribute = 'GUNUNG' # As in e.g. BNPB hazard map # Get names of volcanos considered if name_attribute in my_hazard.get_attribute_names(): D = {} for att in my_hazard.get_data(): # Run through all polygons and get unique names D[att[name_attribute]] = None volcano_names = '' for name in D: volcano_names += '%s, ' % name volcano_names = volcano_names[:-2] # Strip trailing ', ' else: volcano_names = tr('Not specified in data') if not category_title in my_hazard.get_attribute_names(): msg = ('Hazard data %s did not contain expected ' 'attribute %s ' % (my_hazard.get_name(), category_title)) # noinspection PyExceptionInherit raise InaSAFEError(msg) # Run interpolation function for polygon2raster P = assign_hazard_values_to_exposure_data(my_hazard, my_exposure) # Initialise attributes of output dataset with all attributes # from input polygon and a building count of zero new_attributes = my_hazard.get_data() categories = {} for attr in new_attributes: attr[self.target_field] = 0 cat = attr[category_title] categories[cat] = 0 # Count impacted building per polygon and total for attr in P.get_data(): # Update building count for associated polygon poly_id = attr['polygon_id'] if poly_id is not None: new_attributes[poly_id][self.target_field] += 1 # Update building count for each category cat = new_attributes[poly_id][category_title] categories[cat] += 1 # Count totals total = len(my_exposure) # Generate simple impact report blank_cell = '' table_body = [ question, TableRow( [tr('Volcanos considered'), '%s' % volcano_names, blank_cell], header=True), TableRow([tr('Distance [km]'), tr('Total'), tr('Cumulative')], header=True) ] cum = 0 for name in category_names: # prevent key error count = categories.get(name, 0) cum += count if is_point_data: name = int(name) / 1000 table_body.append( TableRow([name, format_int(count), format_int(cum)])) table_body.append( TableRow( tr('Map shows buildings affected in ' 'each of volcano hazard polygons.'))) impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Total number of buildings %s in the viewable ' 'area') % format_int(total), tr('Only buildings available in OpenStreetMap ' 'are considered.') ]) impact_summary = Table(table_body).toNewlineFreeString() building_counts = [x[self.target_field] for x in new_attributes] if max(building_counts) == 0 == min(building_counts): table_body = [ question, TableRow([ tr('Number of buildings affected'), '%s' % format_int(cum), blank_cell ], header=True) ] my_message = Table(table_body).toNewlineFreeString() raise ZeroImpactException(my_message) # Create style colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] classes = create_classes(building_counts, len(colours)) interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class['label'] = create_label(interval_classes[i]) if i == 0: transparency = 100 style_class['min'] = 0 else: transparency = 30 style_class['min'] = classes[i - 1] style_class['transparency'] = transparency style_class['colour'] = colours[i] style_class['max'] = classes[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='graduatedSymbol') # For printing map purpose map_title = tr('Buildings affected by volcanic hazard zone') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) legend_units = tr('(building)') legend_title = tr('Building count') # Create vector layer and return V = Vector(data=new_attributes, projection=my_hazard.get_projection(), geometry=my_hazard.get_geometry(as_geometry_objects=True), name=tr('Buildings affected by volcanic hazard zone'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title }, style_info=style_info) return V
def run(self, layers): """Earthquake impact to buildings (e.g. from Open Street Map) """ LOGGER.debug('Running earthquake building impact') # Thresholds for mmi breakdown t0 = self.parameters['low_threshold'] t1 = self.parameters['medium_threshold'] t2 = self.parameters['high_threshold'] class_1 = tr('Low') class_2 = tr('Medium') class_3 = tr('High') # 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) # Define attribute name for hazard levels hazard_attribute = 'mmi' # Determine if exposure data have NEXIS attributes attribute_names = E.get_attribute_names() if ('FLOOR_AREA' in attribute_names and 'BUILDING_C' in attribute_names and 'CONTENTS_C' in attribute_names): is_NEXIS = True else: is_NEXIS = False # 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 lo = 0 me = 0 hi = 0 building_values = {} contents_values = {} for key in range(4): building_values[key] = 0 contents_values[key] = 0 for i in range(N): # Classify building according to shake level # and calculate dollar losses if is_NEXIS: try: area = float(attributes[i]['FLOOR_AREA']) except (ValueError, KeyError): #print 'Got area', attributes[i]['FLOOR_AREA'] area = 0.0 try: building_value_density = float(attributes[i]['BUILDING_C']) except (ValueError, KeyError): #print 'Got bld value', attributes[i]['BUILDING_C'] building_value_density = 0.0 try: contents_value_density = float(attributes[i]['CONTENTS_C']) except (ValueError, KeyError): #print 'Got cont value', attributes[i]['CONTENTS_C'] contents_value_density = 0.0 building_value = building_value_density * area contents_value = contents_value_density * area x = float(attributes[i][hazard_attribute]) # MMI if t0 <= x < t1: lo += 1 cls = 1 elif t1 <= x < t2: me += 1 cls = 2 elif t2 <= x: hi += 1 cls = 3 else: # Not reported for less than level t0 cls = 0 attributes[i][self.target_field] = cls if is_NEXIS: # Accumulate values in 1M dollar units building_values[cls] += building_value contents_values[cls] += contents_value if is_NEXIS: # Convert to units of one million dollars for key in range(4): building_values[key] = int(building_values[key] / 1000000) contents_values[key] = int(contents_values[key] / 1000000) if is_NEXIS: # Generate simple impact report for NEXIS type buildings table_body = [question, TableRow([tr('Hazard Level'), tr('Buildings Affected'), tr('Buildings value ($M)'), tr('Contents value ($M)')], header=True), TableRow([class_1, lo, building_values[1], contents_values[1]]), TableRow([class_2, me, building_values[2], contents_values[2]]), TableRow([class_3, hi, building_values[3], contents_values[3]])] else: # Generate simple impact report for unspecific buildings table_body = [question, TableRow([tr('Hazard Level'), tr('Buildings Affected')], header=True), TableRow([class_1, str(lo)]), TableRow([class_2, str(me)]), TableRow([class_3, str(hi)])] table_body.append(TableRow(tr('Notes'), header=True)) table_body.append(tr('High hazard is defined as shake levels greater ' 'than %i on the MMI scale.') % t2) table_body.append(tr('Medium hazard is defined as shake levels ' 'between %i and %i on the MMI scale.') % (t1, t2)) table_body.append(tr('Low hazard is defined as shake levels ' 'between %i and %i on the MMI scale.') % (t0, t1)) if is_NEXIS: table_body.append(tr('Values are in units of 1 million Australian ' 'Dollars')) impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary map_title = tr('Buildings affected') # Create style style_classes = [dict(label=class_1, min=1, max=1, colour='#ffff00', transparency=1), dict(label=class_2, min=2, max=2, colour='#ffaa00', transparency=1), dict(label=class_3, min=3, max=3, colour='#ff0000', transparency=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) LOGGER.debug('Created vector layer %s' % str(V)) return V
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: hazard_attribute = 'depth' else: hazard_attribute = 'FLOODPRONE' # 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 hazard_attribute == 'depth': # Get the interpolated depth x = float(attributes[i]['depth']) x = x > threshold elif hazard_attribute == 'FLOODPRONE': # Use interpolated polygon attribute atts = attributes[i] if 'FLOODPRONE' in atts: res = atts['FLOODPRONE'] if res is None: x = False else: x = res.lower() == 'yes' else: # If there isn't a flood prone attribute, # assume that building is wet if inside polygon # as flag by generic attribute AFFECTED res = atts['Affected'] if res is None: x = False else: x = res else: msg = (_('Unknown hazard type %s. ' 'Must be either "depth" or "floodprone"') % hazard_attribute) raise Exception(msg) # Count affected buildings by usage type if available if 'type' in attribute_names: usage = attributes[i]['type'] else: usage = None 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' % (_('Building type'), ## _('Temporarily closed'), ## _('Total'))) ## fid.write('%s, %i, %i\n' % (_('All'), count, N)) # Generate simple impact report table_body = [question, TableRow([_('Building type'), _('Temporarily closed'), _('Total')], header=True), TableRow([_('All'), count, N])] ## fid.write('%s, %s, %s\n' % (_('Building type'), ## _('Temporarily closed'), ## _('Total'))) # Generate break down by building usage type is available if 'type' in attribute_names: # Make list of building types building_list = [] for usage in buildings: building_type = usage.replace('_', ' ') # Lookup internationalised value if available if building_type in internationalised_values: building_type = internationalised_values[building_type] else: print ('WARNING: %s could not be translated' % building_type) building_list.append([building_type.capitalize(), affected_buildings[usage], 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([_('Building type'), # _('Temporarily closed'), # _('Total')], header=True)) table_body.append(TableRow(_('Breakdown by building type'), header=True)) for row in building_list: s = TableRow(row) table_body.append(s) ## fid.close() table_body.append(TableRow(_('Action Checklist:'), header=True)) table_body.append(TableRow(_('Are the critical facilities still ' 'open?'))) table_body.append(TableRow(_('Notes'), header=True)) assumption = _('Buildings are said to be flooded when ') if hazard_attribute == 'depth': assumption += _('flood levels exceed %.1f m') % threshold else: assumption += _('in areas marked as flood prone') table_body.append(assumption) impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary map_title = _('Buildings inundated') # Create style style_classes = [dict(label=_('Not Flooded'), min=0, max=0, colour='#1EFC7C', transparency=0, size=1), dict(label=_('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=_('Estimated buildings affected'), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title}, style_info=style_info) return V
def run(self, layers): """Experimental impact function for flood polygons on roads. :param layers: List of layers expected to contain H: Polygon layer of inundation areas E: Vector layer of roads """ target_field = self.parameters['target_field'] road_type_field = self.parameters['road_type_field'] affected_field = self.parameters['affected_field'] affected_value = self.parameters['affected_value'] # Extract data hazard = get_hazard_layer(layers) # Flood exposure = get_exposure_layer(layers) # Roads question = get_question(hazard.get_name(), exposure.get_name(), self) hazard = hazard.get_layer() hazard_provider = hazard.dataProvider() affected_field_index = hazard_provider.fieldNameIndex(affected_field) # see #818: should still work if there is no valid attribute if affected_field_index == -1: pass # message = tr('''Parameter "Affected Field"(='%s') # is not present in the attribute table of the hazard layer. # ''' % (affected_field, )) # raise GetDataError(message) LOGGER.info('Affected field: %s' % affected_field) LOGGER.info('Affected field index: %s' % affected_field_index) exposure = exposure.get_layer() # Filter geometry and data using the extent extent = QgsRectangle(*self.extent) request = QgsFeatureRequest() request.setFilterRect(extent) # Split line_layer by hazard and save as result: # 1) Filter from hazard inundated features # 2) Mark roads as inundated (1) or not inundated (0) if affected_field_index != -1: affected_field_type = hazard_provider.fields( )[affected_field_index].typeName() if affected_field_type in ['Real', 'Integer']: affected_value = float(affected_value) ################################# # REMARK 1 # In qgis 2.2 we can use request to filter inundated # polygons directly (it allows QgsExpression). Then # we can delete the lines and call # # request = .... # hazard_poly = union_geometry(H, request) # ################################ hazard_features = hazard.getFeatures(request) hazard_poly = None for feature in hazard_features: attributes = feature.attributes() if affected_field_index != -1: if attributes[affected_field_index] != affected_value: continue if hazard_poly is None: hazard_poly = QgsGeometry(feature.geometry()) else: # Make geometry union of inundated polygons # But some feature.geometry() could be invalid, skip them tmp_geometry = hazard_poly.combine(feature.geometry()) try: if tmp_geometry.isGeosValid(): hazard_poly = tmp_geometry except AttributeError: pass ############################################### # END REMARK 1 ############################################### if hazard_poly is None: message = tr( '''There are no objects in the hazard layer with "Affected value"='%s'. Please check the value or use a different extent.''' % (affected_value, )) raise GetDataError(message) # Clip exposure by the extent extent_as_polygon = QgsGeometry().fromRect(extent) line_layer = clip_by_polygon(exposure, extent_as_polygon) # Find inundated roads, mark them line_layer = split_by_polygon(line_layer, hazard_poly, request, mark_value=(target_field, 1)) # Generate simple impact report epsg = get_utm_epsg(self.extent[0], self.extent[1]) destination_crs = QgsCoordinateReferenceSystem(epsg) transform = QgsCoordinateTransform(exposure.crs(), destination_crs) road_len = flooded_len = 0 # Length of roads roads_by_type = dict() # Length of flooded roads by types roads_data = line_layer.getFeatures() road_type_field_index = line_layer.fieldNameIndex(road_type_field) target_field_index = line_layer.fieldNameIndex(target_field) for road in roads_data: attributes = road.attributes() road_type = attributes[road_type_field_index] if road_type.__class__.__name__ == 'QPyNullVariant': road_type = tr('Other') geom = road.geometry() geom.transform(transform) length = geom.length() road_len += length if road_type not in roads_by_type: roads_by_type[road_type] = {'flooded': 0, 'total': 0} roads_by_type[road_type]['total'] += length if attributes[target_field_index] == 1: flooded_len += length roads_by_type[road_type]['flooded'] += length table_body = [ question, TableRow([ tr('Road Type'), tr('Temporarily closed (m)'), tr('Total (m)') ], header=True), TableRow([tr('All'), int(flooded_len), int(road_len)]), TableRow(tr('Breakdown by road type'), header=True) ] for road_type, value in roads_by_type.iteritems(): table_body.append( TableRow( [road_type, int(value['flooded']), int(value['total'])])) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('Roads inundated') style_classes = [ dict(label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=0.5), dict(label=tr('Inundated'), value=1, colour='#F31A1C', transparency=0, size=0.5) ] style_info = dict(target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') # Convert QgsVectorLayer to inasafe layer and return it line_layer = Vector(data=line_layer, name=tr('Flooded roads'), keywords={ 'impact_summary': impact_summary, 'map_title': map_title, 'target_field': target_field }, style_info=style_info) return line_layer
def run(self, layers): """Risk plugin for flood population evacuation Input layers: List of layers expected to contain H: Raster layer of flood depth P: Raster layer of population data on the same grid as H Counts number of people exposed to flood levels exceeding specified threshold. Return Map of population exposed to flood levels exceeding the threshold Table with number of people evacuated and supplies required """ # Identify hazard and exposure layers H = get_hazard_layer(layers) # Flood inundation E = get_exposure_layer(layers) question = get_question(H.get_name(), E.get_name(), self) # Check that hazard is polygon type if not H.is_vector: msg = ('Input hazard %s was not a vector layer as expected ' % H.get_name()) raise Exception(msg) msg = ('Input hazard must be a polygon layer. I got %s with layer ' 'type %s' % (H.get_name(), H.get_geometry_name())) if not H.is_polygon_data: raise Exception(msg) # Run interpolation function for polygon2raster P = assign_hazard_values_to_exposure_data(H, E, attribute_name='population') # Initialise attributes of output dataset with all attributes # from input polygon and a population count of zero new_attributes = H.get_data() category_title = 'FLOODPRONE' # FIXME: Should come from keywords categories = {} for attr in new_attributes: attr[self.target_field] = 0 cat = attr[category_title] categories[cat] = 0 # Count affected population per polygon, per category and total evacuated = 0 for attr in P.get_data(): # Get population at this location pop = float(attr['population']) # Update population count for associated polygon poly_id = attr['polygon_id'] new_attributes[poly_id][self.target_field] += pop # Update population count for each category cat = new_attributes[poly_id][category_title] categories[cat] += pop # Update total evacuated += pop # Count totals total = int(numpy.sum(E.get_data(nan=0, scaling=False))) # Don't show digits less than a 1000 if total > 1000: total = total // 1000 * 1000 if evacuated > 1000: evacuated = evacuated // 1000 * 1000 # Calculate estimated needs based on BNPB Perka 7/2008 minimum bantuan rice = evacuated * 2.8 drinking_water = evacuated * 17.5 water = evacuated * 67 family_kits = evacuated / 5 toilets = evacuated / 20 # Generate impact report for the pdf map table_body = [question, TableRow([_('People needing evacuation'), '%i' % evacuated], header=True), TableRow(_('Map shows population affected in each flood ' 'prone area ')), TableRow([_('Needs per week'), _('Total')], header=True), [_('Rice [kg]'), int(rice)], [_('Drinking Water [l]'), int(drinking_water)], [_('Clean Water [l]'), int(water)], [_('Family Kits'), int(family_kits)], [_('Toilets'), int(toilets)]] impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([TableRow(_('Notes'), header=True), _('Total population: %i') % total, _('People need evacuation if in area identified ' 'as "Flood Prone"'), _('Minimum needs are defined in BNPB ' 'regulation 7/2008')]) impact_summary = Table(table_body).toNewlineFreeString() map_title = _('People affected by flood prone areas') # Define classes for legend for flooded population counts colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] population_counts = [x['population'] for x in new_attributes] cls = [0] + numpy.linspace(1, max(population_counts), len(colours)).tolist() # Define style info for output polygons showing population counts style_classes = [] for i, colour in enumerate(colours): lo = cls[i] hi = cls[i + 1] if i == 0: label = _('0') else: label = _('%i - %i') % (lo, hi) entry = dict(label=label, colour=colour, min=lo, max=hi, transparency=0, size=1) style_classes.append(entry) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, legend_title=_('Population Count')) # Create vector layer and return V = Vector(data=new_attributes, projection=H.get_projection(), geometry=H.get_geometry(), name=_('Population affected by flood prone areas'), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title}, style_info=style_info) return V
def run(self, layers): """Flood impact to buildings (e.g. from Open Street Map) """ # 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) # Interpolate hazard level to building locations I = assign_hazard_values_to_exposure_data(H, E) # Extract relevant exposure data #attribute_names = I.get_attribute_names() attributes = I.get_data() N = len(I) # Calculate road impact count = 0 #flooded_distance = 0 for i in range(N): # Use interpolated polygon attribute atts = attributes[i] if 'FLOODPRONE' in atts: res = atts['FLOODPRONE'] if res is None: x = False else: x = res.lower() == 'yes' else: # If there isn't a flood prone attribute, # assume that building is wet if inside polygon # as flag by generic attribute AFFECTED res = atts['Affected'] if res is None: x = False else: x = res # Count all roads if x is True: # Count total affected roads count += 1 # Add calculated impact to existing attributes attributes[i][self.target_field] = x if i == 0: print attributes[0].keys() # Generate simple impact report table_body = [ question, TableRow( [tr('Building type'), tr('Temporarily closed'), tr('Total')], header=True), TableRow([tr('All'), count, N]) ] impact_summary = Table(table_body).toNewlineFreeString() #impact_table = impact_summary map_title = tr('Roads 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(), geometry_type=I.get_geometry_type(), name=tr('Estimated roads affected'), keywords={ 'impact_summary': impact_summary, 'map_title': map_title, 'target_field': self.target_field }, style_info=style_info) return V
def run(self, layers): """Impact algorithm """ # Extract data H = get_hazard_layer(layers) # Depth R = get_exposure_layer(layers) # Building locations # Make the delta 10 times the size of the resolution. delta = abs(H.get_geotransform()[1]) * 10 min_value, max_value = H.get_extrema() E = convert_line_to_points(R, delta) # Interpolate hazard level to building locations H = assign_hazard_values_to_exposure_data(H, E, attribute_name='flood_lev') # Extract relevant numerical data coordinates = E.get_geometry() depth = H.get_data() N = len(depth) # List attributes to carry forward to result layer attributes = E.get_attribute_names() # print attributes # print 'Number of population points', N # Calculate population impact road_impact = [] num_classes = 10 classes = range(num_classes) difference = (max_value - min_value) / num_classes for i in range(N): dep = float(depth[i]['flood_lev']) affected = classes[0] for level in classes: normalised_depth = dep - min_value level_value = level * difference if normalised_depth > level_value: affected = level # Collect depth and calculated damage result_dict = {'AFFECTED': affected, 'DEPTH': dep} # Carry all original attributes forward for key in attributes: result_dict[key] = E.get_data(key, i) # Record result for this feature road_impact.append(result_dict) # Create report impact_summary = ('') # Create vector layer and return V = Vector(data=road_impact, projection=E.get_projection(), geometry=coordinates, name='Estimated roads affected', keywords={'impact_summary': impact_summary}) return V
def run(self, layers): """Plugin for impact of population as derived by categorised hazard Input layers: List of layers expected to contain H: Raster layer of categorised hazard P: Raster layer of population data Counts number of people exposed to each category of the hazard Return Map of population exposed to high category Table with number of people in each category """ # The 3 category high_t = 1 medium_t = 0.66 low_t = 0.34 # Identify hazard and exposure layers inundation = get_hazard_layer(layers) # Categorised Hazard population = get_exposure_layer(layers) # Population Raster question = get_question(inundation.get_name(), population.get_name(), self) # Extract data as numeric arrays C = inundation.get_data(nan=0.0) # Category # Calculate impact as population exposed to each category P = population.get_data(nan=0.0, scaling=True) H = numpy.where(C == high_t, P, 0) M = numpy.where(C > medium_t, P, 0) L = numpy.where(C < low_t, P, 0) # Count totals total = int(numpy.sum(P)) high = int(numpy.sum(H)) medium = int(numpy.sum(M)) - int(numpy.sum(H)) low = int(numpy.sum(L)) - int(numpy.sum(M)) total_impact = high + medium + low # Don't show digits less than a 1000 if total > 1000: total = total // 1000 * 1000 if total_impact > 1000: total_impact = total_impact // 1000 * 1000 if high > 1000: high = high // 1000 * 1000 if medium > 1000: medium = medium // 1000 * 1000 if low > 1000: low = low // 1000 * 1000 # Calculate estimated needs based on BNPB Perka 7/2008 minimum bantuan ## rice = evacuated * 2.8 ## drinking_water = evacuated * 17.5 ## water = evacuated * 67 ## family_kits = evacuated / 5 ## toilets = evacuated / 20 # Generate impact report for the pdf map table_body = [question, TableRow([tr('People impacted '), '%i' % total_impact], header=True), TableRow([tr('People in high hazard area '), '%i' % high], header=True), TableRow([tr('People in medium hazard area '), '%i' % medium], header=True), TableRow([tr('People in low hazard area'), '%i' % low], header=True)] ## TableRow([tr('Needs per week'), tr('Total')], ## header=True), ## [tr('Rice [kg]'), int(rice)], ## [tr('Drinking Water [l]'), int(drinking_water)], ## [tr('Clean Water [l]'), int(water)], ## [tr('Family Kits'), int(family_kits)], ## [tr('Toilets'), int(toilets)]] impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([TableRow(tr('Notes'), header=True), tr('Map shows population density in high or medium ' 'hazard area'), tr('Total population: %i') % total]) ## tr('Minimum needs are defined in BNPB ' ## 'regulation 7/2008')]) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('People in high hazard areas') # Generare 8 equidistant classes across the range of flooded population # 8 is the number of classes in the predefined flood population style # as imported classes = numpy.linspace(numpy.nanmin(M.flat[:]), numpy.nanmax(M.flat[:]), 8) # Modify labels in existing flood style to show quantities style_classes = style_info['style_classes'] style_classes[1]['label'] = tr('Low [%i people/cell]') % classes[1] style_classes[4]['label'] = tr('Medium [%i people/cell]') % classes[4] style_classes[7]['label'] = tr('High [%i people/cell]') % classes[7] style_info['legend_title'] = tr('Population Density') # Create raster object and return R = Raster(M, projection=inundation.get_projection(), geotransform=inundation.get_geotransform(), name=tr('Population which %s') % get_function_title(self), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title}, style_info=style_info) return R
def run(self, layers): """Risk plugin for tsunami population """ # Extract data H = get_hazard_layer(layers) # Depth E = get_exposure_layer(layers) # Building locations # Interpolate hazard level to building locations Hi = H.interpolate(E, attribute_name='depth') # Extract relevant numerical data coordinates = Hi.get_geometry() depth = Hi.get_data() N = len(depth) # List attributes to carry forward to result layer attributes = E.get_attribute_names() # Calculate building impact according to guidelines count3 = 0 count1 = 0 count0 = 0 population_impact = [] for i in range(N): if H.is_raster: # Get depth dep = float(depth[i]['depth']) # Classify buildings according to depth if dep >= 3: affected = 3 # FIXME: Colour upper bound is 100 but count3 += 1 # does not catch affected == 100 elif 1 <= dep < 3: affected = 2 count1 += 1 else: affected = 1 count0 += 1 elif H.is_vector: dep = 0 # Just put something here cat = depth[i]['Affected'] if cat is True: affected = 3 count3 += 1 else: affected = 1 count0 += 1 # Collect depth and calculated damage result_dict = {self.target_field: affected, 'DEPTH': dep} # Carry all original attributes forward # FIXME: This should be done in interpolation. Check. #for key in attributes: # result_dict[key] = E.get_data(key, i) # Record result for this feature population_impact.append(result_dict) # Create report Hname = H.get_name() Ename = E.get_name() if H.is_raster: impact_summary = ('<b>In case of "%s" the estimated impact to ' '"%s" ' 'is:</b><br><br><p>' % (Hname, Ename)) impact_summary += ('<table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></tr>' ' <tr></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' '</table>' % (_('Impact'), _('Number of buildings'), _('Low'), count0, _('Medium'), count1, _('High'), count3)) else: impact_summary = ('<table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></tr>' ' <tr></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' '</table>' % ('Terdampak oleh tsunami', 'Jumlah gedung', 'Terdampak', count3, 'Tidak terdampak', count0, 'Semua', N)) impact_summary += '<br>' # Blank separation row impact_summary += '<b>' + _('Assumption') + ':</b><br>' impact_summary += ('Levels of impact are defined by BNPB\'s ' '<i>Pengkajian Risiko Bencana</i>') impact_summary += ('<table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></tr>' ' <tr></tr>' ' <tr><td>%s:</td><td>%s:</td></tr>' ' <tr><td>%s:</td><td>%s:</td></tr>' ' <tr><td>%s:</td><td>%s:</td></tr>' '</table>' % (_('Impact'), _('Tsunami height'), _('Low'), '<1 m', _('Medium'), '1-3 m', _('High'), '>3 m')) # Create style style_classes = [dict(label='< 1 m', min=0, max=1, colour='#1EFC7C', transparency=0, size=1), dict(label='1 - 3 m', min=1, max=2, colour='#FFA500', transparency=0, size=1), dict(label='> 3 m', min=2, max=4, colour='#F31A1C', transparency=0, size=1)] style_info = dict(target_field=self.target_field, style_classes=style_classes) # Create vector layer and return if Hi.is_line_data: name = 'Roads flooded' elif Hi.is_point_data: name = 'Buildings flooded' V = Vector(data=population_impact, projection=E.get_projection(), geometry=coordinates, keywords={'impact_summary': impact_summary}, geometry_type=Hi.geometry_type, name=name, style_info=style_info) return V
def run(self, layers): """Experimental impact function. :param layers: List of layers expected to contain at least: H: Polygon layer of inundation areas E: Vector layer of roads :type layers: list :returns: A new line layer with inundated roads marked. :type: safe_layer """ target_field = self.parameters['target_field'] road_type_field = self.parameters['road_type_field'] threshold_min = self.parameters['min threshold [m]'] threshold_max = self.parameters['max threshold [m]'] if threshold_min > threshold_max: message = tr( 'The minimal threshold is greater then the maximal specified ' 'threshold. Please check the values.') raise GetDataError(message) # Extract data H = get_hazard_layer(layers) # Flood E = get_exposure_layer(layers) # Roads question = get_question(H.get_name(), E.get_name(), self) H = H.get_layer() E = E.get_layer() # reproject self.extent to the hazard projection hazard_crs = H.crs() hazard_authid = hazard_crs.authid() if hazard_authid == 'EPSG:4326': viewport_extent = self.extent else: geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) viewport_extent = extent_to_geo_array(QgsRectangle(*self.extent), geo_crs, hazard_crs) # Align raster extent and viewport # assuming they are both in the same projection raster_extent = H.dataProvider().extent() clip_xmin = raster_extent.xMinimum() # clip_xmax = raster_extent.xMaximum() clip_ymin = raster_extent.yMinimum() # clip_ymax = raster_extent.yMaximum() if viewport_extent[0] > clip_xmin: clip_xmin = viewport_extent[0] if viewport_extent[1] > clip_ymin: clip_ymin = viewport_extent[1] # TODO: Why have these two clauses when they are not used? # Commenting out for now. # if viewport_extent[2] < clip_xmax: # clip_xmax = viewport_extent[2] # if viewport_extent[3] < clip_ymax: # clip_ymax = viewport_extent[3] height = ((viewport_extent[3] - viewport_extent[1]) / H.rasterUnitsPerPixelY()) height = int(height) width = ((viewport_extent[2] - viewport_extent[0]) / H.rasterUnitsPerPixelX()) width = int(width) raster_extent = H.dataProvider().extent() xmin = raster_extent.xMinimum() xmax = raster_extent.xMaximum() ymin = raster_extent.yMinimum() ymax = raster_extent.yMaximum() x_delta = (xmax - xmin) / H.width() x = xmin for i in range(H.width()): if abs(x - clip_xmin) < x_delta: # We have found the aligned raster boundary break x += x_delta _ = i y_delta = (ymax - ymin) / H.height() y = ymin for i in range(H.width()): if abs(y - clip_ymin) < y_delta: # We have found the aligned raster boundary break y += y_delta clip_extent = [x, y, x + width * x_delta, y + height * y_delta] # Clip and polygonize small_raster = clip_raster(H, width, height, QgsRectangle(*clip_extent)) (flooded_polygon_inside, flooded_polygon_outside) = polygonize_gdal(small_raster, threshold_min, threshold_max) # Filter geometry and data using the extent extent = QgsRectangle(*self.extent) request = QgsFeatureRequest() request.setFilterRect(extent) if flooded_polygon_inside is None: message = tr( 'There are no objects in the hazard layer with "value">%s.' 'Please check the value or use other extent.' % (threshold_min, )) raise GetDataError(message) # reproject the flood polygons to exposure projection exposure_crs = E.crs() exposure_authid = exposure_crs.authid() if hazard_authid != exposure_authid: flooded_polygon_inside = reproject_vector_layer( flooded_polygon_inside, E.crs()) flooded_polygon_outside = reproject_vector_layer( flooded_polygon_outside, E.crs()) # Clip exposure by the extent # extent_as_polygon = QgsGeometry().fromRect(extent) # no need to clip since It is using a bbox request # line_layer = clip_by_polygon( # E, # extent_as_polygon # ) # Find inundated roads, mark them line_layer = split_by_polygon_in_out(E, flooded_polygon_inside, flooded_polygon_outside, target_field, 1, request) target_field_index = line_layer.dataProvider().\ fieldNameIndex(target_field) # Generate simple impact report epsg = get_utm_epsg(self.extent[0], self.extent[1]) output_crs = QgsCoordinateReferenceSystem(epsg) transform = QgsCoordinateTransform(E.crs(), output_crs) road_len = flooded_len = 0 # Length of roads roads_by_type = dict() # Length of flooded roads by types roads_data = line_layer.getFeatures() road_type_field_index = line_layer.fieldNameIndex(road_type_field) for road in roads_data: attributes = road.attributes() road_type = attributes[road_type_field_index] if road_type.__class__.__name__ == 'QPyNullVariant': road_type = tr('Other') geom = road.geometry() geom.transform(transform) length = geom.length() road_len += length if road_type not in roads_by_type: roads_by_type[road_type] = {'flooded': 0, 'total': 0} roads_by_type[road_type]['total'] += length if attributes[target_field_index] == 1: flooded_len += length roads_by_type[road_type]['flooded'] += length table_body = [ question, TableRow([ tr('Road Type'), tr('Flooded in the threshold (m)'), tr('Total (m)') ], header=True), TableRow([tr('All'), int(flooded_len), int(road_len)]) ] table_body.append(TableRow(tr('Breakdown by road type'), header=True)) for t, v in roads_by_type.iteritems(): table_body.append(TableRow([t, int(v['flooded']), int(v['total'])])) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('Roads inundated') style_classes = [ dict(label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=0.5), dict(label=tr('Inundated'), value=1, colour='#F31A1C', transparency=0, size=0.5) ] style_info = dict(target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') # Convert QgsVectorLayer to inasafe layer and return it line_layer = Vector(data=line_layer, name=tr('Flooded roads'), keywords={ 'impact_summary': impact_summary, 'map_title': map_title, 'target_field': target_field }, style_info=style_info) return line_layer
def run(self, layers): """Risk plugin for volcano hazard on building/structure. Counts number of building exposed to each volcano hazard zones. :param layers: List of layers expected to contain. * hazard_layer: Hazard layer of volcano * exposure_layer: Vector layer of structure data on the same grid as hazard_layer :returns: Map of building exposed to volcanic hazard zones. Table with number of buildings affected :rtype: dict """ # Identify hazard and exposure layers hazard_layer = get_hazard_layer(layers) # Volcano hazard layer exposure_layer = get_exposure_layer(layers) is_point_data = False question = get_question( hazard_layer.get_name(), exposure_layer.get_name(), self) # Input checks if not hazard_layer.is_vector: msg = ('Input hazard %s was not a vector layer as expected ' % hazard_layer.get_name()) raise Exception(msg) msg = ('Input hazard must be a polygon or point layer. I got %s ' 'with layer type %s' % (hazard_layer.get_name(), hazard_layer.get_geometry_name())) if not (hazard_layer.is_polygon_data or hazard_layer.is_point_data): raise Exception(msg) if hazard_layer.is_point_data: # Use concentric circles radii = self.parameters['distances [km]'] is_point_data = True centers = hazard_layer.get_geometry() attributes = hazard_layer.get_data() rad_m = [x * 1000 for x in radii] # Convert to meters hazard_layer = buffer_points(centers, rad_m, data_table=attributes) # To check category_title = 'Radius' category_names = rad_m name_attribute = 'NAME' # As in e.g. the Smithsonian dataset else: # Use hazard map category_title = 'KRB' # FIXME (Ole): Change to English and use translation system category_names = ['Kawasan Rawan Bencana III', 'Kawasan Rawan Bencana II', 'Kawasan Rawan Bencana I'] name_attribute = 'GUNUNG' # As in e.g. BNPB hazard map # Get names of volcanoes considered if name_attribute in hazard_layer.get_attribute_names(): volcano_name_list = [] for row in hazard_layer.get_data(): # Run through all polygons and get unique names volcano_name_list.append(row[name_attribute]) volcano_names = '' for name in volcano_name_list: volcano_names += '%s, ' % name volcano_names = volcano_names[:-2] # Strip trailing ', ' else: volcano_names = tr('Not specified in data') # Check if category_title exists in hazard_layer if not category_title in hazard_layer.get_attribute_names(): msg = ('Hazard data %s did not contain expected ' 'attribute %s ' % (hazard_layer.get_name(), category_title)) # noinspection PyExceptionInherit raise InaSAFEError(msg) # Find the target field name that has no conflict with default # target attribute_names = hazard_layer.get_attribute_names() new_target_field = get_non_conflicting_attribute_name( self.target_field, attribute_names) self.target_field = new_target_field # Run interpolation function for polygon2raster interpolated_layer = assign_hazard_values_to_exposure_data( hazard_layer, exposure_layer) # Initialise attributes of output dataset with all attributes # from input polygon and a building count of zero new_data_table = hazard_layer.get_data() categories = {} for row in new_data_table: row[self.target_field] = 0 category = row[category_title] categories[category] = 0 # Count impacted building per polygon and total for row in interpolated_layer.get_data(): # Update building count for associated polygon poly_id = row['polygon_id'] if poly_id is not None: new_data_table[poly_id][self.target_field] += 1 # Update building count for each category category = new_data_table[poly_id][category_title] categories[category] += 1 # Count totals total = len(exposure_layer) # Generate simple impact report blank_cell = '' table_body = [question, TableRow([tr('Volcanoes considered'), '%s' % volcano_names, blank_cell], header=True), TableRow([tr('Distance [km]'), tr('Total'), tr('Cumulative')], header=True)] cumulative = 0 for name in category_names: # prevent key error count = categories.get(name, 0) cumulative += count if is_point_data: name = int(name) / 1000 table_body.append(TableRow([name, format_int(count), format_int(cumulative)])) table_body.append(TableRow(tr('Map shows buildings affected in ' 'each of volcano hazard polygons.'))) impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([TableRow(tr('Notes'), header=True), tr('Total number of buildings %s in the viewable ' 'area') % format_int(total), tr('Only buildings available in OpenStreetMap ' 'are considered.')]) impact_summary = Table(table_body).toNewlineFreeString() building_counts = [x[self.target_field] for x in new_data_table] if max(building_counts) == 0 == min(building_counts): table_body = [ question, TableRow([tr('Number of buildings affected'), '%s' % format_int(cumulative), blank_cell], header=True)] my_message = Table(table_body).toNewlineFreeString() raise ZeroImpactException(my_message) # Create style colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] # Create Classes classes = create_classes(building_counts, len(colours)) # Create Interval Classes interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class['label'] = create_label(interval_classes[i]) if i == 0: style_class['min'] = 0 else: style_class['min'] = classes[i - 1] style_class['transparency'] = 30 style_class['colour'] = colours[i] style_class['max'] = classes[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='graduatedSymbol') # For printing map purpose map_title = tr('Buildings affected by volcanic hazard zone') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) legend_units = tr('(building)') legend_title = tr('Building count') # Create vector layer and return impact_layer = Vector( data=new_data_table, projection=hazard_layer.get_projection(), geometry=hazard_layer.get_geometry(as_geometry_objects=True), name=tr('Buildings affected by volcanic hazard zone'), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title}, style_info=style_info) return impact_layer
def run(self, layers): """Indonesian Earthquake Fatality Model Input: :param layers: List of layers expected to contain, my_hazard: Raster layer of MMI ground shaking my_exposure: Raster layer of population density """ displacement_rate = self.parameters['displacement_rate'] # Tolerance for transparency tolerance = self.parameters['tolerance'] # Extract input layers intensity = get_hazard_layer(layers) population = get_exposure_layer(layers) question = get_question(intensity.get_name(), population.get_name(), self) # Extract data grids my_hazard = intensity.get_data() # Ground Shaking my_exposure = population.get_data(scaling=True) # Population Density # Calculate population affected by each MMI level # FIXME (Ole): this range is 2-9. Should 10 be included? mmi_range = self.parameters['mmi_range'] number_of_exposed = {} number_of_displaced = {} number_of_fatalities = {} # Calculate fatality rates for observed Intensity values (my_hazard # based on ITB power model R = numpy.zeros(my_hazard.shape) for mmi in mmi_range: # Identify cells where MMI is in class i and # count population affected by this shake level I = numpy.where( (my_hazard > mmi - self.parameters['step']) * ( my_hazard <= mmi + self.parameters['step']), my_exposure, 0) # Calculate expected number of fatalities per level fatality_rate = self.fatality_rate(mmi) F = fatality_rate * I # Calculate expected number of displaced people per level try: D = displacement_rate[mmi] * I except KeyError, e: msg = 'mmi = %i, I = %s, Error msg: %s' % (mmi, str(I), str(e)) # noinspection PyExceptionInherit raise InaSAFEError(msg) # Adjust displaced people to disregard fatalities. # Set to zero if there are more fatalities than displaced. D = numpy.where(D > F, D - F, 0) # Sum up numbers for map R += D # Displaced # Generate text with result for this study # This is what is used in the real time system exposure table number_of_exposed[mmi] = numpy.nansum(I.flat) number_of_displaced[mmi] = numpy.nansum(D.flat) # noinspection PyUnresolvedReferences number_of_fatalities[mmi] = numpy.nansum(F.flat)
def run(self, layers): """Risk plugin for flood population evacuation Input layers: List of layers expected to contain H: Raster layer of flood depth P: Raster layer of population data on the same grid as H Counts number of people exposed to flood levels exceeding specified threshold. Return Map of population exposed to flood levels exceeding the threshold Table with number of people evacuated and supplies required """ # Identify hazard and exposure layers inundation = get_hazard_layer(layers) # Flood inundation [m] population = get_exposure_layer(layers) question = get_question(inundation.get_name(), population.get_name(), self) # Determine depths above which people are regarded affected [m] # Use thresholds from inundation layer if specified thresholds = get_thresholds(inundation) if len(thresholds) == 0: # Default threshold thresholds = [1.0] verify(isinstance(thresholds, list), 'Expected thresholds to be a list. Got %s' % str(thresholds)) # Extract data as numeric arrays D = inundation.get_data(nan=0.0) # Depth # Calculate impact as population exposed to depths > max threshold P = population.get_data(nan=0.0, scaling=True) # Calculate impact to intermediate thresholds counts = [] for i, lo in enumerate(thresholds): if i == len(thresholds) - 1: # The last threshold I = M = numpy.where(D >= lo, P, 0) else: # Intermediate thresholds hi = thresholds[i + 1] M = numpy.where((D >= lo) * (D < hi), P, 0) # Count val = int(numpy.sum(M)) # Don't show digits less than a 1000 if val > 1000: val = val // 1000 * 1000 counts.append(val) # Count totals evacuated = counts[-1] total = int(numpy.sum(P)) # Don't show digits less than a 1000 if total > 1000: total = total // 1000 * 1000 # Calculate estimated needs based on BNPB Perka 7/2008 minimum bantuan rice = evacuated * 2.8 drinking_water = evacuated * 17.5 water = evacuated * 67 family_kits = evacuated / 5 toilets = evacuated / 20 # Generate impact report for the pdf map table_body = [question, TableRow([_('People needing evacuation'), '%i' % evacuated], header=True), TableRow(_('Map shows population density needing ' 'evacuation')), TableRow([_('Needs per week'), _('Total')], header=True), [_('Rice [kg]'), int(rice)], [_('Drinking Water [l]'), int(drinking_water)], [_('Clean Water [l]'), int(water)], [_('Family Kits'), int(family_kits)], [_('Toilets'), int(toilets)]] impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([TableRow(_('Notes'), header=True), _('Total population: %i') % total, _('People need evacuation if flood levels ' 'exceed %(eps).1f m') % {'eps': thresholds[-1]}, _('Minimum needs are defined in BNPB ' 'regulation 7/2008')]) if len(counts) > 1: table_body.append(TableRow(_('Detailed breakdown'), header=True)) for i, val in enumerate(counts[:-1]): s = (_('People in %(lo).1f m to %(hi).1f m of water: %(val)i') % {'lo': thresholds[i], 'hi': thresholds[i + 1], 'val': val}) table_body.append(TableRow(s, header=False)) impact_summary = Table(table_body).toNewlineFreeString() map_title = _('People in need of evacuation') # Generate 8 equidistant classes across the range of flooded population # 8 is the number of classes in the predefined flood population style # as imported classes = numpy.linspace(numpy.nanmin(I.flat[:]), numpy.nanmax(I.flat[:]), 8) # Modify labels in existing flood style to show quantities style_classes = style_info['style_classes'] style_classes[1]['label'] = _('Low [%i people/cell]') % classes[1] style_classes[4]['label'] = _('Medium [%i people/cell]') % classes[4] style_classes[7]['label'] = _('High [%i people/cell]') % classes[7] style_info['legend_title'] = _('Population Density') # Create raster object and return R = Raster(I, projection=inundation.get_projection(), geotransform=inundation.get_geotransform(), name=_('Population which %s') % get_function_title(self), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title}, style_info=style_info) return R
def run(self, layers): """Earthquake impact to buildings (e.g. from OpenStreetMap). :param layers: All the input layers (Hazard Layer and Exposure Layer) """ LOGGER.debug('Running earthquake building impact') # merely initialize building_value = 0 contents_value = 0 # Thresholds for mmi breakdown. t0 = self.parameters['low_threshold'] t1 = self.parameters['medium_threshold'] t2 = self.parameters['high_threshold'] # Class Attribute and Label. class_1 = {'label': tr('Low'), 'class': 1} class_2 = {'label': tr('Medium'), 'class': 2} class_3 = {'label': tr('High'), 'class': 3} # Extract data hazard_layer = get_hazard_layer(layers) # Depth exposure_layer = get_exposure_layer(layers) # Building locations question = get_question( hazard_layer.get_name(), exposure_layer.get_name(), self ) # Define attribute name for hazard levels. hazard_attribute = 'mmi' # Determine if exposure data have NEXIS attributes. attribute_names = exposure_layer.get_attribute_names() if ('FLOOR_AREA' in attribute_names and 'BUILDING_C' in attribute_names and 'CONTENTS_C' in attribute_names): is_nexis = True else: is_nexis = False # Interpolate hazard level to building locations. my_interpolate_result = assign_hazard_values_to_exposure_data( hazard_layer, exposure_layer, attribute_name=hazard_attribute ) # Extract relevant exposure data #attribute_names = my_interpolate_result.get_attribute_names() attributes = my_interpolate_result.get_data() interpolate_size = len(my_interpolate_result) # Calculate building impact lo = 0 me = 0 hi = 0 building_values = {} contents_values = {} for key in range(4): building_values[key] = 0 contents_values[key] = 0 for i in range(interpolate_size): # Classify building according to shake level # and calculate dollar losses if is_nexis: try: area = float(attributes[i]['FLOOR_AREA']) except (ValueError, KeyError): #print 'Got area', attributes[i]['FLOOR_AREA'] area = 0.0 try: building_value_density = float(attributes[i]['BUILDING_C']) except (ValueError, KeyError): #print 'Got bld value', attributes[i]['BUILDING_C'] building_value_density = 0.0 try: contents_value_density = float(attributes[i]['CONTENTS_C']) except (ValueError, KeyError): #print 'Got cont value', attributes[i]['CONTENTS_C'] contents_value_density = 0.0 building_value = building_value_density * area contents_value = contents_value_density * area try: x = float(attributes[i][hazard_attribute]) # MMI except TypeError: x = 0.0 if t0 <= x < t1: lo += 1 cls = 1 elif t1 <= x < t2: me += 1 cls = 2 elif t2 <= x: hi += 1 cls = 3 else: # Not reported for less than level t0 cls = 0 attributes[i][self.target_field] = cls if is_nexis: # Accumulate values in 1M dollar units building_values[cls] += building_value contents_values[cls] += contents_value if is_nexis: # Convert to units of one million dollars for key in range(4): building_values[key] = int(building_values[key] / 1000000) contents_values[key] = int(contents_values[key] / 1000000) if is_nexis: # Generate simple impact report for NEXIS type buildings table_body = [question, TableRow([tr('Hazard Level'), tr('Buildings Affected'), tr('Buildings value ($M)'), tr('Contents value ($M)')], header=True), TableRow([class_1['label'], format_int(lo), format_int(building_values[1]), format_int(contents_values[1])]), TableRow([class_2['label'], format_int(me), format_int(building_values[2]), format_int(contents_values[2])]), TableRow([class_3['label'], format_int(hi), format_int(building_values[3]), format_int(contents_values[3])])] else: # Generate simple impact report for unspecific buildings table_body = [question, TableRow([tr('Hazard Level'), tr('Buildings Affected')], header=True), TableRow([class_1['label'], format_int(lo)]), TableRow([class_2['label'], format_int(me)]), TableRow([class_3['label'], format_int(hi)])] table_body.append(TableRow(tr('Notes'), header=True)) table_body.append(tr('High hazard is defined as shake levels greater ' 'than %i on the MMI scale.') % t2) table_body.append(tr('Medium hazard is defined as shake levels ' 'between %i and %i on the MMI scale.') % (t1, t2)) table_body.append(tr('Low hazard is defined as shake levels ' 'between %i and %i on the MMI scale.') % (t0, t1)) if is_nexis: table_body.append(tr('Values are in units of 1 million Australian ' 'Dollars')) impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary # Create style style_classes = [dict(label=class_1['label'], value=class_1['class'], colour='#ffff00', transparency=1), dict(label=class_2['label'], value=class_2['class'], colour='#ffaa00', transparency=1), dict(label=class_3['label'], value=class_3['class'], colour='#ff0000', transparency=1)] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') # For printing map purpose map_title = tr('Building affected by earthquake') legend_notes = tr('The level of the impact is according to the ' 'threshold the user input.') legend_units = tr('(mmi)') legend_title = tr('Impact level') # Create vector layer and return result_layer = Vector( data=attributes, projection=my_interpolate_result.get_projection(), geometry=my_interpolate_result.get_geometry(), name=tr('Estimated buildings affected'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title, 'target_field': self.target_field, 'statistics_type': self.statistics_type, 'statistics_classes': self .statistics_classes}, style_info=style_info) msg = 'Created vector layer %s' % str(result_layer) LOGGER.debug(msg) return result_layer
def run(self, layers): """Risk plugin for volcano population evacuation Input layers: List of layers expected to contain H: Vector polygon layer of volcano impact zones P: Raster layer of population data on the same grid as H Counts number of people exposed to volcano event. Return Map of population exposed to the volcano hazard zone. Table with number of people evacuated and supplies required. """ # Identify hazard and exposure layers H = get_hazard_layer(layers) # Flood inundation E = get_exposure_layer(layers) question = get_question(H.get_name(), E.get_name(), self) # Input checks if not H.is_vector: msg = ('Input hazard %s was not a vector layer as expected ' % H.get_name()) raise Exception(msg) msg = ('Input hazard must be a polygon or point layer. ' 'I got %s with layer ' 'type %s' % (H.get_name(), H.get_geometry_name())) if not (H.is_polygon_data or H.is_point_data): raise Exception(msg) if H.is_point_data: # Use concentric circles radii = self.parameters['distance [km]'] centers = H.get_geometry() attributes = H.get_data() rad_m = [x * 1000 for x in radii] # Convert to meters H = make_circular_polygon(centers, rad_m, attributes=attributes) # NOTE (Sunni) : I commented out this one because there will be # a permission problem on windows #H.write_to_file('Evac_zones_%s.shp' % str(radii)) # To check category_title = 'Radius' category_header = tr('Distance [km]') category_names = radii name_attribute = 'NAME' # As in e.g. the Smithsonian dataset else: # Use hazard map category_title = 'KRB' category_header = tr('Category') # FIXME (Ole): Change to English and use translation system category_names = ['Kawasan Rawan Bencana III', 'Kawasan Rawan Bencana II', 'Kawasan Rawan Bencana I'] name_attribute = 'GUNUNG' # As in e.g. BNPB hazard map attributes = H.get_data() # Get names of volcanos considered if name_attribute in H.get_attribute_names(): D = {} for att in H.get_data(): # Run through all polygons and get unique names D[att[name_attribute]] = None volcano_names = '' for name in D: volcano_names += '%s, ' % name volcano_names = volcano_names[:-2] # Strip trailing ', ' else: volcano_names = tr('Not specified in data') if not category_title in H.get_attribute_names(): msg = ('Hazard data %s did not contain expected ' 'attribute %s ' % (H.get_name(), category_title)) raise InaSAFEError(msg) # Run interpolation function for polygon2raster P = assign_hazard_values_to_exposure_data(H, E, attribute_name='population') # Initialise attributes of output dataset with all attributes # from input polygon and a population count of zero new_attributes = H.get_data() categories = {} for attr in new_attributes: attr[self.target_field] = 0 cat = attr[category_title] categories[cat] = 0 # Count affected population per polygon and total evacuated = 0 for attr in P.get_data(): # Get population at this location pop = float(attr['population']) # Update population count for associated polygon poly_id = attr['polygon_id'] new_attributes[poly_id][self.target_field] += pop # Update population count for each category cat = new_attributes[poly_id][category_title] categories[cat] += pop # Count totals total = int(numpy.sum(E.get_data(nan=0))) # Don't show digits less than a 1000 total = round_thousand(total) # Count number and cumulative for each zone cum = 0 pops = {} cums = {} for name in category_names: if category_title == 'Radius': key = name * 1000 # Convert to meters else: key = name pop = int(categories[key]) pop = round_thousand(pop) cum += pop cum = round_thousand(cum) pops[name] = pop cums[name] = cum # Use final accumulation as total number needing evac evacuated = cum # Calculate estimated needs based on BNPB Perka # 7/2008 minimum bantuan # FIXME (Ole): Refactor into one function to be shared rice = int(evacuated * 2.8) drinking_water = int(evacuated * 17.5) water = int(evacuated * 67) family_kits = int(evacuated / 5) toilets = int(evacuated / 20) # Generate impact report for the pdf map blank_cell = '' table_body = [question, TableRow([tr('Volcanos considered'), '%s' % volcano_names, blank_cell], header=True), TableRow([tr('People needing evacuation'), '%s' % format_int(evacuated), blank_cell], header=True), TableRow([category_header, tr('Total'), tr('Cumulative')], header=True)] for name in category_names: table_body.append(TableRow([name, format_int(pops[name]), format_int(cums[name])])) table_body.extend([TableRow(tr('Map shows population affected in ' 'each of volcano hazard polygons.')), TableRow([tr('Needs per week'), tr('Total'), blank_cell], header=True), [tr('Rice [kg]'), format_int(rice), blank_cell], [tr('Drinking Water [l]'), format_int(drinking_water), blank_cell], [tr('Clean Water [l]'), format_int(water), blank_cell], [tr('Family Kits'), format_int(family_kits), blank_cell], [tr('Toilets'), format_int(toilets), blank_cell]]) impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([TableRow(tr('Notes'), header=True), tr('Total population %s in the exposure layer') % format_int(total), tr('People need evacuation if they are within the ' 'volcanic hazard zones.')]) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('People affected by volcanic hazard zone') # Define classes for legend for flooded population counts colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] population_counts = [x[self.target_field] for x in new_attributes] cls = [0] + numpy.linspace(1, max(population_counts), len(colours)).tolist() # Define style info for output polygons showing population counts style_classes = [] for i, colour in enumerate(colours): lo = cls[i] hi = cls[i + 1] if i == 0: label = tr('0') else: label = tr('%i - %i') % (lo, hi) entry = dict(label=label, colour=colour, min=lo, max=hi, transparency=50, size=1) style_classes.append(entry) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, legend_title=tr('Population Count')) # Create vector layer and return V = Vector(data=new_attributes, projection=H.get_projection(), geometry=H.get_geometry(as_geometry_objects=True), name=tr('Population affected by volcanic hazard zone'), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'target_field': self.target_field}, style_info=style_info) return V
def run(self, layers): """Flood impact to buildings (e.g. from Open Street Map). :param layers: List of layers expected to contain. * hazard_layer: Hazard layer of flood * exposure_layer: Vector layer of structure data on the same grid as hazard_layer """ threshold = self.parameters['threshold [m]'] # Flood threshold [m] verify(isinstance(threshold, float), 'Expected thresholds to be a float. Got %s' % str(threshold)) # Extract data hazard_layer = get_hazard_layer(layers) # Depth exposure_layer = get_exposure_layer(layers) # Building locations question = get_question( hazard_layer.get_name(), exposure_layer.get_name(), self) # Determine attribute name for hazard levels if hazard_layer.is_raster: mode = 'grid' hazard_attribute = 'depth' else: mode = 'regions' hazard_attribute = None # Interpolate hazard level to building locations interpolated_layer = assign_hazard_values_to_exposure_data( hazard_layer, exposure_layer, attribute_name=hazard_attribute) # Extract relevant exposure data attribute_names = interpolated_layer.get_attribute_names() features = interpolated_layer.get_data() total_features = len(interpolated_layer) buildings = {} # The number of affected buildings affected_count = 0 # The variable for grid mode inundated_count = 0 wet_count = 0 dry_count = 0 inundated_buildings = {} wet_buildings = {} dry_buildings = {} # The variable for regions mode affected_buildings = {} if mode == 'grid': for i in range(total_features): # Get the interpolated depth water_depth = float(features[i]['depth']) if water_depth <= 0: inundated_status = 0 # dry elif water_depth >= threshold: inundated_status = 1 # inundated else: inundated_status = 2 # wet # Count affected buildings by usage type if available usage = get_osm_building_usage(attribute_names, features[i]) if usage is not None and usage != 0: key = usage else: key = 'unknown' if key not in buildings: buildings[key] = 0 inundated_buildings[key] = 0 wet_buildings[key] = 0 dry_buildings[key] = 0 # Count all buildings by type buildings[key] += 1 if inundated_status is 0: # Count dry buildings by type dry_buildings[key] += 1 # Count total dry buildings dry_count += 1 if inundated_status is 1: # Count inundated buildings by type inundated_buildings[key] += 1 # Count total dry buildings inundated_count += 1 if inundated_status is 2: # Count wet buildings by type wet_buildings[key] += 1 # Count total wet buildings wet_count += 1 # Add calculated impact to existing attributes features[i][self.target_field] = inundated_status elif mode == 'regions': for i in range(total_features): # Use interpolated polygon attribute atts = features[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: inundated_status = False else: inundated_status = bool(res) elif 'FLOODPRONE' in atts: res = atts['FLOODPRONE'] if res is None: inundated_status = False else: inundated_status = 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: inundated_status = False else: inundated_status = res else: # there is no flood related attribute message = ( '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(message) # Count affected buildings by usage type if available usage = get_osm_building_usage(attribute_names, features[i]) 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 inundated_status is True: # Count affected buildings by type affected_buildings[key] += 1 # Count total affected buildings affected_count += 1 # Add calculated impact to existing attributes features[i][self.target_field] = int(inundated_status) else: message = (tr('Unknown hazard type %s. Must be either "depth" or ' '"grid"') % mode) raise Exception(message) if mode == 'grid': affected_count = inundated_count + wet_count # 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 if mode == 'grid': inundated_buildings['other'] = 0 wet_buildings['other'] = 0 dry_buildings['other'] = 0 elif mode == 'regions': affected_buildings['other'] = 0 buildings['other'] += x if mode == 'grid': inundated_buildings['other'] += inundated_buildings[usage] wet_buildings['other'] += wet_buildings[usage] dry_buildings['other'] += dry_buildings[usage] del buildings[usage] del inundated_buildings[usage] del wet_buildings[usage] del dry_buildings[usage] elif mode == 'regions': affected_buildings['other'] += affected_buildings[usage] del buildings[usage] del affected_buildings[usage] # Generate simple impact report table_body = [] if mode == 'grid': table_body = [ question, TableRow([tr('Building type'), tr('Number Inundated'), tr('Number of Wet Buildings'), tr('Number of Dry Buildings'), tr('Total')], header=True), TableRow( [tr('All'), format_int(inundated_count), format_int(wet_count), format_int(dry_count), format_int(total_features)])] elif mode == 'regions': table_body = [ question, TableRow([tr('Building type'), tr('Number flooded'), tr('Total')], header=True), TableRow([tr('All'), format_int(affected_count), format_int(total_features)])] school_closed = 0 hospital_closed = 0 # Generate break down by building usage type if 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) if mode == 'grid': building_list.append([ building_type.capitalize(), format_int(inundated_buildings[usage]), format_int(wet_buildings[usage]), format_int(dry_buildings[usage]), format_int(buildings[usage])]) elif mode == 'regions': building_list.append([ building_type.capitalize(), format_int(affected_buildings[usage]), format_int(buildings[usage])]) if usage.lower() == 'school': school_closed = 0 if mode == 'grid': school_closed += inundated_buildings[usage] school_closed += wet_buildings[usage] elif mode == 'regions': school_closed = affected_buildings[usage] if usage.lower() == 'hospital': hospital_closed = 0 if mode == 'grid': hospital_closed += inundated_buildings[usage] hospital_closed += wet_buildings[usage] elif mode == 'regions': 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) # Action Checklist Section 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))) # Notes Section table_body.append(TableRow(tr('Notes'), header=True)) if mode == 'grid': table_body.append(TableRow( tr('Buildings are said to be inundated when flood levels ' 'exceed %.1f m') % threshold)) table_body.append(TableRow( tr('Buildings are said to be wet when flood levels ' 'are greater than 0 m but less than %.1f m') % threshold)) table_body.append(TableRow( tr('Buildings are said to be dry when flood levels ' 'are less than 0 m'))) table_body.append(TableRow( tr('Buildings are said to be closed if they are inundated or ' 'wet'))) table_body.append(TableRow( tr('Buildings are said to be open if they are dry'))) else: table_body.append(TableRow( tr('Buildings are said to be flooded when in regions marked ' 'as affected'))) # Result impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary # Prepare impact layer map_title = tr('Buildings inundated') legend_title = tr('Structure inundated status') legend_units = '' style_classes = [] if mode == 'grid': style_classes = [ dict( label=tr('Dry (<= 0 m)'), value=0, colour='#1EFC7C', transparency=0, size=1 ), dict( label=tr('Wet (0 m - %.1f m)') % threshold, value=2, colour='#FF9900', transparency=0, size=1 ), dict( label=tr('Inundated (>= %.1f m)') % threshold, value=1, colour='#F31A1C', transparency=0, size=1 )] legend_units = tr('(inundated, wet, or dry)') elif mode == 'regions': style_classes = [ dict( label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=1), dict( label=tr('Inundated'), value=1, colour='#F31A1C', ztransparency=0, size=1)] legend_units = tr('(inundated or not inundated)') style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') # Create vector layer and return vector_layer = Vector( data=features, projection=interpolated_layer.get_projection(), geometry=interpolated_layer.get_geometry(), name=tr('Estimated buildings affected'), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_units': legend_units, 'legend_title': legend_title, 'buildings_total': total_features, 'buildings_affected': affected_count}, style_info=style_info) return vector_layer
def run(self, layers): """Flood impact to buildings (e.g. from Open Street Map) """ # 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) # Interpolate hazard level to building locations I = assign_hazard_values_to_exposure_data(H, E) # Extract relevant exposure data #attribute_names = I.get_attribute_names() attributes = I.get_data() N = len(I) # Calculate road impact count = 0 #flooded_distance = 0 for i in range(N): # Use interpolated polygon attribute atts = attributes[i] if 'FLOODPRONE' in atts: res = atts['FLOODPRONE'] if res is None: x = False else: x = res.lower() == 'yes' else: # If there isn't a flood prone attribute, # assume that building is wet if inside polygon # as flag by generic attribute AFFECTED res = atts['Affected'] if res is None: x = False else: x = res # Count all roads if x is True: # Count total affected roads count += 1 # Add calculated impact to existing attributes attributes[i][self.target_field] = x if i == 0: print attributes[0].keys() # Generate simple impact report table_body = [question, TableRow([tr('Building type'), tr('Temporarily closed'), tr('Total')], header=True), TableRow([tr('All'), count, N])] impact_summary = Table(table_body).toNewlineFreeString() #impact_table = impact_summary map_title = tr('Roads 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(), geometry_type=I.get_geometry_type(), name=tr('Estimated roads affected'), keywords={'impact_summary': impact_summary, 'map_title': map_title, 'target_field': self.target_field}, style_info=style_info) return V
def run(self, layers): """Risk plugin for flood population evacuation Input layers: List of layers expected to contain my_hazard: Raster layer of flood depth my_exposure: Raster layer of population data on the same grid as my_hazard Counts number of people exposed to flood levels exceeding specified threshold. Return Map of population exposed to flood levels exceeding the threshold Table with number of people evacuated and supplies required """ # Identify hazard and exposure layers my_hazard = get_hazard_layer(layers) # Flood inundation [m] my_exposure = get_exposure_layer(layers) question = get_question(my_hazard.get_name(), my_exposure.get_name(), self) # Determine depths above which people are regarded affected [m] # Use thresholds from inundation layer if specified thresholds = self.parameters['thresholds [m]'] verify(isinstance(thresholds, list), 'Expected thresholds to be a list. Got %s' % str(thresholds)) # Extract data as numeric arrays D = my_hazard.get_data(nan=0.0) # Depth # Calculate impact as population exposed to depths > max threshold P = my_exposure.get_data(nan=0.0, scaling=True) # Calculate impact to intermediate thresholds counts = [] # merely initialize my_impact = None for i, lo in enumerate(thresholds): if i == len(thresholds) - 1: # The last threshold my_impact = M = numpy.where(D >= lo, P, 0) else: # Intermediate thresholds hi = thresholds[i + 1] M = numpy.where((D >= lo) * (D < hi), P, 0) # Count val = int(numpy.sum(M)) # Don't show digits less than a 1000 val = round_thousand(val) counts.append(val) # Count totals evacuated = counts[-1] total = int(numpy.sum(P)) # Don't show digits less than a 1000 total = round_thousand(total) # Calculate estimated minimum needs # The default value of each logistic is based on BNPB Perka 7/2008 # minimum bantuan minimum_needs = self.parameters['minimum needs'] mn_rice = minimum_needs['Rice'] mn_drinking_water = minimum_needs['Drinking Water'] mn_water = minimum_needs['Water'] mn_family_kits = minimum_needs['Family Kits'] mn_toilets = minimum_needs['Toilets'] rice = int(evacuated * mn_rice) drinking_water = int(evacuated * mn_drinking_water) water = int(evacuated * mn_water) family_kits = int(evacuated * mn_family_kits) toilets = int(evacuated * mn_toilets) # Generate impact report for the pdf map table_body = [ question, TableRow([(tr('People in %.1f m of water') % thresholds[-1]), '%s*' % format_int(evacuated)], header=True), TableRow(tr('* Number is rounded to the nearest 1000'), header=False), TableRow(tr('Map shows population density needing evacuation')), TableRow([tr('Needs per week'), tr('Total')], header=True), [tr('Rice [kg]'), format_int(rice)], [tr('Drinking Water [l]'), format_int(drinking_water)], [tr('Clean Water [l]'), format_int(water)], [tr('Family Kits'), format_int(family_kits)], [tr('Toilets'), format_int(toilets)] ] table_body.append(TableRow(tr('Action Checklist:'), header=True)) table_body.append(TableRow(tr('How will warnings be disseminated?'))) table_body.append(TableRow(tr('How will we reach stranded people?'))) table_body.append(TableRow(tr('Do we have enough relief items?'))) table_body.append( TableRow( tr('If yes, where are they located and how ' 'will we distribute them?'))) table_body.append( TableRow( tr('If no, where can we obtain additional relief items from and how ' 'will we transport them to here?'))) # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Total population: %s') % format_int(total), tr('People need evacuation if flood levels exceed %(eps).1f m') % { 'eps': thresholds[-1] }, tr('Minimum needs are defined in BNPB regulation 7/2008'), tr('All values are rounded up to the nearest integer in order to ' 'avoid representing human lives as fractionals.') ]) if len(counts) > 1: table_body.append(TableRow(tr('Detailed breakdown'), header=True)) for i, val in enumerate(counts[:-1]): s = (tr('People in %(lo).1f m to %(hi).1f m of water: %(val)i') % { 'lo': thresholds[i], 'hi': thresholds[i + 1], 'val': format_int(val) }) table_body.append(TableRow(s, header=False)) # Result impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary # check for zero impact if numpy.nanmax(my_impact) == 0 == numpy.nanmin(my_impact): table_body = [ question, TableRow([(tr('People in %.1f m of water') % thresholds[-1]), '%s' % format_int(evacuated)], header=True) ] my_message = Table(table_body).toNewlineFreeString() raise ZeroImpactException(my_message) # Create style colours = [ '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000' ] classes = create_classes(my_impact.flat[:], len(colours)) interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() if i == 1: label = create_label(interval_classes[i], 'Low') elif i == 4: label = create_label(interval_classes[i], 'Medium') elif i == 7: label = create_label(interval_classes[i], 'High') else: label = create_label(interval_classes[i]) style_class['label'] = label style_class['quantity'] = classes[i] if i == 0: transparency = 100 else: transparency = 0 style_class['transparency'] = transparency style_class['colour'] = colours[i] style_classes.append(style_class) style_info = dict(target_field=None, style_classes=style_classes, style_type='rasterStyle') # For printing map purpose map_title = tr('People in need of evacuation') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) legend_units = tr('(people per cell)') legend_title = tr('Population density') # Create raster object and return R = Raster(my_impact, projection=my_hazard.get_projection(), geotransform=my_hazard.get_geotransform(), name=tr('Population which %s') % get_function_title(self), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title }, style_info=style_info) return R
def run(self, layers): """Risk plugin for volcano population evacuation. :param layers: List of layers expected to contain where two layers should be present. * hazard_layer: Vector polygon layer of volcano impact zones * exposure_layer: Raster layer of population data on the same grid as hazard_layer Counts number of people exposed to volcano event. :returns: Map of population exposed to the volcano hazard zone. The returned dict will include a table with number of people evacuated and supplies required. :rtype: dict :raises: * Exception - When hazard layer is not vector layer * RadiiException - When radii are not valid (they need to be monotonically increasing) """ # Identify hazard and exposure layers hazard_layer = get_hazard_layer(layers) # Volcano KRB exposure_layer = get_exposure_layer(layers) question = get_question( hazard_layer.get_name(), exposure_layer.get_name(), self) # Input checks if not hazard_layer.is_vector: msg = ('Input hazard %s was not a vector layer as expected ' % hazard_layer.get_name()) raise Exception(msg) msg = ('Input hazard must be a polygon or point layer. I got %s with ' 'layer type %s' % (hazard_layer.get_name(), hazard_layer.get_geometry_name())) if not (hazard_layer.is_polygon_data or hazard_layer.is_point_data): raise Exception(msg) data_table = hazard_layer.get_data() if hazard_layer.is_point_data: # Use concentric circles radii = self.parameters['distance [km]'] centers = hazard_layer.get_geometry() rad_m = [x * 1000 for x in radii] # Convert to meters hazard_layer = buffer_points(centers, rad_m, data_table=data_table) category_title = 'Radius' category_header = tr('Distance [km]') category_names = radii name_attribute = 'NAME' # As in e.g. the Smithsonian dataset else: # Use hazard map category_title = 'KRB' category_header = tr('Category') # FIXME (Ole): Change to English and use translation system category_names = ['Kawasan Rawan Bencana III', 'Kawasan Rawan Bencana II', 'Kawasan Rawan Bencana I'] name_attribute = 'GUNUNG' # As in e.g. BNPB hazard map # Get names of volcanoes considered if name_attribute in hazard_layer.get_attribute_names(): volcano_name_list = [] # Run through all polygons and get unique names for row in data_table: volcano_name_list.append(row[name_attribute]) volcano_names = '' for name in volcano_name_list: volcano_names += '%s, ' % name volcano_names = volcano_names[:-2] # Strip trailing ', ' else: volcano_names = tr('Not specified in data') # Check if category_title exists in hazard_layer if not category_title in hazard_layer.get_attribute_names(): msg = ('Hazard data %s did not contain expected ' 'attribute %s ' % (hazard_layer.get_name(), category_title)) # noinspection PyExceptionInherit raise InaSAFEError(msg) # Find the target field name that has no conflict with default target attribute_names = hazard_layer.get_attribute_names() new_target_field = get_non_conflicting_attribute_name( self.target_field, attribute_names) self.target_field = new_target_field # Run interpolation function for polygon2raster interpolated_layer = assign_hazard_values_to_exposure_data( hazard_layer, exposure_layer, attribute_name=self.target_field) # Initialise data_table of output dataset with all data_table # from input polygon and a population count of zero new_data_table = hazard_layer.get_data() categories = {} for row in new_data_table: row[self.target_field] = 0 category = row[category_title] categories[category] = 0 # Count affected population per polygon and total for row in interpolated_layer.get_data(): # Get population at this location population = float(row[self.target_field]) # Update population count for associated polygon poly_id = row['polygon_id'] new_data_table[poly_id][self.target_field] += population # Update population count for each category category = new_data_table[poly_id][category_title] categories[category] += population # Count totals total = int(numpy.sum(exposure_layer.get_data(nan=0))) # Don't show digits less than a 1000 total = round_thousand(total) # Count number and cumulative for each zone cumulative = 0 all_categories_population = {} all_categories_cumulative = {} for name in category_names: if category_title == 'Radius': key = name * 1000 # Convert to meters else: key = name # prevent key error population = int(categories.get(key, 0)) population = round_thousand(population) cumulative += population cumulative = round_thousand(cumulative) all_categories_population[name] = population all_categories_cumulative[name] = cumulative # Use final accumulation as total number needing evacuation evacuated = cumulative # Calculate estimated minimum needs minimum_needs = self.parameters['minimum needs'] total_needs = evacuated_population_weekly_needs( evacuated, minimum_needs) # Generate impact report for the pdf map blank_cell = '' table_body = [question, TableRow([tr('Volcanoes considered'), '%s' % volcano_names, blank_cell], header=True), TableRow([tr('People needing evacuation'), '%s' % format_int(evacuated), blank_cell], header=True), TableRow([category_header, tr('Total'), tr('Cumulative')], header=True)] for name in category_names: table_body.append( TableRow([name, format_int(all_categories_population[name]), format_int(all_categories_cumulative[name])])) table_body.extend([ TableRow(tr( 'Map shows the number of people affected in each of volcano ' 'hazard polygons.')), TableRow( [tr('Needs per week'), tr('Total'), blank_cell], header=True), [tr('Rice [kg]'), format_int(total_needs['rice']), blank_cell], [ tr('Drinking Water [l]'), format_int(total_needs['drinking_water']), blank_cell], [tr('Clean Water [l]'), format_int(total_needs['water']), blank_cell], [tr('Family Kits'), format_int(total_needs['family_kits']), blank_cell], [tr('Toilets'), format_int(total_needs['toilets']), blank_cell]]) impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend( [TableRow(tr('Notes'), header=True), tr('Total population %s in the exposure layer') % format_int( total), tr('People need evacuation if they are within the ' 'volcanic hazard zones.')]) population_counts = [x[self.target_field] for x in new_data_table] impact_summary = Table(table_body).toNewlineFreeString() # check for zero impact if numpy.nanmax(population_counts) == 0 == numpy.nanmin( population_counts): table_body = [ question, TableRow([tr('People needing evacuation'), '%s' % format_int(evacuated), blank_cell], header=True)] my_message = Table(table_body).toNewlineFreeString() raise ZeroImpactException(my_message) # Create style colours = ['#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600', '#FF0000', '#7A0000'] classes = create_classes(population_counts, len(colours)) interval_classes = humanize_class(classes) # Define style info for output polygons showing population counts style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class['label'] = create_label(interval_classes[i]) if i == 0: transparency = 100 style_class['min'] = 0 else: transparency = 30 style_class['min'] = classes[i - 1] style_class['transparency'] = transparency style_class['colour'] = colours[i] style_class['max'] = classes[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='graduatedSymbol') # For printing map purpose map_title = tr('People affected by volcanic hazard zone') legend_notes = tr('Thousand separator is represented by %s' % get_thousand_separator()) legend_units = tr('(people)') legend_title = tr('Population count') # Create vector layer and return impact_layer = Vector( data=new_data_table, projection=hazard_layer.get_projection(), geometry=hazard_layer.get_geometry(as_geometry_objects=True), name=tr('People affected by volcanic hazard zone'), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'target_field': self.target_field, 'map_title': map_title, 'legend_notes': legend_notes, 'legend_units': legend_units, 'legend_title': legend_title}, style_info=style_info) return impact_layer
def run(self, layers): """Experimental impact function. :param layers: List of layers expected to contain at least: H: Polygon layer of inundation areas E: Vector layer of roads :type layers: list :returns: A new line layer with inundated roads marked. :type: safe_layer """ target_field = self.parameters['target_field'] road_type_field = self.parameters['road_type_field'] threshold_min = self.parameters['min threshold [m]'] threshold_max = self.parameters['max threshold [m]'] if threshold_min > threshold_max: message = tr( 'The minimal threshold is greater then the maximal specified ' 'threshold. Please check the values.') raise GetDataError(message) # Extract data H = get_hazard_layer(layers) # Flood E = get_exposure_layer(layers) # Roads question = get_question( H.get_name(), E.get_name(), self) H = H.get_layer() E = E.get_layer() #reproject self.extent to the hazard projection hazard_crs = H.crs() hazard_authid = hazard_crs.authid() if hazard_authid == 'EPSG:4326': viewport_extent = self.extent else: geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) viewport_extent = extent_to_geo_array( QgsRectangle(*self.extent), geo_crs, hazard_crs) #Align raster extent and viewport #assuming they are both in the same projection raster_extent = H.dataProvider().extent() clip_xmin = raster_extent.xMinimum() # clip_xmax = raster_extent.xMaximum() clip_ymin = raster_extent.yMinimum() # clip_ymax = raster_extent.yMaximum() if viewport_extent[0] > clip_xmin: clip_xmin = viewport_extent[0] if viewport_extent[1] > clip_ymin: clip_ymin = viewport_extent[1] # TODO: Why have these two clauses when they are not used? # Commenting out for now. # if viewport_extent[2] < clip_xmax: # clip_xmax = viewport_extent[2] # if viewport_extent[3] < clip_ymax: # clip_ymax = viewport_extent[3] height = ((viewport_extent[3] - viewport_extent[1]) / H.rasterUnitsPerPixelY()) height = int(height) width = ((viewport_extent[2] - viewport_extent[0]) / H.rasterUnitsPerPixelX()) width = int(width) raster_extent = H.dataProvider().extent() xmin = raster_extent.xMinimum() xmax = raster_extent.xMaximum() ymin = raster_extent.yMinimum() ymax = raster_extent.yMaximum() x_delta = (xmax - xmin) / H.width() x = xmin for i in range(H.width()): if abs(x - clip_xmin) < x_delta: # We have found the aligned raster boundary break x += x_delta _ = i y_delta = (ymax - ymin) / H.height() y = ymin for i in range(H.width()): if abs(y - clip_ymin) < y_delta: # We have found the aligned raster boundary break y += y_delta clip_extent = [x, y, x + width * x_delta, y + height * y_delta] # Clip and polygonize small_raster = clip_raster( H, width, height, QgsRectangle(*clip_extent)) (flooded_polygon_inside, flooded_polygon_outside) = polygonize_gdal( small_raster, threshold_min, threshold_max) # Filter geometry and data using the extent extent = QgsRectangle(*self.extent) request = QgsFeatureRequest() request.setFilterRect(extent) if flooded_polygon_inside is None: message = tr( 'There are no objects in the hazard layer with "value">%s.' 'Please check the value or use other extent.' % ( threshold_min, )) raise GetDataError(message) #reproject the flood polygons to exposure projection exposure_crs = E.crs() exposure_authid = exposure_crs.authid() if hazard_authid != exposure_authid: flooded_polygon_inside = reproject_vector_layer( flooded_polygon_inside, E.crs()) flooded_polygon_outside = reproject_vector_layer( flooded_polygon_outside, E.crs()) # Clip exposure by the extent #extent_as_polygon = QgsGeometry().fromRect(extent) #no need to clip since It is using a bbox request #line_layer = clip_by_polygon( # E, # extent_as_polygon #) # Find inundated roads, mark them line_layer = split_by_polygon_in_out( E, flooded_polygon_inside, flooded_polygon_outside, target_field, 1, request) target_field_index = line_layer.dataProvider().\ fieldNameIndex(target_field) # Generate simple impact report epsg = get_utm_epsg(self.extent[0], self.extent[1]) output_crs = QgsCoordinateReferenceSystem(epsg) transform = QgsCoordinateTransform(E.crs(), output_crs) road_len = flooded_len = 0 # Length of roads roads_by_type = dict() # Length of flooded roads by types roads_data = line_layer.getFeatures() road_type_field_index = line_layer.fieldNameIndex(road_type_field) for road in roads_data: attributes = road.attributes() road_type = attributes[road_type_field_index] if road_type.__class__.__name__ == 'QPyNullVariant': road_type = tr('Other') geom = road.geometry() geom.transform(transform) length = geom.length() road_len += length if not road_type in roads_by_type: roads_by_type[road_type] = {'flooded': 0, 'total': 0} roads_by_type[road_type]['total'] += length if attributes[target_field_index] == 1: flooded_len += length roads_by_type[road_type]['flooded'] += length table_body = [ question, TableRow([ tr('Road Type'), tr('Flooded in the threshold (m)'), tr('Total (m)')], header=True), TableRow([tr('All'), int(flooded_len), int(road_len)]) ] table_body.append(TableRow( tr('Breakdown by road type'), header=True)) for t, v in roads_by_type.iteritems(): table_body.append( TableRow([t, int(v['flooded']), int(v['total'])]) ) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('Roads inundated') style_classes = [ dict( label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=0.5), dict( label=tr('Inundated'), value=1, colour='#F31A1C', transparency=0, size=0.5)] style_info = dict( target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') # Convert QgsVectorLayer to inasafe layer and return it line_layer = Vector( data=line_layer, name=tr('Flooded roads'), keywords={ 'impact_summary': impact_summary, 'map_title': map_title, 'target_field': target_field}, style_info=style_info) return line_layer
def run(self, layers): """Risk plugin for flood population evacuation Input layers: List of layers expected to contain H: Raster layer of flood depth P: Raster layer of population data on the same grid as H Counts number of people exposed to flood levels exceeding specified threshold. Return Map of population exposed to flood levels exceeding the threshold Table with number of people evacuated and supplies required """ # Depth above which people are regarded affected [m] threshold = 1.0 # Threshold [m] # Identify hazard and exposure layers inundation = get_hazard_layer(layers) # Flood inundation [m] population = get_exposure_layer(layers) question = get_question(inundation.get_name(), population.get_name(), self) # Extract data as numeric arrays D = inundation.get_data(nan=0.0) # Depth # Calculate impact as population exposed to depths > threshold P = population.get_data(nan=0.0, scaling=True) I = numpy.where(D > threshold, P, 0) M = numpy.where(D > 0.5, P, 0) L = numpy.where(D > 0.3, P, 0) # Count totals total = int(numpy.sum(P)) evacuated = int(numpy.sum(I)) medium = int(numpy.sum(M)) - int(numpy.sum(I)) low = int(numpy.sum(L)) - int(numpy.sum(M)) # Don't show digits less than a 1000 if total > 1000: total = total // 1000 * 1000 if evacuated > 1000: evacuated = evacuated // 1000 * 1000 if medium > 1000: medium = medium // 1000 * 1000 if low > 1000: low = low // 1000 * 1000 # Calculate estimated needs based on BNPB Perka 7/2008 minimum bantuan rice = evacuated * 2.8 drinking_water = evacuated * 17.5 water = evacuated * 67 family_kits = evacuated / 5 toilets = evacuated / 20 # Generate impact report for the pdf map table_body = [question, TableRow([tr('People needing evacuation'), '%i' % evacuated], header=True), TableRow(tr('Map shows population density needing ' 'evacuation'))] #, ## TableRow([tr('People in 50cm to 1m of water '), ## '%i' % medium], ## header=True), ## TableRow([tr('People in 30cm to 50cm of water'), ## '%i' % low], ## header=True)] ## TableRow([tr('Needs per week'), tr('Total')], ## header=True), ## [tr('Rice [kg]'), int(rice)], ## [tr('Drinking Water [l]'), int(drinking_water)], ## [tr('Clean Water [l]'), int(water)], ## [tr('Family Kits'), int(family_kits)], ## [tr('Toilets'), int(toilets)]] impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([TableRow(tr('Notes:'), header=True), tr('Total population: %i') % total, tr('People need evacuation if flood levels ' 'exceed %(eps)i m') % {'eps': threshold}, tr('People in 50cm to 1m of water: %i') % medium, tr('People in 30cm to 50cm of water: %i') % low]) ## tr('Minimum needs are defined in BNPB ' ## 'regulation 7/2008')]) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('People in need of evacuation') style_info['legend_title'] = tr('Population Density') # Create raster object and return R = Raster(I, projection=inundation.get_projection(), geotransform=inundation.get_geotransform(), name=tr('Population which %s') % ( get_function_title(self).lower()), keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title}, style_info=style_info) return R
def run(self, layers): """Risk plugin for Padang building survey """ # Extract data H = get_hazard_layer(layers) # Ground shaking E = get_exposure_layer(layers) # Building locations question = get_question(H.get_name(), E.get_name(), self) # Map from different kinds of datasets to Padang vulnerability classes datatype = E.get_keywords()['datatype'] vclass_tag = 'VCLASS' if datatype.lower() == 'osm': # Map from OSM attributes Emap = osm2padang(E) elif datatype.lower() == 'sigab': # Map from SIGAB attributes Emap = sigab2padang(E) else: Emap = E # Interpolate hazard level to building locations I = assign_hazard_values_to_exposure_data(H, Emap, attribute_name='MMI') # Extract relevant numerical data attributes = I.get_data() N = len(I) # Calculate building damage count_high = count_medium = count_low = count_none = 0 for i in range(N): mmi = float(attributes[i]['MMI']) building_type = Emap.get_data(vclass_tag, i) damage_params = damage_curves[building_type] beta = damage_params['beta'] median = damage_params['median'] percent_damage = lognormal_cdf(mmi, median=median, sigma=beta) * 100 # Add calculated impact to existing attributes attributes[i][self.target_field] = percent_damage # Calculate statistics if percent_damage < 10: count_none += 1 if 10 <= percent_damage < 33: count_low += 1 if 33 <= percent_damage < 66: count_medium += 1 if 66 <= percent_damage: count_high += 1 # Generate impact report table_body = [question, TableRow([_('Buildings'), _('Total')], header=True), TableRow([_('All'), N]), TableRow([_('No damage'), count_none]), TableRow([_('Low damage'), count_low]), TableRow([_('Medium damage'), count_medium]), TableRow([_('High damage'), count_high])] table_body.append(TableRow(_('Notes'), header=True)) table_body.append(_('Levels of impact are defined by post 2009 ' 'Padang earthquake survey conducted by Geoscience ' 'Australia and Institute of Teknologi Bandung.')) table_body.append(_('Unreinforced masonry is assumed where no ' 'structural information is available.')) impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary map_title = _('Earthquake damage to buildings') # Create style style_classes = [dict(label=_('No damage'), min=0, max=10, colour='#00ff00', transparency=1), dict(label=_('Low damage'), min=10, max=33, colour='#ffff00', transparency=1), dict(label=_('Medium damage'), min=33, max=66, colour='#ffaa00', transparency=1), dict(label=_('High damage'), min=66, max=100, colour='#ff0000', transparency=1)] style_info = dict(target_field=self.target_field, style_classes=style_classes) # Create vector layer and return V = Vector(data=attributes, projection=E.get_projection(), geometry=E.get_geometry(), name='Estimated pct damage', keywords={'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title}, style_info=style_info) return V
def run(self, layers): """Experimental impact function. Input layers: List of layers expected to contain H: Polygon layer of inundation areas E: Vector layer of roads """ target_field = self.parameters['target_field'] building_type_field = self.parameters['building_type_field'] affected_field = self.parameters['affected_field'] affected_value = self.parameters['affected_value'] # Extract data H = get_hazard_layer(layers) # Flood E = get_exposure_layer(layers) # Roads question = get_question(H.get_name(), E.get_name(), self) H = H.get_layer() h_provider = H.dataProvider() affected_field_index = h_provider.fieldNameIndex(affected_field) if affected_field_index == -1: message = tr('''Parameter "Affected Field"(='%s') is not present in the attribute table of the hazard layer.''' % (affected_field, )) raise GetDataError(message) E = E.get_layer() srs = E.crs().toWkt() e_provider = E.dataProvider() fields = e_provider.fields() # If target_field does not exist, add it: if fields.indexFromName(target_field) == -1: e_provider.addAttributes([QgsField(target_field, QVariant.Int)]) target_field_index = e_provider.fieldNameIndex(target_field) fields = e_provider.fields() # Create layer for store the lines from E and extent building_layer = QgsVectorLayer('Polygon?crs=' + srs, 'impact_buildings', 'memory') building_provider = building_layer.dataProvider() # Set attributes building_provider.addAttributes(fields.toList()) building_layer.startEditing() building_layer.commitChanges() # Filter geometry and data using the extent extent = QgsRectangle(*self.extent) request = QgsFeatureRequest() request.setFilterRect(extent) # Split building_layer by H and save as result: # 1) Filter from H inundated features # 2) Mark buildings as inundated (1) or not inundated (0) affected_field_type = h_provider.fields( )[affected_field_index].typeName() if affected_field_type in ['Real', 'Integer']: affected_value = float(affected_value) h_data = H.getFeatures(request) hazard_poly = None for mpolygon in h_data: attributes = mpolygon.attributes() if attributes[affected_field_index] != affected_value: continue if hazard_poly is None: hazard_poly = QgsGeometry(mpolygon.geometry()) else: # Make geometry union of inundated polygons # But some mpolygon.geometry() could be invalid, skip them tmp_geometry = hazard_poly.combine(mpolygon.geometry()) try: if tmp_geometry.isGeosValid(): hazard_poly = tmp_geometry except AttributeError: pass if hazard_poly is None: message = tr( '''There are no objects in the hazard layer with "Affected value"='%s'. Please check the value or use other extent.''' % (affected_value, )) raise GetDataError(message) e_data = E.getFeatures(request) for feat in e_data: building_geom = feat.geometry() attributes = feat.attributes() l_feat = QgsFeature() l_feat.setGeometry(building_geom) l_feat.setAttributes(attributes) if hazard_poly.intersects(building_geom): l_feat.setAttribute(target_field_index, 1) else: l_feat.setAttribute(target_field_index, 0) (_, __) = building_layer.dataProvider().addFeatures([l_feat]) building_layer.updateExtents() # Generate simple impact report building_count = flooded_count = 0 # Count of buildings buildings_by_type = dict() # Length of flooded roads by types buildings_data = building_layer.getFeatures() building_type_field_index = building_layer.fieldNameIndex( building_type_field) for building in buildings_data: building_count += 1 attributes = building.attributes() building_type = attributes[building_type_field_index] if building_type in [None, 'NULL', 'null', 'Null']: building_type = 'Unknown type' if building_type not in buildings_by_type: buildings_by_type[building_type] = {'flooded': 0, 'total': 0} buildings_by_type[building_type]['total'] += 1 if attributes[target_field_index] == 1: flooded_count += 1 buildings_by_type[building_type]['flooded'] += 1 table_body = [ question, TableRow([tr('Building Type'), tr('Flooded'), tr('Total')], header=True), TableRow([tr('All'), int(flooded_count), int(building_count)]), TableRow(tr('Breakdown by building type'), header=True) ] for t, v in buildings_by_type.iteritems(): table_body.append(TableRow([t, int(v['flooded']), int(v['total'])])) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('Buildings inundated') style_classes = [ dict(label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=0.5), dict(label=tr('Inundated'), value=1, colour='#F31A1C', transparency=0, size=0.5) ] style_info = dict(target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') # Convert QgsVectorLayer to inasafe layer and return it. building_layer = Vector(data=building_layer, name=tr('Flooded buildings'), keywords={ 'impact_summary': impact_summary, 'map_title': map_title, 'target_field': target_field }, style_info=style_info) return building_layer
def run(self, layers): """Earthquake impact to buildings (e.g. from Open Street Map) """ # Thresholds for mmi breakdown t0 = 6 t1 = 7 t2 = 8 class_1 = 'Low' class_2 = 'Medium' class_3 = 'High' # 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) # Define attribute name for hazard levels hazard_attribute = 'mmi' # 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 lo = 0 me = 0 hi = 0 building_values = {} contents_values = {} for key in range(4): building_values[key] = 0 contents_values[key] = 0 for i in range(N): # Classify building according to shake level x = float(attributes[i][hazard_attribute]) # Interpolated MMI val if t0 <= x < t1: lo += 1 cls = 1 elif t1 <= x < t2: me += 1 cls = 2 elif t2 <= x: hi += 1 cls = 3 else: # Buildings not reported for MMI levels < t0 cls = 0 attributes[i][self.target_field] = cls # Generate simple impact report for unspecific buildings table_body = [ question, TableRow(['Hazard Level', 'Buildings Affected'], header=True), TableRow([class_1, lo]), TableRow([class_2, me]), TableRow([class_3, hi]) ] table_body.append(TableRow('Notes', header=True)) table_body.append('High hazard is defined as shake levels greater ' 'than %i on the MMI scale.' % t2) table_body.append('Medium hazard is defined as shake levels ' 'between %i and %i on the MMI scale.' % (t1, t2)) table_body.append('Low hazard is defined as shake levels ' 'between %i and %i on the MMI scale.' % (t0, t1)) impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary map_title = 'Buildings affected' # Create style style_classes = [ dict(label=class_1, value=1, colour='#ffff00', transparency=1), dict(label=class_2, value=2, colour='#ffaa00', transparency=1), dict(label=class_3, value=3, colour='#ff0000', transparency=1) ] style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') # Create vector layer and return V = Vector(data=attributes, projection=I.get_projection(), geometry=I.get_geometry(), name='Estimated buildings affected', keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'target_field': self.target_field, 'statistics_type': self.statistics_type, 'statistics_classes': self.statistics_classes }, style_info=style_info) return V
def run(self, layers): """Plugin for impact of population as derived by categorised hazard. :param layers: List of layers expected to contain * hazard_layer: Raster layer of categorised hazard * exposure_layer: Raster layer of population data Counts number of people exposed to each category of the hazard :returns: Map of population exposed to high category Table with number of people in each category """ # The 3 category high_t = self.parameters['Categorical thresholds'][2] medium_t = self.parameters['Categorical thresholds'][1] low_t = self.parameters['Categorical thresholds'][0] # Identify hazard and exposure layers hazard_layer = get_hazard_layer(layers) # Categorised Hazard exposure_layer = get_exposure_layer(layers) # Population Raster question = get_question( hazard_layer.get_name(), exposure_layer.get_name(), self) # Extract data as numeric arrays C = hazard_layer.get_data(nan=0.0) # Category # Calculate impact as population exposed to each category P = exposure_layer.get_data(nan=0.0, scaling=True) H = numpy.where(C <= high_t, P, 0) M = numpy.where(C < medium_t, P, 0) L = numpy.where(C < low_t, P, 0) # Count totals total = int(numpy.sum(P)) high = int(numpy.sum(H)) - int(numpy.sum(M)) medium = int(numpy.sum(M)) - int(numpy.sum(L)) low = int(numpy.sum(L)) total_impact = high + medium + low # Don't show digits less than a 1000 total = population_rounding(total) total_impact = population_rounding(total_impact) high = population_rounding(high) medium = population_rounding(medium) low = population_rounding(low) minimum_needs = [ parameter.serialize() for parameter in self.parameters['minimum needs'] ] # Generate impact report for the pdf map table_body = [ question, TableRow([tr('People impacted '), '%s' % format_int(total_impact)], header=True), TableRow([tr('People in high hazard area '), '%s' % format_int(high)], header=True), TableRow([tr('People in medium hazard area '), '%s' % format_int(medium)], header=True), TableRow([tr('People in low hazard area'), '%s' % format_int(low)], header=True)] impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend([ TableRow(tr('Notes'), header=True), tr('Map shows population count in high or medium hazard area'), tr('Total population: %s') % format_int(total), TableRow(tr( 'Table below shows the minimum needs for all ' 'affected people'))]) total_needs = evacuated_population_needs( total_impact, minimum_needs) for frequency, needs in total_needs.items(): table_body.append(TableRow( [ tr('Needs should be provided %s' % frequency), tr('Total') ], header=True)) for resource in needs: table_body.append(TableRow([ tr(resource['table name']), format_int(resource['amount'])])) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('People in high hazard areas') # Generate 8 equidistant classes across the range of flooded population # 8 is the number of classes in the predefined flood population style # as imported # noinspection PyTypeChecker classes = numpy.linspace( numpy.nanmin(M.flat[:]), numpy.nanmax(M.flat[:]), 8) # Modify labels in existing flood style to show quantities style_classes = style_info['style_classes'] style_classes[1]['label'] = tr('Low [%i people/cell]') % classes[1] style_classes[4]['label'] = tr('Medium [%i people/cell]') % classes[4] style_classes[7]['label'] = tr('High [%i people/cell]') % classes[7] style_info['legend_title'] = tr('Population Count') # Create raster object and return raster_layer = Raster( M, projection=hazard_layer.get_projection(), geotransform=hazard_layer.get_geotransform(), name=tr('Population which %s') % ( get_function_title(self).lower()), keywords={ 'impact_summary': impact_summary, 'impact_table': impact_table, 'map_title': map_title, 'total_needs': total_needs}, style_info=style_info) return raster_layer
def run(self, layers): """Risk plugin for Padang building survey """ # Extract data H = get_hazard_layer(layers) # Ground shaking E = get_exposure_layer(layers) # Building locations datatype = E.get_keywords()["datatype"] vclass_tag = "ITB_Class" if datatype.lower() == "osm": # Map from OSM attributes to the ITB building classes # Emap = osm2itb(E) print "osm2itb has not been implemented" elif datatype.lower() == "sigab": # Emap = sigabitb(E) print "sigab2itb has not been implemented" elif datatype.lower() == "itb": Emap = E # Interpolate hazard level to building locations Hi = assign_hazard_values_to_exposure_data(H, Emap, attribute_name="MMI") # Extract relevant numerical data coordinates = Emap.get_geometry() shaking = Hi.get_data() N = len(shaking) # List attributes to carry forward to result layer attributes = Emap.get_attribute_names() # Calculate building damage count50 = 0 count25 = 0 count10 = 0 count0 = 0 building_damage = [] for i in range(N): mmi = float(shaking[i]["MMI"]) building_class = Emap.get_data(vclass_tag, i) building_type = str(building_class) damage_params = vul_curves[building_type] beta = damage_params["beta"] median = damage_params["median"] msg = "Invalid parameter value for " + building_type verify(beta + median > 0.0, msg) percent_damage = lognormal_cdf(mmi, median=median, sigma=beta) * 100 # Collect shake level and calculated damage result_dict = {self.target_field: percent_damage, "MMI": mmi} # Carry all orginal attributes forward for key in attributes: result_dict[key] = Emap.get_data(key, i) # Record result for this feature building_damage.append(result_dict) # Debugging # if percent_damage > 0.01: # print mmi, percent_damage # Calculate statistics if percent_damage < 10: count0 += 1 if 10 <= percent_damage < 33: count10 += 1 if 33 <= percent_damage < 66: count25 += 1 if 66 <= percent_damage: count50 += 1 # fid.close() # Create report Hname = H.get_name() Ename = E.get_name() impact_summary = '<b>In case of "%s" the estimated impact to ' '"%s" ' "is:</b><br><br><p>" % (Hname, Ename) impact_summary += ( '<table border="0" width="320px">' " <tr><th><b>%s</b></th><th><b>%s</b></th></th>" " <tr></tr>" " <tr><td>%s:</td><td>%i</td></tr>" " <tr><td>%s (<10%%):</td><td>%i</td></tr>" " <tr><td>%s (10-33%%):</td><td>%i</td></tr>" " <tr><td>%s (33-66%%):</td><td>%i</td></tr>" " <tr><td>%s (66-100%%):</td><td>%i</td></tr>" "</table></font>" % ( tr("Buildings"), tr("Total"), tr("All"), N, tr("No damage"), count0, tr("Low damage"), count10, tr("Medium damage"), count25, tr("High damage"), count50, ) ) impact_summary += "<br>" # Blank separation row impact_summary += "<b>" + tr("Assumption") + ":</b><br>" # This is the proper text: # tr('Levels of impact are defined by post 2009 ' # 'Padang earthquake survey conducted by Geoscience ' # 'Australia and Institute of Teknologi Bandung.')) # tr('Unreinforced masonry is assumed where no ' # 'structural information is available.')) impact_summary += tr( "Levels of impact are defined by post 2009 " "Padang earthquake survey conducted by Geoscience " "Australia and Institute of Teknologi Bandung." ) impact_summary += tr("Unreinforced masonry is assumed where no " "structural information is available.") # Create style style_classes = [ dict(label=tr("No damage"), min=0, max=10, colour="#00ff00", transparency=0), dict(label=tr("Low damage"), min=10, max=33, colour="#ffff00", transparency=0), dict(label=tr("Medium damage"), min=33, max=66, colour="#ffaa00", transparency=0), dict(label=tr("High damage"), min=66, max=100, colour="#ff0000", transparency=0), ] style_info = dict(target_field=self.target_field, style_classes=style_classes) # Create vector layer and return V = Vector( data=building_damage, projection=E.get_projection(), geometry=coordinates, name="Estimated pct damage", keywords={"impact_summary": impact_summary}, style_info=style_info, ) return V
def run(layers): """Risk plugin for tephra impact """ # Extract data H = get_hazard_layer(layers) # Ash load E = get_exposure_layer(layers) # Building locations # Interpolate hazard level to building locations H = assign_hazard_values_to_exposure_data(H, E, attribute_name='load') # Calculate building damage count3 = 0 count2 = 0 count1 = 0 count0 = 0 result = [] for i in range(len(E)): #------------------- # Extract parameters #------------------- load = H.get_data('load', i) #------------------------ # Compute damage level #------------------------ # FIXME: The thresholds have been greatly reduced # for the purpose of demonstration. Any real analyis # should bring them back to 0, 90, 150, 300 if 0.01 <= load < 0.5: # Loss of crops and livestock impact = 0 count0 += 1 elif 0.5 <= load < 2.0: # Cosmetic damage impact = 1 count1 += 1 elif 2.0 <= load < 10.0: # Partial building collapse impact = 2 count2 += 1 elif load >= 10.0: # Complete building collapse impact = 3 count3 += 1 else: impact = 0 count0 += 1 result.append({'DAMAGE': impact, 'ASHLOAD': load}) # Create report impact_summary = ('<font size="3"> <table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></th>' ' <tr></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' '</table></font>' % ('Beban abu', 'Gedung dampak', '< 0.5 kg/m2', count0, '0.5 - 2 kg/m2', count1, '2 - 10 kg/m2', count2, '> 10 kg/m2', count3)) #'</table>' % # ('Beban abu', 'Gedung dampak', # 'Gangguan (< 90 kg/m2)', count0, # 'Kerusakan kosmetik (90 - 150 kg/m2', count1, # 'parsial runtuhnya (150 - 300 kg/m2', count2, # 'runtuhnya lengkap (> 300 kg/m2', count3)) V = Vector(data=result, projection=E.get_projection(), geometry=E.get_geometry(), name='Estimated ashload damage', keywords={'impact_summary': impact_summary}) return V
def run(self, layers): """Risk plugin for volcano hazard on building/structure Input layers: List of layers expected to contain my_hazard: Hazard layer of volcano my_exposure: Vector layer of structure data on the same grid as my_hazard Counts number of building exposed to each volcano hazard zones. Return Map of building exposed to volcanic hazard zones Table with number of buildings affected """ # Identify hazard and exposure layers my_hazard = get_hazard_layer(layers) # Volcano hazard layer my_exposure = get_exposure_layer(layers) is_point_data = False question = get_question(my_hazard.get_name(), my_exposure.get_name(), self) # Input checks if not my_hazard.is_vector: msg = "Input hazard %s was not a vector layer as expected " % my_hazard.get_name() raise Exception(msg) msg = "Input hazard must be a polygon or point layer. I got %s " "with layer type %s" % ( my_hazard.get_name(), my_hazard.get_geometry_name(), ) if not (my_hazard.is_polygon_data or my_hazard.is_point_data): raise Exception(msg) if my_hazard.is_point_data: # Use concentric circles radii = self.parameters["distances [km]"] is_point_data = True centers = my_hazard.get_geometry() attributes = my_hazard.get_data() rad_m = [x * 1000 for x in radii] # Convert to meters Z = make_circular_polygon(centers, rad_m, attributes=attributes) # To check category_title = "Radius" my_hazard = Z category_names = rad_m name_attribute = "NAME" # As in e.g. the Smithsonian dataset else: # Use hazard map category_title = "KRB" # FIXME (Ole): Change to English and use translation system category_names = ["Kawasan Rawan Bencana III", "Kawasan Rawan Bencana II", "Kawasan Rawan Bencana I"] name_attribute = "GUNUNG" # As in e.g. BNPB hazard map # Get names of volcanos considered if name_attribute in my_hazard.get_attribute_names(): D = {} for att in my_hazard.get_data(): # Run through all polygons and get unique names D[att[name_attribute]] = None volcano_names = "" for name in D: volcano_names += "%s, " % name volcano_names = volcano_names[:-2] # Strip trailing ', ' else: volcano_names = tr("Not specified in data") if not category_title in my_hazard.get_attribute_names(): msg = "Hazard data %s did not contain expected " "attribute %s " % (my_hazard.get_name(), category_title) # noinspection PyExceptionInherit raise InaSAFEError(msg) # Run interpolation function for polygon2raster P = assign_hazard_values_to_exposure_data(my_hazard, my_exposure) # Initialise attributes of output dataset with all attributes # from input polygon and a building count of zero new_attributes = my_hazard.get_data() categories = {} for attr in new_attributes: attr[self.target_field] = 0 cat = attr[category_title] categories[cat] = 0 # Count impacted building per polygon and total for attr in P.get_data(): # Update building count for associated polygon poly_id = attr["polygon_id"] if poly_id is not None: new_attributes[poly_id][self.target_field] += 1 # Update building count for each category cat = new_attributes[poly_id][category_title] categories[cat] += 1 # Count totals total = len(my_exposure) # Generate simple impact report blank_cell = "" table_body = [ question, TableRow([tr("Volcanos considered"), "%s" % volcano_names, blank_cell], header=True), TableRow([tr("Distance [km]"), tr("Total"), tr("Cumulative")], header=True), ] cum = 0 for name in category_names: # prevent key error count = categories.get(name, 0) cum += count if is_point_data: name = int(name) / 1000 table_body.append(TableRow([name, format_int(count), format_int(cum)])) table_body.append(TableRow(tr("Map shows buildings affected in " "each of volcano hazard polygons."))) impact_table = Table(table_body).toNewlineFreeString() # Extend impact report for on-screen display table_body.extend( [ TableRow(tr("Notes"), header=True), tr("Total number of buildings %s in the viewable " "area") % format_int(total), tr("Only buildings available in OpenStreetMap " "are considered."), ] ) impact_summary = Table(table_body).toNewlineFreeString() building_counts = [x[self.target_field] for x in new_attributes] if max(building_counts) == 0 == min(building_counts): table_body = [ question, TableRow([tr("Number of buildings affected"), "%s" % format_int(cum), blank_cell], header=True), ] my_message = Table(table_body).toNewlineFreeString() raise ZeroImpactException(my_message) # Create style colours = ["#FFFFFF", "#38A800", "#79C900", "#CEED00", "#FFCC00", "#FF6600", "#FF0000", "#7A0000"] classes = create_classes(building_counts, len(colours)) interval_classes = humanize_class(classes) style_classes = [] for i in xrange(len(colours)): style_class = dict() style_class["label"] = create_label(interval_classes[i]) if i == 0: transparency = 100 style_class["min"] = 0 else: transparency = 30 style_class["min"] = classes[i - 1] style_class["transparency"] = transparency style_class["colour"] = colours[i] style_class["max"] = classes[i] style_classes.append(style_class) # Override style info with new classes and name style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type="graduatedSymbol") # For printing map purpose map_title = tr("Buildings affected by volcanic hazard zone") legend_notes = tr("Thousand separator is represented by %s" % get_thousand_separator()) legend_units = tr("(building)") legend_title = tr("Building count") # Create vector layer and return V = Vector( data=new_attributes, projection=my_hazard.get_projection(), geometry=my_hazard.get_geometry(as_geometry_objects=True), name=tr("Buildings affected by volcanic hazard zone"), keywords={ "impact_summary": impact_summary, "impact_table": impact_table, "target_field": self.target_field, "map_title": map_title, "legend_notes": legend_notes, "legend_units": legend_units, "legend_title": legend_title, }, style_info=style_info, ) return V
def run(self, layers, x=0.62275231, y=8.03314466): # , zeta=2.15): """Gender specific earthquake impact model Input layers: List of layers expected to contain H: Raster layer of MMI ground shaking P: Raster layer of population density """ # Define percentages of people being displaced at each mmi level displacement_rate = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0.1, 8: 0.5, 9: 0.75, 10: 1.0 } # Extract input layers intensity = get_hazard_layer(layers) population = get_exposure_layer(layers) question = get_question(intensity.get_name(), population.get_name(), self) # Extract data grids H = intensity.get_data() # Ground Shaking P = population.get_data() # Population Density # Calculate population affected by each MMI level # FIXME (Ole): this range is 2-9. Should 10 be included? mmi_range = range(2, 10) number_of_exposed = {} number_of_fatalities = {} # Calculate fatality rates for observed Intensity values (H # based on ITB power model R = numpy.zeros(H.shape) for mmi in mmi_range: # Identify cells where MMI is in class i mask = (H > mmi - 0.5) * (H <= mmi + 0.5) # Count population affected by this shake level I = numpy.where(mask, P, 0) # Calculate expected number of fatalities per level fatality_rate = numpy.power(10.0, x * mmi - y) F = fatality_rate * I # Sum up fatalities to create map R += F # Generate text with result for this study # This is what is used in the real time system exposure table number_of_exposed[mmi] = numpy.nansum(I.flat) number_of_fatalities[mmi] = numpy.nansum(F.flat) # Set resulting layer to zero when less than a threshold. This is to # achieve transparency (see issue #126). R[R < 1] = numpy.nan # Total statistics total = numpy.nansum(P.flat) # Compute number of fatalities fatalities = numpy.nansum(number_of_fatalities.values()) # Compute number of people displaced due to building collapse displaced = 0 for mmi in mmi_range: displaced += displacement_rate[mmi] * number_of_exposed[mmi] displaced_women = displaced * 0.52 # Could be made province dependent displaced_pregnant_women = displaced_women * 0.01387 # CHECK # Generate impact report table_body = [question] # Add total fatality estimate s = str(int(fatalities)).rjust(10) table_body.append( TableRow([tr('Number of fatalities'), s], header=True)) # Add total estimate of people displaced s = str(int(displaced)).rjust(10) table_body.append( TableRow([tr('Number of people displaced'), s], header=True)) s = str(int(displaced_women)).rjust(10) table_body.append( TableRow([tr('Number of women displaced'), s], header=True)) s = str(int(displaced_pregnant_women)).rjust(10) table_body.append( TableRow([tr('Number of pregnant women displaced'), s], header=True)) table_body.append(TableRow(tr('Action Checklist:'), header=True)) table_body.append( tr('Are enough shelters available for %i women?') % displaced_women) table_body.append( tr('Are enough facilities available to assist %i ' 'pregnant women?') % displaced_pregnant_women) table_body.append(TableRow(tr('Notes'), header=True)) table_body.append( tr('Fatality model is from ' 'Institute of Teknologi Bandung 2012.')) impact_summary = Table(table_body).toNewlineFreeString() impact_table = impact_summary map_title = tr('Earthquake impact to population') # Create new layer and return L = Raster(R, projection=population.get_projection(), geotransform=population.get_geotransform(), keywords={ 'impact_summary': impact_summary, 'total_population': total, 'total_fatalities': fatalities, 'impact_table': impact_table, 'map_title': map_title }, name=tr('Estimated fatalities'), style_info=earthquake_fatality_style) # Maybe return a shape file with contours instead return L