def test_pre_processors_nearby_places(self): """Test the pre_processors_nearby_places""" hazard_layer = load_test_raster_layer('gisv4', 'hazard', 'earthquake.asc') exposure_layer = load_test_vector_layer('gisv4', 'exposure', 'building-points.geojson') impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.crs = QgsCoordinateReferenceSystem(4326) status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) # The exposure is not place but buildings self.assertFalse( pre_processors_nearby_places['condition'](impact_function)) hazard_layer = load_test_raster_layer('gisv4', 'hazard', 'earthquake.asc') exposure_layer = load_test_vector_layer('gisv4', 'exposure', 'places.geojson') impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.crs = QgsCoordinateReferenceSystem(4326) status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) # EQ on places, it must be OK. self.assertTrue( pre_processors_nearby_places['condition'](impact_function))
def test_pre_processors_earthquake_contour(self): """Test the pre_processors_earthquake_contour""" hazard_layer = load_test_raster_layer('gisv4', 'hazard', 'earthquake.asc') exposure_layer = load_test_vector_layer('gisv4', 'exposure', 'building-points.geojson') impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.crs = QgsCoordinateReferenceSystem(4326) status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) self.assertTrue( pre_processor_earthquake_contour['condition'](impact_function)) hazard_layer = load_test_raster_layer('hazard', 'classified_flood_20_20.asc') exposure_layer = load_test_vector_layer('gisv4', 'exposure', 'places.geojson') impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.crs = QgsCoordinateReferenceSystem(4326) status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) # not ok, since the hazard is flood, not earthquake self.assertFalse( pre_processor_earthquake_contour['condition'](impact_function))
def test_pre_processors_earthquake_contour(self): """Test the pre_processors_earthquake_contour""" hazard_layer = load_test_raster_layer( 'gisv4', 'hazard', 'earthquake.asc') exposure_layer = load_test_vector_layer( 'gisv4', 'exposure', 'building-points.geojson') impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.crs = QgsCoordinateReferenceSystem(4326) status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) self.assertTrue( pre_processor_earthquake_contour['condition'](impact_function)) hazard_layer = load_test_raster_layer( 'hazard', 'classified_flood_20_20.asc') exposure_layer = load_test_vector_layer( 'gisv4', 'exposure', 'places.geojson') impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.crs = QgsCoordinateReferenceSystem(4326) status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) # not ok, since the hazard is flood, not earthquake self.assertFalse( pre_processor_earthquake_contour['condition'](impact_function))
def test_pre_processors_nearby_places(self): """Test the pre_processors_nearby_places""" hazard_layer = load_test_raster_layer( 'gisv4', 'hazard', 'earthquake.asc') exposure_layer = load_test_vector_layer( 'gisv4', 'exposure', 'building-points.geojson') impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.crs = QgsCoordinateReferenceSystem(4326) status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) # The exposure is not place but buildings self.assertFalse( pre_processors_nearby_places['condition'](impact_function)) hazard_layer = load_test_raster_layer( 'gisv4', 'hazard', 'earthquake.asc') exposure_layer = load_test_vector_layer( 'gisv4', 'exposure', 'places.geojson') impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.crs = QgsCoordinateReferenceSystem(4326) status, message = impact_function.prepare() self.assertEqual(PREPARE_SUCCESS, status, message) # EQ on places, it must be OK. self.assertTrue( pre_processors_nearby_places['condition'](impact_function))
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: # self.extent.crs is the map canvas CRS. impact_function.crs = self.extent.crs 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.asWkt() impact_function.requested_extent = wkt_to_rectangle(wkt) elif mode == HAZARD_EXPOSURE_VIEW: impact_function.requested_extent = ( self.iface.mapCanvas().extent()) elif mode == EXPOSURE: impact_function.use_exposure_view_only = True # We don't have any checkbox in the wizard for the debug mode. impact_function.debug_mode = False return impact_function
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: # self.extent.crs is the map canvas CRS. impact_function.crs = self.extent.crs 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.asWkt() impact_function.requested_extent = wkt_to_rectangle(wkt) elif mode == HAZARD_EXPOSURE_VIEW: impact_function.requested_extent = ( self.iface.mapCanvas().extent()) elif mode == EXPOSURE: impact_function.use_exposure_view_only = True # We don't have any checkbox in the wizard for the debug mode. impact_function.debug_mode = False return impact_function
def test_earthquake_population_without_aggregation(self): """Testing Earthquake in Population without aggregation. .. versionadded:: 4.0 """ output_folder = self.fixtures_dir('../output/earthquake_population') # Classified vector with building-points shutil.rmtree(output_folder, ignore_errors=True) hazard_layer = load_test_raster_layer('hazard', 'earthquake.tif') exposure_layer = load_test_raster_layer('exposure', 'pop_binary_raster_20_20.asc') impact_function = ImpactFunction() impact_function.exposure = exposure_layer impact_function.hazard = hazard_layer impact_function.crs = QgsCoordinateReferenceSystem(4326) impact_function.prepare() return_code, message = impact_function.run() self.assertEqual(return_code, ANALYSIS_SUCCESS, message) report_metadata = ReportMetadata( metadata_dict=standard_impact_report_metadata_html) impact_report = ImpactReport(IFACE, report_metadata, impact_function=impact_function) impact_report.output_folder = output_folder return_code, message = impact_report.process_components() self.assertEqual(return_code, ImpactReport.REPORT_GENERATION_SUCCESS, message) """Checking generated context.""" empty_component_output_message = 'Empty component output' # Check Analysis Summary analysis_summary = impact_report.metadata.component_by_key( general_report_component['key']) """:type: safe.report.report_metadata.Jinja2ComponentsMetadata""" expected_context = { 'table_header': (u'Estimated Number of people affected per MMI intensity'), 'header': u'General Report', 'summary': [{ 'header_label': u'Hazard Zone', 'rows': [{ 'numbers': ['0'], 'name': u'X', 'key': 'X' }, { 'numbers': ['0'], 'name': u'IX', 'key': 'IX' }, { 'numbers': ['200'], 'name': u'VIII', 'key': 'VIII' }, { 'numbers': ['0'], 'name': u'VII', 'key': 'VII' }, { 'numbers': ['0'], 'name': u'VI', 'key': 'VI' }, { 'numbers': ['0'], 'name': u'V', 'key': 'V' }, { 'numbers': ['0'], 'name': u'IV', 'key': 'IV' }, { 'numbers': ['0'], 'name': u'III', 'key': 'III' }, { 'numbers': ['0'], 'name': u'II', 'key': 'II' }, { 'numbers': ['0'], 'name': u'I', 'key': 'I' }, { 'as_header': True, 'key': 'total_exposed_field', 'name': u'Total Exposed', 'numbers': ['200'] }], 'value_labels': [u'Count'] }, { 'header_label': u'Population', 'rows': [{ 'numbers': ['200'], 'name': u'Affected', 'key': 'total_affected_field', }, { 'key': 'total_not_affected_field', 'name': u'Not Affected', 'numbers': ['0'] }, { 'key': 'total_not_exposed_field', 'name': u'Not Exposed', 'numbers': ['0'] }, { 'numbers': ['200'], 'name': u'Displaced', 'key': 'displaced_field' }, { 'numbers': ['0 - 100'], 'name': u'Fatalities', 'key': 'fatalities_field' }], 'value_labels': [u'Count'] }], 'notes': [ u'Exposed People: People who are present in hazard zones and ' u'are thereby subject to potential losses. In InaSAFE, people ' u'who are exposed are those people who are within the extent ' u'of the hazard.', u'Affected People: People who are affected by a hazardous ' u'event. People can be affected directly or indirectly. ' u'Affected people may experience short-term or long-term ' u'consequences to their lives, livelihoods or health and in ' u'the economic, physical, social, cultural and environmental ' u'assets. In InaSAFE, people who are killed during the event ' u'are also considered affected.', u'Displaced People: Displaced people are people who, for ' u'different reasons and circumstances because of risk or ' u'disaster, have to leave their place of residence. ' u'In InaSAFE, demographic and minimum needs reports are based ' u'on displaced / evacuated people.' ] } actual_context = analysis_summary.context self.assertDictEqual(expected_context, actual_context) self.assertTrue(analysis_summary.output, empty_component_output_message) report_metadata = ReportMetadata(metadata_dict=infographic_report) infographic_impact_report = ImpactReport( IFACE, report_metadata, impact_function=impact_function) infographic_impact_report.output_folder = output_folder return_code, message = infographic_impact_report.process_components() self.assertEqual(return_code, ImpactReport.REPORT_GENERATION_SUCCESS, message) # check population pie chart if we have 100% donut slice population_chart_svg = ( infographic_impact_report.metadata.component_by_key( population_chart_svg_component['key'])) expected_slices = [{ 'value': 200, 'show_label': True, 'center': (224.0, 128.0), 'stroke_opacity': 1, 'path': 'M128.000000,0.000000a128.000000,128.000000 0 0 1 ' '0.000000,256.000000l-0.000000,-64.000000a64.000000,' '64.000000 0 0 0 0.000000,-128.000000Z', 'percentage': 100, 'label': u'VIII', 'stroke': u'#ff7000', 'label_position': (256, 0), 'fill': u'#ff7000' }, { 'value': 100, 'show_label': False, 'center': (32.0, 128.0), 'stroke_opacity': 1, 'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 ' '-0.000000,-256.000000l0.000000,64.000000a64.000000,' '64.000000 0 0 0 0.000000,128.000000Z', 'percentage': 50.0, 'label': '', 'stroke': u'#ff7000', 'label_position': (256, 0), 'fill': u'#ff7000' }, { 'value': 0, 'show_label': False, 'center': (128.0, 224.0), 'stroke_opacity': 1, 'path': 'M128.000000,256.000000a128.000000,128.000000 0 0 1 ' '0.000000,0.000000l-0.000000,-64.000000a64.000000,' '64.000000 0 0 0 0.000000,0.000000Z', 'percentage': 0.0, 'label': u'Total Not Affected', 'stroke': '#fff', 'label_position': (256, 0), 'fill': u'#1a9641' }] actual_context = population_chart_svg.context['context'] actual_slices = actual_context.slices self.assertEqual(expected_slices, actual_slices) self.assertTrue(population_chart_svg.output, empty_component_output_message) shutil.rmtree(output_folder, ignore_errors=True)
def run_task(self, task_item, status_item, count=0, index=''): """Run a single task. :param task_item: Table task_item containing task name / details. :type task_item: QTableWidgetItem :param status_item: Table task_item that holds the task status. :type status_item: QTableWidgetItem :param count: Count of scenarios that have been run already. :type count: :param index: The index for the table item that will be run. :type index: int :returns: Flag indicating if the task succeeded or not. :rtype: bool """ self.enable_busy_cursor() for layer_group in self.layer_group_container: layer_group.setItemVisibilityChecked(False) # set status to 'running' status_item.setText(self.tr('Running')) # .. see also:: :func:`appendRow` to understand the next 2 lines variant = task_item.data(QtCore.Qt.UserRole) value = variant[0] result = True if isinstance(value, str): filename = value # run script try: self.run_script(filename) # set status to 'OK' status_item.setText(self.tr('Script OK')) except Exception as e: # pylint: disable=W0703 # set status to 'fail' status_item.setText(self.tr('Script Fail')) LOGGER.exception( 'Running macro failed. The exception: ' + str(e)) result = False elif isinstance(value, dict): # start in new project if toggle is active if self.start_in_new_project: self.iface.newProject() # create layer group group_name = value['scenario_name'] self.layer_group = self.root.addGroup(group_name) self.layer_group_container.append(self.layer_group) # Its a dict containing files for a scenario success, parameters = self.prepare_task(value) if not success: # set status to 'running' status_item.setText(self.tr('Please update scenario')) self.disable_busy_cursor() return False directory = self.output_directory.text() if self.scenario_directory_radio.isChecked(): directory = self.source_directory.text() output_directory = os.path.join(directory, group_name) if not os.path.exists(output_directory): os.makedirs(output_directory) # If impact function parameters loaded successfully, initiate IF. impact_function = ImpactFunction() impact_function.datastore = Folder(output_directory) impact_function.datastore.default_vector_format = "geojson" impact_function.hazard = parameters[layer_purpose_hazard['key']] impact_function.exposure = ( parameters[layer_purpose_exposure['key']]) if parameters[layer_purpose_aggregation['key']]: impact_function.aggregation = ( parameters[layer_purpose_aggregation['key']]) elif parameters['extent']: impact_function.requested_extent = parameters['extent'] impact_function.crs = parameters['crs'] prepare_status, prepare_message = impact_function.prepare() if prepare_status == PREPARE_SUCCESS: LOGGER.info('Impact function ready') status, message = impact_function.run() if status == ANALYSIS_SUCCESS: status_item.setText(self.tr('Analysis Success')) impact_layer = impact_function.impact if impact_layer.isValid(): layer_list = [ impact_layer, impact_function.analysis_impacted, parameters[layer_purpose_hazard['key']], parameters[layer_purpose_exposure['key']], parameters[layer_purpose_aggregation['key']]] QgsProject.instance().addMapLayers( layer_list, False) for layer in layer_list: self.layer_group.addLayer(layer) map_canvas = QgsProject.instance().mapLayers() for layer in map_canvas: # turn of layer visibility if not impact layer if map_canvas[layer].id() == impact_layer.id(): self.set_layer_visible( map_canvas[layer], True) else: self.set_layer_visible( map_canvas[layer], False) # we need to set analysis_impacted as an active layer # because we need to get all qgis variables that we # need from this layer for infographic. if self.iface: self.iface.setActiveLayer( impact_function.analysis_impacted) report_directory = os.path.join( output_directory, 'output') # generate map report and impact report try: error_code, message = ( impact_function.generate_report( all_default_report_components, report_directory)) except BaseException: status_item.setText( self.tr('Report failed to generate.')) else: LOGGER.info('Impact layer is invalid') elif status == ANALYSIS_FAILED_BAD_INPUT: LOGGER.info('Bad input detected') elif status == ANALYSIS_FAILED_BAD_CODE: LOGGER.info( 'Impact function encountered a bug: %s' % message) else: LOGGER.warning('Impact function not ready') send_error_message(self, prepare_message) else: LOGGER.exception('Data type not supported: "%s"' % value) result = False self.disable_busy_cursor() return result