def get_exposure(oqparam): """ Read the full exposure in memory and build a list of :class:`openquake.risklib.asset.Asset` instances. :param oqparam: an :class:`openquake.commonlib.oqvalidation.OqParam` instance :returns: an :class:`Exposure` instance """ out_of_region = 0 if oqparam.region_constraint: region = wkt.loads(oqparam.region_constraint) else: region = None all_cost_types = set(oqparam.all_cost_types) fname = oqparam.inputs['exposure'] exposure, assets_node = _get_exposure(fname, all_cost_types) relevant_cost_types = all_cost_types - set(['occupants']) asset_refs = set() ignore_missing_costs = set(oqparam.ignore_missing_costs) for idx, asset_node in enumerate(assets_node): values = {} deductibles = {} insurance_limits = {} retrofitteds = {} with context(fname, asset_node): asset_id = asset_node['id'].encode('utf8') if asset_id in asset_refs: raise read_nrml.DuplicatedID(asset_id) asset_refs.add(asset_id) exposure.asset_refs.append(asset_id) taxonomy = asset_node['taxonomy'] if 'damage' in oqparam.calculation_mode: # calculators of 'damage' kind require the 'number' # if it is missing a KeyError is raised number = asset_node.attrib['number'] else: # some calculators ignore the 'number' attribute; # if it is missing it is considered 1, since we are going # to multiply by it try: number = asset_node['number'] except KeyError: number = 1 else: if 'occupants' in all_cost_types: values['occupants_None'] = number location = asset_node.location['lon'], asset_node.location['lat'] if region and not geometry.Point(*location).within(region): out_of_region += 1 continue tagnode = getattr(asset_node, 'tags', None) assets_by_tag = exposure.assets_by_tag if tagnode is not None: # fill missing tagvalues with "?" and raise an error for # unknown tagnames with context(fname, tagnode): dic = tagnode.attrib.copy() for tagname in assets_by_tag.tagnames: try: tagvalue = dic.pop(tagname) except KeyError: tagvalue = '?' else: if tagvalue in '?*': raise ValueError( 'Invalid tagvalue="%s"' % tagvalue) tag = '%s=%s' % (tagname, tagvalue) assets_by_tag[tag].append(idx) if dic: raise ValueError( 'Unknown tagname %s or <tagNames> not ' 'specified in the exposure' % ', '.join(dic)) exposure.assets_by_tag['taxonomy=' + taxonomy].append(idx) try: costs = asset_node.costs except AttributeError: costs = Node('costs', []) try: occupancies = asset_node.occupancies except AttributeError: occupancies = Node('occupancies', []) for cost in costs: with context(fname, cost): cost_type = cost['type'] if cost_type in relevant_cost_types: values[cost_type] = cost['value'] retrovalue = cost.attrib.get('retrofitted') if retrovalue is not None: retrofitteds[cost_type] = retrovalue if oqparam.insured_losses: deductibles[cost_type] = cost['deductible'] insurance_limits[cost_type] = cost['insuranceLimit'] # check we are not missing a cost type missing = relevant_cost_types - set(values) if missing and missing <= ignore_missing_costs: logging.warn( 'Ignoring asset %s, missing cost type(s): %s', asset_id, ', '.join(missing)) for cost_type in missing: values[cost_type] = None elif missing and 'damage' not in oqparam.calculation_mode: # missing the costs is okay for damage calculators with context(fname, asset_node): raise ValueError("Invalid Exposure. " "Missing cost %s for asset %s" % ( missing, asset_id)) tot_occupants = 0 for occupancy in occupancies: with context(fname, occupancy): exposure.time_events.add(occupancy['period']) occupants = 'occupants_%s' % occupancy['period'] values[occupants] = occupancy['occupants'] tot_occupants += values[occupants] if occupancies: # store average occupants values['occupants_None'] = tot_occupants / len(occupancies) area = float(asset_node.attrib.get('area', 1)) ass = asset.Asset(idx, taxonomy, number, location, values, area, deductibles, insurance_limits, retrofitteds, exposure.cost_calculator) exposure.assets.append(ass) if region: logging.info('Read %d assets within the region_constraint ' 'and discarded %d assets outside the region', len(exposure.assets), out_of_region) if len(exposure.assets) == 0: raise RuntimeError('Could not find any asset within the region!') # sanity checks values = any(len(ass.values) + ass.number for ass in exposure.assets) assert values, 'Could not find any value??' return exposure
def _add_asset(self, idx, asset_node, param): values = {} deductibles = {} insurance_limits = {} retrofitteds = {} asset_id = asset_node['id'].encode('utf8') with context(param['fname'], asset_node): self.asset_refs.append(asset_id) taxonomy = asset_node['taxonomy'] if 'damage' in param['calculation_mode']: # calculators of 'damage' kind require the 'number' # if it is missing a KeyError is raised number = asset_node['number'] else: # some calculators ignore the 'number' attribute; # if it is missing it is considered 1, since we are going # to multiply by it try: number = asset_node['number'] except KeyError: number = 1 else: if 'occupants' in param['all_cost_types']: values['occupants_None'] = number location = asset_node.location['lon'], asset_node.location['lat'] if param['region'] and not geometry.Point(*location).within( param['region']): param['out_of_region'] += 1 return tagnode = getattr(asset_node, 'tags', None) dic = {} if tagnode is None else tagnode.attrib.copy() with context(param['fname'], tagnode): dic['taxonomy'] = taxonomy idxs = self.tagcol.add_tags(dic) try: costs = asset_node.costs except AttributeError: costs = Node('costs', []) try: occupancies = asset_node.occupancies except AttributeError: occupancies = Node('occupancies', []) for cost in costs: with context(param['fname'], cost): cost_type = cost['type'] if cost_type in param['relevant_cost_types']: values[cost_type] = cost['value'] retrovalue = cost.get('retrofitted') if retrovalue is not None: retrofitteds[cost_type] = retrovalue if param['insured_losses']: deductibles[cost_type] = cost['deductible'] insurance_limits[cost_type] = cost['insuranceLimit'] # check we are not missing a cost type missing = param['relevant_cost_types'] - set(values) if missing and missing <= param['ignore_missing_costs']: logging.warn('Ignoring asset %s, missing cost type(s): %s', asset_id, ', '.join(missing)) for cost_type in missing: values[cost_type] = None elif missing and 'damage' not in param['calculation_mode']: # missing the costs is okay for damage calculators with context(param['fname'], asset_node): raise ValueError("Invalid Exposure. " "Missing cost %s for asset %s" % (missing, asset_id)) tot_occupants = 0 for occupancy in occupancies: with context(param['fname'], occupancy): occupants = 'occupants_%s' % occupancy['period'] values[occupants] = occupancy['occupants'] tot_occupants += values[occupants] if occupancies: # store average occupants values['occupants_None'] = tot_occupants / len(occupancies) area = float(asset_node.get('area', 1)) ass = asset.Asset(idx, idxs, number, location, values, area, deductibles, insurance_limits, retrofitteds, self.cost_calculator) self.assets.append(ass)