def _expected_area(self): incr_mfd = mfd.EvenlyDiscretizedMFD( min_mag=6.55, bin_width=0.1, occurrence_rates=[ 0.0010614989, 8.8291627E-4, 7.3437777E-4, 6.108288E-4, 5.080653E-4]) np1 = geo.NodalPlane(strike=0.0, dip=90.0, rake=0.0) np2 = geo.NodalPlane(strike=90.0, dip=45.0, rake=90.0) npd = pmf.PMF([(0.3, np1), (0.7, np2)]) hd = pmf.PMF([(0.5, 4.0), (0.5, 8.0)]) polygon = geo.Polygon( [geo.Point(-122.5, 37.5), geo.Point(-121.5, 37.5), geo.Point(-121.5, 38.5), geo.Point(-122.5, 38.5)]) area = source.AreaSource( source_id="1", name="Quito", tectonic_region_type="Active Shallow Crust", mfd=incr_mfd, rupture_mesh_spacing=self.rupture_mesh_spacing, magnitude_scaling_relationship=scalerel.PeerMSR(), rupture_aspect_ratio=1.5, upper_seismogenic_depth=0.0, lower_seismogenic_depth=10.0, nodal_plane_distribution=npd, hypocenter_distribution=hd, polygon=polygon, area_discretization=2, temporal_occurrence_model=PoissonTOM(50.)) area.num_ruptures = area.count_ruptures() return area
def test_area_with_tgr_mfd(self): trunc_mfd = mfd.TruncatedGRMFD( a_val=2.1, b_val=4.2, bin_width=0.1, min_mag=6.55, max_mag=8.91 ) np1 = geo.NodalPlane(strike=0.0, dip=90.0, rake=0.0) np2 = geo.NodalPlane(strike=90.0, dip=45.0, rake=90.0) npd = pmf.PMF([(0.3, np1), (0.7, np2)]) hd = pmf.PMF([(0.5, 4.0), (0.5, 8.0)]) polygon = geo.Polygon( [geo.Point(-122.5, 37.5), geo.Point(-121.5, 37.5), geo.Point(-121.5, 38.5), geo.Point(-122.5, 38.5)]) area = source.AreaSource( source_id="1", name="source A", tectonic_region_type="Active Shallow Crust", mfd=trunc_mfd, rupture_mesh_spacing=self.rupture_mesh_spacing, magnitude_scaling_relationship=scalerel.PeerMSR(), rupture_aspect_ratio=1.0, upper_seismogenic_depth=0.0, lower_seismogenic_depth=10.0, nodal_plane_distribution=npd, hypocenter_distribution=hd, polygon=polygon, area_discretization=10, temporal_occurrence_model=PoissonTOM(50.)) actual = list(area) self.assertEqual(len(actual), 96) # expected 96 points self.assertAlmostEqual(actual[0].mfd.a_val, 0.1177287669604317)
def test_area_with_incr_mfd(self): incr_mfd = mfd.EvenlyDiscretizedMFD( min_mag=6.55, bin_width=0.1, occurrence_rates=[ 0.0010614989, 8.8291627E-4, 7.3437777E-4, 6.108288E-4, 5.080653E-4]) np1 = geo.NodalPlane(strike=0.0, dip=90.0, rake=0.0) np2 = geo.NodalPlane(strike=90.0, dip=45.0, rake=90.0) npd = pmf.PMF([(0.3, np1), (0.7, np2)]) hd = pmf.PMF([(0.5, 4.0), (0.5, 8.0)]) polygon = geo.Polygon( [geo.Point(-122.5, 37.5), geo.Point(-121.5, 37.5), geo.Point(-121.5, 38.5), geo.Point(-122.5, 38.5)]) area = source.AreaSource( source_id="1", name="source A", tectonic_region_type="Active Shallow Crust", mfd=incr_mfd, rupture_mesh_spacing=self.rupture_mesh_spacing, magnitude_scaling_relationship=scalerel.PeerMSR(), rupture_aspect_ratio=1.0, upper_seismogenic_depth=0.0, lower_seismogenic_depth=10.0, nodal_plane_distribution=npd, hypocenter_distribution=hd, polygon=polygon, area_discretization=10, temporal_occurrence_model=PoissonTOM(50.0), ) actual = list(area) self.assertEqual(len(actual), 96) # expected 96 points assert_allclose( actual[0].mfd.occurrence_rates, [1.10572802083e-05, 9.197044479166666e-06, 7.6497684375e-06, 6.3627999999999995e-06, 5.292346875e-06])
def convert_areaSource(self, node): """ Convert the given node into an area source object. :param node: a node with tag areaGeometry :returns: a :class:`openquake.hazardlib.source.AreaSource` instance """ geom = node.areaGeometry coords = split_coords_2d(~geom.Polygon.exterior.LinearRing.posList) polygon = geo.Polygon([geo.Point(*xy) for xy in coords]) msr = valid.SCALEREL[~node.magScaleRel]() area_discretization = geom.attrib.get('discretization', self.area_source_discretization) if area_discretization is None: raise ValueError( 'The source %r has no `discretization` parameter and the job.' 'ini file has no `area_source_discretization` parameter either' % node['id']) return source.AreaSource( source_id=node['id'], name=node['name'], tectonic_region_type=node.attrib.get('tectonicRegion'), mfd=self.convert_mfdist(node), rupture_mesh_spacing=self.rupture_mesh_spacing, magnitude_scaling_relationship=msr, rupture_aspect_ratio=~node.ruptAspectRatio, upper_seismogenic_depth=~geom.upperSeismoDepth, lower_seismogenic_depth=~geom.lowerSeismoDepth, nodal_plane_distribution=self.convert_npdist(node), hypocenter_distribution=self.convert_hpdist(node), polygon=polygon, area_discretization=area_discretization, temporal_occurrence_model=self.tom)
def test_mesh_spacing_uniformness(self): MESH_SPACING = 10 tl = geo.Point(60, 60) tr = geo.Point(70, 60) bottom_line = [geo.Point(lon, 58) for lon in range(70, 59, -1)] poly = geo.Polygon([tl, tr] + bottom_line) mesh = poly.discretize(mesh_spacing=MESH_SPACING) self.assertIsInstance(mesh, geo.Mesh) mesh = list(mesh) for i, point in enumerate(mesh): if i == len(mesh) - 1: # the point is last in the mesh break next_point = mesh[i + 1] if next_point.longitude < point.longitude: # this is the next row (down along the meridian). # let's check that the new row stands exactly # mesh spacing kilometers below the previous one. self.assertAlmostEqual(point.distance( geo.Point(point.longitude, next_point.latitude)), MESH_SPACING, places=4) continue dist = point.distance(next_point) self.assertAlmostEqual(MESH_SPACING, dist, places=4)
def get_mesh(oqparam): """ Extract the mesh of points to compute from the sites, the sites_csv, or the region. :param oqparam: an :class:`openquake.commonlib.oqvalidation.OqParam` instance """ if oqparam.sites: lons, lats = zip(*sorted(oqparam.sites)) return geo.Mesh(numpy.array(lons), numpy.array(lats)) elif 'sites' in oqparam.inputs: csv_data = open(oqparam.inputs['sites'], 'U').read() coords = valid.coordinates(csv_data.strip().replace(',', ' ').replace( '\n', ',')) lons, lats = zip(*sorted(coords)) return geo.Mesh(numpy.array(lons), numpy.array(lats)) elif oqparam.region: # close the linear polygon ring by appending the first # point to the end firstpoint = geo.Point(*oqparam.region[0]) points = [geo.Point(*xy) for xy in oqparam.region] + [firstpoint] try: mesh = geo.Polygon(points).discretize(oqparam.region_grid_spacing) lons, lats = zip(*sorted(zip(mesh.lons, mesh.lats))) return geo.Mesh(numpy.array(lons), numpy.array(lats)) except: raise ValueError( 'Could not discretize region %(region)s with grid spacing ' '%(region_grid_spacing)s' % vars(oqparam)) elif 'site_model' in oqparam.inputs: coords = [(param.lon, param.lat) for param in get_site_model(oqparam)] lons, lats = zip(*sorted(coords)) return geo.Mesh(numpy.array(lons), numpy.array(lats))
def setUp(self): self.corners = [ geo.Point(-10, 10), geo.Point(10, 10), geo.Point(10, -10), geo.Point(-10, -10), ] self.poly = geo.Polygon(self.corners)
def get_mesh(oqparam): """ Extract the mesh of points to compute from the sites, the sites_csv, or the region. :param oqparam: an :class:`openquake.commonlib.oqvalidation.OqParam` instance """ global pmap, exposure if 'exposure' in oqparam.inputs and exposure is None: # read it only once exposure = get_exposure(oqparam) if oqparam.sites: return geo.Mesh.from_coords(oqparam.sites) elif 'sites' in oqparam.inputs: csv_data = open(oqparam.inputs['sites'], 'U').readlines() has_header = csv_data[0].startswith('site_id') if has_header: # strip site_id data = [] for i, line in enumerate(csv_data[1:]): row = line.replace(',', ' ').split() sid = row[0] if sid != str(i): raise InvalidFile('%s: expected site_id=%d, got %s' % ( oqparam.inputs['sites'], i, sid)) data.append(' '.join(row[1:])) elif 'gmfs' in oqparam.inputs: raise InvalidFile('Missing header in %(sites)s' % oqparam.inputs) else: data = [line.replace(',', ' ') for line in csv_data] coords = valid.coordinates(','.join(data)) start, stop = oqparam.sites_slice c = coords[start:stop] if has_header else sorted(coords[start:stop]) # TODO: sort=True below would break a lot of tests :-( return geo.Mesh.from_coords(c, sort=False) elif 'hazard_curves' in oqparam.inputs: fname = oqparam.inputs['hazard_curves'] if fname.endswith('.csv'): mesh, pmap = get_pmap_from_csv(oqparam, fname) elif fname.endswith('.xml'): mesh, pmap = get_pmap_from_nrml(oqparam, fname) else: raise NotImplementedError('Reading from %s' % fname) return mesh elif oqparam.region: # close the linear polygon ring by appending the first # point to the end firstpoint = geo.Point(*oqparam.region[0]) points = [geo.Point(*xy) for xy in oqparam.region] + [firstpoint] try: mesh = geo.Polygon(points).discretize(oqparam.region_grid_spacing) return geo.Mesh.from_coords(zip(mesh.lons, mesh.lats)) except: raise ValueError( 'Could not discretize region %(region)s with grid spacing ' '%(region_grid_spacing)s' % vars(oqparam)) elif 'exposure' in oqparam.inputs: return exposure.mesh
def get_mesh(oqparam): """ Extract the mesh of points to compute from the sites, the sites_csv, or the region. :param oqparam: an :class:`openquake.commonlib.oqvalidation.OqParam` instance """ if oqparam.sites: return geo.Mesh.from_coords(sorted(oqparam.sites)) elif 'sites' in oqparam.inputs: csv_data = open(oqparam.inputs['sites'], 'U').readlines() has_header = csv_data[0].startswith('site_id') if has_header: # strip site_id data = [] for i, line in enumerate(csv_data[1:]): row = line.replace(',', ' ').split() sid = row[0] if sid != str(i): raise InvalidFile('%s: expected site_id=%d, got %s' % ( oqparam.inputs['sites'], i, sid)) data.append(' '.join(row[1:])) elif oqparam.calculation_mode == 'gmf_ebrisk': raise InvalidFile('Missing header in %(sites)s' % oqparam.inputs) else: data = [line.replace(',', ' ') for line in csv_data] coords = valid.coordinates(','.join(data)) start, stop = oqparam.sites_slice c = coords[start:stop] if has_header else sorted(coords[start:stop]) return geo.Mesh.from_coords(c) elif oqparam.region: # close the linear polygon ring by appending the first # point to the end firstpoint = geo.Point(*oqparam.region[0]) points = [geo.Point(*xy) for xy in oqparam.region] + [firstpoint] try: mesh = geo.Polygon(points).discretize(oqparam.region_grid_spacing) lons, lats = zip(*sorted(zip(mesh.lons, mesh.lats))) return geo.Mesh(numpy.array(lons), numpy.array(lats)) except: raise ValueError( 'Could not discretize region %(region)s with grid spacing ' '%(region_grid_spacing)s' % vars(oqparam)) elif oqparam.hazard_calculation_id: sitecol = datastore.read(oqparam.hazard_calculation_id)['sitecol'] return geo.Mesh(sitecol.lons, sitecol.lats, sitecol.depths) elif 'exposure' in oqparam.inputs: # the mesh is extracted from get_sitecol_assetcol return elif 'site_model' in oqparam.inputs: coords = [(param.lon, param.lat, param.depth) for param in get_site_model(oqparam)] mesh = geo.Mesh.from_coords(sorted(coords)) mesh.from_site_model = True return mesh
def test_valid_points(self): points = [geo.Point(170, -10), geo.Point(170, 10), geo.Point(176, 0), geo.Point(-170, -5), geo.Point(-175, -10), geo.Point(-178, -6)] poly = geo.Polygon(points) self.assertEqual(len(poly.lons), 6) self.assertEqual(len(poly.lats), 6) self.assertEqual(list(poly.lons), [170, 170, 176, -170, -175, -178]) self.assertEqual(list(poly.lats), [-10, 10, 0, -5, -10, -6]) self.assertEqual(poly.lons.dtype, 'float') self.assertEqual(poly.lats.dtype, 'float')
def area_source_to_point_sources(area_src, area_src_disc): """ Split an area source into a generator of point sources. MFDs will be rescaled appropriately for the number of points in the area mesh. :param area_src: :class:`openquake.nrmllib.models.AreaSource` :param float area_src_disc: Area source discretization step, in kilometers. """ shapely_polygon = wkt.loads(area_src.geometry.wkt) area_polygon = geo.Polygon( # We ignore the last coordinate in the sequence here, since it is a # duplicate of the first. hazardlib will close the loop for us. [geo.Point(*x) for x in list(shapely_polygon.exterior.coords)[:-1]]) mesh = area_polygon.discretize(area_src_disc) num_points = len(mesh) area_mfd = area_src.mfd if isinstance(area_mfd, nrml_models.TGRMFD): new_a_val = math.log10(10**area_mfd.a_val / float(num_points)) new_mfd = nrml_models.TGRMFD(a_val=new_a_val, b_val=area_mfd.b_val, min_mag=area_mfd.min_mag, max_mag=area_mfd.max_mag) elif isinstance(area_mfd, nrml_models.IncrementalMFD): new_occur_rates = [float(x) / num_points for x in area_mfd.occur_rates] new_mfd = nrml_models.IncrementalMFD(min_mag=area_mfd.min_mag, bin_width=area_mfd.bin_width, occur_rates=new_occur_rates) for i, (lon, lat) in enumerate(izip(mesh.lons, mesh.lats)): pt = nrml_models.PointSource( # Generate a new ID and name id='%s-%s' % (area_src.id, i), name='%s-%s' % (area_src.name, i), trt=area_src.trt, geometry=nrml_models.PointGeometry( upper_seismo_depth=area_src.geometry.upper_seismo_depth, lower_seismo_depth=area_src.geometry.lower_seismo_depth, wkt='POINT(%s %s)' % (lon, lat)), mag_scale_rel=area_src.mag_scale_rel, rupt_aspect_ratio=area_src.rupt_aspect_ratio, mfd=new_mfd, nodal_plane_dist=area_src.nodal_plane_dist, hypo_depth_dist=area_src.hypo_depth_dist) yield pt
def _area_to_hazardlib(src, mesh_spacing, bin_width, area_src_disc): """Convert a NRML area source to the HazardLib equivalent. See :mod:`openquake.nrmllib.models` and :mod:`openquake.hazardlib.source`. :param src: :class:`openquake.nrmllib.models.PointSource` instance. :param float mesh_spacing: Rupture mesh spacing, in km. :param float bin_width: Truncated Gutenberg-Richter MFD (Magnitude Frequency Distribution) bin width. :param float area_src_disc: Area source discretization, in km. Applies only to area sources. :returns: The HazardLib representation of the input source. """ shapely_polygon = wkt.loads(src.geometry.wkt) hazardlib_polygon = geo.Polygon( # We ignore the last coordinate in the sequence here, since it is a # duplicate of the first. hazardlib will close the loop for us. [geo.Point(*x) for x in list(shapely_polygon.exterior.coords)[:-1]]) mf_dist = _mfd_to_hazardlib(src.mfd, bin_width) # nodal plane distribution: npd = pmf.PMF([(x.probability, geo.NodalPlane(strike=x.strike, dip=x.dip, rake=x.rake)) for x in src.nodal_plane_dist]) # hypocentral depth distribution: hd = pmf.PMF([(x.probability, x.depth) for x in src.hypo_depth_dist]) msr = scalerel.get_available_magnitude_scalerel()[src.mag_scale_rel]() area = source.AreaSource( source_id=src.id, name=src.name, tectonic_region_type=src.trt, mfd=mf_dist, rupture_mesh_spacing=mesh_spacing, magnitude_scaling_relationship=msr, rupture_aspect_ratio=src.rupt_aspect_ratio, upper_seismogenic_depth=src.geometry.upper_seismo_depth, lower_seismogenic_depth=src.geometry.lower_seismo_depth, nodal_plane_distribution=npd, hypocenter_distribution=hd, polygon=hazardlib_polygon, area_discretization=area_src_disc) return area
def get_mesh(oqparam): """ Extract the mesh of points to compute from the sites, the sites_csv, or the region. :param oqparam: an :class:`openquake.commonlib.oqvalidation.OqParam` instance """ if oqparam.sites: return geo.Mesh.from_coords(oqparam.sites) elif 'sites' in oqparam.inputs: csv_data = open(oqparam.inputs['sites'], 'U').read() coords = valid.coordinates(csv_data.strip().replace(',', ' ').replace( '\n', ',')) start, stop = oqparam.sites_slice return geo.Mesh.from_coords(coords[start:stop]) elif oqparam.region: # close the linear polygon ring by appending the first # point to the end firstpoint = geo.Point(*oqparam.region[0]) points = [geo.Point(*xy) for xy in oqparam.region] + [firstpoint] try: mesh = geo.Polygon(points).discretize(oqparam.region_grid_spacing) lons, lats = zip(*sorted(zip(mesh.lons, mesh.lats))) return geo.Mesh(numpy.array(lons), numpy.array(lats)) except: raise ValueError( 'Could not discretize region %(region)s with grid spacing ' '%(region_grid_spacing)s' % vars(oqparam)) elif 'gmfs' in oqparam.inputs: return get_gmfs(oqparam)[0].mesh elif oqparam.hazard_calculation_id: sitecol = datastore.read(oqparam.hazard_calculation_id)['sitecol'] return geo.Mesh(sitecol.lons, sitecol.lats, sitecol.depths) elif 'exposure' in oqparam.inputs: # the mesh is extracted from get_sitecol_assetcol return elif 'site_model' in oqparam.inputs: coords = [(param.lon, param.lat, param.depth) for param in get_site_model(oqparam)] mesh = geo.Mesh.from_coords(coords) mesh.from_site_model = True return mesh
def validate_site_model(sm_nodes, mesh): """Given the geometry for a site model and the geometry of interest for the calculation (``mesh``, make sure the geometry of interest lies completely inside of the convex hull formed by the site model locations. If a point of interest lies directly on top of a vertex or edge of the site model area (a polygon), it is considered "inside" :param sm_nodes: Sequence of :class:`~openquake.engine.db.models.SiteModel` objects. :param mesh: A :class:`openquake.hazardlib.geo.mesh.Mesh` which represents the calculation points of interest. :raises: :exc:`RuntimeError` if the area of interest (given as a mesh) is not entirely contained by the site model. """ sm_mp = geometry.MultiPoint([(n.location.x, n.location.y) for n in sm_nodes]) sm_ch = sm_mp.convex_hull # Enlarging the area if the site model nodes # create a straight line with zero area. if sm_ch.area == 0: sm_ch = sm_ch.buffer(DILATION_ONE_METER) sm_poly = hazardlib_geo.Polygon( [hazardlib_geo.Point(*x) for x in sm_ch.exterior.coords]) # "Intersects" is the correct operation (not "contains"), since we're just # checking a collection of points (mesh). "Contains" would tell us if the # points are inside the polygon, but would return `False` if a point was # directly on top of a polygon edge or vertex. We want these points to be # included. intersects = sm_poly.intersects(mesh) if not intersects.all(): raise RuntimeError([ 'Sites of interest are outside of the site model coverage area.' ' This configuration is invalid.' ])
def test_no_points_outside_of_polygon(self): dist = 1e-4 points = [ geo.Point(0, 0), geo.Point(dist * 4.5, 0), geo.Point(dist * 4.5, -dist * 4.5), geo.Point(dist * 3.5, -dist * 4.5), geo.Point(dist * (4.5 - 0.8), -dist * 1.5), geo.Point(0, -dist * 1.5) ] poly = geo.Polygon(points) mesh = list(poly.discretize(mesh_spacing=1.1e-2)) self.assertEqual(mesh, [ geo.Point(dist, -dist), geo.Point(dist * 2, -dist), geo.Point(dist * 3, -dist), geo.Point(dist * 4, -dist), geo.Point(dist * 4, -dist * 2), geo.Point(dist * 4, -dist * 3), geo.Point(dist * 4, -dist * 4), ])
def test_polygon_on_international_date_line(self): MESH_SPACING = 10 bl = geo.Point(177, 40) bml = geo.Point(179, 40) bmr = geo.Point(-179, 40) br = geo.Point(-177, 40) tr = geo.Point(-177, 43) tmr = geo.Point(-179, 43) tml = geo.Point(179, 43) tl = geo.Point(177, 43) poly = geo.Polygon([bl, bml, bmr, br, tr, tmr, tml, tl]) mesh = list(poly.discretize(mesh_spacing=MESH_SPACING)) west = east = mesh[0] for point in mesh: if geo_utils.get_longitudinal_extent(point.longitude, west.longitude) > 0: west = point if geo_utils.get_longitudinal_extent(point.longitude, east.longitude) < 0: east = point self.assertLess(west.longitude, 177.15) self.assertGreater(east.longitude, -177.15)
from hmtk.sources import source_model, area_source from openquake.nrmllib import models from openquake.hazardlib import geo from decimal import Decimal a = area_source.mtkAreaSource(identifier = "01", name = "area source name", trt = "stable crust", geometry = geo.Polygon([geo.Point(-58.73, -10.33), geo.Point(-58.74, -13.54), geo.Point(-55.94, -13.59), geo.Point(-56.58, -10.31), geo.Point(-58.73, -10.33)]), upper_depth = "0", lower_depth = "30", mag_scale_rel = "WC1994", # default rupt_aspect_ratio = 1, mfd = models.TGRMFD(min_mag=3.0, max_mag=7.0, b_val=0.847, a_val=0.737), nodal_plane_dist = models.NodalPlane(Decimal('1.0'), strike=0., dip=90., rake=0.), hypo_depth_dist = None) #a.create_oqnrml_source
def assert_failed_creation(self, points, exc, msg): with self.assertRaises(exc) as ae: geo.Polygon(points) self.assertEqual(str(ae.exception), msg)