def single_cc(filename, obsds, synts, windows, calc_type, conf, rec_weights, write_now=False): """Compute CC Adjoint for one trace """ config = ConfigCrossCorrelation(conf.adjoint.freq_min, conf.adjoint.freq_max, conf.adjoint.taper_type, conf.adjoint.taper_percentage) obsd = obsds[filename] synt = synts[filename] adj_windows = windows[filename] try: info = conf.get_info_from_filename(filename) sta = info["station"] cat = (info["event"], sta[-1]) except AttributeError: net, name, comp, ev = filename.split(".") sta = ".".join([net, name, comp]) cat = (ev, comp[-1]) rec_weight = rec_weights.get(cat, sta) p = pyadjoint.calculate_adjoint_source( "cc_traveltime_misfit", obsd, synt, config, adj_windows, adjoint_src=bool(calc_type & CALC_ADJOINT), # NOQA plot=False) try: _, event, _, basefilename = filename.split("/") net, sta, _, _ = basefilename.split(".") except ValueError: net, sta, _, event = filename.split(".") res = {filename: {}} weight = conf.adjoint.weight_cc * rec_weight if calc_type & CALC_MISFIT: res[filename]["misfit"] = weight * p.misfit if calc_type & CALC_ADJOINT: times = obsd.times() adj_data = np.zeros((len(times), 2)) adj_data[:, 0] = times adj_data[:, 1] = weight * p.adjoint_source[::-1] if write_now: np.savetxt( filename.replace("DATA_obs", "SEM").replace("semd", "adj"), adj_data) else: res[filename]["src"] = adj_data[:, 1] return res
def test_no_adjoint_src_calculation_is_honored(adj_src): """ If no adjoint source is requested, it should not be returned/calculated. """ config = pyadjoint.Config(min_period=30.0, max_period=75.0, lnpt=15, transfunc_waterlevel=1.0E-10, water_threshold=0.02, ipower_costaper=10, min_cycle_in_window=3, taper_percentage=0.3, taper_type='hann', mt_nw=4, phase_step=1.5, use_cc_error=False, use_mt_error=False) obs, syn = pyadjoint.utils.get_example_data() obs = obs.select(component="Z")[0] syn = syn.select(component="Z")[0] window = [[2076., 2418.0]] a_src = pyadjoint.calculate_adjoint_source(adj_src_type=adj_src, observed=obs, synthetic=syn, config=config, window=window, adjoint_src=False, plot=False) # start, end = pyadjoint.utils.EXAMPLE_DATA_PDIFF # a_src = pyadjoint.calculate_adjoint_source( # adj_src, obs, syn, 20, 100, start, end, adjoint_src=False) assert a_src.adjoint_source is None
def test_no_adjoint_src_calculation_is_honored(adj_src): """ If no adjoint source is requested, it should not be returned/calculated. """ config = pyadjoint.Config(min_period=30.0, max_period=75.0, lnpt=15, transfunc_waterlevel=1.0E-10, water_threshold=0.02, ipower_costaper=10, min_cycle_in_window=3, taper_percentage=0.3, taper_type='hann', mt_nw=4, phase_step=1.5, use_cc_error=False, use_mt_error=False) obs, syn = pyadjoint.utils.get_example_data() obs = obs.select(component="Z")[0] syn = syn.select(component="Z")[0] window = [[2076., 2418.0]] a_src = pyadjoint.calculate_adjoint_source( adj_src_type=adj_src, observed=obs, synthetic=syn, config=config, window=window, adjoint_src=False, plot=False) # start, end = pyadjoint.utils.EXAMPLE_DATA_PDIFF # a_src = pyadjoint.calculate_adjoint_source( # adj_src, obs, syn, 20, 100, start, end, adjoint_src=False) assert a_src.adjoint_source is None
def single_misfit(filename, obsds, synts, windows, adjoint_misfit_type, adjoint_config, calc_type, conf, rec_weights): """Compute an adjoint source/misfit for one trace""" obsd = obsds[filename] synt = synts[filename] adj_windows = windows[(filename, "single")] rec_weight = rec_weights.get_from_stationname(filename, "single") p = pyadjoint.calculate_adjoint_source(adjoint_misfit_type, obsd, synt, adjoint_config, adj_windows, adjoint_src=bool(calc_type & CALC_ADJOINT), # NOQA plot=False) res = {filename: {}} weight = conf.adjoint.weight_single*rec_weight if calc_type & CALC_MISFIT: res[filename]["misfit"] = weight*p.misfit if calc_type & CALC_ADJOINT: res[filename]["src"] = weight*p.adjoint_source[::-1] return res
def test_no_adjoint_src_calculation_is_honored(adj_src): """ If no adjoint source is requested, it should not be returned/calculated. """ obs, syn = pyadjoint.utils.get_example_data() obs = obs.select(component="Z")[0] syn = syn.select(component="Z")[0] start, end = pyadjoint.utils.EXAMPLE_DATA_PDIFF a_src = pyadjoint.calculate_adjoint_source( adj_src, obs, syn, 20, 100, start, end, adjoint_src=False) assert a_src.adjoint_source is None assert a_src.misfit >= 0.0 # But the misfit should nonetheless be identical as if the adjoint # source would have been calculated. assert a_src.misfit == pyadjoint.calculate_adjoint_source( adj_src, obs, syn, 20, 100, start, end, adjoint_src=True).misfit
def calculate_adjsrc_on_trace(obs, syn, windows, config, adj_src_type, figure_mode=False, figure_dir=None, adjoint_src_flag=True): """ Calculate adjoint source on a pair of trace and windows selected :param obs: observed trace :type obs: obspy.Trace :param syn: synthetic trace :type syn: obspy.Trace :param window_time: window time information, 2-dimension array, like [[win_1_left, win_1_right], [win_2_left, win_2_right], ...] :type windows: 2-d list or numpy.array :param config: config of pyadjoint :type config: pyadjoint.Config :param adj_src_type: adjoint source type, options include: 1) "cc_traveltime_misfit" 2) "multitaper_misfit" 3) "waveform_misfit" :type adj_src_type: str :param adjoint_src_flag: whether calcualte adjoint source or not. If False, only make measurements :type adjoint_src_flag: bool :param plot_flag: whether make plots or not. If True, it will lot a adjoint source figure right after calculation :type plot_flag: bool :return: adjoint source(pyadjoit.AdjointSource) """ if not isinstance(obs, Trace): raise ValueError("Input obs should be obspy.Trace") if not isinstance(syn, Trace): raise ValueError("Input syn should be obspy.Trace") # if not isinstance(config, pyadjoint.Config): # raise ValueError("Input config should be pyadjoint.Config") window_time = _extract_window_time(windows) if len(window_time.shape) != 2 or window_time.shape[1] != 2: raise ValueError("Input windows dimension incorrect, dimension" "(*, 2) expected") adjsrc = pyadjoint.calculate_adjoint_source( adj_src_type=adj_src_type, observed=obs, synthetic=syn, config=config, window=window_time, adjoint_src=adjoint_src_flag, plot=figure_mode) if figure_mode: if figure_dir is None: figname = None else: figname = os.path.join(figure_dir, "%s.pdf" % obs.id) plot_adjoint_source(adjsrc, win_times=window_time, obs_tr=obs, syn_tr=syn, figname=figname) return adjsrc
def test_normal_adjoint_source_calculation(adj_src): """ Make sure everything at least runs. Executed for every adjoint source type. """ obs, syn = pyadjoint.utils.get_example_data() obs = obs.select(component="Z")[0] syn = syn.select(component="Z")[0] start, end = pyadjoint.utils.EXAMPLE_DATA_PDIFF a_src = pyadjoint.calculate_adjoint_source( adj_src, obs, syn, 20, 100, start, end) assert a_src.adjoint_source.any() assert a_src.misfit >= 0.0 assert isinstance(a_src.adjoint_source, np.ndarray)
def test_normal_adjoint_source_calculation(adj_src): """ Make sure everything at least runs. Executed for every adjoint source type. """ obs, syn = pyadjoint.utils.get_example_data() obs = obs.select(component="Z")[0] syn = syn.select(component="Z")[0] start, end = pyadjoint.utils.EXAMPLE_DATA_PDIFF a_src = pyadjoint.calculate_adjoint_source(adj_src, obs, syn, 20, 100, start, end) assert a_src.adjoint_source.any() assert a_src.misfit >= 0.0 assert isinstance(a_src.adjoint_source, np.ndarray)
def test_no_adjoint_src_calculation_is_honored(adj_src): """ If no adjoint source is requested, it should not be returned/calculated. """ obs, syn = pyadjoint.utils.get_example_data() obs = obs.select(component="Z")[0] syn = syn.select(component="Z")[0] start, end = pyadjoint.utils.EXAMPLE_DATA_PDIFF a_src = pyadjoint.calculate_adjoint_source(adj_src, obs, syn, 20, 100, start, end, adjoint_src=False) assert a_src.adjoint_source is None assert a_src.misfit >= 0.0 # But the misfit should nonetheless be identical as if the adjoint # source would have been calculated. assert a_src.misfit == pyadjoint.calculate_adjoint_source( adj_src, obs, syn, 20, 100, start, end, adjoint_src=True).misfit
def calculate_adjsrc_on_trace(obs, syn, windows, config, adj_src_type, adjoint_src_flag=True, plot_flag=False): """ Calculate adjoint source on a pair of trace and windows selected :param obs: observed trace :type obs: obspy.Trace :param syn: synthetic trace :type syn: obspy.Trace :param windows: windows information, 2-dimension array, like [[win_1_left, win_1_right], [win_2_left, win_2_right], ...] :type windows: list or numpy.array :param config: config of pyadjoint :type config: pyadjoint.Config :param adj_src_type: adjoint source type, like "multitaper" :type adj_src_type: str :param adjoint_src_flag: whether calcualte adjoint source or not. If False, only make measurements :type adjoint_src_flag: bool :param plot_flag: whether make plots or not. If True, it will lot a adjoint source figure right after calculation :type plot_flag: bool :return: adjoint source(pyadjoit.AdjointSource) """ if not isinstance(obs, Trace): raise ValueError("Input obs should be obspy.Trace") if not isinstance(syn, Trace): raise ValueError("Input syn should be obspy.Trace") if not isinstance(config, pyadjoint.Config): raise ValueError("Input config should be pyadjoint.Config") windows = np.array(windows) if len(windows.shape) != 2 or windows.shape[1] != 2: raise ValueError("Input windows dimension incorrect, dimention" "(*, 2) expected") try: adjsrc = pyadjoint.calculate_adjoint_source( adj_src_type=adj_src_type, observed=obs, synthetic=syn, config=config, window=windows, adjoint_src=adjoint_src_flag, plot=plot_flag) except: adjsrc = None return adjsrc
def test_normal_adjoint_source_calculation(adj_src): """ Make sure everything at least runs. Executed for every adjoint source type. """ config = pyadjoint.Config(min_period=30.0, max_period=75.0, lnpt=15, transfunc_waterlevel=1.0E-10, water_threshold=0.02, ipower_costaper=10, min_cycle_in_window=3, taper_percentage=0.3, taper_type='hann', mt_nw=4, phase_step=1.5, use_cc_error=False, use_mt_error=False) obs, syn = pyadjoint.utils.get_example_data() obs = obs.select(component="Z")[0] syn = syn.select(component="Z")[0] # start, end = pyadjoint.utils.EXAMPLE_DATA_PDIFF window = [[2076., 2418.0]] a_src = pyadjoint.calculate_adjoint_source(adj_src_type=adj_src, observed=obs, synthetic=syn, config=config, window=window, adjoint_src=True, plot=False) # a_src = pyadjoint.calculate_adjoint_source( # adj_src, obs, syn, 20, 100, start, end) assert a_src.adjoint_source.any() assert a_src.misfit >= 0.0 assert isinstance(a_src.adjoint_source, np.ndarray)
def test_normal_adjoint_source_calculation(adj_src): """ Make sure everything at least runs. Executed for every adjoint source type. """ config = pyadjoint.Config(min_period=30.0, max_period=75.0, lnpt=15, transfunc_waterlevel=1.0E-10, water_threshold=0.02, ipower_costaper=10, min_cycle_in_window=3, taper_percentage=0.3, taper_type='hann', mt_nw=4, phase_step=1.5, use_cc_error=False, use_mt_error=False) obs, syn = pyadjoint.utils.get_example_data() obs = obs.select(component="Z")[0] syn = syn.select(component="Z")[0] # start, end = pyadjoint.utils.EXAMPLE_DATA_PDIFF window = [[2076., 2418.0]] a_src = pyadjoint.calculate_adjoint_source( adj_src_type=adj_src, observed=obs, synthetic=syn, config=config, window=window, adjoint_src=True, plot=False) # a_src = pyadjoint.calculate_adjoint_source( # adj_src, obs, syn, 20, 100, start, end) assert a_src.adjoint_source.any() assert a_src.misfit >= 0.0 assert isinstance(a_src.adjoint_source, np.ndarray)
def measure(self, force=False, save=True): """ Measure misfit and calculate adjoint sources using PyAdjoint. Method for caluculating misfit set in Config, Pyadjoint expects standardized traces with the same spectral content, so this function will not run unless these flags are passed. Returns a dictionary of adjoint sources based on component. Saves resultant dictionary to a pyasdf dataset if given. .. note:: Pyadjoint returns an unscaled misfit value for an entire set of windows. To return a "total misfit" value as defined by Tape (2010) Eq. 6, the total summed misfit will need to be scaled by the number of misfit windows chosen in Manager.window(). :type force: bool :param force: ignore flag checks and run function, useful if e.g. external preprocessing is used that doesn't meet flag criteria :type save: bool :param save: save adjoint sources to ASDFDataSet """ self.check() if self.config.adj_src_type is None: logger.info("adjoint source type is 'None', will not measure") return # Check that data has been filtered and standardized if not self.stats.standardized and not force: raise ManagerError("cannot measure misfit, not standardized") elif not (self.stats.obs_processed and self.stats.syn_processed) \ and not force: raise ManagerError("cannot measure misfit, not filtered") elif self.stats.nwin == 0 and not force: raise ManagerError("cannot measure misfit, no windows recovered") logger.debug(f"running Pyadjoint w/ type: {self.config.adj_src_type}") # Create list of windows needed for Pyadjoint adjoint_windows = self._format_windows() # Run Pyadjoint to retrieve adjoint source objects total_misfit, adjoint_sources = 0, {} for comp, adj_win in adjoint_windows.items(): try: adj_src = pyadjoint.calculate_adjoint_source( adj_src_type=self.config.adj_src_type, config=self.config.pyadjoint_config, observed=self.st_obs.select(component=comp)[0], synthetic=self.st_syn.select(component=comp)[0], window=adj_win, plot=False) # Re-format component name to reflect SPECFEM convention adj_src.component = f"{channel_code(adj_src.dt)}X{comp}" # Save adjoint sources in dictionary object. Sum total misfit adjoint_sources[comp] = adj_src logger.info(f"{adj_src.misfit:.3f} misfit for comp {comp}") total_misfit += adj_src.misfit except IndexError: continue # Save adjoint source internally and to dataset self.adjsrcs = adjoint_sources if save: self.save_adjsrcs() # Run check to get total misfit self.check() logger.info(f"total misfit {self.stats.misfit:.3f}") return self
def calculate_adjsrc_on_trace(obs, syn, window_time, config, adj_src_type, figure_mode=False, figure_dir=None, adjoint_src_flag=True): """ Calculate adjoint source on a pair of trace and windows selected :param obs: observed trace :type obs: obspy.Trace :param syn: synthetic trace :type syn: obspy.Trace :param window_time: window time information, 2-dimension array, like [[win_1_left, win_1_right], [win_2_left, win_2_right], ...] :type windows: 2-d list or numpy.array :param config: config of pyadjoint :type config: pyadjoint.Config :param adj_src_type: adjoint source type, options include: 1) "cc_traveltime_misfit" 2) "multitaper_misfit" 3) "waveform_misfit" :type adj_src_type: str :param adjoint_src_flag: whether calcualte adjoint source or not. If False, only make measurements :type adjoint_src_flag: bool :param plot_flag: whether make plots or not. If True, it will lot a adjoint source figure right after calculation :type plot_flag: bool :return: adjoint source(pyadjoit.AdjointSource) """ if not isinstance(obs, Trace): raise ValueError("Input obs should be obspy.Trace") if not isinstance(syn, Trace): raise ValueError("Input syn should be obspy.Trace") if not isinstance(config, pyadjoint.Config): raise ValueError("Input config should be pyadjoint.Config") windows = np.array(window_time) if len(windows.shape) != 2 or windows.shape[1] != 2: raise ValueError("Input windows dimension incorrect, dimention" "(*, 2) expected") adjsrc = pyadjoint.calculate_adjoint_source(adj_src_type=adj_src_type, observed=obs, synthetic=syn, config=config, window=window_time, adjoint_src=adjoint_src_flag, plot=figure_mode) if figure_mode: if figure_dir is None: figname = None else: figname = os.path.join(figure_dir, "%s.pdf" % obs.id) plot_adjoint_source(adjsrc, win_times=windows, obs_tr=obs, syn_tr=syn, figname=figname) return adjsrc
# ### Elastic Adjoint Source # Cross-correlation elastic adjoint source is computed using following equation: # $$ # f^{\dagger}(t) = - \left[ T^{obs} - T(\mathbf{m}) \right] ~ \frac{1}{N} ~ # \partial_t \mathbf{s}(T - t, \mathbf{m}) # $$ # In[7]: # Define the adjoint source config cc_config = ConfigCrossCorrelation(40.0, 250.0, taper_type="cos_p10", taper_percentage=1.0, measure_type="dt") # Calculate the adjoint source elastic_adj = pyadjoint.calculate_adjoint_source("cc_traveltime_misfit", obsd, synt, cc_config, windows) times = synt.times() + offset win_offset = windows + offset fig, axes = plt.subplots(figsize=(16, 8), nrows=2, sharex=True) axes[0].plot(times, obsd.data, "k", label="obsd") axes[0].plot(times, synt.data, "r", label="synt") axes[0].set_xlim((win_offset[0][0]*0.8, win_offset[0][1]*1.2)) axes[0].axvline(win_offset[0][0], color="gray", linestyle="--") axes[0].axvline(win_offset[0][1], color="gray", linestyle="--") axes[0].set_ylim(get_ylim(axes[0], obsd)) axes[0].legend() axes[1].plot(times, elastic_adj.adjoint_source[::-1], "b", label="Elastic Adjoint Source")
horizontalalignment="right", verticalalignment="top", size="small", multialignment="right") pretty_colors = ["#5B76A1", "#619C6F", "#867CA8", "#BFB281", "#74ACBD"] _i = 0 for key, value in srcs: _i += 1 plt.subplot(len(srcs) + 1, 1, _i + 1) adj_src = pyadjoint.calculate_adjoint_source(key, obs, syn, 20, 100, start, end, adjoint_src=True) plt.plot(obs.times(), adj_src.adjoint_source, color=pretty_colors[(_i - 1) % len(pretty_colors)], lw=2, label=value[1]) plt.xlim(x_range - right_window_border, x_range - left_window_border) plt.legend(fancybox=True, framealpha=0.5) plt.grid() plt.tight_layout() plt.show()
fwindow_chi = "%s_%s_window_chi.txt" % (tag_type, catlog) fchi = open(fwindow_chi, 'w') adjsrc_all = [] # R fobsd = os.path.join(obsd_dir, "IU.KBL..BHR.proc_obsd_60_100.sac") fsynt = os.path.join(synt_dir, "IU.KBL.S3.MXR.proc_synt_60_100.sac") obs = read(fobsd) syn = read(fsynt) fadjsrc_r = "IU.KBL..BHR.%s.%s.adj" % (tag_type, config.measure_type) window_r = [[4032., 4304.6]] adjsrc_r =\ pyadjoint.calculate_adjoint_source(adj_src_type=src_type, observed=obs[0], synthetic=syn[0], config=config, window=window_r, adjoint_src=True, plot=False) adjsrc_r.write(filename=fadjsrc_r, format="SPECFEM", time_offset=0) fchi.write("%s %f\n" % (fadjsrc_r, adjsrc_r.misfit)) print("%s %s tr_chi %f am_chi %f" % (fadjsrc_r, adjsrc_r.measurement[0]["type"], adjsrc_r.measurement[0]["misfit_dt"], adjsrc_r.measurement[0]["misfit_dlna"])) adjsrc_all.append(adjsrc_r) # T fobsd = os.path.join(obsd_dir, "IU.KBL..BHT.proc_obsd_60_100.sac") fsynt = os.path.join(synt_dir, "IU.KBL.S3.MXT.proc_synt_60_100.sac") obs = read(fobsd)
plt.gca().add_patch(re) plt.text(x=end - 0.02 * (end - start), y=plt.ylim()[1] - 0.01 * (plt.ylim()[1] - plt.ylim()[0]), s="Chosen window", color="0.2", fontweight=900, horizontalalignment="right", verticalalignment="top", size="small", multialignment="right") pretty_colors = ["#5B76A1", "#619C6F", "#867CA8", "#BFB281", "#74ACBD"] _i = 0 for key, value in srcs: _i += 1 plt.subplot(len(srcs) + 1, 1, _i + 1) adj_src = pyadjoint.calculate_adjoint_source(key, obs, syn, 20, 100, start, end, adjoint_src=True) plt.plot(obs.times(), adj_src.adjoint_source, color=pretty_colors[(_i - 1) % len(pretty_colors)], lw=2, label=value[1]) plt.xlim(x_range - right_window_border, x_range - left_window_border) plt.legend(fancybox=True, framealpha=0.5) plt.grid() plt.tight_layout() plt.show()