def test_create_fault_geometry(self): ''' Tests the creation of the fault geometry. Testing only behaviour for creating SimpleFaultSurface classes - not the values in the class (assumes nhlib implementation is correct) ''' # Case 1 - trace input as instance of nhlib.geo.line.Line class self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') trace_as_line = line.Line([point.Point(2.0, 3.0), point.Point(3.0, 2.0)]) self.fault_source.create_geometry(trace_as_line, 60., 0., 30.) self.assertIsInstance(self.fault_source.geometry, SimpleFaultSurface) # Case 2 - trace input as numpy array trace_as_array = np.array([[2.0, 3.0], [3.0, 2.0]]) self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') self.fault_source.create_geometry(trace_as_array, 60., 0., 30.) self.assertIsInstance(self.fault_source.geometry, SimpleFaultSurface) # Case 3 - raises error when something else is input with self.assertRaises(ValueError) as ver: self.fault_source.create_geometry('a bad input!', 60., 0., 30.) self.assertEqual(ver.exception.message, 'Unrecognised or unsupported geometry definition')
def test_select_within_fault_distance(self): ''' Tests the selection of events within a distance from the fault ''' # Set up catalouge self.catalogue = Catalogue() self.catalogue.data['longitude'] = np.arange(0., 5.5, 0.5) self.catalogue.data['latitude'] = np.arange(0., 5.5, 0.5) self.catalogue.data['depth'] = np.zeros(11, dtype=float) self.catalogue.data['eventID'] = np.arange(0, 11, 1) self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') trace_as_line = line.Line([point.Point(2.0, 3.0), point.Point(3.0, 2.0)]) self.fault_source.create_geometry(trace_as_line, 30., 0., 30.) selector0 = CatalogueSelector(self.catalogue) # Test 1 - simple case Joyner-Boore distance self.fault_source.select_catalogue(selector0, 40.) np.testing.assert_array_almost_equal( np.array([2., 2.5]), self.fault_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([2., 2.5]), self.fault_source.catalogue.data['latitude']) # Test 2 - simple case Rupture distance self.fault_source.catalogue = None self.fault_source.select_catalogue(selector0, 40., 'rupture') np.testing.assert_array_almost_equal( np.array([2.5]), self.fault_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([2.5]), self.fault_source.catalogue.data['latitude']) # Test 3 - for vertical fault ensure that Joyner-Boore distance # behaviour is the same as for rupture distance fault1 = mtkSimpleFaultSource('102', 'A vertical fault') fault1.create_geometry(trace_as_line, 90., 0., 30.) self.fault_source.create_geometry(trace_as_line, 90., 0., 30.) # Joyner-Boore self.fault_source.select_catalogue(selector0, 40.) # Rupture fault1.select_catalogue(selector0, 40., 'rupture') np.testing.assert_array_almost_equal( self.fault_source.catalogue.data['longitude'], fault1.catalogue.data['longitude']) np.testing.assert_array_almost_equal( self.fault_source.catalogue.data['latitude'], fault1.catalogue.data['latitude']) # The usual test to ensure error is raised when no events in catalogue self.catalogue = Catalogue() selector0 = CatalogueSelector(self.catalogue) with self.assertRaises(ValueError) as ver: self.fault_source.select_catalogue(selector0, 40.0) self.assertEqual(ver.exception.message, 'No events found in catalogue!')
def test_select_within_fault_distance(self): ''' Tests the selection of events within a distance from the fault ''' # Set up catalouge self.catalogue = Catalogue() self.catalogue.data['longitude'] = np.arange(0., 5.5, 0.5) self.catalogue.data['latitude'] = np.arange(0., 5.5, 0.5) self.catalogue.data['depth'] = np.zeros(11, dtype=float) self.catalogue.data['eventID'] = np.arange(0, 11, 1) self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') trace_as_line = line.Line( [point.Point(2.0, 3.0), point.Point(3.0, 2.0)]) self.fault_source.create_geometry(trace_as_line, 30., 0., 30.) selector0 = CatalogueSelector(self.catalogue) # Test 1 - simple case Joyner-Boore distance self.fault_source.select_catalogue(selector0, 40.) np.testing.assert_array_almost_equal( np.array([2., 2.5]), self.fault_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([2., 2.5]), self.fault_source.catalogue.data['latitude']) # Test 2 - simple case Rupture distance self.fault_source.catalogue = None self.fault_source.select_catalogue(selector0, 40., 'rupture') np.testing.assert_array_almost_equal( np.array([2.5]), self.fault_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([2.5]), self.fault_source.catalogue.data['latitude']) # Test 3 - for vertical fault ensure that Joyner-Boore distance # behaviour is the same as for rupture distance fault1 = mtkSimpleFaultSource('102', 'A vertical fault') fault1.create_geometry(trace_as_line, 90., 0., 30.) self.fault_source.create_geometry(trace_as_line, 90., 0., 30.) # Joyner-Boore self.fault_source.select_catalogue(selector0, 40.) # Rupture fault1.select_catalogue(selector0, 40., 'rupture') np.testing.assert_array_almost_equal( self.fault_source.catalogue.data['longitude'], fault1.catalogue.data['longitude']) np.testing.assert_array_almost_equal( self.fault_source.catalogue.data['latitude'], fault1.catalogue.data['latitude']) # The usual test to ensure error is raised when no events in catalogue self.catalogue = Catalogue() selector0 = CatalogueSelector(self.catalogue) with self.assertRaises(ValueError) as ver: self.fault_source.select_catalogue(selector0, 40.0) self.assertEqual(ver.exception.message, 'No events found in catalogue!')
def parse_simple_fault_node(node, mfd_spacing=0.1, mesh_spacing=1.0): """ Parses a "simpleFaultSource" node and returns an instance of the :class: hmtk.sources.simple_fault.mtkSimpleFaultSource """ assert "simpleFaultSource" in node.tag sf_taglist = get_taglist(node) # Get metadata sf_id, name, trt = (node.attrib["id"], node.attrib["name"], node.attrib["tectonicRegion"]) # Process geometry trace, dip, upper_depth, lower_depth = node_to_simple_fault_geometry( node.nodes[sf_taglist.index("simpleFaultGeometry")]) # Process scaling relation msr = node_to_scalerel(node.nodes[sf_taglist.index("magScaleRel")]) # Process aspect ratio aspect = float_(node.nodes[sf_taglist.index("ruptAspectRatio")].text) # Process MFD mfd = node_to_mfd(node, sf_taglist) # Process rake rake = float_(node.nodes[sf_taglist.index("rake")].text) simple_fault = mtkSimpleFaultSource(sf_id, name, trt, geometry=None, dip=dip, upper_depth=upper_depth, lower_depth=lower_depth, mag_scale_rel=msr, rupt_aspect_ratio=aspect, mfd=mfd, rake=rake) simple_fault.create_geometry(trace, dip, upper_depth, lower_depth, mesh_spacing) return simple_fault
def _parse_simple(cls, src_elem, mesh_spacing): """ :param src_elem: :class:`lxml.etree._Element` instance representing a source. :returns: Fully populated :class:`openquake.nrmllib.models.SimpleFaultSource` object. """ # Instantiate with identifier and name simple = mtkSimpleFaultSource(src_elem.get('id'), src_elem.get('name')) print 'Simple Fault source - ID: %s, name: %s' % (simple.id, simple.name) # Set common attributes cls._set_common_attrs(simple, src_elem) # Create the simple geometry trace, dip, upper_depth, lower_depth = \ cls._parse_simple_geometry(src_elem) simple.create_geometry(trace, dip, upper_depth, lower_depth, mesh_spacing) #simple.geometry = simple_geom simple.mfd = cls._parse_mfd(src_elem) if _xpath(src_elem, './/nrml:rake')[0].text: simple.rake = float(_xpath(src_elem, './/nrml:rake')[0].text) return simple
def test_simple_fault_instantiation(self): """ Tests the core instantiation of the module """ # Simple instantiation - minimual data self.fault_source = mtkSimpleFaultSource("101", "A simple fault") self.assertListEqual(self.fault_source.__dict__.keys(), SOURCE_ATTRIBUTES) self.assertEqual(self.fault_source.id, "101") self.assertEqual(self.fault_source.name, "A simple fault") self.assertEqual(self.fault_source.typology, "SimpleFault") # Simple instantiation with dip self.fault_source = mtkSimpleFaultSource("101", "A simple fault", dip=60.0) self.assertAlmostEqual(self.fault_source.dip, 60.0) # Instantiation with an invalid dip range - raises AssertionError self.assertRaises(AssertionError, mtkSimpleFaultSource, identifier="101", name="A simple fault", dip=95.0)
def test_check_seismogenic_depths(self): """ Tests the check on seismogenic depths - behaviour different from equivalent function in area and point sources as simple faults cannot have an undefined lower seismogenic depth, and upper seismogenic depth with default to 0 if undefined """ self.fault_source = mtkSimpleFaultSource("101", "A simple fault") # Test 1 - Good case - upper and lower seismogenic depths defined self.fault_source._check_seismogenic_depths(2.0, 30.0) self.assertAlmostEqual(self.fault_source.upper_depth, 2.0) self.assertAlmostEqual(self.fault_source.lower_depth, 30.0) # Test 2 - Acceptable case - upper depth not defined, lower depth given self.fault_source._check_seismogenic_depths(None, 30.0) self.assertAlmostEqual(self.fault_source.upper_depth, 0.0) self.assertAlmostEqual(self.fault_source.lower_depth, 30.0) # Test 3 - Raises error when no lower depth is defined with self.assertRaises(ValueError) as ver: self.fault_source._check_seismogenic_depths(2.0, None) self.assertEqual(ver.exception.message, "Lower seismogenic depth must be defined for " "simple fault source!") # Test 4 - Raises error when lower depth is less than upper depth with self.assertRaises(ValueError) as ver: self.fault_source._check_seismogenic_depths(upper_depth=20.0, lower_depth=15.0) self.assertEqual( ver.exception.message, "Lower seismogenic depth must take a greater value" " than upper seismogenic depth" ) # Test 4 - Raises value error when upper depth is less than 0. with self.assertRaises(ValueError) as ver: self.fault_source._check_seismogenic_depths(upper_depth=-0.5, lower_depth=15.0) self.assertEqual(ver.exception.message, "Upper seismogenic depth must be greater than or " "equal to 0.0!")
def test_create_oqhazardlib_source(self): """ Tests to ensure the hazardlib source is created """ trace = line.Line([point.Point(10., 10.), point.Point(11., 10.)]) self.fault_source = mtkSimpleFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry = None, dip = 90., upper_depth = 0., lower_depth = 20., mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=models.TGRMFD(a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=0.) self.fault_source.create_geometry(trace, 90., 0., 20., 1.0) test_source = self.fault_source.create_oqhazardlib_source(TOM, 2.0, True) self.assertIsInstance(test_source, SimpleFaultSource) self.assertIsInstance(test_source.mfd, TruncatedGRMFD) self.assertAlmostEqual(test_source.mfd.b_val, 1.0) self.assertIsInstance(test_source.magnitude_scaling_relationship, WC1994)
def test_create_oqhazardlib_source(self): """ Tests to ensure the hazardlib source is created """ trace = line.Line([point.Point(10., 10.), point.Point(11., 10.)]) mfd1 = TruncatedGRMFD(5.0, 8.0, 0.1, 3.0, 1.0) self.fault_source = mtkSimpleFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry=None, dip=90., upper_depth=0., lower_depth=20., mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=mfd1, rake=0.) self.fault_source.create_geometry(trace, 90., 0., 20., 1.0) test_source = self.fault_source.create_oqhazardlib_source( TOM, 2.0, True) self.assertIsInstance(test_source, SimpleFaultSource) self.assertIsInstance(test_source.mfd, TruncatedGRMFD) self.assertAlmostEqual(test_source.mfd.b_val, 1.0) self.assertIsInstance(test_source.magnitude_scaling_relationship, WC1994)
def test_simple_fault_instantiation(self): # Tests the core instantiation of the module # Simple instantiation - minimual data self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') self.assertListEqual(sorted(self.fault_source.__dict__), sorted(SOURCE_ATTRIBUTES)) self.assertEqual(self.fault_source.id, '101') self.assertEqual(self.fault_source.name, 'A simple fault') self.assertEqual(self.fault_source.typology, 'SimpleFault') # Simple instantiation with dip self.fault_source = mtkSimpleFaultSource('101', 'A simple fault', dip=60.) self.assertAlmostEqual(self.fault_source.dip, 60.) # Instantiation with an invalid dip range - raises AssertionError self.assertRaises(AssertionError, mtkSimpleFaultSource, identifier='101', name='A simple fault', dip=95.)
def test_create_fault_geometry(self): # Tests the creation of the fault geometry. Testing only behaviour # for creating SimpleFaultSurface classes - not the values in the # class (assumes nhlib implementation is correct) # Case 1 - trace input as instance of nhlib.geo.line.Line class self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') trace_as_line = line.Line( [point.Point(2.0, 3.0), point.Point(3.0, 2.0)]) self.fault_source.create_geometry(trace_as_line, 60., 0., 30.) self.assertIsInstance(self.fault_source.geometry, SimpleFaultSurface) # Case 2 - trace input as numpy array trace_as_array = np.array([[2.0, 3.0], [3.0, 2.0]]) self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') self.fault_source.create_geometry(trace_as_array, 60., 0., 30.) self.assertIsInstance(self.fault_source.geometry, SimpleFaultSurface) # Case 3 - raises error when something else is input with self.assertRaises(ValueError) as ver: self.fault_source.create_geometry('a bad input!', 60., 0., 30.) self.assertEqual(str(ver.exception), 'Unrecognised or unsupported geometry definition')
def test_create_oqnmrl_simple_fault_source(self): ''' Tests the conversion of a point source to an instance of the :class: oqnrmllib.models.SimpleFaultSource ''' trace = line.Line([point.Point(10., 10.), point.Point(11., 10.)]) #sflt_geom = SimpleFaultSurface.from_fault_data(trace, 0., 20., 90., 1.) # Define a complete source self.fault_source = mtkSimpleFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry=None, dip=90., upper_depth=0., lower_depth=20., mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=models.TGRMFD( a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=0.) self.fault_source.create_geometry(trace, 90., 0., 20., 1.0) expected_geometry = models.SimpleFaultGeometry( wkt='LINESTRING (10.0 10.0, 11.0 10.0)', dip=90., upper_seismo_depth=0., lower_seismo_depth=20.) expected_source = models.SimpleFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry=expected_geometry, mag_scale_rel='WC1994', rupt_aspect_ratio=1.0, mfd=models.TGRMFD( a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=0.) test_source = self.fault_source.create_oqnrml_source(use_defaults=True) self.assertTrue(isinstance(test_source, models.SimpleFaultSource)) self.assertEqual(test_source.id, expected_source.id) self.assertEqual(test_source.name, expected_source.name) self.assertDictEqual(test_source.geometry.__dict__, expected_source.geometry.__dict__) self.assertAlmostEqual(test_source.mfd.b_val, expected_source.mfd.b_val)
def generate_fault_source_model(self): ''' Creates a resulting hmtk fault source set. :returns: source_model - list of instances of either the :class:`hmtk.sources.simple_fault_source.mtkSimpleFaultSource` or :class:`hmtk.sources.complex_fault_source.mtkComplexFaultSource` model_weight - Corresponding weights for each source model ''' source_model = [] model_weight = [] for iloc in range(0, self.get_number_mfd_models()): model_mfd = EvenlyDiscretizedMFD( self.mfd[0][iloc].min_mag, self.mfd[0][iloc].bin_width, self.mfd[0][iloc].occur_rates.tolist()) if isinstance(self.geometry, ComplexFaultGeometry): # Complex fault class source = mtkComplexFaultSource( self.id, self.name, self.trt, self.geometry.surface, self.mfd[2][iloc], self.rupt_aspect_ratio, model_mfd, self.rake) source.fault_edges = self.geometry.trace else: # Simple Fault source source = mtkSimpleFaultSource( self.id, self.name, self.trt, self.geometry.surface, self.geometry.dip, self.geometry.upper_depth, self.geometry.lower_depth, self.mfd[2][iloc], self.rupt_aspect_ratio, model_mfd, self.rake) source.fault_trace = self.geometry.trace source_model.append(source) model_weight.append(self.mfd[1][iloc]) return source_model, model_weight
def test_create_oqnmrl_simple_fault_source(self): ''' Tests the conversion of a point source to an instance of the :class: oqnrmllib.models.SimpleFaultSource ''' trace = line.Line([point.Point(10., 10.), point.Point(11., 10.)]) #sflt_geom = SimpleFaultSurface.from_fault_data(trace, 0., 20., 90., 1.) # Define a complete source self.fault_source = mtkSimpleFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry = None, dip = 90., upper_depth = 0., lower_depth = 20., mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=models.TGRMFD(a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=0.) self.fault_source.create_geometry(trace, 90., 0., 20., 1.0) expected_geometry = models.SimpleFaultGeometry( wkt='LINESTRING (10.0 10.0, 11.0 10.0)', dip=90., upper_seismo_depth=0., lower_seismo_depth=20.) expected_source = models.SimpleFaultSource( '001', 'A Fault Source', trt='Active Shallow Crust', geometry=expected_geometry, mag_scale_rel='WC1994', rupt_aspect_ratio=1.0, mfd=models.TGRMFD(a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=0.) test_source = self.fault_source.create_oqnrml_source(use_defaults=True) self.assertTrue(isinstance(test_source, models.SimpleFaultSource)) self.assertEqual(test_source.id, expected_source.id) self.assertEqual(test_source.name, expected_source.name) self.assertDictEqual(test_source.geometry.__dict__, expected_source.geometry.__dict__) self.assertAlmostEqual(test_source.mfd.b_val, expected_source.mfd.b_val)
def test_check_seismogenic_depths(self): ''' Tests the check on seismogenic depths - behaviour different from equivalent function in area and point sources as simple faults cannot have an undefined lower seismogenic depth, and upper seismogenic depth with default to 0 if undefined ''' self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') # Test 1 - Good case - upper and lower seismogenic depths defined self.fault_source._check_seismogenic_depths(2.0, 30.0) self.assertAlmostEqual(self.fault_source.upper_depth, 2.) self.assertAlmostEqual(self.fault_source.lower_depth, 30.) # Test 2 - Acceptable case - upper depth not defined, lower depth given self.fault_source._check_seismogenic_depths(None, 30.0) self.assertAlmostEqual(self.fault_source.upper_depth, 0.) self.assertAlmostEqual(self.fault_source.lower_depth, 30.) # Test 3 - Raises error when no lower depth is defined with self.assertRaises(ValueError) as ver: self.fault_source._check_seismogenic_depths(2., None) self.assertEqual( ver.exception.message, 'Lower seismogenic depth must be defined for ' 'simple fault source!') # Test 4 - Raises error when lower depth is less than upper depth with self.assertRaises(ValueError) as ver: self.fault_source._check_seismogenic_depths(upper_depth=20., lower_depth=15.) self.assertEqual( ver.exception.message, 'Lower seismogenic depth must take a greater value' ' than upper seismogenic depth') # Test 4 - Raises value error when upper depth is less than 0. with self.assertRaises(ValueError) as ver: self.fault_source._check_seismogenic_depths(upper_depth=-0.5, lower_depth=15.) self.assertEqual( ver.exception.message, 'Upper seismogenic depth must be greater than or ' 'equal to 0.0!')
def test_check_seismogenic_depths(self): # Tests the check on seismogenic depths - behaviour different from # equivalent function in area and point sources as simple faults cannot # have an undefined lower seismogenic depth, and upper seismogenic # depth with default to 0 if undefined self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') # Test 1 - Good case - upper and lower seismogenic depths defined self.fault_source._check_seismogenic_depths(2.0, 30.0) self.assertAlmostEqual(self.fault_source.upper_depth, 2.) self.assertAlmostEqual(self.fault_source.lower_depth, 30.) # Test 2 - Acceptable case - upper depth not defined, lower depth given self.fault_source._check_seismogenic_depths(None, 30.0) self.assertAlmostEqual(self.fault_source.upper_depth, 0.) self.assertAlmostEqual(self.fault_source.lower_depth, 30.) # Test 3 - Raises error when no lower depth is defined with self.assertRaises(ValueError) as ver: self.fault_source._check_seismogenic_depths(2., None) self.assertEqual(str(ver.exception), 'Lower seismogenic depth must be defined for ' 'simple fault source!') # Test 4 - Raises error when lower depth is less than upper depth with self.assertRaises(ValueError) as ver: self.fault_source._check_seismogenic_depths(upper_depth=20., lower_depth=15.) self.assertEqual(str(ver.exception), 'Lower seismogenic depth must take a greater value' ' than upper seismogenic depth') # Test 4 - Raises value error when upper depth is less than 0. with self.assertRaises(ValueError) as ver: self.fault_source._check_seismogenic_depths(upper_depth=-0.5, lower_depth=15.) self.assertEqual(str(ver.exception), 'Upper seismogenic depth must be greater than or ' 'equal to 0.0!')