def test_filter_by_metadata(self): """TestRegistry: Test filtering IF by hazard and exposure metadata.""" hazard_metadata = { 'subcategory': hazard_flood, 'units': unit_wetdry, 'layer_constraints': layer_vector_polygon } exposure_metadata = { 'subcategory': exposure_structure, 'units': unit_building_type_type, 'layer_constraints': layer_vector_polygon } registry = Registry() impact_functions = registry.filter(hazard_metadata, exposure_metadata) expected = [FloodPolygonBuildingFunction] message = 'Expecting %s. Got %s instead' % (expected, impact_functions) self.assertEqual(expected, impact_functions, message)
def test_filter_by_metadata(self): """TestRegistry: Test filtering IF by hazard and exposure metadata.""" hazard_metadata = { 'layer_mode': layer_mode_continuous, 'layer_geometry': layer_geometry_raster, 'hazard_category': hazard_category_single_event, 'hazard': hazard_earthquake, 'continuous_hazard_unit': unit_mmi } exposure_metadata = { 'layer_mode': layer_mode_classified, 'layer_geometry': layer_geometry_point, 'exposure': exposure_structure, } registry = Registry() impact_functions = registry.filter(hazard_metadata, exposure_metadata) expected = [EarthquakeBuildingFunction] message = 'Expecting \n%s.\n\nGot \n%s instead' % ('\n'.join([ x.__name__ for x in expected ]), '\n'.join([x.__name__ for x in impact_functions])) self.assertEqual(expected, impact_functions, message)
def test_filter_by_metadata(self): """TestRegistry: Test filtering IF by hazard and exposure metadata.""" hazard_metadata = { 'layer_mode': layer_mode_continuous, 'layer_geometry': layer_geometry_raster, 'hazard_category': hazard_category_single_event, 'hazard': hazard_earthquake, 'continuous_hazard_unit': unit_mmi } exposure_metadata = { 'layer_mode': layer_mode_classified, 'layer_geometry': layer_geometry_point, 'exposure': exposure_structure, } registry = Registry() impact_functions = registry.filter(hazard_metadata, exposure_metadata) expected = [EarthquakeBuildingFunction] message = 'Expecting \n%s.\n\nGot \n%s instead' % ( '\n'.join([x.__name__ for x in expected]), '\n'.join([x.__name__ for x in impact_functions])) self.assertEqual(expected, impact_functions, message)
class ImpactFunctionManager(object): """Class for managing metadata for all impact function. .. versionadded:: 2.1 """ def __init__(self): """Constructor.""" # Singleton Registry to track all the registered Impact Functions self.registry = Registry() @property def impact_functions(self): """Return all registered impact functions.""" return self.registry.impact_functions def get_instance(self, class_name): """Return an instance of an impact function given its class name. .. example:: if_manager = ImpactFunctionManager() if_class_name = 'FloodBuildingImpactFunction' if = if_manager.get_instance(if_class_name) :param class_name: The name of IF class. :type class_name: str :return: Impact function instance that matches the argument. :rtype: safe.impact_functions.base.ImpactFunction """ return self.registry.get_instance(class_name) def get_class(self, class_name): """Return the class of an impact function given its class name. .. example:: if_manager = ImpactFunctionManager() if_class_name = 'FloodBuildingImpactFunction' if_class = if_manager.get_class(if_class_name) :param class_name: the name of IF class :type class_name: str :return: impact function class that matches the argument. :rtype: safe.impact_functions.base.ImpactFunction """ return self.registry.get_class(class_name) def get(self, impact_function_id): """Return an instance of an impact function given its ID. This is a preferred way to get an instance of IF. IF should have a unique human readable ID in their metadata. .. example:: if_manager = ImpactFunctionManager() if_id = 'FloodBuildingImpactFunction' if = if_manager.get(if_id) :param impact_function_id: The ID of impact function in the metadata. :type impact_function_id: str :return An Impact function instance that has matched id. :rtype: safe.impact_functions.base.ImpactFunction """ impact_functions = self.registry.filter_by_metadata("id", impact_function_id) if len(impact_functions) == 0: raise Exception("Impact function with ID: %s not found" % impact_function_id) elif len(impact_functions) > 1: raise Exception("There are some Impact Functions that have the same ID: %s" % impact_function_id) return impact_functions[0].instance() def filter(self, hazard_metadata=None, exposure_metadata=None): """Get available impact functions from hazard and exposure metadata. Disabled impact function will not be loaded. .. example:: if_manager = ImpactFunctionManager() hazard_metadata = { 'subcategory': hazard_flood, 'units': unit_wetdry, 'layer_constraints': layer_vector_polygon } exposure_metadata = { 'subcategory': exposure_structure, 'units': unit_building_type_type, 'layer_constraints': layer_vector_polygon } ifs = if_manager.filter(hazard_metadata, exposure_metadata) :param hazard_metadata: The metadata of the hazard. :type hazard_metadata: dict :param exposure_metadata: The metadata of the exposure. :type exposure_metadata: dict """ return self.registry.filter(hazard_metadata, exposure_metadata) def filter_by_keywords(self, hazard_keywords=None, exposure_keywords=None): """Get available impact functions from hazard and exposure keywords. Disabled impact function will not be loaded. .. example:: if_manager = ImpactFunctionManager() hazard_keywords = { 'subcategory': 'flood', 'units': 'wetdry', 'layer_type': 'vector', 'data_type': 'polygon' } exposure_keywords = { 'subcategory': 'structure', 'units': 'building_type', 'layer_type': 'vector', 'data_type': 'polygon' } ifs = if_manager.filter_by_keywords(hazard_keywords, exposure_keywords) :param hazard_keywords: The keywords of the hazard. :type hazard_keywords: dict :param exposure_keywords: The keywords of the exposure. :type exposure_keywords: dict """ return self.registry.filter_by_keyword_string(hazard_keywords, exposure_keywords) def filter_by_metadata(self, metadata_key, metadata_value): """Return IF classes given its metadata key and value. .. example:: if_manager = ImpactFunctionManager() metadata_key = 'author' metadata_value = 'Akbar Gumbira' ifs = if_manager.filter_by_metadata(metadata_key, metadata_value) :param metadata_key: The key of the metadata e.g 'id', 'name' :type metadata_key: str :param metadata_value: The value of the metadata, e.g for the key 'id' the value is 'FloodNativePolygonExperimentalFunction' :type metadata_value: str, dict :return: Impact Function classes match the arguments :rtype: list """ return self.registry.filter_by_metadata(metadata_key, metadata_value) @staticmethod def get_function_id(impact_function): """Get the ID of the impact function. :param impact_function: Class of an impact function :type impact_function: safe.impact_functions.base.ImpactFunction :returns: The ID of the impact function specified in its metadata. :rtype: str """ return impact_function.metadata().as_dict().get("id", None) @staticmethod def get_function_title(impact_function): """Get title of the impact function. :param impact_function: Class of an impact function :type impact_function: safe.impact_functions.base.ImpactFunction :returns: The title of the impact function specified in its metadata. :rtype: str """ return impact_function.metadata().as_dict().get("title", None) @staticmethod def get_function_name(impact_function): """Get the human readable name of the impact function. :param impact_function: Class of an impact function. :type impact_function: safe.impact_functions.base.ImpactFunction """ return impact_function.metadata().as_dict().get("name", None) @staticmethod def get_function_type(impact_function): """Return the impact function type. :param impact_function: The impact function. :type impact_function: safe.impact_functions.base.ImpactFunction """ return impact_function.function_type() def allowed_subcategories(self, category=None): """Determine allowed subcategories, optionally filtered by category. :param category: Optional category which will be used to subset the allowed subcategories. If omitted, all supported subcategories will be returned (for both hazard and exposure). Default is None. :type category: str :returns: A list of strings is returned. :rtype: list """ result = [] for impact_function in self.impact_functions: my_allowed_subcategories = impact_function.metadata().allowed_subcategories(category) result = add_to_list(result, my_allowed_subcategories) return result def allowed_data_types(self, subcategory): """Determine allowed data types for all impact functions. It uses subcategory as a filter. Passing a subcategory is required otherwise the context of the data_type(s) would be ambiguous (i.e. whether they can be used as exposure or hazards). :param subcategory: Required subcategory which will be used to subset the allowed data_types. :type subcategory: str :returns: A list of one or more strings is returned. :rtype: list """ result = [] for impact_function in self.impact_functions: my_allowed_data_types = impact_function.metadata().allowed_data_types(subcategory) result = add_to_list(result, my_allowed_data_types) return result def allowed_units(self, subcategory, data_type): """Determine allowed units from all impact functions. It uses subcategory and data_type as a filter. .. note:: One data_type could be used by more than one subcategory, so we need to explicitly pass the subcategory to this function. :param subcategory: Required subcategory which will be used to subset the allowed data_types. :type subcategory: str :param data_type: Required data_type which will be used to subset the allowed units. :type data_type: str :returns: A list of one or more strings is returned. :rtype: list """ result = [] for impact_function in self.impact_functions: my_allowed_units = impact_function.metadata().allowed_units(subcategory, data_type) result = add_to_list(result, my_allowed_units) return result def units_for_layer(self, subcategory, layer_type, data_type): """Get the valid units for a layer. Example usage:: foo = units_for_layer('flood', 'vector', 'polygon') print foo Would output this:: {'Wet/Dry': ['wet','dry']} While passing a raster layer:: foo = units_for_layer('flood', 'raster', None) print foo Might return this:: { 'metres': None, 'feet': None, 'wet/dry': ['wet', 'dry'], } In the returned dictionary the keys are unit types and the values are the categories (if any) applicable for that unit type. :param subcategory: The subcategory for this layer. :type subcategory: str :param layer_type: The type for this layer. Valid values would be, 'raster' or 'vector'. :type layer_type: str :param data_type: The data_type for this layer. Valid possibilities would be 'numeric' (for raster), point, line, polygon (for vectors). :type data_type: str :returns: A dictionary as per the example above where each key represents a unit and each value that is not None represents a list of categories. :rtype: dict """ result = [] for impact_function in self.impact_functions: my_units = impact_function.metadata().units_for_layer(subcategory, layer_type, data_type) result = add_to_list(result, my_units) return result def categories_for_layer(self, layer_type, data_type): """Return a list of valid categories for a layer. This method is used to determine if a given layer can be used as a hazard, exposure or aggregation layer. Example usage:: foo = categories_for_layer('vector', 'polygon') print foo Would output this:: ['hazard', 'exposure', 'aggregation'] While passing a vector point layer:: foo = units_for_layer('vector', 'point') print foo Might return this:: ['hazard', 'exposure'] In the returned the values are categories (if any) applicable for that layer_type and data_type. :param layer_type: The type for this layer. Valid values would be, 'raster' or 'vector'. :type layer_type: str :param data_type: The data_type for this layer. Valid possibilities would be 'numeric' (for raster), point, line, polygon (for vectors). :type data_type: str :returns: A list as per the example above where each value represents a valid category. :rtype: list """ result = [] for impact_function in self.impact_functions: categories = impact_function.metadata().categories_for_layer(layer_type, data_type) result = add_to_list(result, categories) categories_definitions = [] for category in result: if category == "hazard": categories_definitions.append(hazard_definition) elif category == "exposure": categories_definitions.append(exposure_definition) else: raise Exception("Unsupported categories") return categories_definitions def subcategories_for_layer(self, category, layer_type, data_type): """Return a list of valid subcategories for a layer. This method is used to determine which subcategories a given layer can be for. Example usage:: foo = subcategories_for_layer('vector', 'polygon', 'exposure') print foo Would output this:: ['flood', 'landuse'] In the returned the values are categories (if any) applicable for that layer_type and data_type. :param layer_type: The type for this layer. Valid values would be, 'raster' or 'vector'. :type layer_type: str :param data_type: The data_type for this layer. Valid possibilities would be 'numeric' (for raster), point, line, polygon (for vectors). :type data_type: str :param category: The category for this layer. Valid possibilities would be 'hazard', 'exposure' and 'aggregation'. :type category: str :returns: A list as per the example above where each value represents a valid subcategory. :rtype: list """ result = [] for impact_function in self.impact_functions: subcategories = impact_function.metadata().subcategories_for_layer(category, layer_type, data_type) result = add_to_list(result, subcategories) return result def get_available_hazards(self, impact_function=None, ascending=True): """Return a list of valid available hazards for an impact function. If impact_function is None, return all available hazards .. versionadded:: 2.2 :param impact_function: Impact Function object. :type impact_function: FunctionProvider :param ascending: Sort ascending or not. :type ascending: bool :returns: A list of hazard full metadata. :rtype: list """ hazards = [] if impact_function is None: for impact_function in self.impact_functions: add_to_list(hazards, impact_function.metadata().get_hazards()) else: # noinspection PyUnresolvedReferences hazards = impact_function.metadata().get_hazards() # make it sorted if ascending: hazards = sorted(hazards, key=lambda k: k["id"]) return hazards def get_functions_for_hazard(self, hazard): """Return all function metadata that has hazard in their metadata. .. versionadded:: 2.2 :param hazard: Dictionary that represent the hazard :type hazard: dict :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_hazard(hazard): impact_functions_metadata.append(impact_function.metadata().as_dict()) return impact_functions_metadata def get_functions_for_hazard_id(self, hazard_id): """Return all function metadata that has hazard_id in their metadata. .. versionadded:: 2.2 :param hazard_id: String that represent the hazard id. :type hazard_id: str :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_hazard_id(hazard_id): impact_functions_metadata.append(impact_function.metadata().as_dict()) return impact_functions_metadata def get_available_exposures(self, impact_function=None, ascending=True): """Return a list of valid available exposures for an impact function. If impact_function is None, return all available exposures .. versionadded:: 2.2 :param impact_function: Impact Function object. :type impact_function: FunctionProvider :param ascending: Sort ascending or not. :type ascending: bool :returns: A list of exposures full metadata. :rtype: list """ exposures = [] if impact_function is None: for impact_function in self.impact_functions: add_to_list(exposures, impact_function.metadata().get_exposures()) else: # noinspection PyUnresolvedReferences exposures = impact_function.metadata().get_exposures() # make it sorted if ascending: exposures = sorted(exposures, key=lambda k: k["id"]) return exposures def get_functions_for_exposure(self, exposure): """Return all function metadata that has exposure in their metadata. .. versionadded:: 2.2 :param exposure: Dictionary that represent the exposure :type exposure: dict :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_exposure(exposure): impact_functions_metadata.append(impact_function.metadata().as_dict()) return impact_functions_metadata def get_functions_for_exposure_id(self, exposure_id): """Return all function metadata that has exposure_id in their metadata. .. versionadded:: 2.2 :param exposure_id: String that represent the exposure id. :type exposure_id: str :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_exposure_id(exposure_id): impact_functions_metadata.append(impact_function.metadata().as_dict()) return impact_functions_metadata def get_functions_for_constraint(self, hazard, exposure, hazard_constraint=None, exposure_constraint=None): """Get all impact functions that match the hazard n exposure metadata. :param hazard: The hazard metadata. :type hazard: dict :param exposure: The exposure metadata. :type exposure: dict :param hazard_constraint: :param exposure_constraint: :return: """ result = [] if_hazard = self.get_functions_for_hazard(hazard) if_exposure = self.get_functions_for_exposure(exposure) if_exposure_id = [function["id"] for function in if_exposure] for f in if_hazard: if f["id"] in if_exposure_id: if not hazard_constraint or hazard_constraint in f["categories"]["hazard"]["layer_constraints"]: if ( not exposure_constraint or exposure_constraint in f["categories"]["exposure"]["layer_constraints"] ): result.append(f) return result
class ImpactFunctionManager(object): """Class for managing metadata for all impact function. .. versionadded:: 2.1 """ def __init__(self): """Constructor.""" # Singleton Registry to track all the registered Impact Functions self.registry = Registry() @property def impact_functions(self): """Return all registered impact functions.""" return self.registry.impact_functions def get_instance(self, class_name): """Return an instance of an impact function given its class name. .. example:: if_manager = ImpactFunctionManager() if_class_name = 'FloodBuildingImpactFunction' if = if_manager.get_instance(if_class_name) :param class_name: The name of IF class. :type class_name: str :return: Impact function instance that matches the argument. :rtype: safe.impact_functions.base.ImpactFunction """ return self.registry.get_instance(class_name) def get_class(self, class_name): """Return the class of an impact function given its class name. .. example:: if_manager = ImpactFunctionManager() if_class_name = 'FloodBuildingImpactFunction' if_class = if_manager.get_class(if_class_name) :param class_name: the name of IF class :type class_name: str :return: impact function class that matches the argument. :rtype: safe.impact_functions.base.ImpactFunction """ return self.registry.get_class(class_name) def get(self, impact_function_id): """Return an instance of an impact function given its ID. This is a preferred way to get an instance of IF. IF should have a unique human readable ID in their metadata. .. example:: if_manager = ImpactFunctionManager() if_id = 'FloodBuildingImpactFunction' if = if_manager.get(if_id) :param impact_function_id: The ID of impact function in the metadata. :type impact_function_id: str :return An Impact function instance that has matched id. :rtype: safe.impact_functions.base.ImpactFunction """ impact_functions = self.registry.filter_by_metadata( 'id', impact_function_id) if len(impact_functions) == 0: raise Exception('Impact function with ID: %s not found' % impact_function_id) elif len(impact_functions) > 1: raise Exception( 'There are some Impact Functions that have the same ID: %s' % impact_function_id) return impact_functions[0].instance() def filter(self, hazard_metadata=None, exposure_metadata=None): """Get available impact functions from hazard and exposure metadata. Disabled impact function will not be loaded. .. example:: if_manager = ImpactFunctionManager() hazard_metadata = { 'subcategory': hazard_flood, 'units': unit_wetdry, 'layer_constraints': layer_vector_polygon } exposure_metadata = { 'subcategory': exposure_structure, 'units': unit_building_type_type, 'layer_constraints': layer_vector_polygon } ifs = if_manager.filter(hazard_metadata, exposure_metadata) :param hazard_metadata: The metadata of the hazard. :type hazard_metadata: dict :param exposure_metadata: The metadata of the exposure. :type exposure_metadata: dict """ return self.registry.filter(hazard_metadata, exposure_metadata) def filter_by_keywords(self, hazard_keywords=None, exposure_keywords=None): """Get available impact functions from hazard and exposure keywords. Disabled impact function will not be loaded. .. example:: if_manager = ImpactFunctionManager() hazard_keywords = { 'subcategory': 'flood', 'units': 'wetdry', 'layer_type': 'vector', 'data_type': 'polygon' } exposure_keywords = { 'subcategory': 'structure', 'units': 'building_type', 'layer_type': 'vector', 'data_type': 'polygon' } ifs = if_manager.filter_by_keywords(hazard_keywords, exposure_keywords) :param hazard_keywords: The keywords of the hazard. :type hazard_keywords: dict :param exposure_keywords: The keywords of the exposure. :type exposure_keywords: dict """ return self.registry.filter_by_keyword_string(hazard_keywords, exposure_keywords) def filter_by_metadata(self, metadata_key, metadata_value): """Return IF classes given its metadata key and value. .. example:: if_manager = ImpactFunctionManager() metadata_key = 'author' metadata_value = 'Akbar Gumbira' ifs = if_manager.filter_by_metadata(metadata_key, metadata_value) :param metadata_key: The key of the metadata e.g 'id', 'name' :type metadata_key: str :param metadata_value: The value of the metadata, e.g for the key 'id' the value is 'FloodNativePolygonExperimentalFunction' :type metadata_value: str, dict :return: Impact Function classes match the arguments :rtype: list """ return self.registry.filter_by_metadata(metadata_key, metadata_value) @staticmethod def get_function_id(impact_function): """Get the ID of the impact function. :param impact_function: Class of an impact function :type impact_function: safe.impact_functions.base.ImpactFunction :returns: The ID of the impact function specified in its metadata. :rtype: str """ return impact_function.metadata().as_dict().get('id', None) @staticmethod def get_function_title(impact_function): """Get title of the impact function. :param impact_function: Class of an impact function :type impact_function: safe.impact_functions.base.ImpactFunction :returns: The title of the impact function specified in its metadata. :rtype: str """ return impact_function.metadata().as_dict().get('title', None) @staticmethod def get_function_name(impact_function): """Get the human readable name of the impact function. :param impact_function: Class of an impact function. :type impact_function: safe.impact_functions.base.ImpactFunction """ return impact_function.metadata().as_dict().get('name', None) @staticmethod def get_function_type(impact_function): """Return the impact function type. :param impact_function: The impact function. :type impact_function: safe.impact_functions.base.ImpactFunction """ return impact_function.function_type() def get_functions_for_hazard(self, hazard): """Return all function metadata that has hazard in their metadata. .. versionadded:: 2.2 :param hazard: Dictionary that represent the hazard :type hazard: dict :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_hazard(hazard): impact_functions_metadata.append( impact_function.metadata().as_dict()) return impact_functions_metadata def purposes_for_layer(self, layer_geometry_key): """Get purposes of a layer geometry id. :param layer_geometry_key: The geometry id :type layer_geometry_key: str """ layer_purposes = [] for impact_function in self.impact_functions: if_layer_purposes = impact_function.metadata().purposes_for_layer( layer_geometry_key) if if_layer_purposes: add_to_list(layer_purposes, if_layer_purposes) return layer_purposes def hazard_categories_for_layer(self, layer_geometry_key, hazard_key=None): """Get hazard categories form layer_geometry_key :param layer_geometry_key: The geometry id :type layer_geometry_key: str :param hazard_key: The hazard key :type hazard_key: str :returns: List of hazard_categories :rtype: list """ hazard_categories = [] for impact_function in self.impact_functions: if_hazard_categories = impact_function.metadata()\ .hazard_categories_for_layer(layer_geometry_key, hazard_key) if if_hazard_categories: add_to_list(hazard_categories, if_hazard_categories) return hazard_categories def hazards_for_layer(self, layer_geometry_key, hazard_category_key=None): """Get hazard categories form layer_geometry_key :param layer_geometry_key: The geometry id :type layer_geometry_key: str :param hazard_category_key: The hazard category :type hazard_category_key: str :returns: List of hazard :rtype: list """ hazards = [] for impact_function in self.impact_functions: if_hazards = impact_function.metadata().hazards_for_layer( layer_geometry_key, hazard_category_key) if if_hazards: add_to_list(hazards, if_hazards) return hazards def exposures_for_layer(self, layer_geometry_key): """Get hazard categories form layer_geometry_key :param layer_geometry_key: The geometry id :type layer_geometry_key: str :returns: List of hazard :rtype: list """ exposures = [] for impact_function in self.impact_functions: if_exposures = impact_function.metadata().exposures_for_layer( layer_geometry_key) if if_exposures: add_to_list(exposures, if_exposures) return exposures def exposure_units_for_layer(self, exposure_key, layer_geometry_key, layer_mode_key): """Get hazard categories form layer_geometry_key :param exposure_key: The exposure key :type exposure_key: str :param layer_geometry_key: The geometry key :type layer_geometry_key: str :param layer_mode_key: The layer mode key :type layer_mode_key: str :returns: List of exposure unit :rtype: list """ exposure_units = [] for impact_function in self.impact_functions: if_exposure_units = impact_function.metadata().\ exposure_units_for_layer( exposure_key, layer_geometry_key, layer_mode_key) if if_exposure_units: add_to_list(exposure_units, if_exposure_units) return exposure_units def continuous_hazards_units_for_layer(self, hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key): """Get continuous hazard units. :param hazard_key: The hazard key :type hazard_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param layer_mode_key: The layer mode key :type layer_mode_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of continuous hazard unit :rtype: list """ continuous_hazards_units = [] for impact_function in self.impact_functions: if_continuous_hazard_units = impact_function.metadata().\ continuous_hazards_units_for_layer( hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key) if if_continuous_hazard_units: add_to_list(continuous_hazards_units, if_continuous_hazard_units) return continuous_hazards_units def vector_hazards_classifications_for_layer(self, hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key): """Get continuous hazard units. :param hazard_key: The hazard key :type hazard_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param layer_mode_key: The layer mode key :type layer_mode_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of vector_hazards_classifications :rtype: list """ vector_hazards_classifications = [] for impact_function in self.impact_functions: if_vector_hazards_classifications = impact_function.metadata().\ vector_hazards_classifications_for_layer( hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key) if if_vector_hazards_classifications: add_to_list(vector_hazards_classifications, if_vector_hazards_classifications) return vector_hazards_classifications def raster_hazards_classifications_for_layer(self, hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key): """Get continuous hazard units. :param hazard_key: The hazard key :type hazard_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param layer_mode_key: The layer mode key :type layer_mode_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of raster_hazards_classifications :rtype: list """ raster_hazards_classifications = [] for impact_function in self.impact_functions: if_vector_hazards_classifications = impact_function.metadata().\ raster_hazards_classifications_for_layer( hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key) if if_vector_hazards_classifications: add_to_list(raster_hazards_classifications, if_vector_hazards_classifications) return raster_hazards_classifications def available_hazards(self, hazard_category_key, ascending=True): """available_hazards from hazard_category_key :param hazard_category_key: The hazard category key :type hazard_category_key: str :param ascending: Sort ascending or not. :type ascending: bool :returns: List of available hazards :rtype: list """ hazards = [] for impact_function in self.impact_functions: if_hazards = impact_function.metadata(). \ available_hazards(hazard_category_key) if if_hazards: add_to_list(hazards, if_hazards) # make it sorted if ascending and hazards: hazards = sorted(hazards, key=lambda k: k['key']) return hazards def available_exposures(self, ascending=True): """Return a list of valid available exposures :param ascending: Sort ascending or not. :type ascending: bool :returns: A list of exposures full metadata. :rtype: list """ exposures = [] for impact_function in self.impact_functions: if_exposures = impact_function.metadata().available_exposures() if if_exposures: add_to_list(exposures, if_exposures) # make it sorted if ascending and exposures: exposures = sorted(exposures, key=lambda k: k['key']) return exposures def functions_for_constraint(self, hazard_key, exposure_key, hazard_geometry_key=None, exposure_geometry_key=None, hazard_mode_key=None, exposure_mode_key=None): """Obtain all functions that match with the constraints :param hazard_key: The hazard key :type hazard_key: str :param exposure_key: the exposure key :type exposure_key: str :param hazard_geometry_key: The hazard geometry key :type hazard_geometry_key: str :param exposure_geometry_key: The exposure geometry key :type exposure_geometry_key: str :param hazard_mode_key: The hazard mode key :type hazard_mode_key: str :param exposure_mode_key: The exposure mode key :type exposure_mode_key: str :returns: List of matched Impact Function :rtype: list """ impact_functions = [] for impact_function in self.impact_functions: if impact_function.metadata().is_function_for_constraint( hazard_key, exposure_key, hazard_geometry_key, exposure_geometry_key, hazard_mode_key, exposure_mode_key): impact_functions.append(impact_function.metadata().as_dict()) return impact_functions def available_hazard_constraints(self, hazard_key, hazard_category_key): """Get hazard constraints for hazard_key and hazard_category_key :param hazard_key: The hazard key :type hazard_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of tuple of layer_mode and layer_geometry :rtype: list """ hazard_constraints = [] for impact_function in self.impact_functions: if_hazard_constraints = impact_function.metadata().\ available_hazard_constraints( hazard_key, hazard_category_key) if if_hazard_constraints: add_to_list(hazard_constraints, if_hazard_constraints) return hazard_constraints def available_exposure_constraints(self, exposure_key): """Get exposure constraints for exposure_key. :param exposure_key: The exposure key :type exposure_key: str :returns: List of tuple of layer_mode and layer_geometry :rtype: list """ exposure_constraints = [] for impact_function in self.impact_functions: if_exposure_constraints = impact_function.metadata(). \ available_exposure_constraints(exposure_key) if if_exposure_constraints: add_to_list(exposure_constraints, if_exposure_constraints) return exposure_constraints def available_hazard_layer_modes(self, hazard_key, hazard_geometry_key, hazard_category_key): """Return all available layer_mode. :param hazard_key: The hazard key :type hazard_key: str :param hazard_geometry_key: The hazard geometry key :type hazard_geometry_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of layer_mode :rtype: list """ layer_modes = [] for impact_function in self.impact_functions: if_hazard_layer_mode = impact_function.metadata().\ available_hazard_layer_mode( hazard_key, hazard_geometry_key, hazard_category_key) if if_hazard_layer_mode: add_to_list(layer_modes, if_hazard_layer_mode) return layer_modes def available_exposure_layer_modes(self, exposure_key, exposure_geometry_key): """Get exposure layer mode for exposure_key. :param exposure_key: The exposure key :type exposure_key: str :param exposure_geometry_key: The exposure geometry key :type exposure_geometry_key: str :returns: List of layer_mode :rtype: list """ layer_modes = [] for impact_function in self.impact_functions: if_exposure_layer_mode = impact_function.metadata().\ available_exposure_layer_mode( exposure_key, exposure_geometry_key) if if_exposure_layer_mode: add_to_list(layer_modes, if_exposure_layer_mode) return layer_modes def hazard_additional_keywords(self, layer_mode_key=None, layer_geometry_key=None, hazard_category_key=None, hazard_key=None): """Return additional_keywords for hazard. :param layer_mode_key: The layer mode key :type layer_mode_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :param hazard_key: The hazard key :type hazard_key: str :returns: List of additional keywords :rtype: list """ additional_keywords = [] for impact_function in self.impact_functions: if_additional_keywords = impact_function.metadata().\ hazard_additional_keywords( layer_mode_key=layer_mode_key, layer_geometry_key=layer_geometry_key, hazard_category_key=hazard_category_key, hazard_key=hazard_key) if if_additional_keywords: add_to_list(additional_keywords, if_additional_keywords) return additional_keywords def exposure_additional_keywords(self, layer_mode_key=None, layer_geometry_key=None, exposure_key=None): """Return additional_keywords for exposure. :param layer_mode_key: The layer mode key :type layer_mode_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param exposure_key: The hazard key :type exposure_key: str :returns: List of additional keywords :rtype: list """ additional_keywords = [] for impact_function in self.impact_functions: if_additional_keywords = impact_function.metadata().\ exposure_additional_keywords( layer_mode_key=layer_mode_key, layer_geometry_key=layer_geometry_key, exposure_key=exposure_key) if if_additional_keywords: add_to_list(additional_keywords, if_additional_keywords) return additional_keywords def exposure_class_fields(self, layer_mode_key=None, layer_geometry_key=None, exposure_key=None): """Return list of exposure class field. :param layer_mode_key: The layer mode key :type layer_mode_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param exposure_key: The exposure key :type exposure_key: str :returns: List of exposure class field. :rtype: list """ result = [] for impact_function in self.impact_functions: if_exposure_class_field = impact_function.metadata(). \ exposure_class_fields( layer_mode_key=layer_mode_key, layer_geometry_key=layer_geometry_key, exposure_key=exposure_key) if if_exposure_class_field: add_to_list(result, if_exposure_class_field) return result
class ImpactFunctionManager(object): """Class for managing metadata for all impact function. .. versionadded:: 2.1 """ def __init__(self): """Constructor.""" # Singleton Registry to track all the registered Impact Functions self.registry = Registry() @property def impact_functions(self): """Return all registered impact functions.""" return self.registry.impact_functions def get_instance(self, class_name): """Return an instance of an impact function given its class name. .. example:: if_manager = ImpactFunctionManager() if_class_name = 'FloodBuildingImpactFunction' if = if_manager.get_instance(if_class_name) :param class_name: The name of IF class. :type class_name: str :return: Impact function instance that matches the argument. :rtype: safe.impact_functions.base.ImpactFunction """ return self.registry.get_instance(class_name) def get_class(self, class_name): """Return the class of an impact function given its class name. .. example:: if_manager = ImpactFunctionManager() if_class_name = 'FloodBuildingImpactFunction' if_class = if_manager.get_class(if_class_name) :param class_name: the name of IF class :type class_name: str :return: impact function class that matches the argument. :rtype: safe.impact_functions.base.ImpactFunction """ return self.registry.get_class(class_name) def get(self, impact_function_id): """Return an instance of an impact function given its ID. This is a preferred way to get an instance of IF. IF should have a unique human readable ID in their metadata. .. example:: if_manager = ImpactFunctionManager() if_id = 'FloodBuildingImpactFunction' if = if_manager.get(if_id) :param impact_function_id: The ID of impact function in the metadata. :type impact_function_id: str :return An Impact function instance that has matched id. :rtype: safe.impact_functions.base.ImpactFunction """ impact_functions = self.registry.filter_by_metadata( 'id', impact_function_id) if len(impact_functions) == 0: raise Exception( 'Impact function with ID: %s not found' % impact_function_id) elif len(impact_functions) > 1: raise Exception( 'There are some Impact Functions that have the same ID: %s' % impact_function_id) return impact_functions[0].instance() def filter(self, hazard_metadata=None, exposure_metadata=None): """Get available impact functions from hazard and exposure metadata. Disabled impact function will not be loaded. .. example:: if_manager = ImpactFunctionManager() hazard_metadata = { 'subcategory': hazard_flood, 'units': unit_wetdry, 'layer_constraints': layer_vector_polygon } exposure_metadata = { 'subcategory': exposure_structure, 'units': unit_building_type_type, 'layer_constraints': layer_vector_polygon } ifs = if_manager.filter(hazard_metadata, exposure_metadata) :param hazard_metadata: The metadata of the hazard. :type hazard_metadata: dict :param exposure_metadata: The metadata of the exposure. :type exposure_metadata: dict """ return self.registry.filter(hazard_metadata, exposure_metadata) def filter_by_keywords( self, hazard_keywords=None, exposure_keywords=None): """Get available impact functions from hazard and exposure keywords. Disabled impact function will not be loaded. .. example:: if_manager = ImpactFunctionManager() hazard_keywords = { 'subcategory': 'flood', 'units': 'wetdry', 'layer_type': 'vector', 'data_type': 'polygon' } exposure_keywords = { 'subcategory': 'structure', 'units': 'building_type', 'layer_type': 'vector', 'data_type': 'polygon' } ifs = if_manager.filter_by_keywords(hazard_keywords, exposure_keywords) :param hazard_keywords: The keywords of the hazard. :type hazard_keywords: dict :param exposure_keywords: The keywords of the exposure. :type exposure_keywords: dict """ return self.registry.filter_by_keyword_string( hazard_keywords, exposure_keywords) def filter_by_metadata(self, metadata_key, metadata_value): """Return IF classes given its metadata key and value. .. example:: if_manager = ImpactFunctionManager() metadata_key = 'author' metadata_value = 'Akbar Gumbira' ifs = if_manager.filter_by_metadata(metadata_key, metadata_value) :param metadata_key: The key of the metadata e.g 'id', 'name' :type metadata_key: str :param metadata_value: The value of the metadata, e.g for the key 'id' the value is 'FloodNativePolygonExperimentalFunction' :type metadata_value: str, dict :return: Impact Function classes match the arguments :rtype: list """ return self.registry.filter_by_metadata(metadata_key, metadata_value) @staticmethod def get_function_id(impact_function): """Get the ID of the impact function. :param impact_function: Class of an impact function :type impact_function: safe.impact_functions.base.ImpactFunction :returns: The ID of the impact function specified in its metadata. :rtype: str """ return impact_function.metadata().as_dict().get('id', None) @staticmethod def get_function_title(impact_function): """Get title of the impact function. :param impact_function: Class of an impact function :type impact_function: safe.impact_functions.base.ImpactFunction :returns: The title of the impact function specified in its metadata. :rtype: str """ return impact_function.metadata().as_dict().get('title', None) @staticmethod def get_function_name(impact_function): """Get the human readable name of the impact function. :param impact_function: Class of an impact function. :type impact_function: safe.impact_functions.base.ImpactFunction """ return impact_function.metadata().as_dict().get('name', None) @staticmethod def get_function_type(impact_function): """Return the impact function type. :param impact_function: The impact function. :type impact_function: safe.impact_functions.base.ImpactFunction """ return impact_function.function_type() def get_functions_for_hazard(self, hazard): """Return all function metadata that has hazard in their metadata. .. versionadded:: 2.2 :param hazard: Dictionary that represent the hazard :type hazard: dict :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_hazard(hazard): impact_functions_metadata.append( impact_function.metadata().as_dict()) return impact_functions_metadata def purposes_for_layer(self, layer_geometry_key): """Get purposes of a layer geometry id. :param layer_geometry_key: The geometry id :type layer_geometry_key: str """ layer_purposes = [] for impact_function in self.impact_functions: if_layer_purposes = impact_function.metadata().purposes_for_layer( layer_geometry_key) if if_layer_purposes: add_to_list(layer_purposes, if_layer_purposes) return layer_purposes def hazard_categories_for_layer(self, layer_geometry_key, hazard_key=None): """Get hazard categories form layer_geometry_key :param layer_geometry_key: The geometry id :type layer_geometry_key: str :param hazard_key: The hazard key :type hazard_key: str :returns: List of hazard_categories :rtype: list """ hazard_categories = [] for impact_function in self.impact_functions: if_hazard_categories = impact_function.metadata()\ .hazard_categories_for_layer(layer_geometry_key, hazard_key) if if_hazard_categories: add_to_list(hazard_categories, if_hazard_categories) return hazard_categories def hazards_for_layer(self, layer_geometry_key, hazard_category_key=None): """Get hazard categories form layer_geometry_key :param layer_geometry_key: The geometry id :type layer_geometry_key: str :param hazard_category_key: The hazard category :type hazard_category_key: str :returns: List of hazard :rtype: list """ hazards = [] for impact_function in self.impact_functions: if_hazards = impact_function.metadata().hazards_for_layer( layer_geometry_key, hazard_category_key) if if_hazards: add_to_list(hazards, if_hazards) return hazards def exposures_for_layer(self, layer_geometry_key): """Get hazard categories form layer_geometry_key :param layer_geometry_key: The geometry id :type layer_geometry_key: str :returns: List of hazard :rtype: list """ exposures = [] for impact_function in self.impact_functions: if_exposures = impact_function.metadata().exposures_for_layer( layer_geometry_key) if if_exposures: add_to_list(exposures, if_exposures) return exposures def exposure_units_for_layer( self, exposure_key, layer_geometry_key, layer_mode_key): """Get hazard categories form layer_geometry_key :param exposure_key: The exposure key :type exposure_key: str :param layer_geometry_key: The geometry key :type layer_geometry_key: str :param layer_mode_key: The layer mode key :type layer_mode_key: str :returns: List of exposure unit :rtype: list """ exposure_units = [] for impact_function in self.impact_functions: if_exposure_units = impact_function.metadata().\ exposure_units_for_layer( exposure_key, layer_geometry_key, layer_mode_key) if if_exposure_units: add_to_list(exposure_units, if_exposure_units) return exposure_units def continuous_hazards_units_for_layer( self, hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key): """Get continuous hazard units. :param hazard_key: The hazard key :type hazard_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param layer_mode_key: The layer mode key :type layer_mode_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of continuous hazard unit :rtype: list """ continuous_hazards_units = [] for impact_function in self.impact_functions: if_continuous_hazard_units = impact_function.metadata().\ continuous_hazards_units_for_layer( hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key) if if_continuous_hazard_units: add_to_list( continuous_hazards_units, if_continuous_hazard_units) return continuous_hazards_units def vector_hazards_classifications_for_layer( self, hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key): """Get continuous hazard units. :param hazard_key: The hazard key :type hazard_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param layer_mode_key: The layer mode key :type layer_mode_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of vector_hazards_classifications :rtype: list """ vector_hazards_classifications = [] for impact_function in self.impact_functions: if_vector_hazards_classifications = impact_function.metadata().\ vector_hazards_classifications_for_layer( hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key) if if_vector_hazards_classifications: add_to_list( vector_hazards_classifications, if_vector_hazards_classifications) return vector_hazards_classifications def raster_hazards_classifications_for_layer( self, hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key): """Get continuous hazard units. :param hazard_key: The hazard key :type hazard_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param layer_mode_key: The layer mode key :type layer_mode_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of raster_hazards_classifications :rtype: list """ raster_hazards_classifications = [] for impact_function in self.impact_functions: if_vector_hazards_classifications = impact_function.metadata().\ raster_hazards_classifications_for_layer( hazard_key, layer_geometry_key, layer_mode_key, hazard_category_key) if if_vector_hazards_classifications: add_to_list( raster_hazards_classifications, if_vector_hazards_classifications) return raster_hazards_classifications def available_hazards(self, hazard_category_key, ascending=True): """available_hazards from hazard_category_key :param hazard_category_key: The hazard category key :type hazard_category_key: str :param ascending: Sort ascending or not. :type ascending: bool :returns: List of available hazards :rtype: list """ hazards = [] for impact_function in self.impact_functions: if_hazards = impact_function.metadata(). \ available_hazards(hazard_category_key) if if_hazards: add_to_list(hazards, if_hazards) # make it sorted if ascending and hazards: hazards = sorted(hazards, key=lambda k: k['key']) return hazards def available_exposures(self, ascending=True): """Return a list of valid available exposures :param ascending: Sort ascending or not. :type ascending: bool :returns: A list of exposures full metadata. :rtype: list """ exposures = [] for impact_function in self.impact_functions: if_exposures = impact_function.metadata().available_exposures() if if_exposures: add_to_list(exposures, if_exposures) # make it sorted if ascending and exposures: exposures = sorted(exposures, key=lambda k: k['key']) return exposures def functions_for_constraint( self, hazard_key, exposure_key, hazard_geometry_key=None, exposure_geometry_key=None, hazard_mode_key=None, exposure_mode_key=None): """Obtain all functions that match with the constraints :param hazard_key: The hazard key :type hazard_key: str :param exposure_key: the exposure key :type exposure_key: str :param hazard_geometry_key: The hazard geometry key :type hazard_geometry_key: str :param exposure_geometry_key: The exposure geometry key :type exposure_geometry_key: str :param hazard_mode_key: The hazard mode key :type hazard_mode_key: str :param exposure_mode_key: The exposure mode key :type exposure_mode_key: str :returns: List of matched Impact Function :rtype: list """ impact_functions = [] for impact_function in self.impact_functions: if impact_function.metadata().is_function_for_constraint( hazard_key, exposure_key, hazard_geometry_key, exposure_geometry_key, hazard_mode_key, exposure_mode_key): impact_functions.append(impact_function.metadata().as_dict()) return impact_functions def available_hazard_constraints( self, hazard_key, hazard_category_key): """Get hazard constraints for hazard_key and hazard_category_key :param hazard_key: The hazard key :type hazard_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of tuple of layer_mode and layer_geometry :rtype: list """ hazard_constraints = [] for impact_function in self.impact_functions: if_hazard_constraints = impact_function.metadata().\ available_hazard_constraints( hazard_key, hazard_category_key) if if_hazard_constraints: add_to_list(hazard_constraints, if_hazard_constraints) return hazard_constraints def available_exposure_constraints(self, exposure_key): """Get exposure constraints for exposure_key. :param exposure_key: The exposure key :type exposure_key: str :returns: List of tuple of layer_mode and layer_geometry :rtype: list """ exposure_constraints = [] for impact_function in self.impact_functions: if_exposure_constraints = impact_function.metadata(). \ available_exposure_constraints(exposure_key) if if_exposure_constraints: add_to_list(exposure_constraints, if_exposure_constraints) return exposure_constraints def available_hazard_layer_modes( self, hazard_key, hazard_geometry_key, hazard_category_key): """Return all available layer_mode. :param hazard_key: The hazard key :type hazard_key: str :param hazard_geometry_key: The hazard geometry key :type hazard_geometry_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :returns: List of layer_mode :rtype: list """ layer_modes = [] for impact_function in self.impact_functions: if_hazard_layer_mode = impact_function.metadata().\ available_hazard_layer_mode( hazard_key, hazard_geometry_key, hazard_category_key) if if_hazard_layer_mode: add_to_list(layer_modes, if_hazard_layer_mode) return layer_modes def available_exposure_layer_modes( self, exposure_key, exposure_geometry_key): """Get exposure layer mode for exposure_key. :param exposure_key: The exposure key :type exposure_key: str :param exposure_geometry_key: The exposure geometry key :type exposure_geometry_key: str :returns: List of layer_mode :rtype: list """ layer_modes = [] for impact_function in self.impact_functions: if_exposure_layer_mode = impact_function.metadata().\ available_exposure_layer_mode( exposure_key, exposure_geometry_key) if if_exposure_layer_mode: add_to_list(layer_modes, if_exposure_layer_mode) return layer_modes def hazard_additional_keywords( self, layer_mode_key=None, layer_geometry_key=None, hazard_category_key=None, hazard_key=None): """Return additional_keywords for hazard. :param layer_mode_key: The layer mode key :type layer_mode_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param hazard_category_key: The hazard category key :type hazard_category_key: str :param hazard_key: The hazard key :type hazard_key: str :returns: List of additional keywords :rtype: list """ additional_keywords = [] for impact_function in self.impact_functions: if_additional_keywords = impact_function.metadata().\ hazard_additional_keywords( layer_mode_key=layer_mode_key, layer_geometry_key=layer_geometry_key, hazard_category_key=hazard_category_key, hazard_key=hazard_key) if if_additional_keywords: add_to_list(additional_keywords, if_additional_keywords) return additional_keywords def exposure_additional_keywords( self, layer_mode_key=None, layer_geometry_key=None, exposure_key=None): """Return additional_keywords for exposure. :param layer_mode_key: The layer mode key :type layer_mode_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param exposure_key: The hazard key :type exposure_key: str :returns: List of additional keywords :rtype: list """ additional_keywords = [] for impact_function in self.impact_functions: if_additional_keywords = impact_function.metadata().\ exposure_additional_keywords( layer_mode_key=layer_mode_key, layer_geometry_key=layer_geometry_key, exposure_key=exposure_key) if if_additional_keywords: add_to_list(additional_keywords, if_additional_keywords) return additional_keywords def exposure_class_fields( self, layer_mode_key=None, layer_geometry_key=None, exposure_key=None): """Return list of exposure class field. :param layer_mode_key: The layer mode key :type layer_mode_key: str :param layer_geometry_key: The layer geometry key :type layer_geometry_key: str :param exposure_key: The exposure key :type exposure_key: str :returns: List of exposure class field. :rtype: list """ result = [] for impact_function in self.impact_functions: if_exposure_class_field = impact_function.metadata(). \ exposure_class_fields( layer_mode_key=layer_mode_key, layer_geometry_key=layer_geometry_key, exposure_key=exposure_key) if if_exposure_class_field: add_to_list(result, if_exposure_class_field) return result
class ImpactFunctionManager(object): """Class for managing metadata for all impact function. .. versionadded:: 2.1 """ def __init__(self): """Constructor.""" # Singleton Registry to track all the registered Impact Functions self.registry = Registry() @property def impact_functions(self): """Return all registered impact functions.""" return self.registry.impact_functions def get_instance(self, class_name): """Return an instance of an impact function given its class name. .. example:: if_manager = ImpactFunctionManager() if_class_name = 'FloodBuildingImpactFunction' if = if_manager.get_instance(if_class_name) :param class_name: The name of IF class. :type class_name: str :return: Impact function instance that matches the argument. :rtype: safe.impact_functions.base.ImpactFunction """ return self.registry.get_instance(class_name) def get_class(self, class_name): """Return the class of an impact function given its class name. .. example:: if_manager = ImpactFunctionManager() if_class_name = 'FloodBuildingImpactFunction' if_class = if_manager.get_class(if_class_name) :param class_name: the name of IF class :type class_name: str :return: impact function class that matches the argument. :rtype: safe.impact_functions.base.ImpactFunction """ return self.registry.get_class(class_name) def get(self, impact_function_id): """Return an instance of an impact function given its ID. This is a preferred way to get an instance of IF. IF should have a unique human readable ID in their metadata. .. example:: if_manager = ImpactFunctionManager() if_id = 'FloodBuildingImpactFunction' if = if_manager.get(if_id) :param impact_function_id: The ID of impact function in the metadata. :type impact_function_id: str :return An Impact function instance that has matched id. :rtype: safe.impact_functions.base.ImpactFunction """ impact_functions = self.registry.filter_by_metadata( 'id', impact_function_id) if len(impact_functions) == 0: raise Exception('Impact function with ID: %s not found' % impact_function_id) elif len(impact_functions) > 1: raise Exception( 'There are some Impact Functions that have the same ID: %s' % impact_function_id) return impact_functions[0].instance() def filter(self, hazard_metadata=None, exposure_metadata=None): """Get available impact functions from hazard and exposure metadata. Disabled impact function will not be loaded. .. example:: if_manager = ImpactFunctionManager() hazard_metadata = { 'subcategory': hazard_flood, 'units': unit_wetdry, 'layer_constraints': layer_vector_polygon } exposure_metadata = { 'subcategory': exposure_structure, 'units': unit_building_type_type, 'layer_constraints': layer_vector_polygon } ifs = if_manager.filter(hazard_metadata, exposure_metadata) :param hazard_metadata: The metadata of the hazard. :type hazard_metadata: dict :param exposure_metadata: The metadata of the exposure. :type exposure_metadata: dict """ return self.registry.filter(hazard_metadata, exposure_metadata) def filter_by_keywords(self, hazard_keywords=None, exposure_keywords=None): """Get available impact functions from hazard and exposure keywords. Disabled impact function will not be loaded. .. example:: if_manager = ImpactFunctionManager() hazard_keywords = { 'subcategory': 'flood', 'units': 'wetdry', 'layer_type': 'vector', 'data_type': 'polygon' } exposure_keywords = { 'subcategory': 'structure', 'units': 'building_type', 'layer_type': 'vector', 'data_type': 'polygon' } ifs = if_manager.filter_by_keywords(hazard_keywords, exposure_keywords) :param hazard_keywords: The keywords of the hazard. :type hazard_keywords: dict :param exposure_keywords: The keywords of the exposure. :type exposure_keywords: dict """ return self.registry.filter_by_keyword_string(hazard_keywords, exposure_keywords) def filter_by_metadata(self, metadata_key, metadata_value): """Return IF classes given its metadata key and value. .. example:: if_manager = ImpactFunctionManager() metadata_key = 'author' metadata_value = 'Akbar Gumbira' ifs = if_manager.filter_by_metadata(metadata_key, metadata_value) :param metadata_key: The key of the metadata e.g 'id', 'name' :type metadata_key: str :param metadata_value: The value of the metadata, e.g for the key 'id' the value is 'FloodNativePolygonExperimentalFunction' :type metadata_value: str, dict :return: Impact Function classes match the arguments :rtype: list """ return self.registry.filter_by_metadata(metadata_key, metadata_value) @staticmethod def get_function_id(impact_function): """Get the ID of the impact function. :param impact_function: Class of an impact function :type impact_function: safe.impact_functions.base.ImpactFunction :returns: The ID of the impact function specified in its metadata. :rtype: str """ return impact_function.metadata().as_dict().get('id', None) @staticmethod def get_function_title(impact_function): """Get title of the impact function. :param impact_function: Class of an impact function :type impact_function: safe.impact_functions.base.ImpactFunction :returns: The title of the impact function specified in its metadata. :rtype: str """ return impact_function.metadata().as_dict().get('title', None) @staticmethod def get_function_name(impact_function): """Get the human readable name of the impact function. :param impact_function: Class of an impact function. :type impact_function: safe.impact_functions.base.ImpactFunction """ return impact_function.metadata().as_dict().get('name', None) @staticmethod def get_function_type(impact_function): """Return the impact function type. :param impact_function: The impact function. :type impact_function: safe.impact_functions.base.ImpactFunction """ return impact_function.function_type() def allowed_subcategories(self, category=None): """Determine allowed subcategories, optionally filtered by category. :param category: Optional category which will be used to subset the allowed subcategories. If omitted, all supported subcategories will be returned (for both hazard and exposure). Default is None. :type category: str :returns: A list of strings is returned. :rtype: list """ result = [] for impact_function in self.impact_functions: my_allowed_subcategories = impact_function.metadata()\ .allowed_subcategories(category) result = add_to_list(result, my_allowed_subcategories) return result def allowed_data_types(self, subcategory): """Determine allowed data types for all impact functions. It uses subcategory as a filter. Passing a subcategory is required otherwise the context of the data_type(s) would be ambiguous (i.e. whether they can be used as exposure or hazards). :param subcategory: Required subcategory which will be used to subset the allowed data_types. :type subcategory: str :returns: A list of one or more strings is returned. :rtype: list """ result = [] for impact_function in self.impact_functions: my_allowed_data_types = impact_function.metadata() \ .allowed_data_types(subcategory) result = add_to_list(result, my_allowed_data_types) return result def allowed_units(self, subcategory, data_type): """Determine allowed units from all impact functions. It uses subcategory and data_type as a filter. .. note:: One data_type could be used by more than one subcategory, so we need to explicitly pass the subcategory to this function. :param subcategory: Required subcategory which will be used to subset the allowed data_types. :type subcategory: str :param data_type: Required data_type which will be used to subset the allowed units. :type data_type: str :returns: A list of one or more strings is returned. :rtype: list """ result = [] for impact_function in self.impact_functions: my_allowed_units = impact_function.metadata()\ .allowed_units(subcategory, data_type) result = add_to_list(result, my_allowed_units) return result def units_for_layer(self, subcategory, layer_type, data_type): """Get the valid units for a layer. Example usage:: foo = units_for_layer('flood', 'vector', 'polygon') print foo Would output this:: {'Wet/Dry': ['wet','dry']} While passing a raster layer:: foo = units_for_layer('flood', 'raster', None) print foo Might return this:: { 'metres': None, 'feet': None, 'wet/dry': ['wet', 'dry'], } In the returned dictionary the keys are unit types and the values are the categories (if any) applicable for that unit type. :param subcategory: The subcategory for this layer. :type subcategory: str :param layer_type: The type for this layer. Valid values would be, 'raster' or 'vector'. :type layer_type: str :param data_type: The data_type for this layer. Valid possibilities would be 'numeric' (for raster), point, line, polygon (for vectors). :type data_type: str :returns: A dictionary as per the example above where each key represents a unit and each value that is not None represents a list of categories. :rtype: dict """ result = [] for impact_function in self.impact_functions: my_units = impact_function.metadata()\ .units_for_layer(subcategory, layer_type, data_type) result = add_to_list(result, my_units) return result def categories_for_layer(self, layer_type, data_type): """Return a list of valid categories for a layer. This method is used to determine if a given layer can be used as a hazard, exposure or aggregation layer. Example usage:: foo = categories_for_layer('vector', 'polygon') print foo Would output this:: ['hazard', 'exposure', 'aggregation'] While passing a vector point layer:: foo = units_for_layer('vector', 'point') print foo Might return this:: ['hazard', 'exposure'] In the returned the values are categories (if any) applicable for that layer_type and data_type. :param layer_type: The type for this layer. Valid values would be, 'raster' or 'vector'. :type layer_type: str :param data_type: The data_type for this layer. Valid possibilities would be 'numeric' (for raster), point, line, polygon (for vectors). :type data_type: str :returns: A list as per the example above where each value represents a valid category. :rtype: list """ result = [] for impact_function in self.impact_functions: categories = impact_function.metadata()\ .categories_for_layer(layer_type, data_type) result = add_to_list(result, categories) categories_definitions = [] for category in result: if category == 'hazard': categories_definitions.append(hazard_definition) elif category == 'exposure': categories_definitions.append(exposure_definition) else: raise Exception('Unsupported categories') return categories_definitions def subcategories_for_layer(self, category, layer_type, data_type): """Return a list of valid subcategories for a layer. This method is used to determine which subcategories a given layer can be for. Example usage:: foo = subcategories_for_layer('vector', 'polygon', 'exposure') print foo Would output this:: ['flood', 'landuse'] In the returned the values are categories (if any) applicable for that layer_type and data_type. :param layer_type: The type for this layer. Valid values would be, 'raster' or 'vector'. :type layer_type: str :param data_type: The data_type for this layer. Valid possibilities would be 'numeric' (for raster), point, line, polygon (for vectors). :type data_type: str :param category: The category for this layer. Valid possibilities would be 'hazard', 'exposure' and 'aggregation'. :type category: str :returns: A list as per the example above where each value represents a valid subcategory. :rtype: list """ result = [] for impact_function in self.impact_functions: subcategories = impact_function.metadata()\ .subcategories_for_layer(category, layer_type, data_type) result = add_to_list(result, subcategories) return result def get_available_hazards(self, impact_function=None, ascending=True): """Return a list of valid available hazards for an impact function. If impact_function is None, return all available hazards .. versionadded:: 2.2 :param impact_function: Impact Function object. :type impact_function: FunctionProvider :param ascending: Sort ascending or not. :type ascending: bool :returns: A list of hazard full metadata. :rtype: list """ hazards = [] if impact_function is None: for impact_function in self.impact_functions: add_to_list(hazards, impact_function.metadata().get_hazards()) else: # noinspection PyUnresolvedReferences hazards = impact_function.metadata().get_hazards() # make it sorted if ascending: hazards = sorted(hazards, key=lambda k: k['id']) return hazards def get_functions_for_hazard(self, hazard): """Return all function metadata that has hazard in their metadata. .. versionadded:: 2.2 :param hazard: Dictionary that represent the hazard :type hazard: dict :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_hazard(hazard): impact_functions_metadata.append( impact_function.metadata().as_dict()) return impact_functions_metadata def get_functions_for_hazard_id(self, hazard_id): """Return all function metadata that has hazard_id in their metadata. .. versionadded:: 2.2 :param hazard_id: String that represent the hazard id. :type hazard_id: str :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_hazard_id(hazard_id): impact_functions_metadata.append( impact_function.metadata().as_dict()) return impact_functions_metadata def get_available_exposures(self, impact_function=None, ascending=True): """Return a list of valid available exposures for an impact function. If impact_function is None, return all available exposures .. versionadded:: 2.2 :param impact_function: Impact Function object. :type impact_function: FunctionProvider :param ascending: Sort ascending or not. :type ascending: bool :returns: A list of exposures full metadata. :rtype: list """ exposures = [] if impact_function is None: for impact_function in self.impact_functions: add_to_list(exposures, impact_function.metadata().get_exposures()) else: # noinspection PyUnresolvedReferences exposures = impact_function.metadata().get_exposures() # make it sorted if ascending: exposures = sorted(exposures, key=lambda k: k['id']) return exposures def get_functions_for_exposure(self, exposure): """Return all function metadata that has exposure in their metadata. .. versionadded:: 2.2 :param exposure: Dictionary that represent the exposure :type exposure: dict :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_exposure(exposure): impact_functions_metadata.append( impact_function.metadata().as_dict()) return impact_functions_metadata def get_functions_for_exposure_id(self, exposure_id): """Return all function metadata that has exposure_id in their metadata. .. versionadded:: 2.2 :param exposure_id: String that represent the exposure id. :type exposure_id: str :return: List of impact function metadata. :rtype: list """ impact_functions_metadata = [] for impact_function in self.impact_functions: if impact_function.metadata().has_exposure_id(exposure_id): impact_functions_metadata.append( impact_function.metadata().as_dict()) return impact_functions_metadata def get_functions_for_constraint(self, hazard, exposure, hazard_constraint=None, exposure_constraint=None): """Get all impact functions that match the hazard n exposure metadata. :param hazard: The hazard metadata. :type hazard: dict :param exposure: The exposure metadata. :type exposure: dict :param hazard_constraint: :param exposure_constraint: :return: """ result = [] if_hazard = self.get_functions_for_hazard(hazard) if_exposure = self.get_functions_for_exposure(exposure) if_exposure_id = [function['id'] for function in if_exposure] for f in if_hazard: if f['id'] in if_exposure_id: if (not hazard_constraint or hazard_constraint in f['categories']['hazard']['layer_constraints']): if (not exposure_constraint or exposure_constraint in f['categories']['exposure']['layer_constraints']): result.append(f) return result