def test_select_within_magnitude_range(self): ''' Tests the function to select within the magnitude range ''' # Setup function self.catalogue = Catalogue() self.catalogue.data['magnitude'] = np.array([4., 5., 6., 7., 8.]) selector0 = CatalogueSelector(self.catalogue) # Test case 1: No limits specified - all catalogue valid test_cat_1 = selector0.within_magnitude_range() np.testing.assert_array_almost_equal(test_cat_1.data['magnitude'], self.catalogue.data['magnitude']) # Test case 2: Lower depth limit specfied only test_cat_1 = selector0.within_magnitude_range(lower_mag=5.5) np.testing.assert_array_almost_equal(test_cat_1.data['magnitude'], np.array([6., 7., 8.])) # Test case 3: Upper depth limit specified only test_cat_1 = selector0.within_magnitude_range(upper_mag=5.5) np.testing.assert_array_almost_equal(test_cat_1.data['magnitude'], np.array([4., 5.])) # Test case 4: Both depth limits specified test_cat_1 = selector0.within_magnitude_range(upper_mag=7.5, lower_mag=5.5) np.testing.assert_array_almost_equal(test_cat_1.data['magnitude'], np.array([6., 7.]))
def test_select_within_polygon(self): # Tests the selection of points within polygon # Setup polygon nodes = np.array([[5.0, 6.0], [6.0, 6.0], [6.0, 5.0], [5.0, 5.0]]) polygon0 = Polygon([Point(nodes[iloc, 0], nodes[iloc, 1]) for iloc in range(0, 4)]) self.catalogue.data['longitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['latitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['depth'] = np.ones(7, dtype=float) # Simple case with nodes inside, outside and on the border of polygon selector0 = CatalogueSelector(self.catalogue) test_cat1 = selector0.within_polygon(polygon0) self.assertTrue(np.allclose(test_cat1.data['longitude'], np.array([5.0, 5.5, 6.0]))) self.assertTrue(np.allclose(test_cat1.data['latitude'], np.array([5.0, 5.5, 6.0]))) self.assertTrue(np.allclose(test_cat1.data['depth'], np.array([1.0, 1.0, 1.0]))) # CASE 2: As case 1 with one of the inside nodes outside of the depths self.catalogue.data['depth'] = \ np.array([1.0, 1.0, 1.0, 50.0, 1.0, 1.0, 1.0], dtype=float) selector0 = CatalogueSelector(self.catalogue) test_cat1 = selector0.within_polygon(polygon0, upper_depth=0.0, lower_depth=10.0) self.assertTrue(np.allclose(test_cat1.data['longitude'], np.array([5.0, 6.0]))) self.assertTrue(np.allclose(test_cat1.data['latitude'], np.array([5.0, 6.0]))) self.assertTrue(np.allclose(test_cat1.data['depth'], np.array([1.0])))
def test_select_within_depth_range(self): # Tests the function to select within the depth range # Setup function self.catalogue = Catalogue() self.catalogue.data['depth'] = np.array([5., 15., 25., 35., 45.]) selector0 = CatalogueSelector(self.catalogue) # Test case 1: No limits specified - all catalogue valid test_cat_1 = selector0.within_depth_range() np.testing.assert_array_almost_equal(test_cat_1.data['depth'], self.catalogue.data['depth']) # Test case 2: Lower depth limit specfied only test_cat_1 = selector0.within_depth_range(lower_depth=30.) np.testing.assert_array_almost_equal(test_cat_1.data['depth'], np.array([5., 15., 25.])) # Test case 3: Upper depth limit specified only test_cat_1 = selector0.within_depth_range(upper_depth=20.) np.testing.assert_array_almost_equal(test_cat_1.data['depth'], np.array([25., 35., 45.])) # Test case 4: Both depth limits specified test_cat_1 = selector0.within_depth_range(upper_depth=20., lower_depth=40.) np.testing.assert_array_almost_equal(test_cat_1.data['depth'], np.array([25., 35.]))
def test_catalogue_selection(self): # Tests the tools for selecting events within the catalogue self.catalogue.data['longitude'] = np.arange(1.,6., 1.) self.catalogue.data['latitude'] = np.arange(6., 11., 1.) self.catalogue.data['depth'] = np.ones(5, dtype=bool) # No events selected flag_none = np.zeros(5, dtype=bool) selector0 = CatalogueSelector(self.catalogue) test_cat1 = selector0.select_catalogue(flag_none) self.assertEqual(len(test_cat1.data['longitude']), 0) self.assertEqual(len(test_cat1.data['latitude']), 0) self.assertEqual(len(test_cat1.data['depth']), 0) # All events selected flag_all = np.ones(5, dtype=bool) test_cat1 = selector0.select_catalogue(flag_all) self.assertTrue(np.allclose(test_cat1.data['longitude'], self.catalogue.data['longitude'])) self.assertTrue(np.allclose(test_cat1.data['latitude'], self.catalogue.data['latitude'])) self.assertTrue(np.allclose(test_cat1.data['depth'], self.catalogue.data['depth'])) # Some events selected flag_1 = np.array([True, False, True, False, True]) test_cat1 = selector0.select_catalogue(flag_1) self.assertTrue(np.allclose(test_cat1.data['longitude'], np.array([1., 3., 5.]))) self.assertTrue(np.allclose(test_cat1.data['latitude'], np.array([6., 8., 10]))) self.assertTrue(np.allclose(test_cat1.data['depth'], np.array([1., 1., 1.])))
def test_select_within_time(self): # Tests the function to select within a time period self.catalogue.data['year'] = np.arange(1900, 2010, 20) self.catalogue.data['month'] = np.arange(1, 12, 2) self.catalogue.data['day'] = np.ones(6, dtype=int) self.catalogue.data['hour'] = np.ones(6, dtype=int) self.catalogue.data['minute'] = np.zeros(6, dtype=int) self.catalogue.data['second'] = np.ones(6, dtype=float) selector0 = CatalogueSelector(self.catalogue) # Start time and End time not defined test_cat_1 = selector0.within_time_period() self._compare_time_data_dictionaries(test_cat_1.data, self.catalogue.data) # Start time defined - end time not defined begin_time = datetime.datetime(1975, 1, 1, 0, 0, 0, 0) expected_data = {'year': np.array([1980, 2000]), 'month': np.array([9, 11]), 'day': np.array([1, 1]), 'hour': np.array([1, 1]), 'minute': np.array([0, 0]), 'second': np.array([1., 1.])} test_cat_1 = selector0.within_time_period(start_time=begin_time) self._compare_time_data_dictionaries(expected_data, test_cat_1.data) # Test 3 - Start time not defined, end-time defined finish_time = datetime.datetime(1965, 1, 1, 0, 0, 0, 0) expected_data = {'year': np.array([1900, 1920, 1940, 1960]), 'month': np.array([1, 3, 5, 7]), 'day': np.array([1, 1, 1, 1]), 'hour': np.array([1, 1, 1, 1]), 'minute': np.array([0, 0, 0, 0]), 'second': np.array([1., 1., 1., 1.])} test_cat_1 = selector0.within_time_period(end_time=finish_time) self._compare_time_data_dictionaries(expected_data, test_cat_1.data) # Test 4 - both start time and end-time defined begin_time = datetime.datetime(1935, 1, 1, 0, 0, 0, 0) finish_time = datetime.datetime(1995, 1, 1, 0, 0, 0, 0) expected_data = {'year': np.array([1940, 1960, 1980]), 'month': np.array([5, 7, 9]), 'day': np.array([1, 1, 1]), 'hour': np.array([1, 1, 1]), 'minute': np.array([0, 0, 0]), 'second': np.array([1., 1., 1.])} test_cat_1 = selector0.within_time_period(begin_time, finish_time) self._compare_time_data_dictionaries(expected_data, test_cat_1.data)
def main(argv): filename = argv[0] parser = CsvCatalogueParser(filename) cat = parser.read_file() output_path = './catalogue_ori.p' fou = open(output_path, 'wb') pickle.dump(cat, fou) fou.close() lomin = -180 lomax = +180 lamin = -90 lamax = +90 if len(argv) > 1: lomin = float(argv[1]) if len(argv) > 2: lomax = float(argv[2]) if len(argv) > 3: lamin = float(argv[3]) if len(argv) > 4: lamax = float(argv[4]) idxo = numpy.nonzero((cat.data['longitude'] >= lomin) & (cat.data['longitude'] <= lomax) & (cat.data['latitude'] >= lamin) & (cat.data['latitude'] <= lamax)) idxs = idxo[0].astype(int) boo = numpy.zeros_like(cat.data['magnitude'], dtype=int) boo[idxs] = 1 selector = CatalogueSelector(cat, create_copy=True) newcat = selector.select_catalogue(boo) output_path = './catalogue_ext.p' fou = open(output_path, 'wb') pickle.dump(newcat, fou) fou.close()
def set_catalogue(self, catalogue, bffer=75.): """ :param catalogue: An instance of :class:`openquake.hmtk.seismicity.catalogue.Catalogue` :param buffer: A float defining the maximum distance [km] from the cross-section used to select seismicity """ print('setting catalogue') _, _, _, _, qual = self.csec.get_mm() if qual == 1: idxs = self.csec.get_eqks_within_buffer_idl(catalogue, bffer) else: idxs = self.csec.get_eqks_within_buffer(catalogue, bffer) boo = numpy.zeros_like(catalogue.data['magnitude'], dtype=int) boo[idxs] = 1 selector = CatalogueSelector(catalogue, create_copy=True) newcat = selector.select_catalogue(boo) self.ecat = newcat
def test_select_within_time(self): # Tests the function to select within a time period self.catalogue.data['year'] = np.arange(1900, 2010, 20) self.catalogue.data['month'] = np.arange(1, 12, 2) self.catalogue.data['day'] = np.ones(6, dtype=int) self.catalogue.data['hour'] = np.ones(6, dtype=int) self.catalogue.data['minute'] = np.zeros(6, dtype=int) self.catalogue.data['second'] = np.ones(6, dtype=float) selector0 = CatalogueSelector(self.catalogue) # Start time and End time not defined test_cat_1 = selector0.within_time_period() self._compare_time_data_dictionaries(test_cat_1.data, self.catalogue.data) # Start time defined - end time not defined begin_time = datetime.datetime(1975, 1, 1, 0, 0, 0, 0) expected_data = { 'year': np.array([1980, 2000]), 'month': np.array([9, 11]), 'day': np.array([1, 1]), 'hour': np.array([1, 1]), 'minute': np.array([0, 0]), 'second': np.array([1., 1.]) } test_cat_1 = selector0.within_time_period(start_time=begin_time) self._compare_time_data_dictionaries(expected_data, test_cat_1.data) # Test 3 - Start time not defined, end-time defined finish_time = datetime.datetime(1965, 1, 1, 0, 0, 0, 0) expected_data = { 'year': np.array([1900, 1920, 1940, 1960]), 'month': np.array([1, 3, 5, 7]), 'day': np.array([1, 1, 1, 1]), 'hour': np.array([1, 1, 1, 1]), 'minute': np.array([0, 0, 0, 0]), 'second': np.array([1., 1., 1., 1.]) } test_cat_1 = selector0.within_time_period(end_time=finish_time) self._compare_time_data_dictionaries(expected_data, test_cat_1.data) # Test 4 - both start time and end-time defined begin_time = datetime.datetime(1935, 1, 1, 0, 0, 0, 0) finish_time = datetime.datetime(1995, 1, 1, 0, 0, 0, 0) expected_data = { 'year': np.array([1940, 1960, 1980]), 'month': np.array([5, 7, 9]), 'day': np.array([1, 1, 1]), 'hour': np.array([1, 1, 1]), 'minute': np.array([0, 0, 0]), 'second': np.array([1., 1., 1.]) } test_cat_1 = selector0.within_time_period(begin_time, finish_time) self._compare_time_data_dictionaries(expected_data, test_cat_1.data)
def test_point_in_circular_distance(self): # Tests point in circular distance self.catalogue.data['longitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['latitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['depth'] = np.ones(7, dtype=float) test_point = Point(5.5, 5.5) test_mesh = self.catalogue.hypocentres_as_mesh() selector0 = CatalogueSelector(self.catalogue) # Within 10 km test_cat_10 = selector0.circular_distance_from_point( test_point, 10., distance_type='epicentral') np.testing.assert_array_equal(test_cat_10.data['longitude'], np.array([5.5])) np.testing.assert_array_equal(test_cat_10.data['latitude'], np.array([5.5])) np.testing.assert_array_equal(test_cat_10.data['depth'], np.array([1.0])) # Within 100 km test_cat_100 = selector0.circular_distance_from_point( test_point, 100., distance_type='epicentral') np.testing.assert_array_equal(test_cat_100.data['longitude'], np.array([5.0, 5.5, 6.0])) np.testing.assert_array_equal(test_cat_100.data['latitude'], np.array([5.0, 5.5, 6.0])) np.testing.assert_array_equal(test_cat_100.data['depth'], np.array([1.0, 1.0, 1.0])) # Within 1000 km test_cat_1000 = selector0.circular_distance_from_point( test_point, 1000., distance_type='epicentral') np.testing.assert_array_equal(test_cat_1000.data['longitude'], self.catalogue.data['longitude']) np.testing.assert_array_equal(test_cat_1000.data['latitude'], self.catalogue.data['latitude']) np.testing.assert_array_equal(test_cat_1000.data['depth'], self.catalogue.data['depth'])
def test_cartesian_square_on_point(self): # Tests the cartesian square centres on point self.catalogue.data['longitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['latitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['depth'] = np.ones(7, dtype=float) test_point = Point(5.5, 5.5) test_mesh = self.catalogue.hypocentres_as_mesh() selector0 = CatalogueSelector(self.catalogue) # Within 10 km test_cat_10 = selector0.cartesian_square_centred_on_point( test_point, 10., distance_type='epicentral') np.testing.assert_array_equal(test_cat_10.data['longitude'], np.array([5.5])) np.testing.assert_array_equal(test_cat_10.data['latitude'], np.array([5.5])) np.testing.assert_array_equal(test_cat_10.data['depth'], np.array([1.0])) # Within 100 km test_cat_100 = selector0.cartesian_square_centred_on_point( test_point, 100., distance_type='epicentral') np.testing.assert_array_almost_equal( test_cat_100.data['longitude'], np.array([5.0, 5.5, 6.0])) np.testing.assert_array_almost_equal( test_cat_100.data['latitude'], np.array([5.0, 5.5, 6.0])) np.testing.assert_array_almost_equal( test_cat_100.data['depth'], np.array([1.0, 1.0, 1.0])) # Within 1000 km test_cat_1000 = selector0.cartesian_square_centred_on_point( test_point, 1000., distance_type='epicentral') np.testing.assert_array_almost_equal( test_cat_1000.data['longitude'], self.catalogue.data['longitude']) np.testing.assert_array_almost_equal( test_cat_1000.data['latitude'], self.catalogue.data['latitude']) np.testing.assert_array_almost_equal( test_cat_1000.data['depth'], self.catalogue.data['depth'])
def test_select_within_distance(self): ''' Tests the selection of earthquakes within distance of fault ''' # Create fault self.fault_source = mtkComplexFaultSource('101', 'A complex fault') # Test case when input as list of nhlib.geo.line.Line self.fault_source.create_geometry(self.trace_line, mesh_spacing=2.0) self.assertIsInstance(self.fault_source.geometry, ComplexFaultSurface) # Create simple catalogue self.catalogue.data['longitude'] = np.arange(0., 4.1, 0.1) self.catalogue.data['latitude'] = np.arange(0., 4.1, 0.1) self.catalogue.data['depth'] = np.ones(41, dtype=float) self.catalogue.data['eventID'] = np.arange(0, 41, 1) selector0 = CatalogueSelector(self.catalogue) # Test when considering Joyner-Boore distance self.fault_source.select_catalogue(selector0, 50.) np.testing.assert_array_equal( self.fault_source.catalogue.data['eventID'], np.arange(2, 14, 1)) # Test when considering rupture distance self.fault_source.select_catalogue(selector0, 50., 'rupture') np.testing.assert_array_equal( self.fault_source.catalogue.data['eventID'], np.arange(2, 12, 1)) # 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(str(ver.exception), 'No events found in catalogue!')
def get_catalogue(cat_pickle_fname, treg_filename, label): """ :param cat_pickle_fname: :param treg_filename: :param label: """ # # loading TR if treg_filename is not None: f = h5py.File(treg_filename, 'r') tr = f[label][:] f.close() # # loading the catalogue # catalogue = pickle.load(open(cat_pickle_fname, 'rb')) catalogue = load_catalogue(cat_pickle_fname) catalogue.sort_catalogue_chronologically() # # if a label and a TR are provided we filter the catalogue if treg_filename is not None: selector = CatalogueSelector(catalogue, create_copy=False) catalogue = selector.select_catalogue(tr) return catalogue
def test_within_rupture_distance(self): # Tests the function to select within Joyner-Boore distance self.catalogue.data['longitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['latitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['depth'] = np.ones(7, dtype=float) selector0 = CatalogueSelector(self.catalogue) # Construct Fault trace0 = np.array([[5.5, 6.0], [5.5, 5.0]]) fault_trace = Line([Point(trace0[i, 0], trace0[i, 1]) for i in range(0, 2)]) # Simple fault with vertical dip fault0 = SimpleFaultSurface.from_fault_data(fault_trace, 0., 20., 90., 1.) # Within 100 km test_cat_100 = selector0.within_rupture_distance(fault0, 100.) np.testing.assert_array_almost_equal( test_cat_100.data['longitude'], np.array([5.0, 5.5, 6.0])) np.testing.assert_array_almost_equal( test_cat_100.data['latitude'], np.array([5.0, 5.5, 6.0])) np.testing.assert_array_almost_equal( test_cat_100.data['depth'], np.array([1.0, 1.0, 1.0])) # Simple fault with 30 degree dip fault0 = SimpleFaultSurface.from_fault_data( fault_trace, 0., 20., 30., 1.) # Within 100 km test_cat_100 = selector0.within_rupture_distance(fault0, 100.) np.testing.assert_array_almost_equal( test_cat_100.data['longitude'], np.array([4.5, 5.0, 5.5, 6.0])) np.testing.assert_array_almost_equal( test_cat_100.data['latitude'], np.array([4.5, 5.0, 5.5, 6.0])) np.testing.assert_array_almost_equal( test_cat_100.data['depth'], np.array([1.0, 1.0, 1.0, 1.0]))
def test_create_cluster_set(self): """ """ # Setup function self.catalogue = Catalogue() self.catalogue.data["EventID"] = np.array([1, 2, 3, 4, 5, 6]) self.catalogue.data["magnitude"] = np.array([7.0, 5.0, 5.0, 5.0, 4.0, 4.0]) selector0 = CatalogueSelector(self.catalogue) vcl = np.array([0, 1, 1, 1, 2, 2]) cluster_set = selector0.create_cluster_set(vcl) np.testing.assert_array_equal(cluster_set[0].data["EventID"], np.array([1])) np.testing.assert_array_almost_equal(cluster_set[0].data["magnitude"], np.array([7.0])) np.testing.assert_array_equal(cluster_set[1].data["EventID"], np.array([2, 3, 4])) np.testing.assert_array_almost_equal(cluster_set[1].data["magnitude"], np.array([5.0, 5.0, 5.0])) np.testing.assert_array_equal(cluster_set[2].data["EventID"], np.array([5, 6])) np.testing.assert_array_almost_equal(cluster_set[2].data["magnitude"], np.array([4.0, 4.0]))
def test_select_events_in_circular_distance(self): # Basic test of method to select events within a distance of the point self.point_source = mtkPointSource('101', 'A Point Source') simple_point = Point(4.5, 4.5) self.catalogue.data['eventID'] = np.arange(0, 7, 1) self.catalogue.data['longitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['latitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['depth'] = np.ones(7, dtype=float) # Simple Case - 100 km epicentral distance selector0 = CatalogueSelector(self.catalogue) self.point_source.create_geometry(simple_point, 0., 30.) self.point_source.select_catalogue_within_distance(selector0, 100., 'epicentral') np.testing.assert_array_almost_equal( np.array([0, 1, 2]), self.point_source.catalogue.data['eventID']) np.testing.assert_array_almost_equal( np.array([4., 4.5, 5.]), self.point_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([4., 4.5, 5.]), self.point_source.catalogue.data['latitude']) np.testing.assert_array_almost_equal( np.array([1., 1., 1.]), self.point_source.catalogue.data['depth']) # Simple case - 100 km hypocentral distance (hypocentre at 70 km) self.point_source.select_catalogue_within_distance( selector0, 100., 'hypocentral', 70.) np.testing.assert_array_almost_equal( np.array([1]), self.point_source.catalogue.data['eventID']) np.testing.assert_array_almost_equal( np.array([4.5]), self.point_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([4.5]), self.point_source.catalogue.data['latitude']) np.testing.assert_array_almost_equal( np.array([1.]), self.point_source.catalogue.data['depth'])
def test_select_events_within_cell(self): # Tests the selection of events within a cell centred on the point self.point_source = mtkPointSource('101', 'A Point Source') simple_point = Point(4.5, 4.5) self.point_source.create_geometry(simple_point, 0., 30.) self.catalogue = Catalogue() self.catalogue.data['eventID'] = np.arange(0, 7, 1) self.catalogue.data['longitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['latitude'] = np.arange(4.0, 7.5, 0.5) self.catalogue.data['depth'] = np.ones(7, dtype=float) selector0 = CatalogueSelector(self.catalogue) # Simple case - 200 km by 200 km cell centred on point self.point_source.select_catalogue_within_cell(selector0, 100.) np.testing.assert_array_almost_equal( np.array([4., 4.5, 5.]), self.point_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([4., 4.5, 5.]), self.point_source.catalogue.data['latitude']) np.testing.assert_array_almost_equal( np.array([1., 1., 1.]), self.point_source.catalogue.data['depth'])
def create_sub_catalogue(alen, aaa, pck_fname, treg_fname, out_cata, out_path): """ Creates .csv files with the subcatalogues :param alen: Number of earthquakes in the original catalogue :param aaa: List of the labels used to define the various tectonic regions :param pck_fname: Name of the file with the pickled catalogue :param treg_fname: Name of the .hdf5 file with the classification of the catalogue :param out_cata: Name of the .hdf5 file with the classification of the catalogue :param out_path: Name of the .hdf5 file with the classification of the catalogue :returns: A :class:`numpy.ndarray` vector of length N where N is the number of earthquakes in the original catalogue. """ # The output vector tot_lab = np.zeros(alen) print(' ') fmt = '# earthquakes in the catalogue: {:d}' print(fmt.format(len(tot_lab))) # Loop over the tectonic regions for label in (aaa): # Output file name csv_filename = out_cata + "_TR_{:s}.csv".format(label) csv_filename = os.path.join(out_path, csv_filename) # Read the TR classification f = h5py.File(treg_fname, 'r') tr = f[label][:] f.close() if sum(tr) > 0: tmp_lab = tr * 1 tot_lab = tot_lab + tmp_lab catalogue = pickle.load(open(pck_fname, 'rb')) for lab in ['month', 'day', 'hour', 'minute', 'second']: idx = np.isnan(catalogue.data[lab]) if lab == 'day' or lab == 'month': catalogue.data[lab][idx] = 1 elif lab == 'second': catalogue.data[lab][idx] = 0.0 else: catalogue.data[lab][idx] = 0 selector = CatalogueSelector(catalogue, create_copy=False) catalogue = selector.select_catalogue(tr) catalogue.data['hour'] = catalogue.data['hour'].astype(int) catalogue.data['minute'] = catalogue.data['minute'].astype(int) print(' ') fmt = '# earthquakes in this TR : {:d}' print(fmt.format(len(catalogue.data['longitude']))) # Sub-catalogue print(csv_filename) csvcat = CsvCatalogueWriter(csv_filename) # Write the purged catalogue csvcat.write_file(catalogue) print("Catalogue successfully written to %s" % csv_filename) return tot_lab
def create_mtd(catalogue_fname, label, tr_fname, cumulative, store, mwid=0.1, twid=20., pmint=None, pmaxt=None, ylim=None): """ :param catalogue_fname: :param label: :param tr_fname: """ mwid = float(mwid) twid = float(twid) if pmint is not None: pmint = int(pmint) if pmaxt is not None: pmaxt = int(pmaxt) # # loading catalogue if isinstance(catalogue_fname, str): cat = _load_catalogue(catalogue_fname) elif isinstance(catalogue_fname, Catalogue): cat = catalogue_fname else: raise ValueError('Unknown instance') # Check catalogue if cat is None or len(cat.data['magnitude']) < 1: return None # Select earthquakes belonging to a given TR idx = numpy.full(cat.data['magnitude'].shape, True, dtype=bool) if label is not None and tr_fname is not None: f = h5py.File(tr_fname, 'r') idx = f[label][:] f.close() # # select catalogue sel = CatalogueSelector(cat, create_copy=False) sel.select_catalogue(idx) start = datetime.datetime(pmint, 1, 1) if pmint is not None else None stop = datetime.datetime(pmaxt, 12, 31) if pmaxt is not None else None sel.within_time_period(start, stop) # Check if the catalogue contains earthquakes if len(cat.data['magnitude']) < 1: return None # Get matrix bins_time, bins_ma, his = get_mtd(cat, mwid, twid, ylim, cumulative) # Plotting fig = plt.figure() ax = fig.add_subplot(1, 1, 1) X, Y = numpy.meshgrid(bins_time, bins_ma) tmp_col = colors.LogNorm(vmin=1e-1, vmax=his.max()) pcm = ax.pcolormesh(X, Y, his, norm=tmp_col, cmap='BuGn') # Plotting number of occurrences for it, vt in enumerate(bins_time[:-1]): for im, vm in enumerate(bins_ma[:-1]): ax.text(vt + twid / 2, vm + mwid / 2, '{:.0f}'.format(his[im, it]), fontsize=7, ha='center') # Plotting colorbar cb = fig.colorbar(pcm, ax=ax, extend='max') cb.set_label('Number of occurrences') # Finishing the plot plt.ylabel('Magnitude') plt.xlabel('Time') if label is not None: plt.title('label: {:s}'.format(label)) plt.grid(linestyle='-') return fig
def classify(self, compute_distances, remove_from): """ :param bool compute_distances: A boolean indicating if distances between earthquakes and the subduction surface should be computed. If False the distances stored in `self.distance_folder` will be used. :param list remove_from: A list of labels identifying TR from where the earthquakes assigned to this TR must be removed """ # # set parameters treg_filename = self.treg_filename distance_folder = self.distance_folder edges_folder = self.edges_folder distance_buffer_below = self.distance_buffer_below distance_buffer_above = self.distance_buffer_above catalogue_filename = self.catalogue_filename lower_depth = self.lower_depth if lower_depth is None: lower_depth = 400 # # open log file and prepare the group flog = h5py.File(self.log_fname, 'a') if self.label not in flog.keys(): grp = flog.create_group('/{:s}'.format(self.label)) else: grp = flog['/{:s}'.format(self.label)] # # read the catalogue catalogue = get_catalogue(catalogue_filename) neq = len(catalogue.data['longitude']) f = h5py.File(treg_filename, "a") if self.label in f.keys(): treg = f[self.label] else: treg = np.full((neq), False, dtype=bool) # # create the spatial index sidx = get_rtree_index(catalogue) # # build the complex fault surface tedges = _read_edges(edges_folder) surface = build_complex_surface_from_edges(edges_folder) mesh = surface.mesh # # create polygon encompassing the mesh plo = list(mesh.lons[0, :]) pla = list(mesh.lats[0, :]) # plo += list(mesh.lons[:, -1]) pla += list(mesh.lats[:, -1]) # plo += list(mesh.lons[-1, ::-1]) pla += list(mesh.lats[-1, ::-1]) # plo += list(mesh.lons[::-1, 0]) pla += list(mesh.lats[::-1, 0]) # # set variables used in griddata data = np.array([mesh.lons.flatten().T, mesh.lats.flatten().T]).T values = mesh.depths.flatten().T ddd = np.array([ mesh.lons.flatten().T, mesh.lats.flatten().T, mesh.depths.flatten() ]).T if self.label not in flog.keys(): grp.create_dataset('mesh', data=ddd) # # set bounding box of the subduction surface min_lo_sub = np.amin(mesh.lons) min_la_sub = np.amin(mesh.lats) max_lo_sub = np.amax(mesh.lons) max_la_sub = np.amax(mesh.lats) # # select earthquakes within the bounding box idxs = sorted( list( sidx.intersection( (min_lo_sub - DELTA, min_la_sub - DELTA, 0, max_lo_sub + DELTA, max_la_sub + DELTA, lower_depth)))) # # Select earthquakes within the bounding box of the surface # projection of the fault sidx = get_idx_points_inside_polygon(catalogue.data['longitude'][idxs], catalogue.data['latitude'][idxs], plo, pla, idxs, buff_distance=5000.) # # Select earthuakes and store indexes of selected ones ccc = [] idxs = [] for idx in sidx: # # Preselection based on magitude and time of occurrence if ((catalogue.data['magnitude'][idx] >= self.low_mag) & (catalogue.data['magnitude'][idx] <= self.upp_mag) & (catalogue.data['year'][idx] >= self.low_year) & (catalogue.data['year'][idx] <= self.upp_year)): idxs.append(idx) # # Update the log file ccc.append([ catalogue.data['longitude'][idx], catalogue.data['latitude'][idx], catalogue.data['depth'][idx] ]) if self.label not in flog.keys(): grp.create_dataset('cat', data=np.array(ccc)) # # Prepare array for the selection of the catalogue flags = np.full((len(catalogue.data['longitude'])), False, dtype=bool) flags[idxs] = True # # Create a selector for the catalogue and select earthquakes within # bounding box sel = CatalogueSelector(catalogue, create_copy=True) cat = sel.select_catalogue(flags) self.cat = cat # # If none of the earthquakes in the catalogue is in the bounding box # used for the selection we stop the processing if len(cat.data['longitude']) < 1: f = h5py.File(treg_filename, "a") if self.label in f.keys(): del f[self.label] f[self.label] = treg f.close() return # # compute distances between the earthquakes in the catalogue and # the surface of the fault out_filename = os.path.join(distance_folder, 'dist_{:s}.pkl'.format(self.label)) # # surf_dist = get_distances_from_surface(cat, surface) """ if compute_distances: tmps = 'Computing distances' logging.info(tmps.format(out_filename)) surf_dist = get_distances_from_surface(cat, surface) pickle.dump(surf_dist, open(out_filename, 'wb')) else: if not os.path.exists(out_filename): raise IOError('Distance file does not exist') surf_dist = pickle.load(open(out_filename, 'rb')) tmps = 'Loading distances from file: {:s}' logging.info(tmps.format(out_filename)) tmps = ' number of values loaded: {:d}' logging.info(tmps.format(len(surf_dist))) """ # # info neqks = len(cat.data['longitude']) tmps = 'Number of eqks in the new catalogue : {:d}' logging.info(tmps.format(neqks)) # # Calculate the depth of the top of the slab for every earthquake # location points = np.array( [[lo, la] for lo, la in zip(cat.data['longitude'], cat.data['latitude'])]) # # compute the depth of the top of the slab at every epicenter # sub_depths = griddata(data, values, (points[:, 0], points[:, 1]), # method='cubic') # # interpolation rbfi = Rbf(data[:, 0], data[:, 1], values) sub_depths = rbfi(points[:, 0], points[:, 1]) # # saving the distances to a file tmps = 'vert_dist_to_slab_{:s}.pkl'.format(self.label) out_filename = os.path.join(distance_folder, tmps) if not os.path.exists(out_filename): pickle.dump(surf_dist, open(out_filename, 'wb')) # # Let's find earthquakes close to the top of the slab idxa = np.nonzero((np.isfinite(surf_dist) & np.isfinite(sub_depths) & np.isfinite(cat.data['depth'])) & ( (surf_dist < distance_buffer_below) & (sub_depths > cat.data['depth'])) | ((surf_dist < distance_buffer_above) & (sub_depths <= cat.data['depth'])))[0] idxa = [] for srfd, subd, dept in zip(surf_dist, sub_depths, cat.data['depth']): if np.isfinite(srfd) & np.isfinite(subd) & np.isfinite(dept): if (float(srfd) < min(distance_buffer_below, distance_buffer_above) * 0.90): idxa.append(True) elif ((float(srfd) < distance_buffer_below) & (float(subd) < float(dept))): idxa.append(True) elif ((float(srfd) < distance_buffer_above) & (float(subd) >= float(dept))): idxa.append(True) else: idxa.append(False) else: idxa.append(False) idxa = np.array(idxa) # # checking the size of lists assert len(idxa) == len(cat.data['longitude']) == len(idxs) # # self.surf_dist = surf_dist self.sub_depths = sub_depths self.tedges = tedges self.idxa = idxa self.treg = treg # # tl = np.zeros(len(idxa), dtype={ 'names': ('lon', 'lat', 'dep', 'subd', 'srfd', 'idx'), 'formats': ('f8', 'f8', 'f8', 'f8', 'f8', 'i4') }) tl['lon'] = cat.data['longitude'] tl['lat'] = cat.data['latitude'] tl['dep'] = cat.data['depth'] tl['subd'] = sub_depths tl['srfd'] = surf_dist tl['idx'] = idxa # # store log data if self.label not in flog.keys(): grp.create_dataset('data', data=np.array(tl)) # # updating the selection array for uuu, iii in enumerate(list(idxa)): aaa = idxs[uuu] assert catalogue.data['eventID'][aaa] == cat.data['eventID'][uuu] if iii: treg[aaa] = True else: treg[aaa] = False # # storing results in the .hdf5 file logging.info('Storing data in:\n{:s}'.format(treg_filename)) f = h5py.File(treg_filename, "a") if len(remove_from): fmt = ' treg: {:d}' logging.info(fmt.format(len(treg))) iii = np.nonzero(treg)[0] for tkey in remove_from: logging.info(' Cleaning {:s}'.format(tkey)) old = f[tkey][:] fmt = ' before: {:d}' logging.info(fmt.format(len(np.nonzero(old)[0]))) del f[tkey] old[iii] = False f[tkey] = old fmt = ' after: {:d}' logging.info(fmt.format(len(np.nonzero(old)[0]))) # # Removing the old classification and adding the new one if self.label in f.keys(): del f[self.label] f[self.label] = treg # # closing files f.close() flog.close()
def create_mtd(catalogue_fname, label, tr_fname, cumulative, store, mwid=0.1, twid=20., pmint=None, pmaxt=None, ylim=None): """ :param catalogue_fname: :param label: :param tr_fname: """ mwid = float(mwid) twid = float(twid) if pmint is not None: pmint = int(pmint) if pmaxt is not None: pmaxt = int(pmaxt) # # loading catalogue if isinstance(catalogue_fname, str): cat = _load_catalogue(catalogue_fname) elif isinstance(catalogue_fname, Catalogue): cat = catalogue_fname else: raise ValueError('Unknown instance') # Check catalogue if cat is None or len(cat.data['magnitude']) < 1: return None # Select earthquakes belonging to a given TR idx = numpy.full(cat.data['magnitude'].shape, True, dtype=bool) if label is not None and tr_fname is not None: f = h5py.File(tr_fname, 'r') idx = f[label][:] f.close() # # select catalogue sel = CatalogueSelector(cat, create_copy=False) sel.select_catalogue(idx) start = datetime.datetime(pmint, 1, 1) if pmint is not None else None stop = datetime.datetime(pmaxt, 12, 31) if pmaxt is not None else None sel.within_time_period(start, stop) # Check if the catalogue contains earthquakes if len(cat.data['magnitude']) < 1: return None # # find rounded min and max magnitude mmin, mmax = _get_extremes(cat.data['magnitude'], mwid) tmin, tmax = _get_extremes(cat.data['year'], twid) if ylim is not None: mmin = ylim[0] mmax = ylim[1] # # if pmint is None: pmint = tmin if pmaxt is None: pmaxt = tmax # # histogram bins_ma = numpy.arange(mmin, mmax + mwid * 0.01, mwid) bins_time = numpy.arange(tmin, tmax + twid * 0.01, twid) his, _, _ = numpy.histogram2d(cat.data['year'], cat.data['magnitude'], bins=(bins_time, bins_ma)) his = his.T # # complementary cumulative if cumulative: ccu = numpy.zeros_like(his) for i in range(his.shape[1]): cc = numpy.cumsum(his[::-1, i]) ccu[:, i] = cc[::-1] # # plotting fig = plt.figure() ax = fig.add_subplot(1, 1, 1) # # X, Y = numpy.meshgrid(bins_time, bins_ma) if cumulative: his = ccu pcm = ax.pcolormesh(X, Y, his, norm=colors.LogNorm(vmin=1e-1, vmax=his.max()), cmap='BuGn') # # plotting number of occurrences for it, vt in enumerate(bins_time[:-1]): for im, vm in enumerate(bins_ma[:-1]): ax.text(vt + twid / 2, vm + mwid / 2, '{:.0f}'.format(his[im, it]), fontsize=7, ha='center') # # plotting colorbar cb = fig.colorbar(pcm, ax=ax, extend='max') cb.set_label('Number of occurrences') # # finishing the plot plt.ylabel('Magnitude') plt.xlabel('Time') if label is not None: plt.title('label: {:s}'.format(label)) plt.grid(linestyle='-') return fig
def decluster(catalogue_hmtk_fname, declustering_meth, declustering_params, output_path, labels=None, tr_fname=None, subcatalogues=False, fmat='csv', olab='', save_af=False, out_fname_ext='', fix_defaults=False): """ :param str catalogue_hmtk_fname: Full path to the file containing the initial catalogue :param str declustering_meth: A string indicating the type of declustering :param dict declustering_params: Parameters required by the declustering algorithm :param str output_path: Folder where the output catalogue/s will be created :param list labels: It can be a string or a list of strings :param str tr_fname: An .hdf5 file containing the TR classification of the catalogue :param bool subcatalogues: When true creates subcatalogues per tectonic region :param str fmat: Can be either 'csv' or 'pkl' :param str olab: Optional label for output catalogues :param boolean save_af: Save aftershocks and foreshocks :param str out_fname_ext: String to be added to the putput filename :param str fix_defaults: Fix defaults values when missing """ # Check if the initial catalogue file exists msg = 'Catalogue {:s} is missing'.format(catalogue_hmtk_fname) assert os.path.exists(catalogue_hmtk_fname), msg # Create output filename lbl = 'all' if labels is not None and len(out_fname_ext) == 0: labels = [labels] if isinstance(labels, str) else labels if len(labels) < 2: lbl = labels[0] else: lbl = '-'.join([l for l in labels]) assert tr_fname is not None assert os.path.exists(tr_fname) ext = '_dec_{:s}_{:s}.{:s}'.format(olab, lbl, fmat) else: ext = '_dec_{:s}_{:s}.{:s}'.format(olab, out_fname_ext, fmat) # Output filename out_fname = Path(os.path.basename(catalogue_hmtk_fname)).stem+ext if output_path is not None: assert os.path.exists(output_path) else: output_path = os.path.dirname(catalogue_hmtk_fname) out_fname = os.path.abspath(os.path.join(output_path, out_fname)) # Read the catalogue and adding default values cat = _load_catalogue(catalogue_hmtk_fname) if fix_defaults: cat = _add_defaults(cat) cato = copy.deepcopy(cat) # Select earthquakes belonging to a given TR. When necessary combining # multiple TRs, use label <TR_1>,<TR_2>AND... idx = numpy.full(cat.data['magnitude'].shape, True, dtype=bool) sumchk = 0 if labels is not None and tr_fname is not None: f = h5py.File(tr_fname, 'r') idx = numpy.array([False for i in range(len(f[labels[0]]))]) for lab in labels: idx_tmp = f[lab][:] idx[numpy.where(idx_tmp.flatten())] = True print(lab, sum(idx_tmp.flatten())) sumchk += sum(idx_tmp.flatten()) f.close() idx = idx.flatten() # Filter catalogue num_eqks_sub = len(cat.data['magnitude']) if labels is not None: sel = CatalogueSelector(cat, create_copy=False) sel.select_catalogue(idx) num_eqks_sub = len(cat.data['magnitude']) assert sumchk == num_eqks_sub # Declustering vcl, flag = dec(declustering_params, declustering_meth, cat) # Save foreshocks and aftershocks catt = copy.deepcopy(cat) catt.select_catalogue_events(numpy.where(flag != 0)[0]) if save_af: ext = '_dec_af_{:s}_{:s}.{:s}'.format(olab, lbl, fmat) outfa_fname = Path(os.path.basename(catalogue_hmtk_fname)).stem+ext outfa_fname = os.path.abspath(os.path.join(output_path, outfa_fname)) # Select mainshocks cat.select_catalogue_events(numpy.where(flag == 0)[0]) tmps = 'Number of earthquakes in the original subcatalogue: {:d}' print('Total eqks : {:d}'.format(num_eqks_sub)) num_main = len(cat.data['magnitude']) num_foaf = len(catt.data['magnitude']) print('Mainshocks : {:d}'.format(num_main)) print('Fore/Aftershocks : {:d}'.format(num_foaf)) assert num_main + num_foaf == num_eqks_sub # Save output if fmat == 'csv': cat.write_catalogue(out_fname) print('Writing catalogue to file: {:s}'.format(out_fname)) if save_af: catt.write_catalogue(outfa_fname) elif fmat == 'pkl': fou = open(out_fname, 'wb') pickle.dump(cat, fou) fou.close() if save_af: fou = open(outfa_fname, 'wb') pickle.dump(catt, fou) fou.close() # Create subcatalogues icat = numpy.nonzero(idx)[0] if subcatalogues: f = h5py.File(tr_fname, 'r') for lab in labels: # # Select mainshocks in a given tectonic region jjj = numpy.where(flag == 0)[0] tmpi = numpy.full((len(idx)), False, dtype=bool) tmpi[icat[jjj.astype(int)]] = True idx_tmp = f[lab][:].flatten() kkk = numpy.logical_and(tmpi, idx_tmp) if save_af: jjj = numpy.where(flag != 0)[0] tmpi = numpy.full((len(idx)), False, dtype=bool) tmpi[icat[jjj.astype(int)]] = True idx_tmp = f[lab][:].flatten() jjj = numpy.logical_and(tmpi, idx_tmp) # # Create output catalogue tsel = CatalogueSelector(cato, create_copy=True) ooo = tsel.select_catalogue(kkk) if save_af: aaa = tsel.select_catalogue(jjj) # # Info tmps = 'Cat: {:s}\n' tmps += ' Earthquakes: {:5d} Mainshocks {:5d} {:4.1f}%' pct = sum(kkk)/sum(idx_tmp)*100. tmpr = ' mmin: {:5.2f} mmax {:5.2f}' tmpsum1 = int(sum(idx_tmp)) tmpsum2 = int(sum(kkk)) logging.info(tmps.format(lab, tmpsum1, tmpsum2, pct)) print(tmps.format(lab, tmpsum1, tmpsum2, pct)) print(tmpr.format(min(ooo.data['magnitude']), max(ooo.data['magnitude']))) # # Output filename ext = '_dec_{:s}_{:s}.{:s}'.format(olab, lab, fmat) tcat_fname = Path(os.path.basename(catalogue_hmtk_fname)).stem+ext tmps = os.path.join(output_path, tcat_fname) tcat_fname = os.path.abspath(tmps) if save_af: ext = '_dec_af_{:s}_{:s}.{:s}'.format(olab, lab, fmat) tcataf_fname = Path( os.path.basename(catalogue_hmtk_fname)).stem + ext tmps = os.path.join(output_path, tcataf_fname) tcataf_fname = os.path.abspath(tmps) # # Dumping data into the pickle file if ooo is not None: if fmat == 'csv': ooo.write_catalogue(tcat_fname) if save_af: aaa.write_catalogue(tcataf_fname) elif fmat == 'pkl': fou = open(tcat_fname, 'wb') pickle.dump(ooo, fou) fou.close() if save_af: fou = open(tcataf_fname, 'wb') pickle.dump(aaa, fou) fou.close() else: tstr = 'Catalogue for region {:s} is empty'.format(lab) logging.warning(tstr) f.close() outl = [out_fname] if save_af: outl.append(outfa_fname) return [out_fname]
def create_catalogue(model, catalogue, area_source_ids_list=None, polygon=None): """ Select earthquakes within the polygon delineating an area source :parameter model: An :class:`openquake.mbt.oqt_project.OQtModel` instance :parameter catalogue: A hmtk-formatted catalogue :parameter area_source_ids_list: The list of source ID to be used for the selection. The IDs are the ones of one or several sources in the `sources` attribute of the `model` instance. :parameter polygon: A polygon (used when the area_source_ids_list is None). :returns: Returns an hmtk-formatted catalogue containing only the earthquakes inside the polygon """ # # if area_source_ids_list is not None and len(area_source_ids_list) > 1: msg = 'We do not support the selection for multiple sources' raise ValueError(msg) # # if area_source_ids_list is not None: # Process the area source src_id = area_source_ids_list[0] src = model.sources[src_id] # Set the geometry if 'polygon' in src.__dict__: # The source has a polygon pass elif src_id in model.nrml_sources: # Set the polygon from nrml src.polygon = model.nrml_sources[src_id].polygon src.name = model.nrml_sources[src_id].name src.source_id = model.nrml_sources[src_id].source_id else: print('The source does not have a geometry assigned') return None elif polygon is not None: assert isinstance(polygon, Polygon) src_id = 'user_defined' src = OQtSource('id', 'AreaSource') src.name = 'dummy' src.polygon = polygon else: msg = 'Either a polygon or a list of src id must be defined' raise ValueError(msg) # # neqk = len(catalogue.data['longitude']) sel_idx = numpy.full((neqk), False, dtype=bool) pnt_idxs = [i for i in range(0, neqk)] idxs = get_idx_points_inside_polygon(catalogue.data['longitude'], catalogue.data['latitude'], src.polygon.lons, src.polygon.lats, pnt_idxs, buff_distance=0.) sel_idx[idxs] = True # # Select earthquakes cat = deepcopy(catalogue) selector = CatalogueSelector(cat, create_copy=False) selector.select_catalogue(sel_idx) # # set label labels = ['%s' % src_id for i in range(0, len(cat.data['longitude']))] cat.data['comment'] = labels # Complete the composite subcatalogue return cat
def plot_mfd(catalogue_fname, grd, label, store, tr_fname, compl_table=None, mwid=0.1, upper_mag=11., title='', xlim=None, ylim=None, figsize=None): """ This function plots the incremental and complementary cumulative distribution of the earthquakes included in a catalogue file. :param catalogue_fname: Full path to the hmtk formatted catalogue :param label: If the user provides a tectonic regionalisation file, this label (or list of labels with the format LAB1, LAB2) defines the tectonic regions to be selected. :param tr_fname: Full path to the .hdf5 file containing the TR :param compl_table: A :class:`numpy.ndarray` instance of shape (2, n) where the first column contains years in a decreasing order and the second column contains magnitude (generally) in an increasing order :param grd: A boolean indicating the need to compute GR parameters :param upper_mag: The upper magnitude threshold used to filter the catalogue. This is useful for example in cases when it is interesting to fit only the exponential component of a magnitude-frequency distribution. :return: A tuple containing the output of the Weichert method in the following order: gr_pars """ mwid = float(mwid) # # loading catalogue cat = _load_catalogue(catalogue_fname) # # select earthquakes belonging to a given TR idx = numpy.full(cat.data['magnitude'].shape, True, dtype=bool) if label is not None and tr_fname is not None: f = h5py.File(tr_fname, 'r') idx = f[label][:] f.close() # # select catalogue sel = CatalogueSelector(cat, create_copy=False) sel.select_catalogue(idx) sel.within_magnitude_range(-1, upper_mag) tmps = 'Selecting earthquakes below magnitude {:.2f}' logging.info(tmps.format(upper_mag)) # # find rounded min and max magnitude mmin, mmax = _get_extremes(cat.data['magnitude'], mwid) tmin, tmax = _get_extremes(cat.data['year'], 10) # # compute histogram bins = numpy.arange(mmin, mmax + mwid * 0.01, mwid) his, _ = numpy.histogram(cat.data['magnitude'], bins) # # plotting if figsize is None: figsize = (8, 6) fig = plt.figure(figsize=figsize) ax = fig.add_subplot(1, 1, 1) # # add cumulative plot cs = numpy.cumsum(his[::-1]) plt.bar(bins[:-1], cs[::-1], mwid, align='edge', ec='cyan', fc='none') plt.plot(bins[:-1] + mwid / 2, cs[::-1], '-r', label='cumulative') # # add incremental plot plt.bar(bins[:-1], his, mwid, align='edge', ec='orange', fc='none') plt.plot(bins[:-1] + mwid / 2, his, '-b', label='incremental') # # if grd: if compl_table is None: compl_table = numpy.array([[tmin, mmin]]) agr, bgr, asig, bsig = _compute_mfd(cat, compl_table, mwid) # # info num = len(cat.data['magnitude']) print('Number of earthquakes in the catalogue : {:d}'.format(num)) num = max(cs) print('Maximum value in the c. cumulative distribution : {:d}'.format(num)) # # finish plot plt.legend() plt.yscale('log') plt.ylabel('Number of earthquakes') plt.xlabel('Magnitude') if label is not None: plt.title('label: {:s}'.format(label)) plt.grid(linestyle='-') if grd: plt.text(0.65, 0.70, 'bval: %.3f (sigma=%.3f)' % (bgr, bsig), horizontalalignment='left', verticalalignment='center', fontsize=8, transform=ax.transAxes) plt.text(0.65, 0.75, 'aval: %.3f (sigma=%.3f)' % (agr, asig), horizontalalignment='left', verticalalignment='center', fontsize=8, transform=ax.transAxes) # # ascaled = numpy.log10(10**agr * (tmax - tmin)) v = 10.**(-bins * bgr + ascaled) plt.plot(bins, v, '--g', lw=2) # # set limits if xlim is not None: plt.xlim(xlim) if ylim is not None: plt.ylim(ylim) # # Set title plt.title(title) # # Storing figure if store is not None: lbl = '' ext = 'png' if label is not None: lbl = label figure_fname = 'fig_mfd_{:s}.{:s}'.format(lbl, ext) plt.savefig(figure_fname, format=ext) else: plt.show() out = (bins[:-1] + mwid / 2, numpy.array([float(h) for h in his])) if grd: return out, (agr, bgr, asig, bsig) else: return out, None