def write_vector_data(data, projection, geometry, filename, keywords=None): """Write point data and any associated attributes to vector file Input: data: List of N dictionaries each with M fields where M is the number of attributes. A value of None is acceptable. projection: WKT projection information geometry: List of points or polygons. filename: Output filename keywords: Optional dictionary Note: The only format implemented is GML and SHP so the extension must be either .gml or .shp # FIXME (Ole): When the GML driver is used, # the spatial reference is not stored. # I suspect this is a bug in OGR. Background: * http://www.gdal.org/ogr/ogr_apitut.html (last example) * http://invisibleroads.com/tutorials/gdal-shapefile-points-save.html """ V = Vector(data, projection, geometry, keywords=keywords) V.write_to_file(filename)
def test_instantiation_of_empty_layers(self): """Vector and Raster objects can be instantiated with None """ v = Vector(None) assert v.get_name().startswith('Vector') r = Raster(None) assert r.get_name().startswith('Raster')
def unspecific2bnpb(E, target_attribute='VCLASS'): """Map Unspecific point data to BNPB vulnerability classes This makes no assumptions about attributes and maps everything to URM: Unreinforced Masonry Input E: Vector object representing the OSM data target_attribute: Optional name of the attribute containing the mapped vulnerability class. Default value is 'VCLASS' Output: Vector object like E, but with one new attribute (e.g. 'VCLASS') representing the vulnerability class used in the guidelines """ # Start mapping N = len(E) attributes = E.get_data() count = 0 for i in range(N): # Store new attribute value attributes[i][target_attribute] = 'URM' # Create new vector instance and return V = Vector(data=attributes, projection=E.get_projection(), geometry=E.get_geometry(), name=E.get_name() + ' mapped to BNPB vulnerability class URM', keywords=E.get_keywords()) return V
def csv2shp(path, lonname='Bujur', latname='Lintang'): # Read csv data reader = csv.DictReader(open(path, 'r')) data = [] for x in reader: data.append(x) # Determine latitude and longitude fields fieldnames = reader.fieldnames msg = ('Could not find requested longitude "%s" in %s. Available ' 'field names are: %s' % (lonname, path, str(fieldnames))) assert lonname in fieldnames, msg msg = ('Could not find requested latitude "%s" in %s. Available ' 'field names are: %s' % (latname, path, str(fieldnames))) assert latname in fieldnames, msg # Extract point geometry lon = [float(x[lonname]) for x in data] lat = [float(x[latname]) for x in data] geometry = zip(lon, lat) # Replace spaces in attribute names with underscores (issue #177) for i, D in enumerate(data): D_clean = {} for key in D: D_clean[key.replace(' ', '_')] = D[key] data[i] = D_clean # Create vector object V = Vector(data=data, projection=DEFAULT_PROJECTION, geometry=geometry) # Write as shapefile basename, _ = os.path.splitext(path) V.write_to_file(basename + '.shp') fid = open(basename + '.keywords', 'w') fid.write('category:exposure\n') fid.write('subcategory:building\n') fid.write('datatype:sigab\n') fid.close()
def test_vector_class(self): """Consistency of vector class for point data """ # Read data file layername = 'lembang_schools.shp' filename = '%s/%s' % (TESTDATA, layername) V = read_layer(filename) # Make a smaller dataset V_ref = V.get_topN('FLOOR_AREA', 5) geometry = V_ref.get_geometry() data = V_ref.get_data() projection = V_ref.get_projection() # Create new object from test data V_new = Vector(data=data, projection=projection, geometry=geometry) # Check assert V_new == V_ref assert not V_new != V_ref # Write this new object, read it again and check tmp_filename = unique_filename(suffix='.shp') V_new.write_to_file(tmp_filename) V_tmp = read_layer(tmp_filename) assert V_tmp == V_ref assert not V_tmp != V_ref # Check that equality raises exception when type is wrong try: V_tmp == Raster() except TypeError: pass else: msg = 'Should have raised TypeError' raise Exception(msg)
def interpolate_raster_vector_points(R, V, name=None): """Interpolate from raster layer to point data Input R: Raster data set (grid) V: Vector data set (points) name: Name for new attribute. If None (default) the name of R is used Output I: Vector data set; points located as V with values interpolated from R """ msg = ('There are no data points to interpolate to. Perhaps zoom out ' 'and try again') assert len(V) > 0, msg # Input checks assert R.is_raster assert V.is_vector assert V.is_point_data # Get raster data and corresponding x and y axes A = R.get_data(nan=True) longitudes, latitudes = R.get_geometry() assert len(longitudes) == A.shape[1] assert len(latitudes) == A.shape[0] # Get vector point geometry as Nx2 array coordinates = numpy.array(V.get_geometry(), dtype='d', copy=False) # Interpolate and create new attribute N = len(V) attributes = [] if name is None: name = R.get_name() values = interpolate_raster(longitudes, latitudes, A, coordinates, mode='linear') # Create list of dictionaries for this attribute and return for i in range(N): attributes.append({name: values[i]}) return Vector(data=attributes, projection=V.get_projection(), geometry=coordinates)
def read_layer(filename): """Read spatial layer from file. This can be either raster or vector data. """ _, ext = os.path.splitext(filename) if ext in ['.asc', '.tif']: return Raster(filename) elif ext in ['.shp', '.gml']: return Vector(filename) else: msg = ('Could not read %s. ' 'Extension "%s" has not been implemented' % (filename, ext)) raise Exception(msg)
def run(layers): """Risk plugin for earthquake school damage """ # Extract data # FIXME (Ole): This will be replaced by a helper function # to separate hazard from exposure using keywords H = layers[0] # Ground shaking E = layers[1] # Building locations # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() shaking = H.get_data() # Calculate building damage building_damage = [] for i in range(len(shaking)): x = float(shaking[i].values()[0]) if x < 6.0: value = 0.0 else: value = (0.692 * (x**4) - 15.82 * (x**3) + 135.0 * (x**2) - 509.0 * x + 714.4) building_damage.append({'DAMAGE': value, 'MMI': x}) # FIXME (Ole): Need helper to generate new layer using # correct spatial reference # (i.e. sensibly wrap the following lines) projection = E.get_projection() V = Vector(data=building_damage, projection=E.get_projection(), geometry=coordinates, name='Estimated pct damage') return V
def run(self, layers): """Risk plugin for earthquake school damage """ # Extract data H = layers[0] # Ground shaking E = layers[1] # Building locations # print # print 'kw', E.get_keywords() # print # FIXME (Ole): Why doesn't this layer have keywords? See issue #164 # Need keyword identifier for each kind of building dataset. # if 'osm' in E.get_keywords('type'): # FIXME (Ole): Not very robust way of deciding if E.get_name().lower().startswith('osm'): # Map from OSM attributes to the padang building classes E = osm2padang(E) vclass_tag = 'VCLASS' else: vclass_tag = 'TestBLDGCl' # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() shaking = H.get_data() N = len(shaking) # List attributes to carry forward to result layer attributes = E.get_attribute_names() # Calculate building damage count50 = 0 count25 = 0 count10 = 0 count0 = 0 building_damage = [] for i in range(N): mmi = float(shaking[i].values()[0]) building_class = E.get_data(vclass_tag, i) building_type = str(int(building_class)) damage_params = damage_curves[building_type] percent_damage = scipy.stats.lognorm.cdf(mmi, damage_params['beta'], scale=damage_params['median']) * 100 # Collect shake level and calculated damage result_dict = {self.target_field: percent_damage, 'MMI': mmi} # Carry all orginal attributes forward for key in attributes: result_dict[key] = E.get_data(key, i) # Record result for this feature building_damage.append(result_dict) # Calculate statistics if percent_damage < 10: count0 += 1 if 10 <= percent_damage < 25: count10 += 1 if 25 <= percent_damage < 50: count25 += 1 if 50 <= percent_damage: count50 += 1 # Create report caption = ('<font size="3"> <table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></th>' ' <tr></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s (<10%%):</td><td>%i</td></tr>' ' <tr><td>%s (10-25%%):</td><td>%i</td></tr>' ' <tr><td>%s (25-50%%):</td><td>%i</td></tr>' ' <tr><td>%s (50-100%%):</td><td>%i</td></tr>' '</table></font>' % (_('Buildings'), _('Total'), _('All'), N, _('No damage'), count0, _('Low damage'), count10, _('Medium damage'), count25, _('High damage'), count50)) # Create vector layer and return V = Vector(data=building_damage, projection=E.get_projection(), geometry=coordinates, name='Estimated pct damage', keywords={'caption': caption}) return V
def run(self, layers): """Risk plugin for tsunami population """ # Extract data # FIXME (Ole): This will be replaced by a helper function # to separate hazard from exposure using keywords H = layers[0] # Depth E = layers[1] # Building locations # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() depth = H.get_data() N = len(depth) # List attributes to carry forward to result layer attributes = E.get_attribute_names() #print attributes #print 'Number of population points', N # Calculate population impact count = 0 building_impact = [] for i in range(N): dep = float(depth[i].values()[0]) # Tag and count if dep > 0.1: affected = 99.5 count += 1 else: affected = 0 # Collect depth and calculated damage result_dict = {'AFFECTED': affected, 'DEPTH': dep} # Carry all original attributes forward for key in attributes: result_dict[key] = E.get_data(key, i) # Record result for this feature building_impact.append(result_dict) # Create report caption = ('<table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></th>' ' <tr></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s (> 10 cm) :</td><td>%i</td></tr>' ' <tr><td>%s (< 10 cm) :</td><td>%i</td></tr>' '</table>' % (_('Buildings'), _('Total'), _('All'), N, _('Inundated'), count, _('Not inundated'), N - count)) # Create vector layer and return V = Vector(data=building_impact, projection=E.get_projection(), geometry=coordinates, name='Estimated buildings affected', keywords={'caption': caption}) return V
def run(self, layers): """Risk plugin for tsunami population """ # Extract data H = layers[0] # Depth E = layers[1] # Building locations #print 'Number of polygons', len(E) # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() depth = H.get_data() N = len(depth) # List attributes to carry forward to result layer attributes = E.get_attribute_names() # Calculate building impact according to guidelines count3 = 0 count1 = 0 count0 = 0 population_impact = [] for i in range(N): # Get depth dep = float(depth[i].values()[0]) # Classify buildings according to depth if dep >= 3: affected = 3 # FIXME: Colour upper bound is 100 but count3 += 1 # does not catch affected == 100 elif 1 <= dep < 3: affected = 2 count1 += 1 else: affected = 1 count0 += 1 # Collect depth and calculated damage result_dict = {self.target_field: affected, 'DEPTH': dep} # Carry all original attributes forward for key in attributes: result_dict[key] = E.get_data(key, i) # Record result for this feature population_impact.append(result_dict) # Create report caption = ('<table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></th>' ' <tr></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' '</table>' % ('ketinggian tsunami', 'Jumlah gedung', '< 1 m', count0, '1 - 3 m', count1, '> 3 m', count3)) # Create vector layer and return V = Vector(data=population_impact, projection=E.get_projection(), geometry=coordinates, name='Estimate of buildings affected', keywords={'caption': caption}) return V
def osm2padang(E): """Map OSM attributes to Padang vulnerability classes This maps attributes collected in the OpenStreetMap exposure data (data.kompetisiosm.org) to 9 vulnerability classes identified by Geoscience Australia and ITB in the post 2009 Padang earthquake survey (http://trove.nla.gov.au/work/38470066). The mapping was developed by Abigail Baca, GFDRR. Input E: Vector object representing the OSM data Output: Vector object like E, but with one new attribute ('VCLASS') representing the vulnerability class used in the Padang dataset Algorithm 1. Class the "levels" field into height bands where 1-3 = low, 4-10 = mid, >10 = high 2. Where height band = mid then building type = 4 "RC medium rise Frame with Masonry in-fill walls" 3. Where height band = high then building type = 6 "Concrete Shear wall high rise* Hazus C2H" 4. Where height band = low and structure = (plastered or reinforced_masonry) then building type = 7 "RC low rise Frame with Masonry in-fill walls" 5. Where height band = low and structure = confined_masonry then building type = 8 "Confined Masonry" 6. Where height band = low and structure = unreinforced_masonry then building type = 2 "URM with Metal Roof" """ # Input check required = ['levels', 'structure'] actual = E.get_attribute_names() msg = ('Input data to osm2padang must have attributes %s. ' 'It has %s' % (str(required), str(actual))) for attribute in required: assert attribute in actual, msg # Start mapping N = len(E) attributes = E.get_data() count = 0 for i in range(N): levels = E.get_data('levels', i) structure = E.get_data('structure', i) if levels is None or structure is None: vulnerability_class = 2 count += 1 else: if levels >= 10: # High vulnerability_class = 6 # Concrete shear elif 4 <= levels < 10: # Mid vulnerability_class = 4 # RC mid elif 1 <= levels < 4: # Low if structure in [ 'plastered', 'reinforced masonry', 'reinforced_masonry' ]: vulnerability_class = 7 # RC low elif structure == 'confined_masonry': vulnerability_class = 8 # Confined elif 'kayu' in structure or 'wood' in structure: vulnerability_class = 9 # Wood else: vulnerability_class = 2 # URM elif numpy.allclose(levels, 0): # A few buildings exist with 0 levels. # In general, we should be assigning here the most # frequent building in the area which could be defined # by admin boundaries. vulnerability_class = 2 else: msg = 'Unknown number of levels: %s' % levels raise Exception(msg) # Store new attribute value attributes[i]['VCLASS'] = vulnerability_class # Selfcheck for use with osm_080811.shp if E.get_name() == 'osm_080811': if levels > 0: msg = ('Got %s expected %s. levels = %f, structure = %s' % (vulnerability_class, attributes[i]['TestBLDGCl'], levels, structure)) assert numpy.allclose(attributes[i]['TestBLDGCl'], vulnerability_class), msg #print 'Got %i without levels or structure (out of %i total)' % (count, N) # Create new vector instance and return V = Vector(data=attributes, projection=E.get_projection(), geometry=E.get_geometry(), name=E.get_name() + ' mapped to Padang vulnerability classes', keywords=E.get_keywords()) return V
def run(self, layers): """Risk plugin for earthquake school damage """ # Extract data H = layers[0] # Ground shaking E = layers[1] # Building locations # Map from OSM attributes to the guideline classes (URM and RM) # FIXME (Ole): Not very robust way of deciding # Need keyword identifier for each kind of building dataset. if E.get_name().lower().startswith('osm'): # Map from OSM attributes to the padang building classes E = osm2bnpb(E, target_attribute=self.vclass_tag) else: E = unspecific2bnpb(E, target_attribute=self.vclass_tag) # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() shaking = H.get_data() N = len(shaking) # List attributes to carry forward to result layer attributes = E.get_attribute_names() # Calculate building damage count3 = 0 count2 = 0 count1 = 0 building_damage = [] for i in range(N): mmi = float(shaking[i].values()[0]) building_class = E.get_data(self.vclass_tag, i) lo, hi = damage_parameters[building_class] if mmi < lo: damage = 1 # Low count1 += 1 elif lo <= mmi < hi: damage = 2 # Medium count2 += 1 else: damage = 3 # High count3 += 1 # Collect shake level and calculated damage result_dict = {self.target_field: damage, 'MMI': mmi} # Carry all orginal attributes forward for key in attributes: result_dict[key] = E.get_data(key, i) # Record result for this feature building_damage.append(result_dict) # Create report caption = ( '<table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></th>' ' <tr></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s (10-25%%):</td><td>%i</td></tr>' ' <tr><td>%s (25-50%%):</td><td>%i</td></tr>' ' <tr><td>%s (50-100%%):</td><td>%i</td></tr>' '</table>' % (_('Buildings'), _('Total'), _('All'), N, _('Low damage'), count1, _('Medium damage'), count2, _('High damage'), count3)) # Create vector layer and return V = Vector(data=building_damage, projection=E.get_projection(), geometry=coordinates, name='Estimated damage level', keywords={'caption': caption}) return V
def run(layers): """Risk plugin for tsunami building damage """ # Extract data # FIXME (Ole): This will be replaced by a helper function # to separate hazard from exposure using keywords H = layers[0] # Ground shaking E = layers[1] # Building locations # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() inundation = H.get_data() # Calculate N = len(H) impact = [] for i in range(N): #------------------- # Extract parameters #------------------- depth = float(inundation[i].values()[0]) shore_distance = E.get_data('SHORE_DIST', i) # FIXME: Get rid of the type casting when # issue #66 is done number_of_people_in_building = int(E.get_data('NEXIS_PEOP', i)) wall_type = E.get_data('WALL_TYPE', i) contents_value = E.get_data('CONT_VALUE', i) structure_value = E.get_data('STR_VALUE', i) #------------------------ # Compute people affected #------------------------ if 0.01 < depth < 1.0: people_affected = number_of_people_in_building else: people_affected = 0 if depth >= 1.0: people_severely_affected = number_of_people_in_building else: people_severely_affected = 0 #---------------------------------------- # Compute impact on buldings and contents #---------------------------------------- depth_floor = depth - 0.3 # Adjust for floor height if depth_floor >= 0.0: buildings_inundated = 1 else: buildings_inundated = 0 if depth_floor < 0.0: structural_damage = contents_damage = 0.0 else: # Water is deep enough to cause damage if wall_type in struct_damage_curve: curve = struct_damage_curve[wall_type] else: # Establish default for unknown wall type curve = struct_damage_curve['Brick veneer'] structural_damage = curve(depth_floor) contents_damage = contents_damage_curve(depth_floor) #--------------- # Compute losses #--------------- structural_loss = structural_damage * structure_value contents_loss = contents_damage * contents_value #------- # Return #------- impact.append({ 'NEXIS_PEOP': number_of_people_in_building, 'PEOPLE_AFFECTED': people_affected, 'PEOPLE_SEV_AFFECTED': people_severely_affected, 'STRUCT_INUNDATED': buildings_inundated, 'STRUCT_DAMAGE_fraction': structural_damage, 'CONTENTS_DAMAGE_fraction': contents_damage, 'STRUCT_LOSS_AUD': structural_loss, 'CONTENTS_LOSS_AUD': contents_loss, 'DEPTH': depth }) # FIXME (Ole): Need helper to generate new layer using # correct spatial reference # (i.e. sensibly wrap the following lines) V = Vector(data=impact, projection=E.get_projection(), geometry=coordinates, name='Estimated tsunami impact') return V
def run(layers): """Risk plugin for tephra impact """ # Extract data H = layers[0] # Ash load E = layers[1] # Building locations # Interpolate hazard level to building locations H = H.interpolate(E, 'load') # Calculate building damage count3 = 0 count2 = 0 count1 = 0 count0 = 0 result = [] for i in range(len(E)): #------------------- # Extract parameters #------------------- load = H.get_data('load', i) #------------------------ # Compute damage level #------------------------ # FIXME: The thresholds have been greatly reduced # for the purpose of demonstration. Any real analyis # should bring them back to 0, 90, 150, 300 if 0.01 <= load < 0.5: # Loss of crops and livestock impact = 0 count0 += 1 elif 0.5 <= load < 2.0: # Cosmetic damage impact = 1 count1 += 1 elif 2.0 <= load < 10.0: # Partial building collapse impact = 2 count2 += 1 elif load >= 10.0: # Complete building collapse impact = 3 count3 += 1 else: impact = 0 count0 += 1 result.append({'DAMAGE': impact, 'ASHLOAD': load}) # Create report caption = ('<font size="3"> <table border="0" width="320px">' ' <tr><th><b>%s</b></th><th><b>%s</b></th></th>' ' <tr></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' '</table></font>' % ('Beban abu', 'Gedung dampak', '< 0.5 kg/m2', count0, '0.5 - 2 kg/m2', count1, '2 - 10 kg/m2', count2, '> 10 kg/m2', count3)) #'</table>' % ('Beban abu', 'Gedung dampak', # 'Gangguan (< 90 kg/m2)', count0, # 'Kerusakan kosmetik (90 - 150 kg/m2', count1, # 'parsial runtuhnya (150 - 300 kg/m2', count2, # 'runtuhnya lengkap (> 300 kg/m2', count3)) V = Vector(data=result, projection=E.get_projection(), geometry=E.get_geometry(), name='Estimated ashload damage', keywords={'caption': caption}) return V
def run(self, layers, a=0.97429, b=11.037): """Risk plugin for earthquake fatalities Input layers: List of layers expected to contain H: Raster layer of MMI ground shaking E: Polygon population data a: Parameter for Allen impact function b: Parameter for Allen impact function """ # Identify input layers H = layers[0] # Intensity E = layers[1] # Exposure - population counts # Interpolate hazard level to building locations H = H.interpolate(E) # Extract relevant numerical data coordinates = E.get_geometry() # Stay with polygons shaking = H.get_data() N = len(shaking) # List attributes to carry forward to result layer attributes = E.get_attribute_names() # Calculate fatilities count = 0 total = 0 result_feature_set = [] for i in range(N): mmi = float(shaking[i].values()[0]) if mmi < 0.0: # FIXME: Hack until interpolation is fixed mmi = 0.0 population_count = E.get_data('Jumlah_Pen', i) # Calculate impact F = 10**(a * mmi - b) * population_count # Collect shake level and calculated damage result_dict = {self.target_field: F, 'MMI': mmi} # Carry all orginal attributes forward for key in attributes: result_dict[key] = E.get_data(key, i) # Record result for this feature result_feature_set.append(result_dict) # Calculate statistics if not numpy.isnan(F): count += F total += population_count # Create report caption = ('<table border="0" width="320px">' ' <tr><td>%s:</td><td>%i</td></tr>' ' <tr><td>%s:</td><td>%i</td></tr>' '</table>' % ('Jumlah Penduduk', int(total), 'Perkiraan Orang Meninggal', int(count))) # Create vector layer and return V = Vector(data=result_feature_set, projection=E.get_projection(), geometry=coordinates, name='Estimated fatalities', keywords={'caption': caption}) return V
def osm2bnpb(E, target_attribute='VCLASS'): """Map OSM attributes to BNPB vulnerability classes This maps attributes collected in the OpenStreetMap exposure data (data.kompetisiosm.org) to 2 vulnerability classes identified by BNPB in Kajian Risiko Gempabumi VERS 1.0, 2011. They are URM: Unreinforced Masonry and RM: Reinforced Masonry Input E: Vector object representing the OSM data target_attribute: Optional name of the attribute containing the mapped vulnerability class. Default value is 'VCLASS' Output: Vector object like E, but with one new attribute (e.g. 'VCLASS') representing the vulnerability class used in the guidelines """ # Input check required = ['levels', 'structure'] actual = E.get_attribute_names() msg = ('Input data to osm2bnpb must have attributes %s. ' 'It has %s' % (str(required), str(actual))) for attribute in required: assert attribute in actual, msg # Start mapping N = len(E) attributes = E.get_data() count = 0 for i in range(N): levels = E.get_data('levels', i) structure = E.get_data('structure', i) if levels is None or structure is None: vulnerability_class = 'URM' count += 1 else: if levels >= 4: # High vulnerability_class = 'RM' elif 1 <= levels < 4: # Low if structure in ['reinforced masonry', 'reinforced_masonry']: vulnerability_class = 'RM' elif structure == 'confined_masonry': vulnerability_class = 'RM' elif 'kayu' in structure or 'wood' in structure: vulnerability_class = 'RM' else: vulnerability_class = 'URM' elif numpy.allclose(levels, 0): # A few buildings exist with 0 levels. # In general, we should be assigning here the most # frequent building in the area which could be defined # by admin boundaries. vulnerability_class = 'URM' else: msg = 'Unknown number of levels: %s' % levels raise Exception(msg) # Store new attribute value attributes[i][target_attribute] = vulnerability_class #print 'Got %i without levels or structure (out of %i total)' % (count, N) # Create new vector instance and return V = Vector(data=attributes, projection=E.get_projection(), geometry=E.get_geometry(), name=E.get_name() + ' mapped to BNPB vulnerability classes', keywords=E.get_keywords()) return V