def hazard_curves_per_trt( sources, sites, imtls, gsims, truncation_level=None, source_site_filter=filters.source_site_noop_filter, rupture_site_filter=filters.rupture_site_noop_filter, monitor=DummyMonitor()): """ Compute the hazard curves for a set of sources belonging to the same tectonic region type for all the GSIMs associated to that TRT. The arguments are the same as in :func:`calc_hazard_curves`, except for ``gsims``, which is a list of GSIM instances. :returns: A list of G arrays of size N, where N is the number of sites and G the number of gsims. Each array contains records with fields given by the intensity measure types; the size of each field is given by the number of levels in ``imtls``. """ gnames = list(map(str, gsims)) imt_dt = numpy.dtype([(imt, float, len(imtls[imt])) for imt in sorted(imtls)]) imts = {from_string(imt): imls for imt, imls in imtls.items()} curves = [numpy.ones(len(sites), imt_dt) for gname in gnames] sources_sites = ((source, sites) for source in sources) ctx_mon = monitor('making contexts', measuremem=False) rup_mon = monitor('getting ruptures', measuremem=False) pne_mon = monitor('computing poes', measuremem=False) monitor.calc_times = [] # pairs (src_id, delta_t) for source, s_sites in source_site_filter(sources_sites): t0 = time.time() try: with rup_mon: rupture_sites = list(rupture_site_filter( (rupture, s_sites) for rupture in source.iter_ruptures())) for rupture, r_sites in rupture_sites: for i, gsim in enumerate(gsims): with ctx_mon: sctx, rctx, dctx = gsim.make_contexts(r_sites, rupture) with pne_mon: for imt in imts: poes = gsim.get_poes( sctx, rctx, dctx, imt, imts[imt], truncation_level) pno = rupture.get_probability_no_exceedance(poes) expanded_pno = r_sites.expand(pno, placeholder=1) curves[i][str(imt)] *= expanded_pno except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, str(err)) raise_(etype, msg, tb) # we are attaching the calculation times to the monitor # so that oq-lite (and the engine) can store them monitor.calc_times.append((source.id, time.time() - t0)) # NB: source.id is an integer; it should not be confused # with source.source_id, which is a string for i in range(len(gnames)): for imt in imtls: curves[i][imt] = 1. - curves[i][imt] return curves
def read_lazy(source, lazytags): """ Convert a NRML file into a validated LiteralNode object. The tree is lazy, i.e. you access nodes by iterating on them. :param source: a file name or file object open for reading :param lazytags: the name of nodes which subnodes must be read lazily :returns: a list of nodes; some of them will contain lazy subnodes """ nodes = [] try: for _, el in iterparse(source, remove_comments=True): tag = striptag(el.tag) if tag in nodefactory: # NRML tag nodes.append(node_from_elem(el, nodefactory[tag], lazy=lazytags)) el.clear() # save memory except: etype, exc, tb = sys.exc_info() msg = str(exc) if str(source) not in msg: msg = "%s in %s" % (msg, source) raise_(etype, msg, tb) return nodes
def stochastic_event_set( sources, sites=None, source_site_filter=filters.source_site_noop_filter, rupture_site_filter=filters.rupture_site_noop_filter): """ Generates a 'Stochastic Event Set' (that is a collection of earthquake ruptures) representing a possible *realization* of the seismicity as described by a source model. The calculator loops over sources. For each source, it loops over ruptures. For each rupture, the number of occurrence is randomly sampled by calling :meth:`openquake.hazardlib.source.rupture.BaseProbabilisticRupture.sample_number_of_occurrences` .. note:: This calculator is using random numbers. In order to reproduce the same results numpy random numbers generator needs to be seeded, see http://docs.scipy.org/doc/numpy/reference/generated/numpy.random.seed.html :param sources: An iterator of seismic sources objects (instances of subclasses of :class:`~openquake.hazardlib.source.base.BaseSeismicSource`). :param sites: A list of sites to consider (or None) :param source_site_filter: The source filter to use (only meaningful is sites is not None) :param source_site_filter: The rupture filter to use (only meaningful is sites is not None) :returns: Generator of :class:`~openquake.hazardlib.source.rupture.Rupture` objects that are contained in an event set. Some ruptures can be missing from it, others can appear one or more times in a row. """ if sites is None: # no filtering for source in sources: try: for rupture in source.iter_ruptures(): for i in range(rupture.sample_number_of_occurrences()): yield rupture except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, err.message) raise_(etype, msg, tb) return # else apply filtering sources_sites = source_site_filter((source, sites) for source in sources) for source, r_sites in sources_sites: try: ruptures_sites = rupture_site_filter( (rupture, r_sites) for rupture in source.iter_ruptures()) for rupture, _sites in ruptures_sites: for i in range(rupture.sample_number_of_occurrences()): yield rupture except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, err.message) raise_(etype, msg, tb)
def _collect_bins_data(trt_num, sources, site, curves, src_group_id, rlzs_assoc, gsims, imtls, poes, truncation_level, n_epsilons, iml_disagg, mon): # returns a BinData instance sitecol = SiteCollection([site]) mags = [] dists = [] lons = [] lats = [] trts = [] pnes = collections.defaultdict(list) sitemesh = sitecol.mesh make_ctxt = mon('making contexts', measuremem=False) disagg_poe = mon('disaggregate_poe', measuremem=False) cmaker = ContextMaker(gsims) for source in sources: try: tect_reg = trt_num[source.tectonic_region_type] for rupture in source.iter_ruptures(): with make_ctxt: try: sctx, rctx, dctx = cmaker.make_contexts( sitecol, rupture) except filters.FarAwayRupture: continue # extract rupture parameters of interest mags.append(rupture.mag) dists.append(dctx.rjb[0]) # single site => single distance [closest_point] = rupture.surface.get_closest_points(sitemesh) lons.append(closest_point.longitude) lats.append(closest_point.latitude) trts.append(tect_reg) # a dictionary rlz.id, poe, imt_str -> (iml, prob_no_exceed) for gsim in gsims: gs = str(gsim) for imt_str, imls in imtls.items(): imt = from_string(imt_str) imls = numpy.array(imls[::-1]) for rlz in rlzs_assoc[src_group_id, gs]: rlzi = rlz.ordinal iml = iml_disagg.get(imt_str) curve_poes = curves[rlzi, imt_str][::-1] for k, v in _disagg( iml, poes, curve_poes, imls, gsim, rupture, rlzi, imt, imt_str, sctx, rctx, dctx, truncation_level, n_epsilons, disagg_poe): pnes[k].append(v) except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, err) raise_(etype, msg, tb) return BinData(numpy.array(mags, float), numpy.array(dists, float), numpy.array(lons, float), numpy.array(lats, float), numpy.array(trts, int), pnes)
def get_sources(self, kind, sitecol): """ :param kind: a string 'light', 'heavy' or 'all' :param sitecol: a SiteCollection instance :returns: the sources of the given kind affecting the given sitecol """ filter_mon = self.monitor('filtering sources') split_mon = self.monitor('splitting sources') for src in self.csm.get_sources(kind): filter_time = split_time = 0 if self.filter_sources: try: max_dist = self.maximum_distance[src.tectonic_region_type] except KeyError: max_dist = self.maximum_distance['default'] with filter_mon: try: sites = src.filter_sites_by_distance_to_source( max_dist, sitecol) except: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s: %s' msg %= (src.source_id, unicode(err)) raise_(etype, msg, tb) filter_time = filter_mon.dt if sites is None: continue if kind == 'heavy': if (src.trt_model_id, src.id) not in self.split_map: logging.info('splitting %s of weight %s', src, src.weight) with split_mon: sources = list(sourceconverter.split_source(src)) self.split_map[src.trt_model_id, src.id] = sources split_time = split_mon.dt self.set_serial(src, sources) for ss in self.split_map[src.trt_model_id, src.id]: ss.id = src.id yield ss else: self.set_serial(src) yield src split_sources = self.split_map.get( (src.trt_model_id, src.id), [src]) info = SourceInfo(src.trt_model_id, src.source_id, src.__class__.__name__, src.weight, len(split_sources), filter_time, split_time, 0) key = (src.trt_model_id, src.source_id) if key in self.infos: self.infos[key] += info else: self.infos[key] = info filter_mon.flush() split_mon.flush()
def get_sources(self, kind, tile): """ :param kind: a string 'light', 'heavy' or 'all' :param tile: a :class:`openquake.hazardlib.site.Tile` instance :returns: the sources of the given kind affecting the given tile """ filter_mon = self.monitor('filtering sources') split_mon = self.monitor('splitting sources') for src in self.csm.get_sources(kind): filter_time = split_time = 0 if self.filter_sources: with filter_mon: try: if src not in tile: continue except: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s: %s' msg %= (src.source_id, err) raise_(etype, msg, tb) filter_time = filter_mon.dt if kind == 'heavy': if (src.trt_model_id, src.id) not in self.split_map: logging.info('splitting %s of weight %s', src, src.weight) with split_mon: sources = list(sourceconverter.split_source(src)) self.split_map[src.trt_model_id, src.id] = sources split_time = split_mon.dt self.set_serial(src, sources) for ss in self.split_map[src.trt_model_id, src.id]: ss.id = src.id yield ss else: self.set_serial(src) yield src split_sources = self.split_map.get( (src.trt_model_id, src.id), [src]) info = SourceInfo(src.trt_model_id, src.source_id, src.__class__.__name__, src.weight, len(split_sources), filter_time, split_time, 0) key = (src.trt_model_id, src.source_id) if key in self.infos: self.infos[key] += info else: self.infos[key] = info filter_mon.flush() split_mon.flush()
def context(fname, node): """ Context manager managing exceptions and adding line number of the current node and name of the current file to the error message. :param fname: the current file being processed :param node: the current node being processed """ try: yield node except: etype, exc, tb = sys.exc_info() msg = 'node %s: %s, line %s of %s' % ( striptag(node.tag), exc, node.lineno, fname) raise_(etype, msg, tb)
def context(src): """ Used to add the source_id to the error message. To be used as with context(src): operation_with(src) Typically the operation is filtering a source, that can fail for tricky geometries. """ try: yield except Exception: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (src.source_id, err) raise_(etype, msg, tb)
def poe_map(src, s_sites, imtls, cmaker, trunclevel, bbs, rup_indep, ctx_mon, pne_mon, disagg_mon): """ Compute the ProbabilityMap generated by the given source. Also, store some information in the monitors and optionally in the bounding boxes. """ pmap = ProbabilityMap.build( len(imtls.array), len(cmaker.gsims), s_sites.sids, initvalue=rup_indep) try: for rup, weight in rupture_weight_pairs(src): with ctx_mon: # compute distances try: sctx, rctx, dctx = cmaker.make_contexts(s_sites, rup) except FarAwayRupture: continue with pne_mon: # compute probabilities and updates the pmap pnes = get_probability_no_exceedance( rup, sctx, rctx, dctx, imtls, cmaker.gsims, trunclevel) for sid, pne in zip(sctx.sites.sids, pnes): if rup_indep: pmap[sid].array *= pne else: pmap[sid].array += pne * weight # add optional disaggregation information (bounding boxes) if bbs: with disagg_mon: sids = set(sctx.sites.sids) jb_dists = dctx.rjb closest_points = rup.surface.get_closest_points( sctx.sites.mesh) bs = [bb for bb in bbs if bb.site_id in sids] # NB: the assert below is always true; we are # protecting against possible refactoring errors assert len(bs) == len(jb_dists) == len(closest_points) for bb, dist, p in zip(bs, jb_dists, closest_points): bb.update([dist], [p.longitude], [p.latitude]) except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (src.source_id, str(err)) raise_(etype, msg, tb) return ~pmap
def _build_trts_branches(self): # do the parsing, called at instantiation time to populate .values trts = [] branches = [] branchsetids = set() for branching_level in self._ltnode: if len(branching_level) > 1: raise InvalidLogicTree( "Branching level %s has multiple branchsets" % branching_level["branchingLevelID"] ) for branchset in branching_level: if branchset["uncertaintyType"] != "gmpeModel": raise InvalidLogicTree("only uncertainties of type " '"gmpeModel" are allowed in gmpe logic tree') bsid = branchset["branchSetID"] if bsid in branchsetids: raise InvalidLogicTree("Duplicated branchSetID %s" % bsid) else: branchsetids.add(bsid) trt = branchset.attrib.get("applyToTectonicRegionType") if trt: trts.append(trt) effective = trt in self.tectonic_region_types weights = [] for branch in branchset: weight = Decimal(branch.uncertaintyWeight.text) weights.append(weight) branch_id = branch["branchID"] uncertainty = branch.uncertaintyModel try: gsim = valid.gsim(uncertainty.text.strip(), **uncertainty.attrib) except: etype, exc, tb = sys.exc_info() raise_(etype, "%s in file %r" % (exc, self.fname), tb) self.values[trt].append(gsim) bt = BranchTuple(branchset, branch_id, gsim, weight, effective) branches.append(bt) assert sum(weights) == 1, weights if len(trts) > len(set(trts)): raise InvalidLogicTree("Found duplicated applyToTectonicRegionType=%s" % trts) branches.sort(key=lambda b: (b.bset["branchSetID"], b.id)) return trts, branches
def read_nodes(fname, filter_elem, nodefactory=Node, remove_comments=True): """ Convert an XML file into a lazy iterator over Node objects satifying the given specification, i.e. a function element -> boolean. :param fname: file name of file object :param filter_elem: element specification In case of errors, add the file name to the error message. """ try: for _, el in iterparse(fname, remove_comments=remove_comments): if filter_elem(el): yield node_from_elem(el, nodefactory) el.clear() # save memory except: etype, exc, tb = sys.exc_info() msg = str(exc) if not str(fname) in msg: msg = '%s in %s' % (msg, fname) raise_(etype, msg, tb)
def stochastic_event_set(sources, source_site_filter=nofilter, **kwargs): """ Generates a 'Stochastic Event Set' (that is a collection of earthquake ruptures) representing a possible *realization* of the seismicity as described by a source model. The calculator loops over sources. For each source, it loops over ruptures. For each rupture, the number of occurrence is randomly sampled by calling :meth:`openquake.hazardlib.source.rupture.BaseProbabilisticRupture.sample_number_of_occurrences` .. note:: This calculator is using random numbers. In order to reproduce the same results numpy random numbers generator needs to be seeded, see http://docs.scipy.org/doc/numpy/reference/generated/numpy.random.seed.html :param sources: An iterator of seismic sources objects (instances of subclasses of :class:`~openquake.hazardlib.source.base.BaseSeismicSource`). :param source_site_filter: The source filter to use (default noop filter) :returns: Generator of :class:`~openquake.hazardlib.source.rupture.Rupture` objects that are contained in an event set. Some ruptures can be missing from it, others can appear one or more times in a row. """ shift_hypo = kwargs['shift_hypo'] if 'shift_hypo' in kwargs else False for source, _ in source_site_filter.filter(sources): try: for rupture in source.iter_ruptures(shift_hypo=shift_hypo): [n_occ] = rupture.sample_number_of_occurrences() for _ in range(n_occ): yield rupture except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, str(err)) raise_(etype, msg, tb)
def poe_map(self, src, sites, imtls, trunclevel, ctx_mon, poe_mon, rup_indep=True): """ :param src: a source object :param sites: a filtered SiteCollection :param imtls: intensity measure and levels :param trunclevel: truncation level :param ctx_mon: a Monitor instance for make_context :param poe_mon: a Monitor instance for get_poes :param rup_indep: True if the ruptures are independent :returns: a ProbabilityMap instance """ with ctx_mon: ruptures = self.filter_ruptures(src, sites) if not ruptures: return {} try: with poe_mon: pmap = self.make_pmap(ruptures, imtls, trunclevel, rup_indep) except Exception as err: etype, err, tb = sys.exc_info() msg = '%s (source id=%s)' % (str(err), src.source_id) raise_(etype, msg, tb) return pmap
def _collect_bins_data(sources, site, imt, iml, gsims, truncation_level, n_epsilons, source_site_filter, rupture_site_filter): """ Extract values of magnitude, distance, closest point, tectonic region types and PoE distribution. This method processes the source model (generates ruptures) and collects all needed parameters to arrays. It also defines tectonic region type bins sequence. """ mags = [] dists = [] lons = [] lats = [] tect_reg_types = [] probs_no_exceed = [] sitecol = SiteCollection([site]) sitemesh = sitecol.mesh _next_trt_num = 0 trt_nums = {} # here we ignore filtered site collection because either it is the same # as the original one (with one site), or the source/rupture is filtered # out and doesn't show up in the filter's output for src_idx, (source, s_sites) in \ enumerate(source_site_filter(sources, sitecol)): try: tect_reg = source.tectonic_region_type gsim = gsims[tect_reg] cmaker = ContextMaker([gsim]) if tect_reg not in trt_nums: trt_nums[tect_reg] = _next_trt_num _next_trt_num += 1 tect_reg = trt_nums[tect_reg] for rupture, r_sites in rupture_site_filter( source.iter_ruptures(), s_sites): # extract rupture parameters of interest mags.append(rupture.mag) [jb_dist] = rupture.surface.get_joyner_boore_distance(sitemesh) dists.append(jb_dist) [closest_point] = rupture.surface.get_closest_points(sitemesh) lons.append(closest_point.longitude) lats.append(closest_point.latitude) tect_reg_types.append(tect_reg) # compute conditional probability of exceeding iml given # the current rupture, and different epsilon level, that is # ``P(IMT >= iml | rup, epsilon_bin)`` for each of epsilon bins sctx, rctx, dctx = cmaker.make_contexts(sitecol, rupture) [poes_given_rup_eps ] = gsim.disaggregate_poe(sctx, rctx, dctx, imt, iml, truncation_level, n_epsilons) # collect probability of a rupture causing no exceedances probs_no_exceed.append( rupture.get_probability_no_exceedance(poes_given_rup_eps)) except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, str(err)) raise_(etype, msg, tb) mags = numpy.array(mags, float) dists = numpy.array(dists, float) lons = numpy.array(lons, float) lats = numpy.array(lats, float) tect_reg_types = numpy.array(tect_reg_types, int) probs_no_exceed = numpy.array(probs_no_exceed, float) trt_bins = [ trt for (num, trt) in sorted((num, trt) for (trt, num) in trt_nums.items()) ] return (mags, dists, lons, lats, tect_reg_types, trt_bins, probs_no_exceed)
def _collect_bins_data(sources, site, imt, iml, gsims, truncation_level, n_epsilons, source_site_filter, rupture_site_filter): """ Extract values of magnitude, distance, closest point, tectonic region types and PoE distribution. This method processes the source model (generates ruptures) and collects all needed parameters to arrays. It also defines tectonic region type bins sequence. """ mags = [] dists = [] lons = [] lats = [] tect_reg_types = [] probs_no_exceed = [] sitecol = SiteCollection([site]) sitemesh = sitecol.mesh _next_trt_num = 0 trt_nums = {} sources_sites = ((source, sitecol) for source in sources) # here we ignore filtered site collection because either it is the same # as the original one (with one site), or the source/rupture is filtered # out and doesn't show up in the filter's output for src_idx, (source, s_sites) in \ enumerate(source_site_filter(sources_sites)): try: tect_reg = source.tectonic_region_type gsim = gsims[tect_reg] if not tect_reg in trt_nums: trt_nums[tect_reg] = _next_trt_num _next_trt_num += 1 tect_reg = trt_nums[tect_reg] ruptures_sites = ((rupture, s_sites) for rupture in source.iter_ruptures()) for rupture, r_sites in rupture_site_filter(ruptures_sites): # extract rupture parameters of interest mags.append(rupture.mag) [jb_dist] = rupture.surface.get_joyner_boore_distance(sitemesh) dists.append(jb_dist) [closest_point] = rupture.surface.get_closest_points(sitemesh) lons.append(closest_point.longitude) lats.append(closest_point.latitude) tect_reg_types.append(tect_reg) # compute conditional probability of exceeding iml given # the current rupture, and different epsilon level, that is # ``P(IMT >= iml | rup, epsilon_bin)`` for each of epsilon bins sctx, rctx, dctx = gsim.make_contexts(sitecol, rupture) [poes_given_rup_eps] = gsim.disaggregate_poe( sctx, rctx, dctx, imt, iml, truncation_level, n_epsilons ) # collect probability of a rupture causing no exceedances probs_no_exceed.append( rupture.get_probability_no_exceedance(poes_given_rup_eps) ) except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, str(err)) raise_(etype, msg, tb) mags = numpy.array(mags, float) dists = numpy.array(dists, float) lons = numpy.array(lons, float) lats = numpy.array(lats, float) tect_reg_types = numpy.array(tect_reg_types, int) probs_no_exceed = numpy.array(probs_no_exceed, float) trt_bins = [ trt for (num, trt) in sorted((num, trt) for (trt, num) in trt_nums.items()) ] return (mags, dists, lons, lats, tect_reg_types, trt_bins, probs_no_exceed)
def hazard_curves_per_trt(sources, sites, imtls, gsims, truncation_level=None, source_site_filter=filters.source_site_noop_filter, rupture_site_filter=filters.rupture_site_noop_filter, monitor=DummyMonitor()): """ Compute the hazard curves for a set of sources belonging to the same tectonic region type for all the GSIMs associated to that TRT. The arguments are the same as in :func:`calc_hazard_curves`, except for ``gsims``, which is a list of GSIM instances. :returns: A list of G arrays of size N, where N is the number of sites and G the number of gsims. Each array contains records with fields given by the intensity measure types; the size of each field is given by the number of levels in ``imtls``. """ gnames = list(map(str, gsims)) imt_dt = numpy.dtype([(imt, float, len(imtls[imt])) for imt in sorted(imtls)]) imts = {from_string(imt): imls for imt, imls in imtls.items()} curves = [numpy.ones(len(sites), imt_dt) for gname in gnames] sources_sites = ((source, sites) for source in sources) ctx_mon = monitor('making contexts', measuremem=False) rup_mon = monitor('getting ruptures', measuremem=False) pne_mon = monitor('computing poes', measuremem=False) monitor.calc_times = [] # pairs (src_id, delta_t) for source, s_sites in source_site_filter(sources_sites): t0 = time.time() try: with rup_mon: rupture_sites = list( rupture_site_filter((rupture, s_sites) for rupture in source.iter_ruptures())) for rupture, r_sites in rupture_sites: for i, gsim in enumerate(gsims): with ctx_mon: sctx, rctx, dctx = gsim.make_contexts(r_sites, rupture) with pne_mon: for imt in imts: poes = gsim.get_poes(sctx, rctx, dctx, imt, imts[imt], truncation_level) pno = rupture.get_probability_no_exceedance(poes) expanded_pno = r_sites.expand(pno, placeholder=1) curves[i][str(imt)] *= expanded_pno except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, str(err)) raise_(etype, msg, tb) # we are attaching the calculation times to the monitor # so that oq-lite (and the engine) can store them monitor.calc_times.append((source.id, time.time() - t0)) # NB: source.id is an integer; it should not be confused # with source.source_id, which is a string for i in range(len(gnames)): for imt in imtls: curves[i][imt] = 1. - curves[i][imt] return curves
def _collect_bins_data(trt_num, source_ruptures, site, curves, src_group_id, rlzs_assoc, gsims, imtls, poes, truncation_level, n_epsilons, mon): # returns a BinData instance sitecol = SiteCollection([site]) mags = [] dists = [] lons = [] lats = [] trts = [] pnes = [] sitemesh = sitecol.mesh make_ctxt = mon('making contexts', measuremem=False) disagg_poe = mon('disaggregate_poe', measuremem=False) cmaker = ContextMaker(gsims) for source, ruptures in source_ruptures: try: tect_reg = trt_num[source.tectonic_region_type] for rupture in ruptures: with make_ctxt: sctx, rctx, dctx = cmaker.make_contexts(sitecol, rupture) # extract rupture parameters of interest mags.append(rupture.mag) dists.append(dctx.rjb[0]) # single site => single distance [closest_point] = rupture.surface.get_closest_points(sitemesh) lons.append(closest_point.longitude) lats.append(closest_point.latitude) trts.append(tect_reg) pne_dict = {} # a dictionary rlz.id, poe, imt_str -> prob_no_exceed for gsim in gsims: gs = str(gsim) for imt_str, imls in imtls.items(): imt = from_string(imt_str) imls = numpy.array(imls[::-1]) for rlz in rlzs_assoc[src_group_id, gs]: rlzi = rlz.ordinal curve_poes = curves[rlzi, imt_str][::-1] for poe in poes: iml = numpy.interp(poe, curve_poes, imls) # compute probability of exceeding iml given # the current rupture and epsilon_bin, that is # ``P(IMT >= iml | rup, epsilon_bin)`` # for each of the epsilon bins with disagg_poe: [poes_given_rup_eps] = \ gsim.disaggregate_poe( sctx, rctx, dctx, imt, iml, truncation_level, n_epsilons) pne = rupture.get_probability_no_exceedance( poes_given_rup_eps) pne_dict[rlzi, poe, imt_str] = (iml, pne) pnes.append(pne_dict) except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, err) raise_(etype, msg, tb) return BinData(numpy.array(mags, float), numpy.array(dists, float), numpy.array(lons, float), numpy.array(lats, float), numpy.array(trts, int), pnes)
def hazard_curves_per_trt( sources, sites, imtls, gsims, truncation_level=None, source_site_filter=filters.source_site_noop_filter, rupture_site_filter=filters.rupture_site_noop_filter, maximum_distance=None, bbs=(), monitor=DummyMonitor()): """ Compute the hazard curves for a set of sources belonging to the same tectonic region type for all the GSIMs associated to that TRT. The arguments are the same as in :func:`calc_hazard_curves`, except for ``gsims``, which is a list of GSIM instances. :returns: A list of G arrays of size N, where N is the number of sites and G the number of gsims. Each array contains records with fields given by the intensity measure types; the size of each field is given by the number of levels in ``imtls``. """ cmaker = ContextMaker(gsims, maximum_distance) gnames = list(map(str, gsims)) imt_dt = numpy.dtype([(imt, float, len(imtls[imt])) for imt in sorted(imtls)]) imts = {from_string(imt): imls for imt, imls in imtls.items()} curves = [numpy.ones(len(sites), imt_dt) for gname in gnames] sources_sites = ((source, sites) for source in sources) ctx_mon = monitor('making contexts', measuremem=False) rup_mon = monitor('getting ruptures', measuremem=False) pne_mon = monitor('computing poes', measuremem=False) monitor.calc_times = [] # pairs (src_id, delta_t) for source, s_sites in source_site_filter(sources_sites): t0 = time.time() try: with rup_mon: rupture_sites = list(rupture_site_filter( (rupture, s_sites) for rupture in source.iter_ruptures())) for rupture, r_sites in rupture_sites: with ctx_mon: try: sctx, rctx, dctx = cmaker.make_contexts( r_sites, rupture) except FarAwayRupture: continue # add optional disaggregation information (bounding boxes) if bbs: sids = set(sctx.sites.sids) jb_dists = dctx.rjb closest_points = rupture.surface.get_closest_points( sctx.sites.mesh) bs = [bb for bb in bbs if bb.site_id in sids] # NB: the assert below is always true; we are # protecting against possible refactoring errors assert len(bs) == len(jb_dists) == len(closest_points) for bb, dist, p in zip(bs, jb_dists, closest_points): if dist < maximum_distance: # ruptures too far away are ignored bb.update([dist], [p.longitude], [p.latitude]) for i, gsim in enumerate(gsims): with pne_mon: for imt in imts: poes = gsim.get_poes( sctx, rctx, dctx, imt, imts[imt], truncation_level) pno = rupture.get_probability_no_exceedance(poes) expanded_pno = sctx.sites.expand(pno, 1.0) curves[i][str(imt)] *= expanded_pno except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, str(err)) raise_(etype, msg, tb) # we are attaching the calculation times to the monitor # so that oq-lite (and the engine) can store them monitor.calc_times.append((source.id, time.time() - t0)) # NB: source.id is an integer; it should not be confused # with source.source_id, which is a string for i in range(len(gnames)): for imt in imtls: curves[i][imt] = 1. - curves[i][imt] return curves
def ucerf_poe_map(hdf5, ucerf_source, rupset_idx, s_sites, imtls, cmaker, trunclevel, bbs, ctx_mon, pne_mon, disagg_mon): """ Compute a ProbabilityMap generated by the given set of indices. :param hdf5: UCERF file as instance of open h5py.File object :param ucerf_source: UCERFControl object :param list rupset_idx: List of rupture indices """ pmap = ProbabilityMap.build(len(imtls.array), len(cmaker.gsims), s_sites.sids, initvalue=1.) try: for ridx in rupset_idx: # Get the ucerf rupture if not hdf5[ucerf_source.idx_set["rate_idx"]][ridx]: # Ruptures seem to have a zero probability from time to time # If this happens, skip it continue rup, ridx_string = get_ucerf_rupture( hdf5, ridx, ucerf_source.idx_set, ucerf_source.tom, s_sites, ucerf_source.integration_distance, ucerf_source.mesh_spacing, ucerf_source.tectonic_region_type) if not rup: # rupture outside of integration distance continue with ctx_mon: # compute distances try: sctx, rctx, dctx = cmaker.make_contexts(s_sites, rup) except FarAwayRupture: continue with pne_mon: # compute probabilities and updates the pmap pnes = get_probability_no_exceedance( rup, sctx, rctx, dctx, imtls, cmaker.gsims, trunclevel) for sid, pne in zip(sctx.sites.sids, pnes): pmap[sid].array *= pne # add optional disaggregation information (bounding boxes) if bbs: with disagg_mon: sids = set(sctx.sites.sids) jb_dists = dctx.rjb closest_points = rup.surface.get_closest_points( sctx.sites.mesh) bs = [bb for bb in bbs if bb.site_id in sids] # NB: the assert below is always true; we are # protecting against possible refactoring errors assert len(bs) == len(jb_dists) == len(closest_points) for bb, dist, p in zip(bs, jb_dists, closest_points): bb.update([dist], [p.longitude], [p.latitude]) except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with rupture=%s. Error: %s' msg %= (ridx, str(err)) raise_(etype, msg, tb) return ~pmap
def hazard_curves_per_trt( sources, sites, imtls, gsims, truncation_level=None, source_site_filter=filters.source_site_noop_filter, rupture_site_filter=filters.rupture_site_noop_filter, maximum_distance=None, bbs=(), monitor=Monitor()): """ Compute the hazard curves for a set of sources belonging to the same tectonic region type for all the GSIMs associated to that TRT. The arguments are the same as in :func:`calc_hazard_curves`, except for ``gsims``, which is a list of GSIM instances. :returns: A list of G arrays of size N, where N is the number of sites and G the number of gsims. Each array contains records with fields given by the intensity measure types; the size of each field is given by the number of levels in ``imtls``. """ cmaker = ContextMaker(gsims, maximum_distance) gnames = list(map(str, gsims)) imt_dt = numpy.dtype([(imt, float, len(imtls[imt])) for imt in sorted(imtls)]) imts = {from_string(imt): imls for imt, imls in imtls.items()} curves = [numpy.ones(len(sites), imt_dt) for gname in gnames] sources_sites = ((source, sites) for source in sources) ctx_mon = monitor('making contexts', measuremem=False) pne_mon = monitor('computing poes', measuremem=False) monitor.calc_times = [] # pairs (src_id, delta_t) monitor.eff_ruptures = 0 # effective number of contributing ruptures for source, s_sites in source_site_filter(sources_sites): t0 = time.time() try: rupture_sites = rupture_site_filter( (rupture, s_sites) for rupture in source.iter_ruptures()) for rupture, r_sites in rupture_sites: with ctx_mon: try: sctx, rctx, dctx = cmaker.make_contexts( r_sites, rupture) except FarAwayRupture: continue monitor.eff_ruptures += 1 # add optional disaggregation information (bounding boxes) if bbs: sids = set(sctx.sites.sids) jb_dists = dctx.rjb closest_points = rupture.surface.get_closest_points( sctx.sites.mesh) bs = [bb for bb in bbs if bb.site_id in sids] # NB: the assert below is always true; we are # protecting against possible refactoring errors assert len(bs) == len(jb_dists) == len(closest_points) for bb, dist, p in zip(bs, jb_dists, closest_points): if dist < maximum_distance: # ruptures too far away are ignored bb.update([dist], [p.longitude], [p.latitude]) for i, gsim in enumerate(gsims): with pne_mon: for imt in imts: poes = gsim.get_poes( sctx, rctx, dctx, imt, imts[imt], truncation_level) pno = rupture.get_probability_no_exceedance(poes) expanded_pno = sctx.sites.expand(pno, 1.0) curves[i][str(imt)] *= expanded_pno except Exception as err: etype, err, tb = sys.exc_info() msg = 'An error occurred with source id=%s. Error: %s' msg %= (source.source_id, str(err)) raise_(etype, msg, tb) # we are attaching the calculation times to the monitor # so that oq-lite (and the engine) can store them monitor.calc_times.append((source.id, time.time() - t0)) # NB: source.id is an integer; it should not be confused # with source.source_id, which is a string for i in range(len(gnames)): for imt in imtls: curves[i][imt] = 1. - curves[i][imt] return curves