def example_propmatrix(): # Example using propagator matrix method crust = LayerProps(6.4, 3.8, 2.7, 38.0) mantle = LayerProps(8.2, 6.8, 3.3, np.nan) src_latlon = 20 * (np.random.random((5, 2)) - 0.5) + np.array([30, 160]) fs = 100.0 time_window = (-50, 150) generator_args = { 'station_latlon': (-20, 140), 'layerprops': [crust, mantle] } synthesize_dataset('propmatrix', 'test_prop_synth.h5', 'SY', 'AAA', src_latlon, fs, time_window, **generator_args)
def example_6(): # Example 6: Using custom MCMC solver on single-layer model. k_initial = np.mean((k_min, k_max)) model_initial_poor = np.array([34, Vp_c / k_initial]) Vp = [Vp_c] rho = [rho_c] fixed_args = (flux_comp, mantle_props, Vp, rho, FLUX_WINDOW) H_min, H_max = (25.0, 50.0) bounds = optimize.Bounds(np.array([H_min, Vp_c / k_max]), np.array([H_max, Vp_c / k_min])) # - Custom MCMC solver logging.info('Trying custom MCMC solver...') soln_mcmc = optimize_minimize_mhmcmc_cluster(objective_fn_wrapper, bounds, fixed_args, x0=model_initial_poor, T=0.025, burnin=500, maxiter=5000, collect_samples=2000, logger=logging) logging.info('Result:\n{}'.format(soln_mcmc)) # Run grid search purely for visualization purposes H_space = np.linspace(H_min, H_max, 51) k_space = np.linspace(k_min, k_max, 51) H, k, Esu = flux_comp.grid_search(mantle_props, [LayerProps(Vp_c, None, rho_c, None)], 0, H_space, k_space, flux_window=FLUX_WINDOW, ncpus=-3) def overlay_mcmc(axes): x = soln_mcmc.x.copy() for i, _x in enumerate(x): color = '#13f50e' cluster = soln_mcmc.clusters[i] axes.scatter(Vp_c / cluster[:, 1], cluster[:, 0], c=color, s=5, alpha=0.3) axes.scatter(_x[0], _x[1], marker='x', s=100, c=color, alpha=0.9) axes.scatter(_x[0], _x[1], marker='o', s=160, facecolors='none', edgecolors=color, alpha=0.9, linewidth=2) # end for # end func plot_Esu_space(H, k, Esu, decorator=overlay_mcmc)
def mcmc_solver_wrapper(model, obj_fn, mantle, Vp, rho, flux_window): """ Wrapper callable for passing to MCMC solver in scipy style, which unpacks inputs into vector variables for solver. :param model: Per-layer model values (the vector being solved for) as flat array of (H, Vs) value pairs ordered by layer. :type model: numpy.array :param obj_fn: Callable to WfContinuationSuFluxComputer to compute SU flux. :param mantle: Mantle properties stored in class LayerProps instance. :type mantle: seismic.model_properties.LayerProps :param Vp: Array of Vp values ordered by layer. :type Vp: numpy.array :param rho: Array of rho values ordered by layer. :type rho: numpy.array :param flux_window: Pair of floats indicating the time window over which to perform SU flux integration :type flux_window: (float, float) :return: Integrated SU flux energy at top of mantle """ num_layers = len(model) // 2 earth_model = [] for i in range(num_layers): earth_model.append( LayerProps(Vp[i], model[2 * i + 1], rho[i], model[2 * i])) # end for earth_model = np.array(earth_model) energy, _, _ = obj_fn(mantle, earth_model, flux_window=flux_window) return energy
def bulk_eval(flux, H_batch, k_batch, layer_props, flux_window): energy = np.zeros_like(H_batch) for i, (H, k) in enumerate(zip(H_batch, k_batch)): Vs = Vp/k lp = layer_props[layer_index] layer_props[layer_index] = LayerProps(lp.Vp, Vs, lp.rho, H) energy[i], _, _ = flux(mantle_props, layer_props, flux_window=flux_window) return energy
def example_1(): # Example 1: Computing energy for a single model proposition. crust_props = LayerProps(Vp_c, 3.7, rho_c, 35) single_layer_model = [crust_props] logging.info("Computing single point mean SU flux...") energy, energy_per_event, wf_mantle = flux_comp(mantle_props, single_layer_model) # pylint: disable=unused-variable logging.info(energy)
def objective_fn_wrapper(model, obj_fn, mantle, Vp, rho, flux_window): num_layers = len(model) // 2 earth_model = [] for i in range(num_layers): earth_model.append( LayerProps(Vp[i], model[2 * i + 1], rho[i], model[2 * i])) # end for earth_model = np.array(earth_model) energy, _, _ = obj_fn(mantle, earth_model, flux_window=flux_window) return energy
def example_2(network, station): # Example 2: Computing energy across a parametric space of models. logging.info("Computing 2D parametric space mean SU flux...") H_space = np.linspace(25, 45, 51) k_space = np.linspace(k_min, k_max, 51) H, k, Esu = flux_comp.grid_search(mantle_props, [LayerProps(Vp_c, None, rho_c, None)], 0, H_space, k_space, flux_window=FLUX_WINDOW) title = '{}.{} $E_{{SU}}$ energy vs. crustal properties'.format( network, station) savename = 'example_{}.{}_crust_props.png'.format(network, station) plot_Esu_space(H, k, Esu, title, savename)
import numpy as np from seismic.synthetics.synth import synthesize_dataset from seismic.model_properties import LayerProps mantle = LayerProps(8.0, 4.5, 3.3, np.nan) sediment = LayerProps(2.5, 1.0, 2.0, 1.0) crust = LayerProps(6.4, 6.4/1.7, 2.7, 40.0) num_events = 10 reference_locus = np.array([15, 140]) src_latlon = 5*(np.random.randn(num_events, 2) - 0.5) + reference_locus fs = 100.0 time_window = (-20, 60) generator_args = { 'station_latlon': (-20, 137), 'layerprops': [sediment, crust, mantle] } synthesize_dataset('propmatrix', 'synth_events_2L_sediment.h5', 'SY', 'OAA', src_latlon, fs, time_window, **generator_args)
"freq_min": 0.05, "min_snr": 3.0, "max_raw_amplitude": 10000.0 } curate_seismograms(data_all, curation_opts) # ----------------------------------------------------------------------------- # Pass cleaned up data set for test station to flux computer class. data_OA = data_all.station(target_station) fs_processing = 20.0 # Hz logging.info("Ingesting source data streams...") flux_comp = WfContinuationSuFluxComputer(data_OA.values(), fs_processing, TIME_WINDOW, CUT_WINDOW) # Define bulk properties of mantle (lowermost half-space) mantle_props = LayerProps(vp=8.0, vs=4.5, rho=3.3, thickness=np.Infinity) # Assumed crust property constants Vp_c = 6.4 rho_c = 2.7 k_min, k_max = (1.5, 2.1) # ----------------------------------------------------------------------------- # Example 1: Computing energy for a single model proposition. example_1() # ----------------------------------------------------------------------------- # Example 2: Computing energy across a parametric space of models. example_2('OA', target_station) # -----------------------------------------------------------------------------
def run_mcmc(waveform_data, config, logger): """ Top level runner function for MCMC solver on SU flux minimization for given settings. :param waveform_data: Collection of waveform data to process :type waveform_data: Iterable obspy.Stream objects :param config: Dict of job settings. See example files for fields and format of settings. :type config: dict :param logger: Log message receiver. Optional, pass None for no logging. :type logger: logging.Logger or NoneType :return: Solution object based on scipy.optimize.OptimizeResult :rtype: scipy.optimize.OptimizeResult with additional custom attributes """ # Create flux computer flux_computer_opts = config["su_energy_opts"] logger.info('Flux computer options:\n{}'.format( json.dumps(flux_computer_opts, indent=4))) fs_processing = flux_computer_opts["sampling_rate"] time_window = flux_computer_opts["time_window"] cut_window = flux_computer_opts["cut_window"] if logger: logger.info("Ingesting source data streams...") flux_comp = WfContinuationSuFluxComputer(waveform_data, fs_processing, time_window, cut_window) # Create model mantle_config = config["mantle_properties"] mantle_props = LayerProps(mantle_config['Vp'], mantle_config['Vs'], mantle_config['rho'], np.Infinity) logger.info('Mantle properties: {}'.format(mantle_props)) layers = config["layers"] for i, layer_config in enumerate(layers): logger.info('Layer {}: {}'.format(i, layer_config)) # end for # Solve model solver_opts = config["solver"] logger.info('Solver options:\n{}'.format(json.dumps(solver_opts, indent=4))) flux_window = flux_computer_opts["flux_window"] Vp = [layer["Vp"] for layer in layers] rho = [layer["rho"] for layer in layers] fixed_args = (flux_comp, mantle_props, Vp, rho, flux_window) bounds_min = [] bounds_max = [] for layer in layers: if "k_range" in layer: Vp_layer = layer["Vp"] bounds_min.extend( [layer["H_range"][0], Vp_layer / layer["k_range"][1]]) bounds_max.extend( [layer["H_range"][1], Vp_layer / layer["k_range"][0]]) else: assert "Vs_range" in layer bounds_min.extend([layer["H_range"][0], layer["Vs_range"][0]]) bounds_max.extend([layer["H_range"][1], layer["Vs_range"][1]]) # end if # end for bounds = optimize.Bounds(np.array(bounds_min), np.array(bounds_max)) logger.info('Running MCMC solver...') temp = solver_opts.get("temp", DEFAULT_TEMP) burnin = solver_opts["burnin"] max_iter = solver_opts["max_iter"] target_ar = solver_opts.get("target_ar", DEFAULT_AR) collect_samples = solver_opts.get("collect_samples", None) cluster_eps = solver_opts.get("cluster_eps", DEFAULT_CLUSTER_EPS) N = solver_opts.get("max_solutions", 3) soln = optimize_minimize_mhmcmc_cluster(mcmc_solver_wrapper, bounds, fixed_args, T=temp, N=N, burnin=burnin, maxiter=max_iter, target_ar=target_ar, cluster_eps=cluster_eps, collect_samples=collect_samples, logger=logger) # Record number of independent events processed soln.num_input_seismograms = len(waveform_data) if soln.success: # Compute energy flux per seismogram for each solution, and return with soln Esu_per_x = [] for i, _x in enumerate(soln.x): num_layers = len(layers) earth_model = [] for j in range(num_layers): earth_model.append( LayerProps(Vp[j], _x[2 * j + 1], rho[j], _x[2 * j])) # end for earth_model = np.array(earth_model) energy, energy_per_event, _ = flux_comp(mantle_props, earth_model, flux_window=flux_window) # Check computed energy matchs what solver produced assert np.isclose(energy, soln.fun[i]) Esu_per_x.append(energy_per_event) # end for # Upward S-wave energy at top of mantle per seismogram per solution point. soln.esu = Esu_per_x # Compute per-event seismograms at bottom of layers that flagged it, and return with soln. # For now we just re-use the original flux computer, but if we want to use a broader # cut_window here, we will need to create a new one. subsurface = {} for i, layer in enumerate(layers): if bool(layer.get("save_seismogram", False)): layer_name = layer["name"] base_seismograms = [] for _x in soln.x: earth_model = [] for j in range(i + 1): earth_model.append( LayerProps(Vp[j], _x[2 * j + 1], rho[j], _x[2 * j])) # end for earth_model = np.array(earth_model) layer_base_vel = flux_comp.propagate_to_base(earth_model) base_seismograms.append(layer_base_vel) # end for subsurface[layer_name] = base_seismograms # end if # end for soln.subsurface = subsurface else: soln.esu = soln.subsurface = None # end if return soln
import numpy as np from seismic.synthetics.synth import synthesize_dataset from seismic.model_properties import LayerProps mantle = LayerProps(8.0, 4.5, 3.3, np.nan) upper_crust = LayerProps(5.6, 5.6/1.65, 2.4, 10.0) lower_crust = LayerProps(6.4, 6.4/1.7, 2.7, 30.0) num_events = 10 reference_locus = np.array([15, 140]) src_latlon = 5*(np.random.randn(num_events, 2) - 0.5) + reference_locus fs = 100.0 time_window = (-20, 60) generator_args = { 'station_latlon': (-20, 137), 'layerprops': [upper_crust, lower_crust, mantle] } synthesize_dataset('propmatrix', 'synth_events_2L.h5', 'SY', 'OAA', src_latlon, fs, time_window, **generator_args)
if time_init < times_rel_mantle: n_leading = int((times_rel_mantle - time_init) / dt) data_new = np.append(np.zeros(n_leading), tr.data[:(npts - n_leading)]) assert data_new.shape == tr.data.shape tr.data = data_new elif time_init > times_rel_mantle: n_trailing = int((time_init - times_rel_mantle) / dt) data_new = np.append(tr.data[(npts - n_trailing):], np.zeros(n_trailing)) assert data_new.shape == tr.data.shape tr.data = data_new # end if # end for traces_zne.differentiate() return traces_zne # end func # end class if __name__ == '__main__': example = SynthesizerMatrixPropagator( (-20, 160), [LayerProps(6.4, 4.2, 2.7, 35.0), LayerProps(8.2, 6.8, 3.3, np.nan)]) test_strm = example.synthesize(((30, 150), ), 100.0, (-10, 30)) print(test_strm) # end if
import numpy as np from seismic.synthetics.synth import synthesize_dataset from seismic.model_properties import LayerProps mantle = LayerProps(8.0, 4.5, 3.3, np.nan) crust = LayerProps(6.4, 6.4 / 1.7, 2.7, 35.0) num_events = 10 reference_locus = np.array([15, 140]) src_latlon = 5 * (np.random.randn(num_events, 2) - 0.5) + reference_locus fs = 100.0 time_window = (-20, 60) generator_args = {'station_latlon': (-20, 137), 'layerprops': [crust, mantle]} synthesize_dataset('propmatrix', 'synth_events_1L.h5', 'SY', 'OAA', src_latlon, fs, time_window, **generator_args)
import os import numpy as np import rf from seismic.synthetics.synth import synthesize_dataset from seismic.model_properties import LayerProps from seismic.receiver_fn.generate_rf import event_waveforms_to_rf mantle = LayerProps(8.0, 4.5, 3.3, np.nan) sediment = LayerProps(3.2, 1.6, 2.0, 2.0) upper_crust = LayerProps(5.6, 5.6 / 1.65, 2.4, 13.0) lower_crust = LayerProps(6.4, 6.4 / 1.7, 2.7, 27.0) src_latlon = ((35, 140), ) fs = 100.0 time_window = (-20, 60) generator_args = { 'station_latlon': (-25, 140), 'layerprops': [sediment, upper_crust, lower_crust, mantle] } raw_file = 'synth_events_3L.h5' synthesize_dataset('propmatrix', raw_file, 'SY', 'AAA', src_latlon, fs, time_window, **generator_args) # Generate receiver function rf_file = 'synth_rf_3L.h5' resample_rate = 6.25 # Hz event_waveforms_to_rf(raw_file, rf_file, resample_rate,
import os import numpy as np import rf from seismic.synthetics.synth import synthesize_dataset from seismic.model_properties import LayerProps from seismic.receiver_fn.generate_rf import event_waveforms_to_rf mantle = LayerProps(8.0, 4.5, 3.3, np.nan) layers = [ LayerProps(5.6, 5.6 / 1.72, 2.3, 5.0), LayerProps(5.6, 5.6 / 1.65, 2.4, 13.0), LayerProps(6.4, 6.4 / 1.7, 2.6, 5.0), LayerProps(6.8, 6.8 / 1.75, 2.75, 3.0), LayerProps(6.4, 6.4 / 1.7, 2.7, 10.0) ] src_latlon = ((35, 140), ) fs = 100.0 time_window = (-20, 60) generator_args = { 'station_latlon': (-25, 140), 'layerprops': layers + [mantle] } raw_file = 'synth_events_NL.h5' synthesize_dataset('propmatrix', raw_file, 'SY', 'AAA', src_latlon, fs, time_window, **generator_args) # Generate receiver function rf_file = 'synth_rf_NL.h5'