def prepare_impact_function(self): """Create analysis as a representation of current situation of IFCW.""" # Impact Functions impact_function = ImpactFunction() impact_function.callback = self.progress_callback # Layers impact_function.hazard = self.parent.hazard_layer impact_function.exposure = self.parent.exposure_layer aggregation = self.parent.aggregation_layer if aggregation: impact_function.aggregation = aggregation impact_function.use_selected_features_only = ( setting('useSelectedFeaturesOnly', False, bool)) else: mode = setting('analysis_extents_mode') if self.extent.user_extent: # This like a hack to transform a geometry to a rectangle. # self.extent.user_extent is a QgsGeometry. # impact_function.requested_extent needs a QgsRectangle. wkt = self.extent.user_extent.exportToWkt() impact_function.requested_extent = wkt_to_rectangle(wkt) impact_function.requested_extent_crs = self.extent.crs elif mode == HAZARD_EXPOSURE_VIEW: impact_function.requested_extent = ( self.iface.mapCanvas().extent()) impact_function.requested_extent_crs = self.extent.crs # We don't have any checkbox in the wizard for the debug mode. impact_function.debug_mode = False return impact_function
def test_ratios_with_raster_exposure(self): """Test if we can add defaults to a raster exposure. See ticket #3851 how to manage ratios with a raster exposure. """ hazard_layer = load_test_vector_layer('gisv4', 'hazard', 'tsunami_vector.geojson') exposure_layer = load_test_raster_layer('gisv4', 'exposure', 'raster', 'population.asc') # Set up impact function impact_function = ImpactFunction() impact_function.debug_mode = True impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.prepare() status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) for layer in impact_function.outputs: if layer.keywords['layer_purpose'] == ( layer_purpose_analysis_impacted['key']): analysis = layer if layer.keywords['layer_purpose'] == ( layer_purpose_aggregate_hazard_impacted['key']): impact = layer # We check in the impact layer if we have : # female default ratio with the default value index = impact.fieldNameIndex(female_ratio_field['field_name']) self.assertNotEqual(-1, index) unique_values = impact.uniqueValues(index) self.assertEqual(1, len(unique_values)) female_ratio = unique_values[0] # female displaced count and youth displaced count self.assertNotEqual( -1, impact.fieldNameIndex(female_displaced_count_field['field_name'])) self.assertNotEqual( -1, impact.fieldNameIndex(youth_displaced_count_field['field_name'])) # Check that we have more than 0 female displaced in the analysis layer index = analysis.fieldNameIndex( female_displaced_count_field['field_name']) female_displaced = analysis.uniqueValues(index)[0] self.assertGreater(female_displaced, 0) # Let's check computation index = analysis.fieldNameIndex(displaced_field['field_name']) displaced_population = analysis.uniqueValues(index)[0] self.assertEqual(int(displaced_population * female_ratio), female_displaced) # Check that we have more than 0 youth displaced in the analysis layer index = analysis.fieldNameIndex( female_displaced_count_field['field_name']) value = analysis.uniqueValues(index)[0] self.assertGreater(value, 0) # Let do another test with the special aggregation layer hazard_layer = load_test_vector_layer('gisv4', 'hazard', 'tsunami_vector.geojson') exposure_layer = load_test_raster_layer('gisv4', 'exposure', 'raster', 'population.asc') aggregation_layer = load_test_vector_layer( 'gisv4', 'aggregation', 'small_grid_ratios.geojson') # This aggregation layer has : # * a field for female ratio : 1, 0.5 and 0 # * use global default for youth ratio # * do not ust for adult ratio # * use custom 0.75 for elderly ratio # Set up impact function impact_function = ImpactFunction() impact_function.debug_mode = True impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.aggregation = aggregation_layer status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) impact = impact_function.impact # We should have a female_ratio with many values index = impact.fieldNameIndex(female_ratio_field['field_name']) self.assertNotEqual(-1, index) values = impact.uniqueValues(index) self.assertEqual(3, len(values)) # We should have a youth_ratio with global default index = impact.fieldNameIndex(youth_ratio_field['field_name']) self.assertNotEqual(-1, index) values = impact.uniqueValues(index) self.assertEqual(1, len(values)) # We should not have an adult_ratio index = impact.fieldNameIndex(adult_ratio_field['field_name']) self.assertEqual(-1, index) # We should have a elderly_ratio = 0.75 index = impact.fieldNameIndex(elderly_ratio_field['field_name']) self.assertNotEqual(-1, index) values = impact.uniqueValues(index) self.assertEqual(1, len(values)) self.assertEqual(0.75, values[0])
def test_ratios_with_vector_exposure(self): """Test if we can add defaults to a vector exposure.""" # First test, if we do not provide an aggregation, hazard_layer = load_test_vector_layer('gisv4', 'hazard', 'classified_vector.geojson') exposure_layer = load_test_vector_layer('gisv4', 'exposure', 'population.geojson') # Set up impact function impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.prepare() # Let's remove one field from keywords. # We monkey patch keywords for testing after `prepare` & before `run`. fields = impact_function.exposure.keywords['inasafe_fields'] del fields[female_count_field['key']] status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) impact = impact_function.impact # We check the field exist after the IF with only one value. field = impact.fieldNameIndex(female_ratio_field['field_name']) self.assertNotEqual(-1, field) unique_ratio = impact.uniqueValues(field) self.assertEqual(1, len(unique_ratio), unique_ratio) self.assertEqual(unique_ratio[0], female_ratio_default_value['default_value']) # Second test, if we provide an aggregation without a default ratio 0.2 expected_ratio = 1.0 hazard_layer = load_test_vector_layer('gisv4', 'hazard', 'classified_vector.geojson') exposure_layer = load_test_vector_layer('gisv4', 'exposure', 'population.geojson') aggregation_layer = load_test_vector_layer('gisv4', 'aggregation', 'small_grid.geojson') # Set up impact function impact_function = ImpactFunction() impact_function.aggregation = aggregation_layer impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.debug_mode = True impact_function.prepare() # The `prepare` reads keywords from the file. impact_function.aggregation.keywords['inasafe_default_values'] = { elderly_ratio_field['key']: expected_ratio } fields = impact_function.exposure.keywords['inasafe_fields'] del fields[female_count_field['key']] status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) impact = impact_function.impact # We check the field exist after the IF with only original values. field = impact.fieldNameIndex(female_ratio_field['field_name']) self.assertNotEqual(-1, field) unique_ratio = impact.uniqueValues(field) self.assertEqual(3, len(unique_ratio), unique_ratio) # We check the field exist after the IF with only one value. field = impact.fieldNameIndex(elderly_ratio_field['field_name']) self.assertNotEqual(-1, field) unique_ratio = impact.uniqueValues(field) self.assertEqual(1, len(unique_ratio), unique_ratio) self.assertEqual(expected_ratio, unique_ratio[0]) # Third test, if we provide an aggregation with a ratio and the # exposure has a count, we should a have a ratio from the exposure # count. hazard_layer = load_test_vector_layer('gisv4', 'hazard', 'classified_vector.geojson') exposure_layer = load_test_vector_layer('gisv4', 'exposure', 'population.geojson') aggregation_layer = load_test_vector_layer('gisv4', 'aggregation', 'small_grid.geojson') # Set up impact function impact_function = ImpactFunction() impact_function.debug_mode = True impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.aggregation = aggregation_layer impact_function.prepare() status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) impact = impact_function.impact # Check that we have don't have only one unique value since the ratio # depends on the "population / female count" and we should have at # least different ratios. field = impact.fieldNameIndex(female_ratio_field['field_name']) self.assertNotEqual(-1, field) unique_ratio = impact.uniqueValues(field) self.assertNotEqual(1, len(unique_ratio), unique_ratio)
def run_scenario(scenario, use_debug=False): """Run scenario. :param scenario: Dictionary of hazard, exposure, and aggregation. :type scenario: dict :param use_debug: If we should use debug_mode when we run the scenario. :type use_debug: bool :returns: Tuple(status, Flow dictionary, outputs). :rtype: list """ if os.path.exists(scenario['exposure']): exposure_path = scenario['exposure'] elif os.path.exists(standard_data_path('exposure', scenario['exposure'])): exposure_path = standard_data_path('exposure', scenario['exposure']) elif os.path.exists( standard_data_path(*(scenario['exposure'].split('/')))): exposure_path = standard_data_path(*(scenario['exposure'].split('/'))) else: raise IOError('No exposure file') if os.path.exists(scenario['hazard']): hazard_path = scenario['hazard'] elif os.path.exists(standard_data_path('hazard', scenario['hazard'])): hazard_path = standard_data_path('hazard', scenario['hazard']) elif os.path.exists(standard_data_path(*(scenario['hazard'].split('/')))): hazard_path = standard_data_path(*(scenario['hazard'].split('/'))) else: raise IOError('No hazard file') if not scenario['aggregation']: aggregation_path = None else: if os.path.exists(scenario['aggregation']): aggregation_path = scenario['aggregation'] elif os.path.exists( standard_data_path('aggregation', scenario['aggregation'])): aggregation_path = standard_data_path('aggregation', scenario['aggregation']) elif os.path.exists( standard_data_path(*(scenario['aggregation'].split('/')))): aggregation_path = standard_data_path( *(scenario['aggregation'].split('/'))) else: raise IOError('No aggregation file') impact_function = ImpactFunction() impact_function.debug_mode = use_debug layer = QgsVectorLayer(hazard_path, 'Hazard', 'ogr') if not layer.isValid(): layer = QgsRasterLayer(hazard_path, 'Hazard') impact_function.hazard = layer layer = QgsVectorLayer(exposure_path, 'Exposure', 'ogr') if not layer.isValid(): layer = QgsRasterLayer(exposure_path, 'Exposure') impact_function.exposure = layer if aggregation_path: impact_function.aggregation = QgsVectorLayer(aggregation_path, 'Aggregation', 'ogr') status, message = impact_function.prepare() if status != 0: return status, message, None status, message = impact_function.run() if status != 0: return status, message, None for layer in impact_function.outputs: if layer.type() == QgsMapLayer.VectorLayer: check_inasafe_fields(layer) return status, impact_function.state, impact_function.outputs
def test_ratios_with_raster_exposure(self): """Test if we can add defaults to a raster exposure. See ticket #3851 how to manage ratios with a raster exposure. """ hazard_layer = load_test_vector_layer( 'gisv4', 'hazard', 'tsunami_vector.geojson') exposure_layer = load_test_raster_layer( 'gisv4', 'exposure', 'raster', 'population.asc') # Set up impact function impact_function = ImpactFunction() impact_function.debug_mode = True impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.prepare() status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) for layer in impact_function.outputs: if layer.keywords['layer_purpose'] == ( layer_purpose_analysis_impacted['key']): analysis = layer if layer.keywords['layer_purpose'] == ( layer_purpose_aggregate_hazard_impacted['key']): impact = layer # We check in the impact layer if we have : # female default ratio with the default value index = impact.fieldNameIndex(female_ratio_field['field_name']) self.assertNotEqual(-1, index) unique_values = impact.uniqueValues(index) self.assertEqual(1, len(unique_values)) female_ratio = unique_values[0] # female displaced count and youth displaced count self.assertNotEqual( -1, impact.fieldNameIndex( female_displaced_count_field['field_name'])) self.assertNotEqual( -1, impact.fieldNameIndex( youth_displaced_count_field['field_name'])) # Check that we have more than 0 female displaced in the analysis layer index = analysis.fieldNameIndex( female_displaced_count_field['field_name']) female_displaced = analysis.uniqueValues(index)[0] self.assertGreater(female_displaced, 0) # Let's check computation index = analysis.fieldNameIndex( displaced_field['field_name']) displaced_population = analysis.uniqueValues(index)[0] self.assertEqual( int(displaced_population * female_ratio), female_displaced) # Check that we have more than 0 youth displaced in the analysis layer index = analysis.fieldNameIndex( female_displaced_count_field['field_name']) value = analysis.uniqueValues(index)[0] self.assertGreater(value, 0) # Let do another test with the special aggregation layer hazard_layer = load_test_vector_layer( 'gisv4', 'hazard', 'tsunami_vector.geojson') exposure_layer = load_test_raster_layer( 'gisv4', 'exposure', 'raster', 'population.asc') aggregation_layer = load_test_vector_layer( 'gisv4', 'aggregation', 'small_grid_ratios.geojson') # This aggregation layer has : # * a field for female ratio : 1, 0.5 and 0 # * use global default for youth ratio # * do not ust for adult ratio # * use custom 0.75 for elderly ratio # Set up impact function impact_function = ImpactFunction() impact_function.debug_mode = True impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.aggregation = aggregation_layer status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) impact = impact_function.impact # We should have a female_ratio with many values index = impact.fieldNameIndex(female_ratio_field['field_name']) self.assertNotEqual(-1, index) values = impact.uniqueValues(index) self.assertEqual(3, len(values)) # We should have a youth_ratio with global default index = impact.fieldNameIndex(youth_ratio_field['field_name']) self.assertNotEqual(-1, index) values = impact.uniqueValues(index) self.assertEqual(1, len(values)) # We should not have an adult_ratio index = impact.fieldNameIndex(adult_ratio_field['field_name']) self.assertEqual(-1, index) # We should have a elderly_ratio = 0.75 index = impact.fieldNameIndex(elderly_ratio_field['field_name']) self.assertNotEqual(-1, index) values = impact.uniqueValues(index) self.assertEqual(1, len(values)) self.assertEqual(0.75, values[0])
def test_ratios_with_vector_exposure(self): """Test if we can add defaults to a vector exposure.""" # First test, if we do not provide an aggregation, hazard_layer = load_test_vector_layer( 'gisv4', 'hazard', 'classified_vector.geojson') exposure_layer = load_test_vector_layer( 'gisv4', 'exposure', 'population.geojson') # Set up impact function impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.prepare() # Let's remove one field from keywords. # We monkey patch keywords for testing after `prepare` & before `run`. fields = impact_function.exposure.keywords['inasafe_fields'] del fields[female_count_field['key']] status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) impact = impact_function.impact # We check the field exist after the IF with only one value. field = impact.fieldNameIndex( female_ratio_field['field_name']) self.assertNotEqual(-1, field) unique_ratio = impact.uniqueValues(field) self.assertEqual(1, len(unique_ratio), unique_ratio) self.assertEqual( unique_ratio[0], female_ratio_default_value['default_value']) # Second test, if we provide an aggregation without a default ratio 0.2 expected_ratio = 1.0 hazard_layer = load_test_vector_layer( 'gisv4', 'hazard', 'classified_vector.geojson') exposure_layer = load_test_vector_layer( 'gisv4', 'exposure', 'population.geojson') aggregation_layer = load_test_vector_layer( 'gisv4', 'aggregation', 'small_grid.geojson') # Set up impact function impact_function = ImpactFunction() impact_function.aggregation = aggregation_layer impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.debug_mode = True impact_function.prepare() # The `prepare` reads keywords from the file. impact_function.aggregation.keywords['inasafe_default_values'] = { elderly_ratio_field['key']: expected_ratio } fields = impact_function.exposure.keywords['inasafe_fields'] del fields[female_count_field['key']] status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) impact = impact_function.impact # We check the field exist after the IF with only original values. field = impact.fieldNameIndex( female_ratio_field['field_name']) self.assertNotEqual(-1, field) unique_ratio = impact.uniqueValues(field) self.assertEqual(3, len(unique_ratio), unique_ratio) # We check the field exist after the IF with only one value. field = impact.fieldNameIndex( elderly_ratio_field['field_name']) self.assertNotEqual(-1, field) unique_ratio = impact.uniqueValues(field) self.assertEqual(1, len(unique_ratio), unique_ratio) self.assertEqual(expected_ratio, unique_ratio[0]) # Third test, if we provide an aggregation with a ratio and the # exposure has a count, we should a have a ratio from the exposure # count. hazard_layer = load_test_vector_layer( 'gisv4', 'hazard', 'classified_vector.geojson') exposure_layer = load_test_vector_layer( 'gisv4', 'exposure', 'population.geojson') aggregation_layer = load_test_vector_layer( 'gisv4', 'aggregation', 'small_grid.geojson') # Set up impact function impact_function = ImpactFunction() impact_function.debug_mode = True impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.aggregation = aggregation_layer impact_function.prepare() status, message = impact_function.run() self.assertEqual(ANALYSIS_SUCCESS, status, message) impact = impact_function.impact # Check that we have don't have only one unique value since the ratio # depends on the "population / female count" and we should have at # least different ratios. field = impact.fieldNameIndex( female_ratio_field['field_name']) self.assertNotEqual(-1, field) unique_ratio = impact.uniqueValues(field) self.assertNotEqual(1, len(unique_ratio), unique_ratio)
def run_scenario(scenario, use_debug=False): """Run scenario. :param scenario: Dictionary of hazard, exposure, and aggregation. :type scenario: dict :param use_debug: If we should use debug_mode when we run the scenario. :type use_debug: bool :returns: Tuple(status, Flow dictionary, outputs). :rtype: list """ if os.path.exists(scenario['exposure']): exposure_path = scenario['exposure'] elif os.path.exists(standard_data_path('exposure', scenario['exposure'])): exposure_path = standard_data_path('exposure', scenario['exposure']) elif os.path.exists( standard_data_path(*(scenario['exposure'].split('/')))): exposure_path = standard_data_path(*(scenario['exposure'].split('/'))) else: raise IOError('No exposure file') if os.path.exists(scenario['hazard']): hazard_path = scenario['hazard'] elif os.path.exists(standard_data_path('hazard', scenario['hazard'])): hazard_path = standard_data_path('hazard', scenario['hazard']) elif os.path.exists(standard_data_path(*(scenario['hazard'].split('/')))): hazard_path = standard_data_path(*(scenario['hazard'].split('/'))) else: raise IOError('No hazard file') if not scenario['aggregation']: aggregation_path = None else: if os.path.exists(scenario['aggregation']): aggregation_path = scenario['aggregation'] elif os.path.exists(standard_data_path( 'aggregation', scenario['aggregation'])): aggregation_path = standard_data_path( 'aggregation', scenario['aggregation']) elif os.path.exists( standard_data_path(*(scenario['aggregation'].split('/')))): aggregation_path = standard_data_path( *(scenario['aggregation'].split('/'))) else: raise IOError('No aggregation file') impact_function = ImpactFunction() impact_function.debug_mode = use_debug layer = QgsVectorLayer(hazard_path, 'Hazard', 'ogr') if not layer.isValid(): layer = QgsRasterLayer(hazard_path, 'Hazard') impact_function.hazard = layer layer = QgsVectorLayer(exposure_path, 'Exposure', 'ogr') if not layer.isValid(): layer = QgsRasterLayer(exposure_path, 'Exposure') impact_function.exposure = layer if aggregation_path: impact_function.aggregation = QgsVectorLayer( aggregation_path, 'Aggregation', 'ogr') status, message = impact_function.prepare() if status != 0: return status, message, None status, message = impact_function.run() if status != 0: return status, message, None for layer in impact_function.outputs: if layer.type() == QgsMapLayer.VectorLayer: check_inasafe_fields(layer) return status, impact_function.state, impact_function.outputs