def test_building_native_impact_experimental(self):
        """Test flood_building_native_impact_experimental."""
        hazard_name = test_data_path('hazard',
                                     'multipart_polygons_osm_4326.shp')
        qgis_hazard = QgsVectorLayer(hazard_name, 'HAZARD', 'ogr')

        exposure_name = test_data_path('exposure', 'buildings_osm_4326.shp')
        qgis_exposure = QgsVectorLayer(exposure_name, 'EXPOSURE', 'ogr')

        plugin_name = "FloodNativePolygonExperimentalFunction"

        params = OrderedDict([('target_field', 'FLOODED'),
                              ('building_type_field', 'TYPE'),
                              ('affected_field', 'FLOOD'),
                              ('affected_value', 'YES')])

        # The params are not match field names of hazard
        self.assertRaises(GetDataError, self._get_impact_function, qgis_hazard,
                          qgis_exposure, plugin_name, params)

        # Set up real field name
        params = OrderedDict([('target_field', 'FLOODED'),
                              ('building_type_field', 'TYPE'),
                              ('affected_field', 'FLOODPRONE'),
                              ('affected_value', 'YES')])
        impact = self._get_impact_function(qgis_hazard, qgis_exposure,
                                           plugin_name, params)

        keywords = impact.get_keywords()
        self.assertEquals(params['target_field'], keywords['target_field'])

        # Count of flooded objects is calculated "by the hands"
        # the count = 68
        count = sum(impact.get_data(attribute=keywords['target_field']))
        self.assertEquals(count, 68)
    def test_run(self):
        function = FloodEvacuationRasterHazardFunction.instance()

        hazard_path = test_data_path('hazard', 'continuous_flood_20_20.asc')
        exposure_path = test_data_path('exposure',
                                       'pop_binary_raster_20_20.asc')
        hazard_layer = read_layer(hazard_path)
        exposure_layer = read_layer(exposure_path)

        function.hazard = hazard_layer
        function.exposure = exposure_layer
        function.run()
        impact = function.impact

        # Count of flooded objects is calculated "by the hands"
        # print "keywords", keywords
        keywords = impact.get_keywords()
        evacuated = float(keywords['evacuated'])
        total_needs_full = keywords['total_needs']
        total_needs_weekly = OrderedDict([[x['table name'], x['amount']]
                                          for x in total_needs_full['weekly']])
        total_needs_single = OrderedDict([[x['table name'], x['amount']]
                                          for x in total_needs_full['single']])

        expected_evacuated = 100
        self.assertEqual(evacuated, expected_evacuated)
        self.assertEqual(total_needs_weekly['Rice [kg]'], 280)
        self.assertEqual(total_needs_weekly['Family Kits'], 20)
        self.assertEqual(total_needs_weekly['Drinking Water [l]'], 1750)
        self.assertEqual(total_needs_weekly['Clean Water [l]'], 6700)
        self.assertEqual(total_needs_single['Toilets'], 5)
    def __init__(self):
        """
        Constructor for postprocessor class,
        It takes care of defining self.impact_total
        """
        AbstractPostprocessor.__init__(self)
        self.impact_total = None
        self.impact_attrs = None
        self.target_field = None
        self.no_features = None
        self.type_fields = None
        self.valid_type_fields = None
        self.fields_values = OrderedDict([
            ('Medical', ['Clinic/Doctor', 'Hospital']),
            ('Schools', [
                'School',
                'University/College',
            ]),
            ('Places of worship', [
                'Place of Worship - Unitarian', 'Place of Worship - Islam',
                'Place of Worship - Buddhist', 'Place of Worship'
            ]), ('Residential', ['Residential']),
            ('Government', ['Government']),
            ('Public Building', ['Public Building']),
            ('Fire Station', ['Fire Station']),
            ('Police Station', ['Police Station']),
            ('Supermarket', ['Supermarket']), ('Commercial', ['Commercial']),
            ('Industrial', ['Industrial']), ('Utility', ['Utility']),
            ('Sports Facility', ['Sports Facility']), ('Other', [])
        ])

        self.known_types = []
        self._update_known_types()
Exemplo n.º 4
0
    def test_run(self):
        function = ContinuousHazardPopulationFunction.instance()

        hazard_path = test_data_path('hazard', 'continuous_flood_20_20.asc')
        exposure_path = test_data_path('exposure',
                                       'pop_binary_raster_20_20.asc')
        hazard_layer = read_layer(hazard_path)
        exposure_layer = read_layer(exposure_path)

        function.hazard = SafeLayer(hazard_layer)
        function.exposure = SafeLayer(exposure_layer)
        function.run()
        impact = function.impact

        # print "keywords", keywords
        keywords = impact.get_keywords()
        total_needs_full = keywords['total_needs']
        total_needs_weekly = OrderedDict([[x['table name'], x['amount']]
                                          for x in total_needs_full['weekly']])
        total_needs_single = OrderedDict([[x['table name'], x['amount']]
                                          for x in total_needs_full['single']])

        self.assertEqual(total_needs_weekly['Rice [kg]'], 336)
        self.assertEqual(total_needs_weekly['Drinking Water [l]'], 2100)
        self.assertEqual(total_needs_weekly['Clean Water [l]'], 8040)
        self.assertEqual(total_needs_weekly['Family Kits'], 24)
        self.assertEqual(total_needs_single['Toilets'], 6)
Exemplo n.º 5
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id': 'FloodRasterRoadsFunction',
            'name': tr('Raster flood on roads'),
            'impact': tr('Be flooded in given thresholds'),
            'title': tr('Be flooded in given thresholds'),
            'function_type': 'qgis2.0',
            'author': 'Dmitry Kolesov',
            'date_implemented': 'N/A',
            'overview': tr('N/A'),
            'detailed_description': '',
            'hazard_input': '',
            'exposure_input': '',
            'output': '',
            'actions': '',
            'limitations': [],
            'citations': [],
            'layer_requirements': {
                'hazard': {
                    'layer_mode': layer_mode_continuous,
                    'layer_geometries': [layer_geometry_raster],
                    'hazard_categories': [
                        hazard_category_single_event,
                        hazard_category_multiple_event
                    ],
                    'hazard_types': [hazard_flood, hazard_tsunami],
                    'continuous_hazard_units': [unit_feet, unit_metres],
                    'vector_hazard_classifications': [],
                    'raster_hazard_classifications': [],
                    'additional_keywords': []
                },
                'exposure': {
                    'layer_mode': layer_mode_classified,
                    'layer_geometries': [layer_geometry_line],
                    'exposure_types': [exposure_road],
                    'exposure_units': [],
                    'exposure_class_fields': [road_class_field],
                    'additional_keywords': []
                }
            },
            'parameters': OrderedDict([
                ('min threshold',
                 parameter_definitions.min_threshold()),
                ('max threshold',
                 parameter_definitions.max_threshold()),
                ('postprocessors', OrderedDict([
                    ('RoadType', road_type_postprocessor())
                ]))
            ])
        }
        return dict_meta
Exemplo n.º 6
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id': 'FloodVectorRoadsExperimentalFunction',
            'name': tr('Polygon flood on roads'),
            'impact': tr('Be flooded'),
            'title': tr('Be flooded'),
            'function_type': 'qgis2.0',
            'author': 'Dmitry Kolesov',
            'date_implemented': 'N/A',
            'overview': tr('N/A'),
            'detailed_description': tr('N/A'),
            'hazard_input': tr(''),
            'exposure_input': tr(''),
            'output': tr(''),
            'actions': tr(''),
            'limitations': [],
            'citations': [],
            'categories': {
                'hazard': {
                    'definition': hazard_definition,
                    'subcategories': [hazard_flood],
                    'units': [unit_wetdry],
                    'layer_constraints': [layer_vector_polygon]
                },
                'exposure': {
                    'definition': exposure_definition,
                    'subcategories': [exposure_road],
                    'units': [unit_road_type_type],
                    'layer_constraints': [layer_vector_line]
                }
            },
            'parameters': OrderedDict([
                # This field of the exposure layer contains
                # information about road types
                ('road_type_field', 'TYPE'),
                # This field of the  hazard layer contains information
                # about inundated areas
                ('affected_field', 'affected'),
                # This value in 'affected_field' of the hazard layer
                # marks the areas as inundated
                ('affected_value', '1'),
                ('postprocessors', OrderedDict([
                    ('RoadType', road_type_postprocessor())
                ]))
            ])
        }
        return dict_meta
Exemplo n.º 7
0
 def __init__(self):
     super(PAGFatalityFunction, self).__init__()
     self.hardcoded_parameters = OrderedDict([
         ('Theta', 11.067),
         ('Beta', 0.106),  # Model coefficients
         # Rates of people displaced for each MMI level
         ('displacement_rate', {
             1: 0,
             1.5: 0,
             2: 0,
             2.5: 0,
             3: 0,
             3.5: 0,
             4: 0,
             4.5: 0,
             5: 0,
             5.5: 0,
             6: 1.0,
             6.5: 1.0,
             7: 1.0,
             7.5: 1.0,
             8: 1.0,
             8.5: 1.0,
             9: 1.0,
             9.5: 1.0,
             10: 1.0
         }),
         ('mmi_range', list(numpy.arange(2, 10, 0.5))),
         ('step', 0.25),
         # Threshold below which layer should be transparent
         ('tolerance', 0.01),
         ('calculate_displaced_people', True)
     ])
Exemplo n.º 8
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id': 'ClassifiedPolygonHazardBuildingFunction',
            'name': tr('Classified polygon hazard on buildings'),
            'impact': tr('Be affected'),
            'title': tr('Be affected'),
            'function_type': 'old-style',
            'author': 'Akbar Gumbira ([email protected])',
            'date_implemented': '17/04/2015',
            'overview': tr(
                'To assess the impact of each hazard zone on buildings.'),
            'detailed_description': '',
            'hazard_input': tr(
                'The hazard layer must be a polygon layer. This layer '
                'must have an attribute representing the hazard '
                'zone that can be specified in the impact function options.'),
            'exposure_input': tr(
                'Vector polygon layer extracted from OSM where each '
                'polygon represents the footprint of a building.'),
            'output': tr(
                'A vector layer of buildings with each tagged according to '
                'the hazard zone in which it falls.'),
            'actions': tr(
                'Provide details about how many buildings fall within '
                'each hazard zone.'),
            'limitations': [],
            'citations': [],
            'categories': {
                'hazard': {
                    'definition': hazard_definition,
                    'subcategories': hazard_all,
                    'units': [unit_classified],
                    'layer_constraints': [layer_vector_polygon]
                },
                'exposure': {
                    'definition': exposure_definition,
                    'subcategories': [exposure_structure],
                    'units': [
                        unit_building_type_type,
                        unit_building_generic],
                    'layer_constraints': [
                        layer_vector_polygon,
                        layer_vector_point]
                }
            },
            'parameters': OrderedDict([
                # The attribute of hazard zone in hazard layer
                ('hazard zone attribute', 'KRB')
            ])
        }
        return dict_meta
Exemplo n.º 9
0
    def test_polygon_roads_impact(self):
        """Test FloodVectorRoadsExperimentalFunction work."""
        hazard_name = os.path.join(UNITDATA, 'hazard',
                                   'multipart_polygons_osm_4326.shp')
        qgis_hazard = QgsVectorLayer(hazard_name, 'HAZARD', 'ogr')

        exposure_name = os.path.join(UNITDATA, 'exposure',
                                     'roads_osm_4326.shp')
        qgis_exposure = QgsVectorLayer(exposure_name, 'EXPOSURE', 'ogr')

        plugin_name = "FloodVectorRoadsExperimentalFunction"

        params = OrderedDict([('target_field', 'flooded'),
                              ('road_type_field', 'TYPE'),
                              ('affected_field', 'FLOODPRONE'),
                              ('affected_value', 'YES')])

        impact = self._get_impact_function(qgis_hazard, qgis_exposure,
                                           plugin_name, params)

        keywords = impact.get_keywords()
        self.assertEquals(params['target_field'], keywords['target_field'])

        # Count of flooded objects is calculated "by hand"
        # the count = 63
        count = sum(impact.get_data(attribute=keywords['target_field']))
        self.assertEquals(count, 63)
Exemplo n.º 10
0
    def __init__(self):
        super(ITBFatalityFunction, self).__init__()
        PopulationExposureReportMixin.__init__(self)

        # AG: Use the proper minimum needs, update the parameters
        self.parameters = add_needs_parameters(self.parameters)
        self.hardcoded_parameters = OrderedDict([
            ('x', 0.62275231),
            ('y', 8.03314466),  # Model coefficients
            # Rates of people displaced for each MMI level
            # should be consistent with defined mmi range below. - Hyeuk
            ('displacement_rate', {
                2: 0.0,
                3: 0.0,
                4: 0.0,
                5: 0.0,
                6: 1.0,
                7: 1.0,
                8: 1.0,
                9: 1.0,
                10: 1.0
            }),
            # it should be range(2,11) if mmi 10 is included. Otherwise we
            # should remove mmi 10 in the displacement_rate as well - Hyeuk
            ('mmi_range', range(2, 11)),
            ('step', 0.5),
            ('calculate_displaced_people', True)
        ])
        self.total_fatalities = None
Exemplo n.º 11
0
    def __init__(self):
        """
        Constructor for postprocessor class,
        It takes care of defining self.impact_total
        """
        AbstractPostprocessor.__init__(self)
        self.impact_total = None
        self.impact_attrs = None
        self.target_field = None
        self.no_features = None
        self.type_fields = None
        self.valid_type_fields = None
        self.fields_values = OrderedDict([
            ('Medical', ['Clinic/Doctor', 'Hospital']),
            ('Schools', ['School', 'University/College', ]),
            ('Places of worship', ['Place of Worship - Unitarian',
                                   'Place of Worship - Islam',
                                   'Place of Worship - Buddhist',
                                   'Place of Worship']),
            ('Residential', ['Residential']),
            ('Government', ['Government']),
            ('Public Building', ['Public Building']),
            ('Fire Station', ['Fire Station']),
            ('Police Station', ['Police Station']),
            ('Supermarket', ['Supermarket']),
            ('Commercial', ['Commercial']),
            ('Industrial', ['Industrial']),
            ('Utility', ['Utility']),
            ('Sports Facility', ['Sports Facility']),
            ('Other', [])])

        self.known_types = []
        self._update_known_types()
Exemplo n.º 12
0
 def __init__(self):
     super(PAGFatalityFunction, self).__init__()
     self.hardcoded_parameters = OrderedDict([
         ('Theta', 13.249),
         ('Beta', 0.151),
         ('Zeta', 1.641),  # Model coefficients
         # Rates of people displaced for each MMI level
         # FIXME: should be independent from fatality model - Hyeuk
         ('displacement_rate', {
             2: 0.0,
             3: 0.0,
             4: 0.0,
             5: 0.0,
             6: 1.0,
             7: 1.0,
             8: 1.0,
             9: 1.0,
             10: 1.0
         }),
         ('mmi_range', range(2, 11)),
         ('step', 0.5),
         # Threshold below which layer should be transparent
         ('tolerance', 0.01),
         ('calculate_displaced_people', True),
         ('magnitude_bin', numpy.power(10, range(0, 6), dtype=float))
     ])
Exemplo n.º 13
0
    def test_run(self):
        function = TsunamiEvacuationFunction.instance()

        hazard_path = test_data_path('hazard', 'tsunami_wgs84.tif')
        exposure_path = test_data_path('exposure',
                                       'pop_binary_raster_20_20.asc')
        # We need clipping for both layers to be in the same dimension
        clipped_hazard, clipped_exposure = clip_layers(hazard_path,
                                                       exposure_path)

        hazard_layer = read_layer(clipped_hazard.source())
        exposure_layer = read_layer(clipped_exposure.source())

        # Let's set the extent to the hazard extent
        function.parameters['thresholds'].value = [0.7, 0.8, 0.9]
        function.hazard = SafeLayer(hazard_layer)
        function.exposure = SafeLayer(exposure_layer)
        function.run()
        impact = function.impact

        # Count of flooded objects is calculated "by the hands"
        # print "keywords", keywords
        keywords = impact.get_keywords()
        evacuated = float(keywords['evacuated'])
        total_needs_full = keywords['total_needs']
        total_needs_weekly = OrderedDict([[x['table name'], x['amount']]
                                          for x in total_needs_full['weekly']])
        total_needs_single = OrderedDict([[x['table name'], x['amount']]
                                          for x in total_needs_full['single']])

        # #FIXME: This doesn't make sense due to clipping above. Update
        # clip_layers
        expected_evacuated = 1198
        self.assertEqual(evacuated, expected_evacuated)
        self.assertEqual(total_needs_weekly['Rice [kg]'], 3355)
        self.assertEqual(total_needs_weekly['Family Kits'], 240)
        self.assertEqual(total_needs_weekly['Drinking Water [l]'], 20965)
        self.assertEqual(total_needs_weekly['Clean Water [l]'], 80266)
        self.assertEqual(total_needs_single['Toilets'], 60)
Exemplo n.º 14
0
    def setup(self, params):
        """
        Abstract method to be called from the concrete implementation
        with AbstractPostprocessor.setup(self, None) it takes care of results
        being initialized

        Args:
            params: dict of parameters to pass to the post processor

        """
        del params
        if self._results is not None:
            self._raise_error('clear needs to be called before setup')
        self._results = OrderedDict()
Exemplo n.º 15
0
 def __init__(self):
     super(ITBBayesianFatalityFunction, self).__init__()
     self.hardcoded_parameters = OrderedDict([
         ('fatality_rate_file',
          "worden_berngamma_log_fat_rate_inasafe_10.csv"),
         # Rates of people displaced for each MMI level
         # FIXME: should be independent from fatality model - Hyeuk
         ('displacement_rate', {
             2: 0.0, 3: 0.0, 4: 0.0, 5: 0.0, 6: 1.0,
             7: 1.0, 8: 1.0, 9: 1.0, 10: 1.0}),
         ('mmi_range', range(2, 11)),
         ('step', 0.5),
         # Threshold below which layer should be transparent
         ('tolerance', 0.01),
         ('calculate_displaced_people', True),
         ('magnitude_bin', numpy.power(10, range(1, 6), dtype=float))
     ])
    def test_raster_roads_impact(self):
        """Test FloodVectorRoadsExperimentalFunction work
        """
        hazard_name = os.path.join(
            UNITDATA,
            'hazard',
            'jakarta_flood_design.tif')
        qgis_hazard = QgsRasterLayer(
            hazard_name,
            'HAZARD'
        )

        exposure_name = os.path.join(
            UNITDATA,
            'exposure',
            'roads_osm_4326.shp')
        qgis_exposure = QgsVectorLayer(
            exposure_name,
            'EXPOSURE',
            'ogr'
        )

        plugin_name = "FloodRasterRoadsExperimentalFunction"

        params = OrderedDict([
            ('target_field', 'flooded'),
            ('road_type_field', 'TYPE'),
            ('min threshold [m]', 0.005),
            ('max threshold [m]', float('inf'))
        ])

        impact = self._get_impact_function(
            qgis_hazard,
            qgis_exposure,
            plugin_name,
            params
        )

        keywords = impact.get_keywords()
        self.assertEquals(
            params['target_field'],
            keywords['target_field']
        )
        count = sum(impact.get_data(attribute=keywords['target_field']))
        self.assertEquals(count, 25)
Exemplo n.º 17
0
def default_minimum_needs():
    """Helper to get the default minimum needs.

    .. note:: Key names will be translated.
    """
    rice = tr(
        'Rice')
    drinking_water = tr('Drinking Water')
    water = tr('Water')
    family_kits = tr('Family Kits')
    toilets = tr('Toilets')
    minimum_needs = OrderedDict([
        (rice, 2.8),
        (drinking_water, 17.5),
        (water, 105),
        (family_kits, 0.2),
        (toilets, 0.05)])
    return minimum_needs
Exemplo n.º 18
0
    def __init__(self):
        super(ITBFatalityFunction, self).__init__()

        # AG: Use the proper minimum needs, update the parameters
        self.parameters = add_needs_parameters(self.parameters)
        self.hardcoded_parameters = OrderedDict([
            ('x', 0.62275231), ('y', 8.03314466),  # Model coefficients
            # Rates of people displaced for each MMI level
            ('displacement_rate', {
                1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 1.0,
                7: 1.0, 8: 1.0, 9: 1.0, 10: 1.0
            }),
            ('mmi_range', range(2, 10)),
            ('step', 0.5),
            # Threshold below which layer should be transparent
            ('tolerance', 0.01),
            ('calculate_displaced_people', True)
        ])
Exemplo n.º 19
0
    def __init__(self):
        """
        Constructor for postprocessor class.

        It takes care of defining self.impact_total
        """

        BuildingTypePostprocessor.__init__(self)
        # Note: Do we need these explicityl defined? With new osm-reporter
        # changes you already get a nicely named list in the 'type' field
        self.fields_values = OrderedDict([
            ('Motorway / highway', ['Motorway or highway']),
            ('Motorway link', ['Motorway link']),
            ('Primary road', ['Primary road']),
            ('Primary link', ['Primary link']), ('Tertiary', ['Tertiary']),
            ('Tertiary link', ['Tertiary link']), ('Secondary', ['Secondary']),
            ('Secondary link', ['Secondary link']),
            ('Road, residential, living street, etc.',
             ['Road, residential, living street, etc.']), ('Track', ['Track']),
            ('Cycleway, footpath, etc.', ['Cycleway, footpath, etc.']),
            ('Other', [])
        ])
        self.known_types = []
        self._update_known_types()
class FloodEvacuationFunctionVectorHazard(FunctionProvider):
    # noinspection PyUnresolvedReferences
    """Impact function for vector flood evacuation.

    :author AIFDR
    :rating 4

    :param requires category=='hazard' and \
                    subcategory=='flood' and \
                    layertype=='vector'

    :param requires category=='exposure' and \
                    subcategory=='population' and \
                    layertype=='raster'
    """
    class Metadata(ImpactFunctionMetadata):
        """Metadata for FloodEvacuationFunctionVectorHazard.

        .. versionadded:: 2.1

        We only need to re-implement get_metadata(), all other behaviours
        are inherited from the abstract base class.
        """
        @staticmethod
        def get_metadata():
            """Return metadata as a dictionary.

            This is a static method. You can use it to get the metadata in
            dictionary format for an impact function.

            :returns: A dictionary representing all the metadata for the
                concrete impact function.
            :rtype: dict
            """
            dict_meta = {
                'id':
                'FloodEvacuationFunctionVectorHazard',
                'name':
                tr('Flood Evacuation Function Vector Hazard'),
                'impact':
                tr('Need evacuation'),
                'author':
                'AIFDR',
                'date_implemented':
                'N/A',
                'overview':
                tr('To assess the impacts of flood inundation '
                   'in vector format on population.'),
                'categories': {
                    'hazard': {
                        'definition': hazard_definition,
                        'subcategory': [hazard_flood],
                        'units': unit_wetdry,
                        'layer_constraints': [layer_vector_polygon]
                    },
                    'exposure': {
                        'definition': exposure_definition,
                        'subcategory': exposure_population,
                        'units': [unit_people_per_pixel],
                        'layer_constraints': [layer_raster_numeric]
                    }
                }
            }
            return dict_meta

    title = tr('Need evacuation')
    # Function documentation
    synopsis = tr('To assess the impacts of flood inundation in vector '
                  'format on population.')
    actions = tr(
        'Provide details about how many people would likely need to be '
        'evacuated, where they are located and what resources would be '
        'required to support them.')

    detailed_description = tr(
        'The population subject to inundation is determined whether in an '
        'area which affected or not. You can also set an evacuation '
        'percentage to calculate how many percent of the total population '
        'affected to be evacuated. This number will be used to estimate needs'
        ' based on BNPB Perka 7/2008 minimum bantuan.')

    hazard_input = tr(
        'A hazard vector layer which has attribute affected the value is '
        'either 1 or 0')
    exposure_input = tr(
        'An exposure raster layer where each cell represent population count.')
    output = tr('Vector layer contains people affected and the minimum needs '
                'based on evacuation percentage.')

    target_field = 'population'
    defaults = get_defaults()

    # Configurable parameters
    # TODO: Share the mimimum needs and make another default value
    parameters = OrderedDict([
        ('evacuation_percentage', 1),  # Percent of affected needing evacuation
        ('postprocessors',
         OrderedDict([
             ('Gender', {
                 'on': True
             }),
             ('Age', {
                 'on':
                 True,
                 'params':
                 OrderedDict([('youth_ratio', defaults['YOUTH_RATIO']),
                              ('adult_ratio', defaults['ADULT_RATIO']),
                              ('elderly_ratio', defaults['ELDERLY_RATIO'])])
             }),
             ('MinimumNeeds', {
                 'on': True
             }),
         ])),
        ('minimum needs', default_minimum_needs()),
        ('provenance', default_provenance())
    ])

    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
Exemplo n.º 21
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id':
            'VolcanoPolygonPopulationFunction',
            'name':
            tr('Polygon volcano on population'),
            'impact':
            tr('Need evacuation'),
            'title':
            tr('Need evacuation'),
            'function_type':
            'old-style',
            'author':
            'AIFDR',
            'date_implemented':
            'N/A',
            'hazard_input':
            tr('The hazard vector layer must be a polygon that has a '
               'specific hazard zone attribute.'),
            'exposure_input':
            tr('An exposure raster layer where each cell represents a '
               'population count for that cell.'),
            'output':
            tr('A vector layer containing people affected per hazard zone '
               'and the minimum needs based on the number of people '
               'affected.'),
            'actions':
            tr('Provide details about the number of people that are within '
               'each hazard zone.'),
            'limitations': [],
            'citations': [],
            'overview':
            tr('To assess the impact of a volcano eruption on people.'),
            'detailed_description':
            '',
            'categories': {
                'hazard': {
                    'definition': hazard_definition,
                    'subcategories': [hazard_volcano],
                    'units': [unit_volcano_categorical],
                    'layer_constraints': [layer_vector_polygon]
                },
                'exposure': {
                    'definition': exposure_definition,
                    'subcategories': [exposure_population],
                    'units': [unit_people_per_pixel],
                    'layer_constraints': [layer_raster_continuous]
                }
            },
            'parameters':
            OrderedDict([
                # The attribute of hazard zone in hazard layer
                ('hazard zone attribute', 'KRB'),
                # The attribute for name of the volcano in hazard layer
                ('volcano name attribute', 'NAME'),
                ('postprocessors',
                 OrderedDict([
                     ('Gender', default_gender_postprocessor()),
                     ('Age', age_postprocessor()),
                     ('MinimumNeeds', minimum_needs_selector()),
                 ])),
                ('minimum needs', default_minimum_needs()),
                ('provenance', default_provenance())
            ])
        }
        return dict_meta
Exemplo n.º 22
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id':
            'FloodPolygonBuildingFunction',
            'name':
            tr('Polygon flood on buildings'),
            'impact':
            tr('Be flooded'),
            'title':
            tr('Be flooded'),
            'function_type':
            'qgis2.0',
            'author':
            'Dmitry Kolesov',
            'date_implemented':
            'N/A',
            'overview':
            tr('To assess the impacts of (flood or tsunami) inundation '
               'on building footprints with hazard in vector format.'),
            'detailed_description':
            tr('The inundation status is calculated for each building '
               '(using the centroid if it is a polygon) based on the value '
               'of hazard attribute. The attribute and the values that are '
               'considered as flooded can be configured in impact function '
               'options.'),
            'hazard_input':
            tr('A hazard vector layer whose attribute that can be used to '
               'mark whether a polygon is flood or not.'),
            'exposure_input':
            tr('Vector polygon or point layer extracted from OSM where '
               'each feature represents the footprint of a building.'),
            'output':
            tr('Vector layer contains building is estimated to be '
               'flooded and the breakdown of the building by type.'),
            'actions':
            '',
            'limitations': [],
            'citations': [],
            'layer_requirements': {
                'hazard': {
                    'layer_mode':
                    layer_mode_classified,
                    'layer_geometries': [layer_geometry_polygon],
                    'hazard_categories': [
                        hazard_category_single_event,
                        hazard_category_multiple_event
                    ],
                    'hazard_types': [hazard_flood],
                    'continuous_hazard_units': [],
                    'vector_hazard_classifications':
                    [flood_vector_hazard_classes],
                    'raster_hazard_classifications': [],
                    'additional_keywords': []
                },
                'exposure': {
                    'layer_mode':
                    layer_mode_classified,
                    'layer_geometries':
                    [layer_geometry_polygon, layer_geometry_point],
                    'exposure_types': [exposure_structure],
                    'exposure_units': [],
                    'exposure_class_fields': [structure_class_field],
                    'additional_keywords': []
                }
            },
            'parameters':
            OrderedDict([('postprocessors',
                          OrderedDict([('BuildingType',
                                        building_type_postprocessor())]))])
        }
        return dict_meta
Exemplo n.º 23
0
class FloodVectorRoadsExperimentalFunction(FunctionProvider):
    # noinspection PyUnresolvedReferences
    """Simple experimental impact function for inundation.

    :author Dmitry Kolesov
    :rating 1
    :param requires category=='hazard' and \
                    subcategory=='flood' and \
                    layertype=='vector'
    :param requires category=='exposure' and \
                    subcategory in ['road'] and \
                    layertype=='vector'
    """
    class Metadata(ImpactFunctionMetadata):
        """Metadata for FloodVectorRoadsExperimentalFunction.

        .. versionadded:: 2.1

        We only need to re-implement get_metadata(), all other behaviours
        are inherited from the abstract base class.
        """
        @staticmethod
        def get_metadata():
            """Return metadata as a dictionary.

            This is a static method. You can use it to get the metadata in
            dictionary format for an impact function.

            :returns: A dictionary representing all the metadata for the
                concrete impact function.
            :rtype: dict
            """
            dict_meta = {
                'id': 'FloodVectorRoadsExperimentalFunction',
                'name': tr('Flood Vector Roads Experimental Function'),
                'impact': tr('Be flooded'),
                'author': 'Dmitry Kolesov',
                'date_implemented': 'N/A',
                'overview': tr('N/A'),
                'categories': {
                    'hazard': {
                        'definition': hazard_definition,
                        'subcategories': [hazard_flood],
                        'units': [unit_wetdry],
                        'layer_constraints': [layer_vector_polygon]
                    },
                    'exposure': {
                        'definition': exposure_definition,
                        'subcategories': [exposure_road],
                        'units': [unit_road_type_type],
                        'layer_constraints': [layer_vector_line]
                    }
                }
            }
            return dict_meta

    title = tr('Be flooded')

    parameters = OrderedDict([
        # This field of impact layer marks inundated roads by '1' value
        ('target_field', 'flooded'),
        # This field of the exposure layer contains
        # information about road types
        ('road_type_field', 'TYPE'),
        # This field of the  hazard layer contains information
        # about inundated areas
        ('affected_field', 'affected'),
        # This value in 'affected_field' of the hazard layer
        # marks the areas as inundated
        ('affected_value', '1'),
        ('postprocessors', OrderedDict([('RoadType', {
            'on': True
        })]))
    ])

    def __init__(self):
        """Constructor."""
        self.extent = None

    # noinspection PyMethodMayBeStatic
    def get_function_type(self):
        """Get type of the impact function.

        :returns:   'qgis2.0'
        """
        return 'qgis2.0'

    def set_extent(self, extent):
        """Set up the extent of area of interest ([xmin, ymin, xmax, ymax]).

        Mandatory method.

        :param extent: Extent for the analysis.
        """
        self.extent = extent

    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
Exemplo n.º 24
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id': 'FloodRasterBuildingFunction',
            'name': tr('Raster flood on buildings'),
            'impact': tr('Be flooded'),
            'title': tr('Be flooded'),
            'function_type': 'old-style',
            # should be a list, but we can do it later.
            'author': 'Ole Nielsen and Kristy van Putten',
            'date_implemented': 'N/A',
            'overview': tr(
                'To assess the impacts of (flood or tsunami) inundation '
                'on building footprints originating from OpenStreetMap '
                '(OSM) with hazard in raster format.'),
            'detailed_description': tr(
                'The inundation status is calculated for each building '
                '(using the centroid if it is a polygon) based on the '
                'flood threshold. The threshold can be configured in '
                'impact function options.'),
            'hazard_input': tr(
                'A hazard raster layer where each cell represents flood '
                'depth (in meters).'),
            'exposure_input': tr(
                'Vector polygon or point layer extracted from OSM where '
                'each feature represents the footprint of a building.'),
            'output': tr(
                'Vector layer contains building is estimated to be '
                'flooded and the breakdown of the building by type.'),
            'actions': tr(
                'Provide details about where critical infrastructure '
                'might be flooded.'),
            'limitations': [
                tr('This function only flags buildings as impacted or not '
                   'either based on a fixed threshold')
            ],
            'citations': [
                {
                    'text': None,
                    'link': None
                }
            ],
            'legend_notes': '',
            'legend_title': tr('Flooded structure status'),
            'legend_units': tr('(flooded, wet, or dry)'),
            'layer_requirements': {
                'hazard': {
                    'layer_mode': layer_mode_continuous,
                    'layer_geometries': [layer_geometry_raster],
                    'hazard_categories': [
                        hazard_category_single_event,
                        hazard_category_multiple_event
                    ],
                    'hazard_types': [hazard_flood],
                    'continuous_hazard_units': [unit_feet, unit_metres],
                    'vector_hazard_classifications': [],
                    'raster_hazard_classifications': [],
                    'additional_keywords': []
                },
                'exposure': {
                    'layer_mode': layer_mode_classified,
                    'layer_geometries': [
                        layer_geometry_point,
                        layer_geometry_polygon
                    ],
                    'exposure_types': [exposure_structure],
                    'exposure_units': [],
                    'exposure_class_fields': [structure_class_field],
                    'additional_keywords': []
                }
            },
            'parameters': OrderedDict([
                ('threshold', threshold()),
                ('postprocessors', OrderedDict([
                    ('BuildingType', building_type_postprocessor())
                ]))
            ])
        }
        return dict_meta
Exemplo n.º 25
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id': 'ClassifiedPolygonHazardLandCoverFunction',
            'name': tr('Classified polygon hazard on land cover'),
            'impact': tr('Be affected'),
            'title': tr('Be affected'),
            'function_type': 'qgis2.0',
            'author': 'Martin Dobias ([email protected])',
            'date_implemented': '15/06/2015',
            'overview': tr(
                'To assess the impact of each hazard zone on land cover.'),
            'detailed_description': '',
            'hazard_input': tr(
                'The hazard layer must be a polygon layer. This layer '
                'must have an attribute representing the hazard '
                'zone that can be specified in the impact function options.'),
            'exposure_input': tr(
                'Vector polygon layer where each '
                'polygon represents a type of land cover.'),
            'output': tr(
                'A vector layer of land cover polygons with each tagged '
                'according to the hazard zone in which it falls.'),
            'actions': tr(
                'Provide details about how big area fall within '
                'each hazard zone.'),
            'limitations': [],
            'citations': [
                {
                    'text': None,
                    'link': None
                }
            ],
            'legend_title': '',
            'legend_units': '',
            'legend_notes': '',
            'layer_requirements': {
                'hazard': {
                    'layer_mode': layer_mode_classified,
                    'layer_geometries': [layer_geometry_polygon],
                    'hazard_categories': [
                        hazard_category_single_event,
                        hazard_category_multiple_event
                    ],
                    'hazard_types': hazard_all,
                    'continuous_hazard_units': [],
                    'vector_hazard_classifications': [
                        generic_vector_hazard_classes],
                    'raster_hazard_classifications': [],
                    'additional_keywords': []
                },
                'exposure': {
                    'layer_mode': layer_mode_classified,
                    'layer_geometries': [layer_geometry_polygon],
                    'exposure_types': [exposure_land_cover],
                    'exposure_units': [],
                    'exposure_class_fields': [],
                    'additional_keywords': []
                }
            },
            'parameters': OrderedDict([])
        }
        return dict_meta
Exemplo n.º 26
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id':
            'TsunamiEvacuationFunction',
            'name':
            tr('Tsunami evacuation'),
            'impact':
            tr('Need evacuation'),
            'title':
            tr('Need evacuation'),
            'function_type':
            'old-style',
            'author':
            'AIFDR',
            'date_implemented':
            'N/A',
            'overview':
            tr('To assess the impacts of tsunami inundation in raster '
               'format on population.'),
            'detailed_description':
            tr('The population subject to inundation exceeding a '
               'threshold (default 0.7m) is calculated and returned as '
               'a raster layer. In addition the total number and the '
               'required needs in terms of the BNPB (Perka 7) are '
               'reported. The threshold can be changed and even contain '
               'multiple numbers in which case evacuation and needs are '
               'calculated using the largest number with population '
               'breakdowns provided for the smaller numbers. The '
               'population raster is resampled to the resolution of the '
               'hazard raster and is rescaled so that the resampled '
               'population counts reflect estimates of population count '
               'per resampled cell. The resulting impact layer has the '
               'same resolution and reflects population count per cell '
               'which are affected by inundation.'),
            'hazard_input':
            tr('A hazard raster layer where each cell represents tsunami '
               'depth (in meters).'),
            'exposure_input':
            tr('An exposure raster layer where each cell represent '
               'population count.'),
            'output':
            tr('Raster layer contains population affected and the minimum '
               'needs based on number of the population affected.'),
            'actions':
            tr('Provide details about how many people would likely need '
               'to be evacuated, where they are located and what '
               'resources would be required to support them.'),
            'limitations': [
                tr('The default threshold of 0.7 meter was selected based on '
                   'consensus, not hard evidence.')
            ],
            'citations': [{
                'text':
                tr('Papadopoulos, Gerassimos A., and Fumihiko Imamura. '
                   '"A proposal for a new tsunami intensity scale." '
                   'ITS 2001 proceedings, no. 5-1, pp. 569-577. 2001.'),
                'link':
                None
            }, {
                'text':
                tr('Hamza Latief. pers com. Default impact threshold for '
                   'tsunami impact on people should be 0.7m. This is '
                   'less than a flood threshold because in a tsunami, '
                   'the water is moving with force.'),
                'link':
                None
            }],
            'legend_title':
            tr('Population'),
            'legend_units':
            tr('(people per cell)'),
            'legend_notes':
            tr('Thousand separator is represented by %s' %
               get_thousand_separator()),
            'layer_requirements': {
                'hazard': {
                    'layer_mode':
                    layer_mode_continuous,
                    'layer_geometries': [layer_geometry_raster],
                    'hazard_categories': [
                        hazard_category_single_event,
                        hazard_category_multiple_event
                    ],
                    'hazard_types': [hazard_tsunami],
                    'continuous_hazard_units': [unit_feet, unit_metres],
                    'vector_hazard_classifications': [],
                    'raster_hazard_classifications': [],
                    'additional_keywords': []
                },
                'exposure': {
                    'layer_mode': layer_mode_continuous,
                    'layer_geometries': [layer_geometry_raster],
                    'exposure_types': [exposure_population],
                    'exposure_units': [count_exposure_unit],
                    'exposure_class_fields': [],
                    'additional_keywords': []
                }
            },
            'parameters':
            OrderedDict([('thresholds', threshold()),
                         ('postprocessors',
                          OrderedDict([
                              ('Gender', default_gender_postprocessor()),
                              ('Age', age_postprocessor()),
                              ('MinimumNeeds', minimum_needs_selector()),
                          ])), ('minimum needs', default_minimum_needs())])
        }
        return dict_meta
Exemplo n.º 27
0
class FloodRasterRoadsExperimentalFunction(FunctionProvider):
    # noinspection PyUnresolvedReferences
    """Simple experimental impact function for inundation.

    :author Dmitry Kolesov
    :rating 1
    :param requires category=='hazard' and \
                    subcategory in ['flood', 'tsunami'] and \
                    layertype=='raster'  and \
                    disabled=='True'
    :param requires category=='exposure' and \
                    subcategory in ['road'] and \
                    layertype=='vector'
        """
    class Metadata(ImpactFunctionMetadata):
        """Metadata for FloodRasterRoadsExperimentalFunction

        .. versionadded:: 2.1

        We only need to re-implement get_metadata(), all other behaviours
        are inherited from the abstract base class.
        """
        @staticmethod
        def get_metadata():
            """Return metadata as a dictionary.

            This is a static method. You can use it to get the metadata in
            dictionary format for an impact function.

            :returns: A dictionary representing all the metadata for the
                concrete impact function.
            :rtype: dict
            """
            dict_meta = {
                'disabled': True,
                'id': 'FloodRasterRoadsExperimentalFunction',
                'name': tr('Flood Raster Roads Experimental Function'),
                'impact': tr('Be flooded in given thresholds'),
                'author': 'Dmitry Kolesov',
                'date_implemented': 'N/A',
                'overview': tr('N/A'),
                'categories': {
                    'hazard': {
                        'definition': hazard_definition,
                        'subcategory': [hazard_flood, hazard_tsunami],
                        'units': [unit_metres_depth, unit_feet_depth],
                        'layer_constraints': [layer_raster_numeric]
                    },
                    'exposure': {
                        'definition': exposure_definition,
                        'subcategory': exposure_road,
                        'units': [unit_road_type_type],
                        'layer_constraints': [layer_vector_line]
                    }
                }
            }
            return dict_meta

    title = tr('Be flooded in given thresholds')

    parameters = OrderedDict([
        # This field of impact layer marks inundated roads by '1' value
        ('target_field', 'flooded'),
        # This field of the exposure layer contains
        # information about road types
        ('road_type_field', 'TYPE'),
        ('min threshold [m]', 1.0),
        ('max threshold [m]', float('inf')),
        ('postprocessors', OrderedDict([('RoadType', {
            'on': True
        })]))
    ])

    def get_function_type(self):
        """Get type of the impact function.

        :returns:   'qgis2.0'
        """
        return 'qgis2.0'

    def set_extent(self, extent):
        """Set up the extent of area of interest ([xmin, ymin, xmax, ymax]).

        Mandatory method.
        """
        self.extent = extent

    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
Exemplo n.º 28
0
class ITBFatalityFunction(FunctionProvider):
    """Indonesian Earthquake Fatality Model

    This model was developed by Institut Teknologi Bandung (ITB) and
    implemented by Dr. Hadi Ghasemi, Geoscience Australia.


    Reference:

    Indonesian Earthquake Building-Damage and Fatality Models and
    Post Disaster Survey Guidelines Development,
    Bali, 27-28 February 2012, 54pp.


    Algorithm:

    In this study, the same functional form as Allen (2009) is adopted
    to express fatality rate as a function of intensity (see Eq. 10 in the
    report). The Matlab built-in function (fminsearch) for  Nelder-Mead
    algorithm was used to estimate the model parameters. The objective
    function (L2G norm) that is minimised during the optimisation is the
    same as the one used by Jaiswal et al. (2010).

    The coefficients used in the indonesian model are
    x=0.62275231, y=8.03314466, zeta=2.15

    Allen, T. I., Wald, D. J., Earle, P. S., Marano, K. D., Hotovec, A. J.,
    Lin, K., and Hearne, M., 2009. An Atlas of ShakeMaps and population
    exposure catalog for earthquake loss modeling, Bull. Earthq. Eng. 7,
    701-718.

    Jaiswal, K., and Wald, D., 2010. An empirical model for global earthquake
    fatality estimation, Earthq. Spectra 26, 1017-1037.


    Caveats and limitations:

    The current model is the result of the above mentioned workshop and
    reflects the best available information. However, the current model
    has a number of issues listed below and is expected to evolve further
    over time.

    1 - The model is based on limited number of observed fatality
        rates during 4 past fatal events.
    2 - The model clearly over-predicts the fatality rates at
        intensities higher than VIII.
    3 - The model only estimates the expected fatality rate for a given
        intensity level; however the associated uncertainty for the proposed
        model is not addressed.
    4 - There are few known mistakes in developing the current model:
        - rounding MMI values to the nearest 0.5,
        - Implementing Finite-Fault models of candidate events, and
        - consistency between selected GMPEs with those in use by BMKG.
          These issues will be addressed by ITB team in the final report.

    Note: Because of these caveats, decisions should not be made solely on
    the information presented here and should always be verified by ground
    truthing and other reliable information sources.

    :author Hadi Ghasemi
    :rating 3

    :param requires category=='hazard' and \
                    subcategory=='earthquake' and \
                    layertype=='raster' and \
                    unit=='MMI'

    :param requires category=='exposure' and \
                    subcategory=='population' and \
                    layertype=='raster'

    """

    title = tr('Die or be displaced')
    synopsis = tr(
        'To assess the impact of earthquake on population based on earthquake '
        'model developed by ITB')
    citations = tr(
        ' * Indonesian Earthquake Building-Damage and Fatality Models and '
        '   Post Disaster Survey Guidelines Development Bali, 27-28 '
        '   February 2012, 54pp.\n'
        ' * Allen, T. I., Wald, D. J., Earle, P. S., Marano, K. D., '
        '   Hotovec, A. J., Lin, K., and Hearne, M., 2009. An Atlas '
        '   of ShakeMaps and population exposure catalog for '
        '   earthquake loss modeling, Bull. Earthq. Eng. 7, 701-718.\n'
        ' * Jaiswal, K., and Wald, D., 2010. An empirical model for '
        '   global earthquake fatality estimation, Earthq. Spectra '
        '   26, 1017-1037.\n')
    limitation = tr(
        ' - The model is based on limited number of observed fatality '
        '   rates during 4 past fatal events. \n'
        ' - The model clearly over-predicts the fatality rates at '
        '   intensities higher than VIII.\n'
        ' - The model only estimates the expected fatality rate '
        '   for a given intensity level; however the associated '
        '   uncertainty for the proposed model is not addressed.\n'
        ' - There are few known mistakes in developing the current '
        '   model:\n\n'
        '   * rounding MMI values to the nearest 0.5,\n'
        '   * Implementing Finite-Fault models of candidate events, and\n'
        '   * consistency between selected GMPEs with those in use by '
        '     BMKG.\n')
    actions = tr(
        'Provide details about the population will be die or displaced')
    detailed_description = tr(
        'This model was developed by Institut Teknologi Bandung (ITB) '
        'and implemented by Dr. Hadi Ghasemi, Geoscience Australia\n'
        'Algorithm:\n'
        'In this study, the same functional form as Allen (2009) is '
        'adopted o express fatality rate as a function of intensity '
        '(see Eq. 10 in the report). The Matlab built-in function '
        '(fminsearch) for  Nelder-Mead algorithm was used to estimate '
        'the model parameters. The objective function (L2G norm) that '
        'is minimized during the optimisation is the same as the one '
        'used by Jaiswal et al. (2010).\n'
        'The coefficients used in the indonesian model are x=0.62275231, '
        'y=8.03314466, zeta=2.15')
    defaults = get_defaults()

    parameters = OrderedDict([
        ('x', 0.62275231),
        ('y', 8.03314466),  # Model coefficients
        # Rates of people displaced for each MMI level
        ('displacement_rate', {
            1: 0,
            2: 0,
            3: 0,
            4: 0,
            5: 0,
            6: 1.0,
            7: 1.0,
            8: 1.0,
            9: 1.0,
            10: 1.0
        }),
        ('mmi_range', range(2, 10)),
        ('step', 0.5),
        # Threshold below which layer should be transparent
        ('tolerance', 0.01),
        ('calculate_displaced_people', True),
        ('postprocessors',
         OrderedDict([
             ('Gender', {
                 'on': True
             }),
             ('Age', {
                 'on':
                 True,
                 'params':
                 OrderedDict([('youth_ratio', defaults['YOUTH_RATIO']),
                              ('adult_ratio', defaults['ADULT_RATIO']),
                              ('elder_ratio', defaults['ELDER_RATIO'])])
             }), ('MinimumNeeds', {
                 'on': True
             })
         ])),
        ('minimum needs', default_minimum_needs())
    ])

    def fatality_rate(self, mmi):
        """
        ITB method to compute fatality rate
        :param mmi:
        """
        # As per email discussion with Ole, Trevor, Hadi, mmi < 4 will have
        # a fatality rate of 0 - Tim
        if mmi < 4:
            return 0

        x = self.parameters['x']
        y = self.parameters['y']
        return numpy.power(10.0, x * mmi - y)

    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)

        # Set resulting layer to NaN when less than a threshold. This is to
        # achieve transparency (see issue #126).
        R[R < tolerance] = numpy.nan

        # Total statistics
        total = int(round(numpy.nansum(my_exposure.flat) / 1000) * 1000)

        # Compute number of fatalities
        fatalities = int(
            round(numpy.nansum(number_of_fatalities.values()) / 1000)) * 1000
        # As per email discussion with Ole, Trevor, Hadi, total fatalities < 50
        # will be rounded down to 0 - Tim
        if fatalities < 50:
            fatalities = 0

        # Compute number of people displaced due to building collapse
        displaced = int(
            round(numpy.nansum(number_of_displaced.values()) / 1000)) * 1000

        # Generate impact report
        table_body = [question]

        # Add total fatality estimate
        s = format_int(fatalities)
        table_body.append(
            TableRow([tr('Number of fatalities'), s], header=True))

        if self.parameters['calculate_displaced_people']:
            # Add total estimate of people displaced
            s = format_int(displaced)
            table_body.append(
                TableRow([tr('Number of people displaced'), s], header=True))
        else:
            displaced = 0

        # Add estimate of total population in area
        s = format_int(int(total))
        table_body.append(
            TableRow([tr('Total number of people'), s], header=True))

        # Calculate estimated needs based on BNPB Perka 7/2008 minimum bantuan
        # FIXME: Refactor and share
        minimum_needs = self.parameters['minimum needs']
        needs = evacuated_population_weekly_needs(displaced, minimum_needs)

        # Generate impact report for the pdf map
        table_body = [
            question,
            TableRow([tr('Fatalities'),
                      '%s' % format_int(fatalities)],
                     header=True),
            TableRow([tr('People displaced'),
                      '%s' % format_int(displaced)],
                     header=True),
            TableRow(
                tr('Map shows density estimate of '
                   'displaced population')),
            TableRow([tr('Needs per week'), tr('Total')], header=True),
            [tr('Rice [kg]'), format_int(needs['rice'])],
            [tr('Drinking Water [l]'),
             format_int(needs['drinking_water'])],
            [tr('Clean Water [l]'),
             format_int(needs['water'])],
            [tr('Family Kits'),
             format_int(needs['family_kits'])],
            TableRow(tr('Action Checklist:'), header=True)
        ]

        if fatalities > 0:
            table_body.append(
                tr('Are there enough victim identification '
                   'units available for %s people?') % format_int(fatalities))
        if displaced > 0:
            table_body.append(
                tr('Are there enough shelters and relief items '
                   'available for %s people?') % format_int(displaced))
            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?')))

        # Extend impact report for on-screen display
        table_body.extend([
            TableRow(tr('Notes'), header=True),
            tr('Total population: %s') % format_int(total),
            tr('People are considered to be displaced if '
               'they experience and survive a shake level'
               'of more than 5 on the MMI scale '),
            tr('Minimum needs are defined in BNPB '
               'regulation 7/2008'),
            tr('The fatality calculation assumes that '
               'no fatalities occur for shake levels below 4 '
               'and fatality counts of less than 50 are '
               'disregarded.'),
            tr('All values are rounded up to the nearest '
               'integer in order to avoid representing human '
               'lives as fractions.')
        ])

        table_body.append(TableRow(tr('Notes'), header=True))
        table_body.append(
            tr('Fatality model is from '
               'Institute of Teknologi Bandung 2012.'))
        table_body.append(tr('Population numbers rounded to nearest 1000.'))

        # Result
        impact_summary = Table(table_body).toNewlineFreeString()
        impact_table = impact_summary

        # check for zero impact
        if numpy.nanmax(R) == 0 == numpy.nanmin(R):
            table_body = [
                question,
                TableRow([tr('Fatalities'),
                          '%s' % format_int(fatalities)],
                         header=True)
            ]
            my_message = Table(table_body).toNewlineFreeString()
            raise ZeroImpactException(my_message)

        # Create style
        colours = ['#EEFFEE', '#FFFF7F', '#E15500', '#E4001B', '#730000']
        classes = create_classes(R.flat[:], 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])
            style_class['quantity'] = classes[i]
            if i == 0:
                transparency = 100
            else:
                transparency = 30
            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('Earthquake impact to population')
        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
        L = Raster(R,
                   projection=population.get_projection(),
                   geotransform=population.get_geotransform(),
                   keywords={
                       'impact_summary': impact_summary,
                       'total_population': total,
                       'total_fatalities': fatalities,
                       'fatalities_per_mmi': number_of_fatalities,
                       'exposed_per_mmi': number_of_exposed,
                       'displaced_per_mmi': number_of_displaced,
                       'impact_table': impact_table,
                       'map_title': map_title,
                       'legend_notes': legend_notes,
                       'legend_units': legend_units,
                       'legend_title': legend_title
                   },
                   name=tr('Estimated displaced population per cell'),
                   style_info=style_info)

        return L
Exemplo n.º 29
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id': 'VolcanoPolygonBuildingFunction',
            'name': tr('Polygon volcano on buildings'),
            'impact': tr('Be affected'),
            'title': tr('Be affected'),
            'function_type': 'old-style',
            'author': 'AIFDR',
            'date_implemented': 'N/A',
            'overview': tr(
                'To assess the impacts of volcano eruption on building.'),
            'detailed_description': '',
            'hazard_input': tr(
                'The hazard layer must be a polygon layer. This layer '
                'must have an attribute representing the volcano hazard '
                'zone that can be specified in the impact function option. '
                'There are three classes low, medium, and high. The default '
                'values are "Kawasan Rawan Bencana I" for low, "Kawasan Rawan '
                'Bencana II" for medium, and "Kawasan  Rawan Bencana III for '
                'high." If you want to see the name of the volcano in the '
                'result, you need to specify the volcano name attribute in '
                'the Impact Function options.'),
            'exposure_input': tr(
                'Vector polygon layer extracted from OSM where each '
                'polygon represents the footprint of a building.'),
            'output': tr(
                'Vector layer contains Map of building exposed to '
                'volcanic hazard zones for each Kawasan Rawan Bencana.'),
            'actions': tr(
                'Provide details about the number of buildings that are '
                'within each hazard zone.'),
            'limitations': [],
            'citations': [
                {
                    'text': None,
                    'link': None
                }
            ],
            'legend_title': tr('Building count'),
            'legend_units': tr('(building)'),
            'legend_notes': tr(
                'Thousand separator is represented by %s' %
                get_thousand_separator()),
            'layer_requirements': {
                'hazard': {
                    'layer_mode': layer_mode_classified,
                    'layer_geometries': [layer_geometry_polygon],
                    'hazard_categories': [
                        hazard_category_multiple_event,
                        hazard_category_single_event
                    ],
                    'hazard_types': [hazard_volcano],
                    'continuous_hazard_units': [],
                    'vector_hazard_classifications': [
                        volcano_vector_hazard_classes],
                    'raster_hazard_classifications': [],
                    'additional_keywords': [
                        volcano_name_field]
                },
                'exposure': {
                    'layer_mode': layer_mode_classified,
                    'layer_geometries': [
                        layer_geometry_polygon,
                        layer_geometry_point
                    ],
                    'exposure_types': [exposure_structure],
                    'exposure_units': [],
                    'exposure_class_fields': [structure_class_field],
                    'additional_keywords': []
                }
            },
            'parameters': OrderedDict([
                ('postprocessors', OrderedDict([(
                    'BuildingType',
                    building_type_postprocessor())]))
            ])
        }
        return dict_meta
Exemplo n.º 30
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id': 'AshRasterPlacesFunction',
            'name': tr('Ash raster on places'),
            'impact': tr('Be affected'),
            'title': tr('Be affected'),
            'function_type': 'old-style',
            'author': 'Etienne Trimaille',
            'date_implemented': '13/07/2016',
            'overview': tr(
                'To assess the impact of each hazard zone on places.'),
            'detailed_description': '',
            'hazard_input': tr(
                'The hazard layer must be an ash raster layer.'),
            'exposure_input': tr(
                'Vector point layer where each feature represents a place.'),
            'output': tr(
                'Map of places exposed to the highest hazard zone and a table '
                'with the number of people in each hazard zone'),
            'actions': tr(
                'Provide details about how big area fall within '
                'each hazard zone.'),
            'limitations': [],
            'citations': [
                {
                    'text': None,
                    'link': None
                }
            ],
            'legend_title': '',
            'legend_units': '',
            'legend_notes': '',
            'layer_requirements': {
                'hazard': {
                    'layer_mode': layer_mode_continuous,
                    'layer_geometries': [layer_geometry_raster],
                    'hazard_categories': [
                        hazard_category_single_event,
                        hazard_category_multiple_event
                    ],
                    'hazard_types': [hazard_volcanic_ash],
                    'continuous_hazard_units': [unit_centimetres],
                    'vector_hazard_classifications': [],
                    'raster_hazard_classifications': [],
                    'additional_keywords': []
                },
                'exposure': {
                    'layer_mode': layer_mode_classified,
                    'layer_geometries': [
                        layer_geometry_point,
                    ],
                    'exposure_types': [exposure_place],
                    'exposure_units': [],
                    'exposure_class_fields': [structure_class_field],
                    'additional_keywords': []
                }
            },
            'parameters': OrderedDict(
                [
                    ('group_threshold', threshold_group_parameter())
                ])
        }
        return dict_meta
Exemplo n.º 31
0
    def as_dict():
        """Return metadata as a dictionary.

        This is a static method. You can use it to get the metadata in
        dictionary format for an impact function.

        :returns: A dictionary representing all the metadata for the
            concrete impact function.
        :rtype: dict
        """
        dict_meta = {
            'id': 'EarthquakeBuildingFunction',
            'name': tr('Earthquake on buildings'),
            'impact': tr('Be affected'),
            'title': tr('Be affected'),
            'function_type': 'old-style',
            'author': 'N/A',
            'date_implemented': 'N/A',
            'overview': tr(
                'This impact function will calculate the impact of an '
                'earthquake on buildings, reporting how many are expected '
                'to be damaged.'),
            'detailed_description': '',
            'hazard_input': '',
            'exposure_input': '',
            'output': '',
            'actions': '',
            'limitations': [],
            'citations': [],
            'layer_requirements': {
                'hazard': {
                    'layer_mode': layer_mode_continuous,
                    'layer_geometries': [layer_geometry_raster],
                    'hazard_categories': [
                        hazard_category_single_event,
                        hazard_category_multiple_event
                    ],
                    'hazard_types': [hazard_earthquake],
                    'continuous_hazard_units': [unit_mmi],
                    'vector_hazard_classifications': [],
                    'raster_hazard_classifications': [],
                    'additional_keywords': []
                },
                'exposure': {
                    'layer_mode': layer_mode_classified,
                    'layer_geometries': [
                        layer_geometry_point,
                        layer_geometry_polygon
                    ],
                    'exposure_types': [exposure_structure],
                    'exposure_units': [],
                    'exposure_class_fields': [structure_class_field],
                    'additional_keywords': []
                }
            },
            'parameters': OrderedDict(
                [('low_threshold', low_threshold()),
                 ('medium_threshold', medium_threshold()),
                 ('high_threshold', high_threshold()),
                 ('postprocessors', OrderedDict([
                     ('BuildingType',
                      building_type_postprocessor())]))]
            )
        }
        return dict_meta
Exemplo n.º 32
0
class BuildingTypePostprocessor(AbstractPostprocessor):
    """
    Postprocessor that calculates building types related statistics.
    see the _calculate_* methods to see indicator specific documentation

    see :mod:`safe.defaults` for default values information
    """

    def __init__(self):
        """
        Constructor for postprocessor class,
        It takes care of defining self.impact_total
        """
        AbstractPostprocessor.__init__(self)
        self.impact_total = None
        self.impact_attrs = None
        self.target_field = None
        self.no_features = None
        self.type_fields = None
        self.valid_type_fields = None
        self.fields_values = OrderedDict([
            ('Medical', ['Clinic/Doctor', 'Hospital']),
            ('Schools', ['School', 'University/College', ]),
            ('Places of worship', ['Place of Worship - Unitarian',
                                   'Place of Worship - Islam',
                                   'Place of Worship - Buddhist',
                                   'Place of Worship']),
            ('Residential', ['Residential']),
            ('Government', ['Government']),
            ('Public Building', ['Public Building']),
            ('Fire Station', ['Fire Station']),
            ('Police Station', ['Police Station']),
            ('Supermarket', ['Supermarket']),
            ('Commercial', ['Commercial']),
            ('Industrial', ['Industrial']),
            ('Utility', ['Utility']),
            ('Sports Facility', ['Sports Facility']),
            ('Other', [])])

        self.known_types = []
        self._update_known_types()

    def description(self):
        """Describe briefly what the post processor does.

        :returns: The translated description.
        :rtype: str
        """
        return tr('Calculates building types related statistics.')

    def setup(self, params):
        """concrete implementation it takes care of the needed parameters being
         initialized

        :param params: dict of parameters to pass to the post processor
        """
        AbstractPostprocessor.setup(self, None)
        if (self.impact_total is not None or
                self.impact_attrs is not None or
                self.target_field is not None or
                self.valid_type_fields is not None or
                self.type_fields is not None):
            self._raise_error('clear needs to be called before setup')

        self.impact_total = params['impact_total']
        self.impact_attrs = params['impact_attrs']
        self.target_field = params['target_field']
        self.valid_type_fields = params['key_attribute']

        #find which attribute field has to be used
        self.type_fields = []
        try:
            for key in self.impact_attrs[0].iterkeys():
                if key.lower() in self.valid_type_fields:
                    self.type_fields.append(key)
        except IndexError:
            pass

        if len(self.type_fields) == 0:
            self.type_fields = None

        self.no_features = False
        #there are no features in this postprocessing polygon
        if self.impact_attrs == []:
            self.no_features = True

    def process(self):
        """Concrete implementation that performs all indicators calculations.
        """
        AbstractPostprocessor.process(self)

        if (self.impact_total is None or
                self.impact_attrs is None or
                self.target_field is None):
            self._log_message('%s not all params have been correctly '
                              'initialized, setup needs to be called before '
                              'process. Skipping this postprocessor'
                              % self.__class__.__name__)
        else:
            self._calculate_total()
            for title, field_values in self.fields_values.iteritems():
                self._calculate_type(title, field_values)

    def clear(self):
        """concrete implementation that ensures needed parameters are cleared.
        """
        AbstractPostprocessor.clear(self)
        self.impact_total = None
        self.impact_attrs = None
        self.target_field = None
        self.type_fields = None
        self.valid_type_fields = None

    def _calculate_total(self):
        """Indicator that shows total population.

        This indicator reports the total population.
        """

        name = tr('Total')
        if self.target_field is not None:
            name = '%s %s' % (name, tr(self.target_field).lower())

        result = self.impact_total
        try:
            result = int(round(result))
        except ValueError:
            result = self.NO_DATA_TEXT
        self._append_result(name, result)

    def _calculate_type(self, title, fields_values):
        """Indicator that shows total population.

        this indicator reports the building by type. the logic is:
        - look for the fields that occurs with a name included in
        self.valid_type_fields
        - look in those fields for any of the values of self.fields_values
        - if a record has one of the valid fields with one of the valid
        fields_values then it is considered affected
        """

        title = tr(title)
        if self.target_field is not None:
            title = '%s %s' % (title, tr(self.target_field).lower())

        result = 0
        if self.type_fields is not None:
            try:
                for building in self.impact_attrs:
                    for type_field in self.type_fields:
                        building_type = building[type_field]
                        if building_type in fields_values:
                            result += building[self.target_field]
                            break
                        elif self._is_unknown_type(building_type):
                            self._update_known_types(building_type)

                result = int(round(result))
            except (ValueError, KeyError):
                result = self.NO_DATA_TEXT
        else:
            if self.no_features:
                result = 0
            else:
                result = self.NO_DATA_TEXT
        self._append_result(title, result)

    def _is_unknown_type(self, building_type):
        """check if the given type is in any of the known_types dictionary

        :param building_type: the name of the type
        :type building_type: str

        :returns: Flag indicating if the building_type is unknown
        :rtype: boolean
        """

        is_unknown = building_type not in self.known_types
        return is_unknown

    def _update_known_types(self, building_type=None):
        """
        Adds a building_type (if passed) and updates the known_types list

        this is called each time a new unknown type is found and is needed so
        that self._is_unknown_type (which is called many times) to perform
        only a simple 'in' check

        :param building_type: the name of the type to add to the known types
        :type building_type: str
        """
        if type is not None:
            self.fields_values['Other'].append(building_type)

        # flatten self.fields_values.values()
        # using http://stackoverflow.com/questions/5286541/#5286614
        self.known_types = list(itertools.chain.from_iterable(
            itertools.repeat(x, 1) if isinstance(x, str) else x for x in
            self.fields_values.values()))