def _get_event_phase_window( self, event, dist_df, sampling_rate, restrict_to_arrivals: bool ): """ Get the pick time, window start and window end for all phases. """ # determine min duration based on min samples and sec/dist # min duration based on required num of samples min_samples = get_default_param("min_samples", obj=self) min_dur_samps = min_samples / sampling_rate # min duration based on distances seconds_per_m = get_default_param("seconds_per_meter", obj=self) dist = dist_df.loc[str(event.resource_id), "hyp_distance_m"] min_dur_dist = pd.Series(dist * seconds_per_m, index=dist.index) # the minimum duration is the max the min sample requirement and the # min distance requirement min_duration = to_timedelta64(np.maximum(min_dur_dist, min_dur_samps)) # get dataframe if not len(event.picks): raise NoPhaseInformationError() df = get_phase_window_df( event, min_duration=min_duration, channel_codes=set(min_duration.index), restrict_to_arrivals=restrict_to_arrivals, ) # make sure there are no NaNs assert not df.isnull().any().any() return df
def add_velocity(self, df, velocity=None): """ Add the velocity to meta dataframe """ if velocity is None: vel_map = dict( S=get_default_param("s_velocity"), P=get_default_param("p_velocity") ) velocity = df.index.get_level_values("phase_hint").map(vel_map) df["velocity"] = velocity return df
def add_radiation_coeficient(self, df, radiation_ceoficient=None): """ Add the factor used to correct for radiation pattern. """ radiation_coef_map = dict( S=get_default_param("s_radiation_coefficient"), P=get_default_param("p_radiation_coefficient"), Noise=1.0, ) rad = df.index.get_level_values("phase_hint").map(radiation_coef_map) df["radiation_coefficient"] = rad return df
def add_shear_modulus(self, df, shear_modulus=None): """ Add the shear modulus to the meta dataframe """ if shear_modulus is None: shear_modulus = get_default_param("shear_modulus") df["shear_modulus"] = shear_modulus return df
def add_density(self, df, density=None): """ Add density to the meta dataframe. If None, use defaults. """ if density is None: density = get_default_param("density") df["density"] = density return df
def _get_noise_windows(self, phase_df, df): """ Get noise window rows by first looking for noise phase, if None just use start of trace. """ # init df for each unique channel that needs a noise spectra noise_df = phase_df[~phase_df["seed_id"].duplicated()] noise_df["phase_hint"] = "Noise" # If no noise spectra is defined use start of traces if df.empty: # get parameters for determining noise windows start and stop noise_end = to_timedelta64( get_default_param("noise_end_before_p", obj=self) ) min_noise_dur = to_timedelta64( get_default_param("noise_min_duration", obj=self) ) largest_window = (phase_df["endtime"] - phase_df["starttime"]).max() # Necessary to do it this way because max and np.max can't # handle NaN/NaT properly min_duration = pd.Series([min_noise_dur, largest_window]).max() # set start and stop for noise window noise_df["endtime"] = phase_df["starttime"].min() - noise_end noise_df["starttime"] = noise_df["endtime"] - min_duration else: # else use either the noise window defined for a specific station # or, if a station has None, use the noise window with the earliest # start time ser_min = df.loc[df["starttime"].idxmin()] t1, t2 = ser_min["starttime"], ser_min["endtime"] # drop columns on df and noise df to facilitate merge df = df[["network", "station", "starttime", "endtime"]] noise_df = noise_df.drop(columns=["starttime", "endtime"]) noise_df = noise_df.merge(df, how="left", on=["network", "station"]) # fill nan noise_df = noise_df.fillna({"starttime": t1, "endtime": t2}) # set time between min and max noise_df["time"] = ( noise_df["starttime"] + (noise_df["endtime"] - noise_df["starttime"]) / 2 ) # noise_df["time"] = noise_df[["starttime", "endtime"]].mean(axis=1) # make sure there are no null values out = noise_df.set_index(list(_INDEX_NAMES)) # drop any duplicate indices return out.loc[~out.index.duplicated()]
def _add_source_velocity( self, df: pd.DataFrame, velocity: Optional[BroadcastableFloatType] = None, na_only: bool = True, ): """ Add the velocity to meta dataframe """ # Determine what the appropriate value should be if velocity is None: velocity = dict(S=get_default_param("s_velocity"), P=get_default_param("p_velocity")) return broadcast_param( df=df, param=velocity, col_name="source_velocity", broadcast_by="phase_hint", na_only=na_only, )
def _add_quality_factor( self, df: pd.DataFrame, quality_factor: Optional[BroadcastableFloatType] = None, na_only: bool = True, ): """Add the quality factor""" if quality_factor is None: quality_factor = dict( S=get_default_param("s_quality_factor"), P=get_default_param("p_quality_factor"), Noise=get_default_param("noise_quality_factor"), ) return broadcast_param( df=df, param=quality_factor, col_name="quality_factor", broadcast_by=("phase_hint", "seed_id_less"), na_only=na_only, )
def _add_radiation_coeficient( self, df: pd.DataFrame, radiation_coefficient: Optional[BroadcastableFloatType] = None, na_only=True, ): """Add the factor used to correct for radiation pattern.""" if radiation_coefficient is None: radiation_coefficient = dict( S=get_default_param("s_radiation_coefficient"), P=get_default_param("p_radiation_coefficient"), Noise=get_default_param("noise_radiation_coefficient"), ) return broadcast_param( df=df, param=radiation_coefficient, col_name="radiation_coefficient", broadcast_by="phase_hint", na_only=na_only, )
def _get_event_phase_window(self, event, dist_df, channel_codes, sampling_rate): """ Get the pick time, window start and window end for all phases. """ # determine min duration based on min samples and sec/dist # min duration based on required num of samples min_samples = get_default_param("min_samples", obj=self) min_dur_samps = min_samples / sampling_rate # min duration based on distances seconds_per_m = get_default_param("seconds_per_meter", obj=self) dist = dist_df.loc[str(event.resource_id), "distance"] min_dur_dist = pd.Series(dist * seconds_per_m, index=dist.index) min_duration = np.maximum(min_dur_dist, min_dur_samps) _percent_taper = get_default_param("percent_taper", obj=self) # get dataframe df = get_phase_window_df( event, min_duration=min_duration, channel_codes=channel_codes, buffer_ratio=_percent_taper, ) # make sure there are no NaNs assert not df.isnull().any().any() return df
def _add_shear_modulus( self, df: pd.DataFrame, shear_modulus: Optional[BroadcastableFloatType] = None, na_only: bool = True, ): """ Add the shear modulus to the meta dataframe """ if shear_modulus is None: shear_modulus = get_default_param("shear_modulus") # Note, "broadcast_by" is a useless parameter for "shear_modulus" return broadcast_param( df=df, param=shear_modulus, col_name="shear_modulus", broadcast_by="phase_hint", na_only=na_only, )
def _add_density( self, df: pd.DataFrame, density: Optional[BroadcastableFloatType] = None, na_only: bool = True, ): """ Add density to the meta dataframe. If None, use defaults. """ if density is None: density = get_default_param("density") # Note, "broadcast_by" is a useless parameter for "density" return broadcast_param( df=df, param=density, col_name="density", broadcast_by="phase_hint", na_only=na_only, )
def process_trace(self, ser): """ Process trace. By default will simply detrend and taper window length in prep for fft. Notes ----- Many phase windows may share the same trace; be sure to copy the data before modification. The parameter ser is a row of the channel info dataframe. """ # slice out time of interest t1, t2 = obspy.UTCDateTime(ser.tw_start), obspy.UTCDateTime(ser.tw_end) tr = ser.trace.slice(starttime=t1, endtime=t2).copy() tr.detrend("linear") # apply taper for ffts taper_ratio = get_default_param('PERCENT_TAPER', obj=self.channel_info) tr.taper(max_percentage=taper_ratio) return tr.data
def add_quality_factor(self, df, quality_factor=None): if quality_factor is None: quality_factor = get_default_param("quality_factor") df["quality_factor"] = quality_factor return df