Пример #1
0
def get_pierce_points(st, phase, depth, h5_out):
    model = TauPyModel(model="prem")
    try:
        f = h5py.File(
            '/home/samhaug/anaconda2/lib/python2.7/site-packages/seispy' +
            h5_out, 'w')
    except IOError:
        os.rmdir('/home/samhaug/anaconda2/lib/python2.7/site-packages/seispy' +
                 h5_out)
        print "Had to remove existing file. Try again"
    evla = st[0].stats.sac['evla']
    evlo = st[0].stats.sac['evlo']
    evdp = st[0].stats.sac['evdp']
    pierce_list = []
    for idx, tr in enumerate(st):
        print tr
        a = model.get_pierce_points(evdp,
                                    tr.stats.sac['gcarc'],
                                    phase_list=[phase])
        b = a[0]
        depth_index = np.argmin(np.abs(b.pierce['depth'] - depth))
        distance = b.pierce['dist'][depth_index]
        pierce_list.append((distance, tr.stats.sac['az']))
    pierce_array = np.array(pierce_list)
    f.create_dataset('pierce', data=pierce_array)
    f.close()
    return pierce_array
Пример #2
0
   def migrate(self,plot=False):
      import geopy
      from geopy.distance import VincentyDistance

      '''
      This is a rewritten function that combines the functions find_pierce_coor and
      migrate_1d so that it's more efficient.  Still in testing stages. RM 2/6/16
      '''

      depth_range = np.arange(50,800,5)        #set range of pierce points
      value       = np.zeros((len(depth_range)))

      #geodetic info
      bearing     = self.az
      lon_s = self.ses3d_seismogram.sy
      lat_s = 90.0-self.ses3d_seismogram.sx
      lon_r = self.ses3d_seismogram.ry
      lat_r = 90.0-self.ses3d_seismogram.rx
      origin      = geopy.Point(lat_s, lon_s)

      #find how far away the pierce point is
      model  = TauPyModel(model='pyrolite_5km')

      for i in range(0,len(depth_range)):
         phase = 'P'+str(depth_range[i])+'s'
         pierce = model.get_pierce_points(self.eq_depth,self.delta_deg,phase_list=[phase])
         tt     = model.get_travel_times(self.eq_depth,self.delta_deg,phase_list=['P',phase])

         #in case there's duplicate phase arrivals
         for j in range(0,len(tt)):
            if tt[j].name == 'P':
               p_arr = tt[j].time           
            elif tt[j].name == phase:
               phase_arr = tt[j].time

         #determine value 
         Pds_time = phase_arr - p_arr
         i_start  = int((0.0 - self.window_start)/self.ses3d_seismogram.dt)
         i_t      = int(Pds_time/self.ses3d_seismogram.dt) + i_start
         value[i] = self.prf[i_t]

         points = pierce[0].pierce
         for j in range(0,len(points)):
            if points[j]['depth'] == depth_range[i] and points[j]['dist']*(180.0/np.pi) > 20.0:
               prc_dist = points[j]['dist']*(180.0/np.pi)
               d_km = prc_dist * ((2*np.pi*6371.0/360.0))
               destination = VincentyDistance(kilometers=d_km).destination(origin,bearing)
               lat = destination[0]
               lon = destination[1]
               row = {'depth':depth_range[i],'dist':prc_dist,'lat':lat,'lon':lon,'value':value[i]}
               self.pierce_dict.append(row)

      if plot == True:
         plt.plot(value,depth_range)
         plt.gca().invert_yaxis()
         plt.show()

      return value,depth_range
def get_taupy_points(
    center_lat, center_lon, ev_lat, ev_lon, ev_depth, stime, etime, mini, maxi, ev_otime, phase_shift, sll, slm
):

    distance = locations2degrees(center_lat, center_lon, ev_lat, ev_lon)
    # print(distance)

    model = TauPyModel(model="ak135")
    arrivals = model.get_pierce_points(ev_depth, distance)
    # arrivals = earthmodel.get_pierce_points(ev_depth,distance,phase_list=('PP','P^410P'))

    # compute the vespagram window
    start_vespa = stime - mini
    end_vespa = etime - maxi

    # compare the arrival times with the time window
    count = 0
    k = 0
    phase_name_info = []
    phase_slowness_info = []
    phase_time_info = []

    for i_elem in arrivals:
        # print(i_elem)
        dummy_phase = arrivals[count]
        # print(dummy_phase)
        # phase time in seconds
        taup_phase_time = dummy_phase.time
        # print(taup_phase_time)
        # slowness of the phase
        taup_phase_slowness = dummy_phase.ray_param_sec_degree
        # compute the UTC travel phase time
        taup_phase_time2 = ev_otime + taup_phase_time + phase_shift

        # print(start_vespa)
        # print(end_vespa)
        # print(taup_phase_time2)

        if start_vespa <= taup_phase_time2 <= end_vespa:  # time window
            if sll <= taup_phase_slowness <= slm:  # slowness window

                # seconds inside the vespagram
                taup_mark = taup_phase_time2 - start_vespa
                # store the information
                phase_name_info.append(dummy_phase.name)
                phase_slowness_info.append(dummy_phase.ray_param_sec_degree)
                phase_time_info.append(taup_mark)
                # print(phases_info[k])
                k += 1

        count += 1

    # print(phase_name_info)

    phase_slowness_info = np.array(phase_slowness_info)
    phase_time_info = np.array(phase_time_info)

    return phase_name_info, phase_slowness_info, phase_time_info
def get_taupy_points(center_lat, center_lon, ev_lat, ev_lon, ev_depth, stime,
                     etime, mini, maxi, ev_otime, phase_shift, sll, slm):

    distance = locations2degrees(center_lat, center_lon, ev_lat, ev_lon)
    #print(distance)

    model = TauPyModel(model="ak135")
    arrivals = model.get_pierce_points(ev_depth, distance)
    #arrivals = earthmodel.get_pierce_points(ev_depth,distance,phase_list=('PP','P^410P'))

    # compute the vespagram window
    start_vespa = stime - mini
    end_vespa = etime - maxi

    # compare the arrival times with the time window
    count = 0
    k = 0
    phase_name_info = []
    phase_slowness_info = []
    phase_time_info = []

    for i_elem in arrivals:
        #print(i_elem)
        dummy_phase = arrivals[count]
        #print(dummy_phase)
        # phase time in seconds
        taup_phase_time = dummy_phase.time
        #print(taup_phase_time)
        # slowness of the phase
        taup_phase_slowness = dummy_phase.ray_param_sec_degree
        # compute the UTC travel phase time
        taup_phase_time2 = ev_otime + taup_phase_time + phase_shift

        # print(start_vespa)
        # print(end_vespa)
        # print(taup_phase_time2)

        if start_vespa <= taup_phase_time2 <= end_vespa:  # time window
            if sll <= taup_phase_slowness <= slm:  # slowness window

                # seconds inside the vespagram
                taup_mark = taup_phase_time2 - start_vespa
                # store the information
                phase_name_info.append(dummy_phase.name)
                phase_slowness_info.append(dummy_phase.ray_param_sec_degree)
                phase_time_info.append(taup_mark)
                #print(phases_info[k])
                k += 1

        count += 1

    #print(phase_name_info)

    phase_slowness_info = np.array(phase_slowness_info)
    phase_time_info = np.array(phase_time_info)

    return phase_name_info, phase_slowness_info, phase_time_info
Пример #5
0
def calculate_depths(i):
#start = time.time()
     
    lhs = np.ones(( len(discon),))
    model = TauPyModel(model="iasp91") 
#for i in range(f):
    for j in range(len(discon)):
        phase = 'S'+ str(discon[j]) + 'p'
        arrivals = model.get_ray_paths(source_depth_in_km=source_info[i,1],                                    distance_in_degree=source_info[i,0] ,                                    phase_list=[phase])

        piercing_points = model.get_pierce_points(source_depth_in_km=source_info[i,1],                                    distance_in_degree=source_info[i,0] ,                                    phase_list=[phase])

        piercing_points_S = model.get_pierce_points(source_depth_in_km=source_info[i,1],                                    distance_in_degree=source_info[i,0] ,                                    phase_list=['S'])

        if piercing_points:  
            t_sp = piercing_points[0].pierce[-1][1]
            t_s = piercing_points_S[0].pierce[-1][1]
            lhs[j] = t_s - t_sp  
            file_name = file_info[i]
    return (lhs, file_name)
Пример #6
0
 def test_pierce_add_depth(self):
     """
     Test pierce points requested at a specific depth.
     """
     model = TauPyModel("iasp91")
     depth = 1000.0
     arrivals = model.get_pierce_points(300.0, 50.0, ["PcP"],
                                        add_depth=[depth])
     pierce = arrivals[0].pierce
     assert pierce[3]['depth'] == depth
     assert abs(pierce[3]['dist'] - 0.051) < 2e-3
Пример #7
0
   def find_pierce_coor(self,plot='False'):
      import geopy
      from geopy.distance import VincentyDistance

      '''
      given an instance of the receiver function class this function
      returns latitude and longitude of all receiver side pierce points
      of Pds in a given depth range (the default range is 50 - 800 km)
      NOTE:
      be careful that ses3d typically uses colatitude, while
      this function returns latitude '''

      depth_range = np.arange(50,800,5)        #set range of pierce points

      #geodetic info
      bearing     = self.az
      lon_s = self.ses3d_seismogram.sy
      lat_s = 90.0-self.ses3d_seismogram.sx
      lon_r = self.ses3d_seismogram.ry
      lat_r = 90.0-self.ses3d_seismogram.rx
      origin      = geopy.Point(lat_s, lon_s)

      #find how far away the pierce point is
      model  = TauPyModel(model='pyrolite_5km')

      for i in range(0,len(depth_range)):
         phase = 'P'+str(depth_range[i])+'s'
         pierce = model.get_pierce_points(self.eq_depth,self.delta_deg,phase_list=[phase])
         points = pierce[0].pierce
         for j in range(0,len(points)):
            if points[j]['depth'] == depth_range[i] and points[j]['dist']*(180.0/np.pi) > 25.0:
               prc_dist = points[j]['dist']*(180.0/np.pi)
               d_km = prc_dist * ((2*np.pi*6371.0/360.0))
               destination = VincentyDistance(kilometers=d_km).destination(origin,bearing)
               lat = destination[0]
               lon = destination[1]
               value = 0
               row = {'depth':depth_range[i],'dist':prc_dist,'lat':lat,'lon':lon,'value':value}
               self.pierce_dict.append(row)

      if plot=='True':
         m = Basemap(projection='hammer',lon_0=0)
         m.drawmapboundary()
         m.drawcoastlines()
         m.drawgreatcircle(lon_s,lat_s,lon_r,lat_r,linewidth=1,color='b',alpha=0.5)

         for i in range(len(self.pierce_dict)):
            x,y = m(self.pierce_dict[i]['lon'],self.pierce_dict[i]['lat'])
            m.scatter(x,y,5,marker='o',color='r')
         plt.show()
Пример #8
0
    def test_pierce_all_phases(self):
        """
        Tests pierce points against those calculated in TauP.
        """
        filename = os.path.join(DATA, "java_taup_pierce_h10_deg35_ttall")
        expected = collections.defaultdict(list)
        with open(filename, "rt") as fh:
            for line in fh:
                line = line.strip()
                if not line:
                    continue
                if line.startswith(">"):
                    current_phase = line[1:].strip().split()[0]
                    continue
                dist, depth, time = list(map(float, line.split()))
                expected[current_phase].append((dist, depth, time))
        expected_phases = sorted(set(expected.keys()))

        m = TauPyModel(model="iasp91")
        arrivals = m.get_pierce_points(source_depth_in_km=10.0,
                                       distance_in_degree=35.0,
                                       phase_list=["ttall"])

        # Make sure the same stuff is available.
        arrival_phases = sorted(set([_i.name for _i in arrivals]))
        self.assertEqual(expected_phases, arrival_phases)

        actual = collections.defaultdict(list)
        for arr in arrivals:
            for p in arr.pierce:
                actual[arr.name].append((
                    round(np.degrees(p['dist']), 2),
                    round(p['depth'], 1),
                    round(p['time'], 1)))

        self.assertEqual(sorted(actual.keys()), sorted(expected.keys()))

        for key in actual.keys():
            actual_values = sorted(actual[key])
            expected_values = sorted(expected[key])
            self.assertEqual(actual_values, expected_values)
Пример #9
0
    def test_pierce_all_phases(self):
        """
        Tests pierce points against those calculated in TauP.
        """
        filename = os.path.join(DATA, "java_taup_pierce_h10_deg35_ttall")
        expected = collections.defaultdict(list)
        with open(filename, "rt") as fh:
            for line in fh:
                line = line.strip()
                if not line:
                    continue
                if line.startswith(">"):
                    current_phase = line[1:].strip().split()[0]
                    continue
                dist, depth, time = list(map(float, line.split()))
                expected[current_phase].append((dist, depth, time))
        expected_phases = sorted(set(expected.keys()))

        m = TauPyModel(model="iasp91")
        arrivals = m.get_pierce_points(source_depth_in_km=10.0,
                                       distance_in_degree=35.0,
                                       phase_list=["ttall"])

        # Make sure the same stuff is available.
        arrival_phases = sorted(set([_i.name for _i in arrivals]))
        self.assertEqual(expected_phases, arrival_phases)

        actual = collections.defaultdict(list)
        for arr in arrivals:
            for p in arr.pierce:
                actual[arr.name].append((
                    round(np.degrees(p['dist']), 2),
                    round(p['depth'], 1),
                    round(p['time'], 1)))

        self.assertEqual(sorted(actual.keys()), sorted(expected.keys()))

        for key in actual.keys():
            actual_values = sorted(actual[key])
            expected_values = sorted(expected[key])
            self.assertEqual(actual_values, expected_values)
Пример #10
0
    def test_pierce_p_iasp91(self):
        """
        Test single pierce point against output from TauP.
        """
        m = TauPyModel(model="iasp91")
        arrivals = m.get_pierce_points(source_depth_in_km=10.0,
                                       distance_in_degree=35.0,
                                       phase_list=["P"])
        self.assertEqual(len(arrivals), 1)
        p_arr = arrivals[0]

        # Open test file.
        filename = os.path.join(DATA, "taup_pierce_-h_10_-ph_P_-deg_35")

        expected = np.genfromtxt(filename, skip_header=1)

        np.testing.assert_almost_equal(expected[:, 0],
                                       np.degrees(p_arr.pierce['dist']), 2)
        np.testing.assert_almost_equal(expected[:, 1], p_arr.pierce['depth'],
                                       1)
        np.testing.assert_almost_equal(expected[:, 2], p_arr.pierce['time'], 1)
Пример #11
0
    def test_pierce_p_iasp91(self):
        """
        Test single pierce point against output from TauP.
        """
        m = TauPyModel(model="iasp91")
        arrivals = m.get_pierce_points(source_depth_in_km=10.0,
                                       distance_in_degree=35.0,
                                       phase_list=["P"])
        self.assertEqual(len(arrivals), 1)
        p_arr = arrivals[0]

        # Open test file.
        filename = os.path.join(DATA, "taup_pierce_-h_10_-ph_P_-deg_35")

        expected = np.genfromtxt(filename, skip_header=1)

        np.testing.assert_almost_equal(expected[:, 0],
                                       np.degrees(p_arr.pierce['dist']), 2)
        np.testing.assert_almost_equal(expected[:, 1],
                                       p_arr.pierce['depth'], 1)
        np.testing.assert_almost_equal(expected[:, 2],
                                       p_arr.pierce['time'], 1)
Пример #12
0
def get_pierce_points(st,phase,depth,h5_out):
   model = TauPyModel(model="prem_50")
   try:
       f = h5py.File('/home/samhaug/anaconda2/lib/python2.7/site-packages/seispy'+
                h5_out,'w')
   except IOError:
       os.rmdir('/home/samhaug/anaconda2/lib/python2.7/site-packages/seispy'+
                h5_out)
       print "Had to remove existing file. Try again"
   evla = st[0].stats.sac['evla']
   evlo = st[0].stats.sac['evlo']
   evdp = st[0].stats.sac['evdp']
   pierce_list = []
   for idx,tr in enumerate(st):
        print tr
        a = model.get_pierce_points(evdp,tr.stats.sac['gcarc'],phase_list=[phase])
        b = a[0]
        depth_index = np.argmin(np.abs(b.pierce['depth']-depth))
        distance = b.pierce['dist'][depth_index]
        pierce_list.append((distance,tr.stats.sac['az']))
   pierce_array = np.array(pierce_list)
   f.create_dataset('pierce',data=pierce_array)
   f.close()
   return pierce_array
Пример #13
0
    def migrate(self, plot=False):
        import geopy
        from geopy.distance import VincentyDistance
        '''
      This is a rewritten function that combines the functions find_pierce_coor and
      migrate_1d so that it's more efficient.  Still in testing stages. RM 2/6/16
      '''

        depth_range = np.arange(50, 800, 5)  #set range of pierce points
        value = np.zeros((len(depth_range)))

        #geodetic info
        bearing = self.az
        lon_s = self.ses3d_seismogram.sy
        lat_s = 90.0 - self.ses3d_seismogram.sx
        lon_r = self.ses3d_seismogram.ry
        lat_r = 90.0 - self.ses3d_seismogram.rx
        origin = geopy.Point(lat_s, lon_s)

        #find how far away the pierce point is
        model = TauPyModel(model='pyrolite_5km')

        for i in range(0, len(depth_range)):
            phase = 'P' + str(depth_range[i]) + 's'
            pierce = model.get_pierce_points(self.eq_depth,
                                             self.delta_deg,
                                             phase_list=[phase])
            tt = model.get_travel_times(self.eq_depth,
                                        self.delta_deg,
                                        phase_list=['P', phase])

            #in case there's duplicate phase arrivals
            for j in range(0, len(tt)):
                if tt[j].name == 'P':
                    p_arr = tt[j].time
                elif tt[j].name == phase:
                    phase_arr = tt[j].time

            #determine value
            Pds_time = phase_arr - p_arr
            i_start = int((0.0 - self.window_start) / self.ses3d_seismogram.dt)
            i_t = int(Pds_time / self.ses3d_seismogram.dt) + i_start
            value[i] = self.prf[i_t]

            points = pierce[0].pierce
            for j in range(0, len(points)):
                if points[j]['depth'] == depth_range[
                        i] and points[j]['dist'] * (180.0 / np.pi) > 20.0:
                    prc_dist = points[j]['dist'] * (180.0 / np.pi)
                    d_km = prc_dist * ((2 * np.pi * 6371.0 / 360.0))
                    destination = VincentyDistance(
                        kilometers=d_km).destination(origin, bearing)
                    lat = destination[0]
                    lon = destination[1]
                    row = {
                        'depth': depth_range[i],
                        'dist': prc_dist,
                        'lat': lat,
                        'lon': lon,
                        'value': value[i]
                    }
                    self.pierce_dict.append(row)

        if plot == True:
            plt.plot(value, depth_range)
            plt.gca().invert_yaxis()
            plt.show()

        return value, depth_range
Пример #14
0
class receiver_function(object):
#######################################################################################
   '''
   The receiver funciton class contains an obspy stream with the three components 
   of the receiver function.  The three trace objects in the stream are, in order:

   rf_st[0] : transverse component receiver function
   rf_st[1] : radial component receiver function
   rf_st[2] : z component receiver function (not usually used)
   '''

   ####################################################################################
   def __init__(self,tr_e,tr_n,tr_z,**kwargs):
   ####################################################################################
      '''
      Initialize receiver function

      params:
      tr_e  :obspy trace object, BHE channel
      tr_n  :obspy trace object, BHN channel
      tr_z  :obspy trace object, BHZ channel

      **kwargs:
      taup_model: TauPyModel instance.  Passing a pre-existing model speeds things up 
                  since it isn't necessary to initialize the the model when creating
                  the receiver function object.

      taup_model_name: If taup_model = 'none', you can tell it which model it use. The
                       default is prem_5km.

      window:  A tuple describing the time window of the receiver function (times given
               relative to P).
      '''
      #inherit taup model to avoid initializing the model for every receiver function
      taup_model = kwargs.get('taup_model','none')
      taup_model_name = kwargs.get('taup_model_name','ak135') #prem_5km if doing migrations

      if taup_model == 'none':
         self.model = TauPyModel(model=taup_model_name)
      else:
         self.model = taup_model

      #cut window centered on P phase
      self.window  = kwargs.get('window',[-10,150])
      self.tr_e    = phase_window(tr_e,phases=['P'],window_tuple=self.window,taup_model=self.model)
      self.tr_n    = phase_window(tr_n,phases=['P'],window_tuple=self.window,taup_model=self.model)
      self.tr_z    = phase_window(tr_z,phases=['P'],window_tuple=self.window,taup_model=self.model)
      self.time    = np.linspace(self.window[0],self.window[1],len(self.tr_e.data))
      self.dt      = 1.0/self.tr_e.stats.sampling_rate

      #make start time zero NOT SURE IF THIS WORKS!!! RM/ 4/13/16
      self.tr_e.starttime = 0
      self.tr_n.starttime = 0
      self.tr_z.starttime = 0

      #initialize obspy stream
      self.rf_st   = obspy.Stream(self.tr_e)
      self.rf_st  += self.tr_n
      self.rf_st  += self.tr_z

      self.gcarc   = self.tr_e.stats.sac['gcarc']
      self.evdp    = self.tr_e.stats.sac['evdp']
      self.pierce  = []

      #read slowness table for moveout correction
      self.slowness_table = np.loadtxt('/geo/work10/romaguir/seismology/seis_tools/seispy/slowness_table.dat')

      #get slowness and predicted P410s, P660s arrival times
      tt = self.model.get_travel_times(source_depth_in_km = self.evdp,
                                       distance_in_degree = self.gcarc,
                                       phase_list=['P','P410s','P660s'])

      #just in case there's more than one phase arrival, loop through tt list
      for i in range(0,len(tt)):
         if tt[i].name == 'P':
            self.predicted_p_arr = tt[i].time 
            #ray parameter (horizontal slowness) of incident plane wave 
            self.ray_param = tt[i].ray_param_sec_degree
         elif tt[i].name == 'P410s':
            self.predicted_p410s_arr = tt[i].time 
         if tt[i].name == 'P660s':
            self.predicted_p660s_arr = tt[i].time 

      #event information
      self.evla  = self.tr_e.stats.sac['evla']
      self.evlo  = self.tr_e.stats.sac['evlo']
      self.stla  = self.tr_e.stats.sac['stla']
      self.stlo  = self.tr_e.stats.sac['stlo']
      self.gcarc = self.tr_e.stats.sac['gcarc']
      self.evdp  = self.tr_e.stats.sac['evdp']

   ####################################################################################
   def plot(self):
   ####################################################################################
      #make axes-----------------------------------------------------------------------
      fig,axes = plt.subplots(3,sharex=True,figsize=(12,6)) 
      font = {'family': 'serif',
        'color':  'black',
        'weight': 'normal',
        'size': 16,
           }

      #plot data-----------------------------------------------------------------------
      axes[0].plot(self.time,self.rf_st[0].data,'k') 
      axes[0].grid()
      axes[0].ticklabel_format(style='sci',scilimits=(0,1),axis='y')
      axes[1].plot(self.time,self.rf_st[1].data,'k') 
      axes[1].grid()
      axes[1].ticklabel_format(style='sci',scilimits=(0,1),axis='y')
      axes[2].plot(self.time,self.rf_st[2].data,'k') 
      axes[2].grid()
      axes[2].ticklabel_format(style='sci',scilimits=(0,1),axis='y')

      #plot expected P410s and P660s arrivals
      t410 = self.predicted_p410s_arr - self.predicted_p_arr
      t660 = self.predicted_p660s_arr - self.predicted_p_arr
      axes[0].axvline(t410, color='r')
      axes[0].axvline(t660, color='r')
      axes[1].axvline(t410, color='r')
      axes[1].axvline(t660, color='r')
      axes[2].axvline(t410, color='r')
      axes[2].axvline(t660, color='r')

      #labels--------------------------------------------------------------------------
      axes[0].set_ylabel('amplitude',fontdict=font)
      axes[0].text(0.05,0.85,self.rf_st[0].stats.channel,
                 horizontalalignment='center',
                 verticalalignment='center',
                 transform=axes[0].transAxes,
                 fontdict=font)
      axes[1].set_ylabel('amplitude',fontdict=font)
      axes[1].text(0.05,0.85,self.rf_st[1].stats.channel,
                 horizontalalignment='center',
                 verticalalignment='center',
                 transform=axes[1].transAxes,
                 fontdict=font)
      axes[2].set_ylabel('amplitude',fontdict=font)
      axes[2].set_xlabel('time after P (s)',fontdict=font)
      axes[2].text(0.05,0.85,self.rf_st[2].stats.channel,
                 horizontalalignment='center',
                 verticalalignment='center',
                 transform=axes[2].transAxes,
                 fontdict=font)
      plt.show()

   ####################################################################################
   def rotate(self,rotation_method='RTZ'):
   ####################################################################################

       #rotate-------------------------------------------------------------------------
       for i in range(0,len(self.rf_st)):
          self.rf_st[i].stats.back_azimuth = self.tr_e.stats.sac['baz']

       self.rf_st.rotate(method='NE->RT')
  
       if rotation_method == 'LQT':
          r_amp           = np.amax(np.amax(self.rf_st[1].data))
          z_amp           = np.amax(np.amax(self.rf_st[2].data))
          incidence_angle = np.arctan(r_amp/z_amp) * (180.0/np.pi)
          
          for i in range(0,len(self.rf_st)):
             self.rf_st[i].stats.inclination = incidence_angle

          self.rf_st.rotate(method='RT->NE')
          self.rf_st.rotate(method='ZNE->LQT')

   ####################################################################################
   def get_prf(self,decon_type='water_level',wl=0.1,damping=5.0,rotation_method='RTZ'):
   ####################################################################################

       #rotate-------------------------------------------------------------------------
       for tr in self.rf_st:
          tr.stats.back_azimuth = tr.stats.sac['baz']

       for tr in self.rf_st:
          tr.stats.starttime = 0

       self.rf_st.rotate(method='NE->RT')
  
       if rotation_method == 'LQT':
          r_amp           = np.amax(np.amax(self.rf_st[1].data))
          z_amp           = np.amax(np.amax(self.rf_st[2].data))
          incidence_angle = np.arctan(r_amp/z_amp) * (180.0/np.pi)

          print 'using LQT rotation'
          
          for i in range(0,len(self.rf_st)):
             self.rf_st[i].stats.inclination = incidence_angle

          self.rf_st.rotate(method='RT->NE')
          self.rf_st.rotate(method='ZNE->LQT')

       #deconvolve---------------------------------------------------------------------
       #divisor should be the L or Z component (depending on rotation method) 
       div = self.rf_st[2].data
       if decon_type == 'water_level':
          #self.rf_st[0].data = water_level(self.rf_st[0].data,div,alpha=wl)
          self.rf_st[1].data = water_level(self.rf_st[1].data,div,alpha=wl)
          #self.rf_st[2].data = water_level(self.rf_st[2].data,div,alpha=wl)
       elif decon_type == 'damped_lstsq':
          #self.rf_st[0].data = damped_lstsq(self.rf_st[0].data,div,damping=damp)

          #self.rf_st[1].data = damped_lstsq(self.rf_st[1].data,div,damping=damping)
          self.rf_st[1].data = damped_lstsq(div,self.rf_st[1].data,damping=damping)

          #self.rf_st[2].data = damped_lstsq(self.rf_st[2].data,div,damping=damp)

       #TESTING FASTER DECON METHODS 5/24/16
       #elif decon_type == 'rf_time_decon':
       #   self.rf_st[1].data = rf_time_decon(self.rf_st[1].data,div)
       #elif decon_type == 'solve_toeplitz':
       #   self.rf_st[1].data = solve_toeplitz(div,self.rf_st[1].data)
       elif decon_type == 'use_lsrn':
          self.rf_st[1].data = use_lsrn(self.rf_st[1].data,div)
          

       #center on P--------------------------------------------------------------------
       spike       = np.exp((-1.0*(self.time)**2)/0.1)
       spike_omega = np.fft.fft(spike)

       for i in range(0,len(self.rf_st)):
          data_omega         = np.fft.fft(self.rf_st[i].data)
          shifted            = spike_omega*data_omega
          self.rf_st[i].data = np.real(np.fft.ifft(shifted))

       #normalize on maximum of L component
       peak_amp = np.max(self.rf_st[2].data)
       for rf in self.rf_st:
         rf.data /= peak_amp

   #TODO write a function to reconvolve and compare misfit
   ####################################################################################
   def check_decon(self):
   ####################################################################################
      recon = np.convolve(self.rf_st[1],self.tr_z)
      plt.plot(self.time,recon)
      plt.plot(self.time,self.tr_e)

   ####################################################################################
   def moveout_correction(self):
   ####################################################################################
      '''
      Moveout correction relative to a reference ray parameter of 6.4 s/deg.  This stretches
      the time axis for smaller ray parameters (larger epicentral distances), and 
      shrinks the time axis for larger ray parameters (smaller epicentral distances).

      #NOTE 3-16-16, Moveout correction doesn't work properly... The time axis seems
      to be stretching in the opposite way that it should.
      '''
      p = self.slowness_table[:,0]
      s = self.slowness_table[:,1]
      
      #interpolate with np.interp. make sure values in the first vector are increasing
      scale = np.interp(self.ray_param,p[::-1],s[::-1])
      #print "ray parameter, scale = ",self.ray_param,scale

      #scale the receiver function and interpolate new time axis
      new_time = self.time * scale

      f        = interp1d(new_time,self.rf_st[0].data,bounds_error=False,fill_value=0)
      self.rf_st[0].data = f(self.time)

      f        = interp1d(new_time,self.rf_st[1].data,bounds_error=False,fill_value=0)
      self.rf_st[1].data = f(self.time)

      f        = interp1d(new_time,self.rf_st[2].data,bounds_error=False,fill_value=0)
      self.rf_st[2].data = f(self.time)

   ####################################################################################
   def migrate_1d(self,**kwargs):
   ####################################################################################
      depth   = kwargs.get('depth_range',np.arange(50,1005,5))
      amp     = np.zeros((len(depth)))
      origin  = geopy.Point(self.evla,self.evlo)
      bearing = self.rf_st[0].stats.sac['az']

      ii = 0
      for d in depth:
         phase  = 'P'+str(d)+'s'
         pierce = self.model.get_pierce_points(self.evdp,self.gcarc,phase_list=[phase])
         arrs   = self.model.get_travel_times(self.evdp,self.gcarc,phase_list=['P',phase])

         #in case there's duplicate phase arrivals
         for arr in arrs:
           if arr.name == 'P':
              p_arr = arr.time
           elif arr.name == phase:
              pds_arr = arr.time

         #determine amplitude at each depth
         window_start = self.window[0]
         pds_minus_p  = pds_arr - p_arr
         i_start      = int((0.0 - window_start)/self.dt)
         i_t          = int(pds_minus_p/self.dt) + i_start
         amp[ii]      = self.rf_st[1].data[i_t]

         #find pierce points and create pierce dictionary
         points = pierce[0].pierce
         for p in points:
            if p['depth'] == d and np.degrees(p['dist']) > 20.0:
               prc_dist = np.degrees(p['dist'])
               d_km     = prc_dist * ((2*np.pi*6371.0/360.0))
               destination = VincentyDistance(kilometers=d_km).destination(origin,bearing)
               lat = destination[0]
               lon = destination[1]
               row = {'depth':d,'dist':prc_dist,'lat':lat,'lon':lon,'amplitude':amp[ii]}
               self.pierce.append(row)
         ii += 1

   ####################################################################################
   def plot_pierce_points(self,depth=410.0,ax='None',**kwargs):
   ####################################################################################
      '''
      Plots pierce points for a given depth.  If an axes object is supplied
      as an argument it will use it for the plot.  Otherwise, a new axes
      object is created.

      kwargs:
             depth:         pierce point depth
             proj:          map projection.  if none given, a default basemap axis is
                            made, defined by the coordinates of the corners. if 'ortho'
                            is given, a globe centered on Lat_0 and Lon_0 is made.
             ll_corner_lat: latitude of lower left corner of map
             ll_corner_lon: longitude of lower left corner of map
             ur_corner_lat: latitude of upper right corner of map
             Lat_0:         latitude center of ortho
             Lon_0:         logitude center of ortho
             return_ax:     whether or you return the basemap axis object. default False

      '''
      proj=kwargs.get('proj','default')
      ll_lat=kwargs.get('ll_corner_lat',-35.0)
      ll_lon=kwargs.get('ll_corner_lon',0.0)
      ur_lat=kwargs.get('ur_corner_lat',35.0)
      ur_lon=kwargs.get('ur_corner_lon',120.0)
      Lat_0=kwargs.get('Lat_0',0.0)
      Lon_0=kwargs.get('Lon_0',0.0)
      return_ax =kwargs.get('return_ax',False)

      if ax == 'None':
         if proj == 'default':
            m = Basemap(llcrnrlon=ll_lon,llcrnrlat=ll_lat,urcrnrlon=ur_lon,urcrnrlat=ur_lat)
         elif proj == 'ortho':
            m = Basemap(projection='ortho',lat_0=Lat_0,lon_0=Lon_0)
         m.drawmapboundary()
         m.drawcoastlines()
         m.fillcontinents()
      else:
         m = ax

      found_points = False
      for ii in self.pierce:
         if ii['depth'] == depth:
            x,y = m(ii['lon'],ii['lat'])
            found_points = True

      if found_points == True:
         m.scatter(x,y,100,marker='+',color='r',zorder=99)
      else:
         print "no pierce points found for the given depth"


   ###############################################################################
   def shift(self,phase,ref_deg=64.0):
   ###############################################################################
      '''
      Shifts the time axis to account for moveout of a given phase
      
      params---------------------------------------------------------------------
      ref_deg: float, reference epicentral distance
      phase:   string, phase name for which to apply moveout correction
      '''
      t_ref = self.model.ge_travel_times(source_depth_in_km=self.evdp,
                                          distance_in_degree=ref_deg,
                                          phase_list=["P",phase])
      t_arr = self.model.get_travel_times(source_depth_in_km=self.evdp,
                                          distance_in_degree=self.gcarc,
                                          phase_list=["P",phase])
      for arr in t_ref:
         if arr.name=='P':
            p_arrival_ref = arr.time
         elif arr.name==phase:
            pds_arrival_ref = arr.time
        
      for arr in t_arr:
         if arr.name=='P':
            p_arrival = arr.time
         elif arr.name==phase:
            pds_arrival = arr.time

      time_shift = (pds_arrival_ref-p_arrival_ref)-(pds_arrival-p_arrival)
      int_shift  = int(time_shift/self.dt)
      self.rf_st[0].data = np.roll(self.rf_st[0].data,int_shift)
      self.rf_st[1].data = np.roll(self.rf_st[1].data,int_shift)
      self.rf_st[2].data = np.roll(self.rf_st[2].data,int_shift)

   ##############################################################################
   def zero_pP(self,**kwargs):
   ##############################################################################
      '''
      Finds predicted pP arrival and zeros a window centered on the arrival

      kwargs---------------------------------------------------------------------
      window_half_dur : half duration of zero window (default = 2.5 s)
      '''
      window_half_dur = kwargs.get('window_half_dur',2.5)
      arrs = self.model.get_travel_times(source_depth_in_km=self.evdp,
                                         distance_in_degree=self.gcarc,
                                         phase_list=['P','pP'])
      P_arr  = 'none'
      pP_arr = 'none'

      for arr in arrs:
         if arr.name == 'P':
            P_arr = arr
         elif arr.name == 'pP': 
            pP_arr = arr

      if P_arr == 'none' or pP_arr == 'none':
         raise ValueError('problem occured in function "zero_pP", no matching arrivals found')
      else:
         P_time = P_arr.time
         pP_time = pP_arr.time
         delay_time = pP_time - P_time
         zero_window_center = -1.0*self.window[0] + delay_time
         zero_window_start  = zero_window_center - window_half_dur
         zero_window_end    = zero_window_center + window_half_dur
         zero_window_start_index = int(zero_window_start/self.dt)
         zero_window_end_index   = int(zero_window_end/self.dt)

         #case 1: entire window is in range
         if zero_window_start_index >= 0 and zero_window_end_index <= len(self.rf_st[1].data):
            self.rf_st[1].data[zero_window_start_index:zero_window_end_index] = 0.0
         #case 2: end of window is out of range
         if zero_window_start_index >= 0 and zero_window_end_index >= len(self.rf_st[1].data):
            self.rf_st[1].data[zero_window_start_index:] = 0.0
         #case 3: entire window is out of range
         if zero_window_start_index >= len(self.rf_st[1].data):
            print "pP arrives outside the receiver function window"

   ##############################################################################
   def zero_PP(self,**kwargs):
   ##############################################################################
      '''
      Finds predicted PP arrival and zeros a window centered on the arrival

      kwargs---------------------------------------------------------------------
      window_half_dur : half duration of zero window (default = 2.5 s)
      '''
      window_half_dur = kwargs.get('window_half_dur',2.5)
      arrs = self.model.get_travel_times(source_depth_in_km=self.evdp,
                                         distance_in_degree=self.gcarc,
                                         phase_list=['P','PP'])
      P_arr  = 'none'
      PP_arr = 'none'

      for arr in arrs:
         if arr.name == 'P':
            P_arr = arr
         elif arr.name == 'PP':
            PP_arr = arr

      if P_arr == 'none' or PP_arr == 'none':
         raise ValueError('problem occured in function "zero_PP", no matching arrivals found')
      else:
         P_time = P_arr.time
         PP_time = PP_arr.time
         delay_time = PP_time - P_time
         zero_window_center = -1.0*self.window[0] + delay_time
         zero_window_start  = zero_window_center - window_half_dur
         zero_window_end    = zero_window_center + window_half_dur
         zero_window_start_index = int(zero_window_start/self.dt)
         zero_window_end_index   = int(zero_window_end/self.dt)

         #case 1: entire window is in range
         if zero_window_start_index >= 0 and zero_window_end_index <= len(self.rf_st[1].data):
            self.rf_st[1].data[zero_window_start_index:zero_window_end_index] = 0.0
         #case 2: end of window is out of range
         if zero_window_start_index >= 0 and zero_window_end_index >= len(self.rf_st[1].data):
            self.rf_st[1].data[zero_window_start_index:] = 0.0
         #case 3: entire window is out of range
         if zero_window_start_index >= len(self.rf_st[1].data):
            print "PP arrives outside the receiver function window"
Пример #15
0
def migrate_1d(rf_trace,**kwargs):
####################################################################################
   '''
   takes an rf trace and returns a dictionary with pierce points and associated
   reciever function ampltiudes

   *note it's best to pass a TauPyModel instance (eg, prem_5km), to avoid having 
    to initiate a new model every time you call this function
   '''

   #get kwargs
   depth      = kwargs.get('depth_range',np.arange(50,805,5))
   taup_model = kwargs.get('taup_model','None')
   format     = kwargs.get('format','rfh5')
   window     = kwargs.get('window',[-10,100])

   #geographical information
   if format == 'rfh5':
      gcarc = rf_trace.stats.gcarc
      dt    = rf_trace.stats.delta
      evla  = rf_trace.stats.evla
      evlo  = rf_trace.stats.evlo
      evdp  = rf_trace.stats.evdp
      stla  = rf_trace.stats.stla
      stlo  = rf_trace.stats.stlo
      az    = rf_trace.stats.az
      o     = rf_trace.stats.o

   #initializations
   amp           = np.zeros((len(depth)))
   origin        = geopy.Point(evla,evlo)
   bearing       = az
   pierce_dict   = []
   if taup_model == 'None':
      taup_model = TauPyModel('prem_5km')

   ii = 0
   for d in depth:
      phase  = 'P'+str(d)+'s'
      pierce = taup_model.get_pierce_points(evdp,gcarc,phase_list=[phase])
      arrs   = taup_model.get_travel_times(evdp,gcarc,phase_list=['P',phase])

      #in case there's duplicate phase arrivals
      P_arrs = []
      Pds_arrs = []
      for arr in arrs:
        if arr.name == 'P':
           P_arrs.append(arr)
           #p_arr = arr.time
        elif arr.name == phase:
           #pds_arr = arr.time
           Pds_arrs.append(arr)
      p_arr = P_arrs[0].time 
      pds_arr = Pds_arrs[0].time

      #determine amplitude at each depth
      #window_start = o #TODO update writeh5py_dict so that win_start win_end are written
      pds_minus_p  = pds_arr - p_arr
      i_start      = int((0.0 - window[0])/dt)
      i_t          = int(pds_minus_p/dt) + i_start
      amp[ii]      = rf_trace.data[i_t]

      #find pierce points and create pierce dictionary
      points = pierce[0].pierce
      for p in points:
         if p['depth'] == d and np.degrees(p['dist']) > 20.0:
            prc_dist = np.degrees(p['dist'])
            d_km     = prc_dist * ((2*np.pi*6371.0/360.0))
            destination = VincentyDistance(kilometers=d_km).destination(origin,bearing)
            lat = destination[0]
            lon = destination[1]
            row = {'depth':d,'dist':prc_dist,'lat':lat,'lon':lon,'amplitude':amp[ii]}
            pierce_dict.append(row)
      ii += 1

   return pierce_dict
Пример #16
0
class receiver_function(object):
#######################################################################################
   '''
   The receiver funciton class contains an obspy stream with the three components 
   of the receiver function.  The three trace objects in the stream are, in order:

   rf_st[0] : transverse component receiver function
   rf_st[1] : radial component receiver function
   rf_st[2] : z component receiver function (not usually used)
   '''

   ####################################################################################
   def __init__(self,tr_e,tr_n,tr_z,**kwargs):
   ####################################################################################
      '''
      Initialize receiver function

      params:
      tr_e  :obspy trace object, BHE channel
      tr_n  :obspy trace object, BHN channel
      tr_z  :obspy trace object, BHZ channel

      **kwargs:
      taup_model: TauPyModel instance.  Passing a pre-existing model speeds things up 
                  since it isn't necessary to initialize the the model when creating
                  the receiver function object.

      taup_model_name: If taup_model = 'none', you can tell it which model it use. The
                       default is prem_5km.

      window:  A tuple describing the time window of the receiver function (times given
               relative to P).
      '''
      #inherit taup model to avoid initializing the model for every receiver function
      taup_model = kwargs.get('taup_model','none')
      taup_model_name = kwargs.get('taup_model_name','ak135') #prem_5km if doing migrations

      if taup_model == 'none':
         self.model = TauPyModel(model=taup_model_name)
      else:
         self.model = taup_model

      #cut window centered on P phase
      self.window  = kwargs.get('window',[-10,150])
      self.tr_e    = phase_window(tr_e,phases=['P'],window_tuple=self.window,taup_model=self.model)
      self.tr_n    = phase_window(tr_n,phases=['P'],window_tuple=self.window,taup_model=self.model)
      self.tr_z    = phase_window(tr_z,phases=['P'],window_tuple=self.window,taup_model=self.model)
      self.time    = np.linspace(self.window[0],self.window[1],len(self.tr_e.data))
      self.dt      = 1.0/self.tr_e.stats.sampling_rate

      #make start time zero NOT SURE IF THIS WORKS!!! RM/ 4/13/16
      self.tr_e.starttime = 0
      self.tr_n.starttime = 0
      self.tr_z.starttime = 0

      #initialize obspy stream
      self.rf_st   = obspy.Stream(self.tr_e)
      self.rf_st  += self.tr_n
      self.rf_st  += self.tr_z

      self.gcarc   = self.tr_e.stats.sac['gcarc']
      self.evdp    = self.tr_e.stats.sac['evdp']
      self.pierce  = []

      #read slowness table for moveout correction
      self.slowness_table = np.loadtxt('/geo/work10/romaguir/seismology/seis_tools/seispy/slowness_table.dat')

      #get slowness and predicted P410s, P660s arrival times
      tt = self.model.get_travel_times(source_depth_in_km = self.evdp,
                                       distance_in_degree = self.gcarc,
                                       phase_list=['P','P410s','P660s'])

      #just in case there's more than one phase arrival, loop through tt list
      for i in range(0,len(tt)):
         if tt[i].name == 'P':
            self.predicted_p_arr = tt[i].time 
            #ray parameter (horizontal slowness) of incident plane wave 
            self.ray_param = tt[i].ray_param_sec_degree
         elif tt[i].name == 'P410s':
            self.predicted_p410s_arr = tt[i].time 
         if tt[i].name == 'P660s':
            self.predicted_p660s_arr = tt[i].time 

      #event information
      self.evla  = self.tr_e.stats.sac['evla']
      self.evlo  = self.tr_e.stats.sac['evlo']
      self.stla  = self.tr_e.stats.sac['stla']
      self.stlo  = self.tr_e.stats.sac['stlo']
      self.gcarc = self.tr_e.stats.sac['gcarc']
      self.evdp  = self.tr_e.stats.sac['evdp']

   ####################################################################################
   def plot(self):
   ####################################################################################
      #make axes-----------------------------------------------------------------------
      fig,axes = plt.subplots(3,sharex=True,figsize=(12,6)) 
      font = {'family': 'serif',
        'color':  'black',
        'weight': 'normal',
        'size': 16,
           }

      #plot data-----------------------------------------------------------------------
      axes[0].plot(self.time,self.rf_st[0].data,'k') 
      axes[0].grid()
      axes[0].ticklabel_format(style='sci',scilimits=(0,1),axis='y')
      axes[1].plot(self.time,self.rf_st[1].data,'k') 
      axes[1].grid()
      axes[1].ticklabel_format(style='sci',scilimits=(0,1),axis='y')
      axes[2].plot(self.time,self.rf_st[2].data,'k') 
      axes[2].grid()
      axes[2].ticklabel_format(style='sci',scilimits=(0,1),axis='y')

      #plot expected P410s and P660s arrivals
      t410 = self.predicted_p410s_arr - self.predicted_p_arr
      t660 = self.predicted_p660s_arr - self.predicted_p_arr
      axes[0].axvline(t410, color='r')
      axes[0].axvline(t660, color='r')
      axes[1].axvline(t410, color='r')
      axes[1].axvline(t660, color='r')
      axes[2].axvline(t410, color='r')
      axes[2].axvline(t660, color='r')

      #labels--------------------------------------------------------------------------
      axes[0].set_ylabel('amplitude',fontdict=font)
      axes[0].text(0.05,0.85,self.rf_st[0].stats.channel,
                 horizontalalignment='center',
                 verticalalignment='center',
                 transform=axes[0].transAxes,
                 fontdict=font)
      axes[1].set_ylabel('amplitude',fontdict=font)
      axes[1].text(0.05,0.85,self.rf_st[1].stats.channel,
                 horizontalalignment='center',
                 verticalalignment='center',
                 transform=axes[1].transAxes,
                 fontdict=font)
      axes[2].set_ylabel('amplitude',fontdict=font)
      axes[2].set_xlabel('time after P (s)',fontdict=font)
      axes[2].text(0.05,0.85,self.rf_st[2].stats.channel,
                 horizontalalignment='center',
                 verticalalignment='center',
                 transform=axes[2].transAxes,
                 fontdict=font)
      plt.show()

   ####################################################################################
   def rotate(self,rotation_method='RTZ'):
   ####################################################################################

       #rotate-------------------------------------------------------------------------
       for i in range(0,len(self.rf_st)):
          self.rf_st[i].stats.back_azimuth = self.tr_e.stats.sac['baz']

       self.rf_st.rotate(method='NE->RT')
  
       if rotation_method == 'LQT':
          r_amp           = np.amax(np.amax(self.rf_st[1].data))
          z_amp           = np.amax(np.amax(self.rf_st[2].data))
          incidence_angle = np.arctan(r_amp/z_amp) * (180.0/np.pi)
          
          for i in range(0,len(self.rf_st)):
             self.rf_st[i].stats.inclination = incidence_angle

          self.rf_st.rotate(method='RT->NE')
          self.rf_st.rotate(method='ZNE->LQT')

   ####################################################################################
   def get_prf(self,decon_type='water_level',wl=0.1,damping=5.0,rotation_method='RTZ'):
   ####################################################################################

       #rotate-------------------------------------------------------------------------
       for tr in self.rf_st:
          tr.stats.back_azimuth = tr.stats.sac['baz']

       for tr in self.rf_st:
          tr.stats.starttime = 0

       self.rf_st.rotate(method='NE->RT')
  
       if rotation_method == 'LQT':
          r_amp           = np.amax(np.amax(self.rf_st[1].data))
          z_amp           = np.amax(np.amax(self.rf_st[2].data))
          incidence_angle = np.arctan(r_amp/z_amp) * (180.0/np.pi)

          print 'using LQT rotation'
          
          for i in range(0,len(self.rf_st)):
             self.rf_st[i].stats.inclination = incidence_angle

          self.rf_st.rotate(method='RT->NE')
          self.rf_st.rotate(method='ZNE->LQT')

       #deconvolve---------------------------------------------------------------------
       #divisor should be the L or Z component (depending on rotation method) 
       div = self.rf_st[2].data
       if decon_type == 'water_level':
          #self.rf_st[0].data = water_level(self.rf_st[0].data,div,alpha=wl)
          self.rf_st[1].data = water_level(self.rf_st[1].data,div,alpha=wl)
          #self.rf_st[2].data = water_level(self.rf_st[2].data,div,alpha=wl)
       elif decon_type == 'damped_lstsq':
          #self.rf_st[0].data = damped_lstsq(self.rf_st[0].data,div,damping=damp)

          #self.rf_st[1].data = damped_lstsq(self.rf_st[1].data,div,damping=damping)
          self.rf_st[1].data = damped_lstsq(div,self.rf_st[1].data,damping=damping)

          #self.rf_st[2].data = damped_lstsq(self.rf_st[2].data,div,damping=damp)

       #TESTING FASTER DECON METHODS 5/24/16
       #elif decon_type == 'rf_time_decon':
       #   self.rf_st[1].data = rf_time_decon(self.rf_st[1].data,div)
       #elif decon_type == 'solve_toeplitz':
       #   self.rf_st[1].data = solve_toeplitz(div,self.rf_st[1].data)

       #elif decon_type == 'use_lsrn':
          #self.rf_st[1].data = use_lsrn(self.rf_st[1].data,div)
          

       #center on P--------------------------------------------------------------------
       spike       = np.exp((-1.0*(self.time)**2)/0.1)
       spike_omega = np.fft.fft(spike)

       for i in range(0,len(self.rf_st)):
          data_omega         = np.fft.fft(self.rf_st[i].data)
          shifted            = spike_omega*data_omega
          self.rf_st[i].data = np.real(np.fft.ifft(shifted))

       #normalize on maximum of L component
       peak_amp = np.max(self.rf_st[2].data)
       for rf in self.rf_st:
         rf.data /= peak_amp

   #TODO write a function to reconvolve and compare misfit
   ####################################################################################
   def check_decon(self):
   ####################################################################################
      recon = np.convolve(self.rf_st[1],self.tr_z)
      plt.plot(self.time,recon)
      plt.plot(self.time,self.tr_e)

   ####################################################################################
   def moveout_correction(self):
   ####################################################################################
      '''
      Moveout correction relative to a reference ray parameter of 6.4 s/deg.  This stretches
      the time axis for smaller ray parameters (larger epicentral distances), and 
      shrinks the time axis for larger ray parameters (smaller epicentral distances).

      #NOTE 3-16-16, Moveout correction doesn't work properly... The time axis seems
      to be stretching in the opposite way that it should.
      '''
      p = self.slowness_table[:,0]
      s = self.slowness_table[:,1]
      
      #interpolate with np.interp. make sure values in the first vector are increasing
      scale = np.interp(self.ray_param,p[::-1],s[::-1])
      #print "ray parameter, scale = ",self.ray_param,scale

      #scale the receiver function and interpolate new time axis
      new_time = self.time * scale

      f        = interp1d(new_time,self.rf_st[0].data,bounds_error=False,fill_value=0)
      self.rf_st[0].data = f(self.time)

      f        = interp1d(new_time,self.rf_st[1].data,bounds_error=False,fill_value=0)
      self.rf_st[1].data = f(self.time)

      f        = interp1d(new_time,self.rf_st[2].data,bounds_error=False,fill_value=0)
      self.rf_st[2].data = f(self.time)

   ####################################################################################
   def migrate_1d(self,**kwargs):
   ####################################################################################
      depth   = kwargs.get('depth_range',np.arange(50,1005,5))
      amp     = np.zeros((len(depth)))
      origin  = geopy.Point(self.evla,self.evlo)
      bearing = self.rf_st[0].stats.sac['az']

      ii = 0
      for d in depth:
         phase  = 'P'+str(d)+'s'
         pierce = self.model.get_pierce_points(self.evdp,self.gcarc,phase_list=[phase])
         arrs   = self.model.get_travel_times(self.evdp,self.gcarc,phase_list=['P',phase])

         #in case there's duplicate phase arrivals
         for arr in arrs:
           if arr.name == 'P':
              p_arr = arr.time
           elif arr.name == phase:
              pds_arr = arr.time

         #determine amplitude at each depth
         window_start = self.window[0]
         pds_minus_p  = pds_arr - p_arr
         i_start      = int((0.0 - window_start)/self.dt)
         i_t          = int(pds_minus_p/self.dt) + i_start
         amp[ii]      = self.rf_st[1].data[i_t]

         #find pierce points and create pierce dictionary
         points = pierce[0].pierce
         for p in points:
            if p['depth'] == d and np.degrees(p['dist']) > 20.0:
               prc_dist = np.degrees(p['dist'])
               d_km     = prc_dist * ((2*np.pi*6371.0/360.0))
               destination = VincentyDistance(kilometers=d_km).destination(origin,bearing)
               lat = destination[0]
               lon = destination[1]
               row = {'depth':d,'dist':prc_dist,'lat':lat,'lon':lon,'amplitude':amp[ii]}
               self.pierce.append(row)
         ii += 1

   ####################################################################################
   def plot_pierce_points(self,depth=410.0,ax='None',**kwargs):
   ####################################################################################
      '''
      Plots pierce points for a given depth.  If an axes object is supplied
      as an argument it will use it for the plot.  Otherwise, a new axes
      object is created.

      kwargs:
             depth:         pierce point depth
             proj:          map projection.  if none given, a default basemap axis is
                            made, defined by the coordinates of the corners. if 'ortho'
                            is given, a globe centered on Lat_0 and Lon_0 is made.
             ll_corner_lat: latitude of lower left corner of map
             ll_corner_lon: longitude of lower left corner of map
             ur_corner_lat: latitude of upper right corner of map
             Lat_0:         latitude center of ortho
             Lon_0:         logitude center of ortho
             return_ax:     whether or you return the basemap axis object. default False

      '''
      proj=kwargs.get('proj','default')
      ll_lat=kwargs.get('ll_corner_lat',-35.0)
      ll_lon=kwargs.get('ll_corner_lon',0.0)
      ur_lat=kwargs.get('ur_corner_lat',35.0)
      ur_lon=kwargs.get('ur_corner_lon',120.0)
      Lat_0=kwargs.get('Lat_0',0.0)
      Lon_0=kwargs.get('Lon_0',0.0)
      return_ax =kwargs.get('return_ax',False)

      if ax == 'None':
         if proj == 'default':
            m = Basemap(llcrnrlon=ll_lon,llcrnrlat=ll_lat,urcrnrlon=ur_lon,urcrnrlat=ur_lat)
         elif proj == 'ortho':
            m = Basemap(projection='ortho',lat_0=Lat_0,lon_0=Lon_0)
         m.drawmapboundary()
         m.drawcoastlines()
         m.fillcontinents()
      else:
         m = ax

      found_points = False
      for ii in self.pierce:
         if ii['depth'] == depth:
            x,y = m(ii['lon'],ii['lat'])
            found_points = True

      if found_points == True:
         m.scatter(x,y,100,marker='+',color='r',zorder=99)
      else:
         print "no pierce points found for the given depth"


   ###############################################################################
   def shift(self,phase,ref_deg=64.0):
   ###############################################################################
      '''
      Shifts the time axis to account for moveout of a given phase
      
      params---------------------------------------------------------------------
      ref_deg: float, reference epicentral distance
      phase:   string, phase name for which to apply moveout correction
      '''
      t_ref = self.model.ge_travel_times(source_depth_in_km=self.evdp,
                                          distance_in_degree=ref_deg,
                                          phase_list=["P",phase])
      t_arr = self.model.get_travel_times(source_depth_in_km=self.evdp,
                                          distance_in_degree=self.gcarc,
                                          phase_list=["P",phase])
      for arr in t_ref:
         if arr.name=='P':
            p_arrival_ref = arr.time
         elif arr.name==phase:
            pds_arrival_ref = arr.time
        
      for arr in t_arr:
         if arr.name=='P':
            p_arrival = arr.time
         elif arr.name==phase:
            pds_arrival = arr.time

      time_shift = (pds_arrival_ref-p_arrival_ref)-(pds_arrival-p_arrival)
      int_shift  = int(time_shift/self.dt)
      self.rf_st[0].data = np.roll(self.rf_st[0].data,int_shift)
      self.rf_st[1].data = np.roll(self.rf_st[1].data,int_shift)
      self.rf_st[2].data = np.roll(self.rf_st[2].data,int_shift)

   ##############################################################################
   def zero_pP(self,**kwargs):
   ##############################################################################
      '''
      Finds predicted pP arrival and zeros a window centered on the arrival

      kwargs---------------------------------------------------------------------
      window_half_dur : half duration of zero window (default = 2.5 s)
      '''
      window_half_dur = kwargs.get('window_half_dur',2.5)
      arrs = self.model.get_travel_times(source_depth_in_km=self.evdp,
                                         distance_in_degree=self.gcarc,
                                         phase_list=['P','pP'])
      P_arr  = 'none'
      pP_arr = 'none'

      for arr in arrs:
         if arr.name == 'P':
            P_arr = arr
         elif arr.name == 'pP': 
            pP_arr = arr

      if P_arr == 'none' or pP_arr == 'none':
         raise ValueError('problem occured in function "zero_pP", no matching arrivals found')
      else:
         P_time = P_arr.time
         pP_time = pP_arr.time
         delay_time = pP_time - P_time
         zero_window_center = -1.0*self.window[0] + delay_time
         zero_window_start  = zero_window_center - window_half_dur
         zero_window_end    = zero_window_center + window_half_dur
         zero_window_start_index = int(zero_window_start/self.dt)
         zero_window_end_index   = int(zero_window_end/self.dt)

         #case 1: entire window is in range
         if zero_window_start_index >= 0 and zero_window_end_index <= len(self.rf_st[1].data):
            self.rf_st[1].data[zero_window_start_index:zero_window_end_index] = 0.0
         #case 2: end of window is out of range
         if zero_window_start_index >= 0 and zero_window_end_index >= len(self.rf_st[1].data):
            self.rf_st[1].data[zero_window_start_index:] = 0.0
         #case 3: entire window is out of range
         if zero_window_start_index >= len(self.rf_st[1].data):
            print "pP arrives outside the receiver function window"

   ##############################################################################
   def zero_PP(self,**kwargs):
   ##############################################################################
      '''
      Finds predicted PP arrival and zeros a window centered on the arrival

      kwargs---------------------------------------------------------------------
      window_half_dur : half duration of zero window (default = 2.5 s)
      '''
      window_half_dur = kwargs.get('window_half_dur',2.5)
      arrs = self.model.get_travel_times(source_depth_in_km=self.evdp,
                                         distance_in_degree=self.gcarc,
                                         phase_list=['P','PP'])
      P_arr  = 'none'
      PP_arr = 'none'

      for arr in arrs:
         if arr.name == 'P':
            P_arr = arr
         elif arr.name == 'PP':
            PP_arr = arr

      if P_arr == 'none' or PP_arr == 'none':
         raise ValueError('problem occured in function "zero_PP", no matching arrivals found')
      else:
         P_time = P_arr.time
         PP_time = PP_arr.time
         delay_time = PP_time - P_time
         zero_window_center = -1.0*self.window[0] + delay_time
         zero_window_start  = zero_window_center - window_half_dur
         zero_window_end    = zero_window_center + window_half_dur
         zero_window_start_index = int(zero_window_start/self.dt)
         zero_window_end_index   = int(zero_window_end/self.dt)

         #case 1: entire window is in range
         if zero_window_start_index >= 0 and zero_window_end_index <= len(self.rf_st[1].data):
            self.rf_st[1].data[zero_window_start_index:zero_window_end_index] = 0.0
         #case 2: end of window is out of range
         if zero_window_start_index >= 0 and zero_window_end_index >= len(self.rf_st[1].data):
            self.rf_st[1].data[zero_window_start_index:] = 0.0
         #case 3: entire window is out of range
         if zero_window_start_index >= len(self.rf_st[1].data):
            print "PP arrives outside the receiver function window"
Пример #17
0
def migrate_1d(rf_trace,**kwargs):
####################################################################################
   '''
   takes an rf trace and returns a dictionary with pierce points and associated
   reciever function ampltiudes

   *note it's best to pass a TauPyModel instance (eg, prem_5km), to avoid having 
    to initiate a new model every time you call this function
   '''

   #get kwargs
   depth      = kwargs.get('depth_range',np.arange(50,805,5))
   taup_model = kwargs.get('taup_model','None')
   form       = kwargs.get('format','rfh5')
   window     = kwargs.get('window',[-10,120])

   #geographical information
   if form == 'rfh5':
      gcarc = rf_trace.stats.gcarc
      dt    = rf_trace.stats.delta
      evla  = rf_trace.stats.evla
      evlo  = rf_trace.stats.evlo
      evdp  = rf_trace.stats.evdp
      stla  = rf_trace.stats.stla
      stlo  = rf_trace.stats.stlo
      az    = rf_trace.stats.az
      o     = rf_trace.stats.o

   #initializations
   amp           = np.zeros((len(depth)))
   origin        = geopy.Point(evla,evlo)
   bearing       = az
   pierce_dict   = []
   if taup_model == 'None':
      taup_model = TauPyModel('prem_5km')

   ii = 0
   for d in depth:
      phase  = 'P'+str(d)+'s'
      pierce = taup_model.get_pierce_points(evdp,gcarc,phase_list=[phase])
      arrs   = taup_model.get_travel_times(evdp,gcarc,phase_list=['P',phase])

      #in case there's duplicate phase arrivals
      P_arrs = []
      Pds_arrs = []
      for arr in arrs:
        if arr.name == 'P':
           P_arrs.append(arr)
           #p_arr = arr.time
        elif arr.name == phase:
           #pds_arr = arr.time
           Pds_arrs.append(arr)
      p_arr = P_arrs[0].time 
      pds_arr = Pds_arrs[0].time

      #determine amplitude at each depth
      #window_start = o #TODO update writeh5py_dict so that win_start win_end are written
      pds_minus_p  = pds_arr - p_arr
      i_start      = int((0.0 - window[0])/dt)
      i_t          = int(pds_minus_p/dt) + i_start
      amp[ii]      = rf_trace.data[i_t]

      #find pierce points and create pierce dictionary
      points = pierce[0].pierce
      for p in points:
         if p['depth'] == d and np.degrees(p['dist']) > 20.0:
            prc_dist = np.degrees(p['dist'])
            d_km     = prc_dist * ((2*np.pi*6371.0/360.0))
            destination = VincentyDistance(kilometers=d_km).destination(origin,bearing)
            lat = destination[0]
            lon = destination[1]
            row = {'depth':d,'dist':prc_dist,'lat':lat,'lon':lon,'amplitude':amp[ii]}
            pierce_dict.append(row)
      ii += 1

   return pierce_dict
Пример #18
0
def calculate_ray_coverage(earthquake_list,stations_list,depth_range,phase='S',**kwargs):
   '''
   args:
      earthquake_list: earthquakes file (same format as used in synth tomo)
      stations_list: stations file (same format as used in synth tomo)
      depth_range: tuple (mindepth,maxdepth)

   kwargs:
      savefig: True or False
      figname: str, name of figure (defaults to fig.pdf)
      plot_title: str, title at the top of the plot (default no title)
   '''
   #the earthquake list format is: eq num, eq lon, eq lat, eq dep
   #the stations list format is: st lon, st lat
   savefig = kwargs.get('savefig',True)
   fig_name = kwargs.get('fig_name','fig.pdf')
   plot_title = kwargs.get('plot_title','None')
   fout_name = kwargs.get('fout_name','None')
   prem = TauPyModel('prem_50km')

   stations_file = np.loadtxt(stations_list)
   quakes_file = np.loadtxt(earthquake_list)
   n_quakes = len(quakes_file)
   n_stats = len(stations_file)
   st_lons = stations_file[:,0]
   st_lats = stations_file[:,1]
   eq_lons = quakes_file[:,1]
   eq_lats = quakes_file[:,2]
   eq_deps = quakes_file[:,3]

   if phase=='S' or phase=='P':
      delta_min = 30.0
      delta_max = 100.0
   elif phase == 'SKS':
      delta_min = 70.0
      delta_max = 140.0

   m = Basemap(projection='hammer',lon_0=204)
   fout = open(fout_name,'w')

   for i in range(0,n_quakes):
      #print 'working on earthquake', i
      for j in range(0,n_stats):

          geodet = gps2dist_azimuth(eq_lats[i], eq_lons[i], st_lats[j], st_lons[j])
          dist_m = geodet[0]
          dist_deg = kilometer2degrees((dist_m/1000.))

          if dist_deg < delta_min:
             continue
          elif dist_deg > delta_max:
             continue

          az = geodet[1]

          #print 'eq_lat, eq_lon, st_lat, st_lon, dist_deg', eq_lats[i],eq_lons[i],st_lats[j],st_lons[j],dist_deg
          arrs = prem.get_pierce_points(source_depth_in_km=eq_deps[i],
                                        distance_in_degree=dist_deg,
                                        phase_list=[phase])
          #print arrs
          arr = arrs[0]
          pierce_dict = arr.pierce
          #items in pierce_dict: 'p' (slowness), 'time' (time in s), 'dist', (distance in rad), 'depth' (depth in km)


          origin = geopy.Point(eq_lats[i],eq_lons[i])
          bearing = az
          geo_path = []
          cross_pt1 = 0
          cross_pt2 = 0
          dist_max = pierce_dict['dist'][::-1][0]
          for ds in pierce_dict:
             #only add points that are past turning depth
             dist_here = ds[2]
             if dist_here >= dist_max / 2:
                time_here = ds[1]
                depth_here = ds[3]
                if depth_here == depth_range[1]:
                   dist_deg = np.degrees(ds[2])
                   dist_km = dist_deg * ((2*np.pi*6371.0/360.0))
                   geo_pt = VincentyDistance(kilometers=dist_km).destination(origin,bearing)
                   lat_pt = geo_pt[0]
                   lon_pt = geo_pt[1]
                   cross_pt1 = (lon_pt,lat_pt)
                if depth_here == depth_range[0]:
                   dist_deg = np.degrees(ds[2])
                   dist_km = dist_deg * ((2*np.pi*6371.0/360.0))
                   geo_pt = VincentyDistance(kilometers=dist_km).destination(origin,bearing)
                   lat_pt = geo_pt[0]
                   lon_pt = geo_pt[1]
                   cross_pt2 = (lon_pt,lat_pt)
          if cross_pt1 != 0 and cross_pt2 != 0:
             m.drawgreatcircle(cross_pt1[0],cross_pt1[1],cross_pt2[0],cross_pt2[1],linewidth=1,alpha=0.15,color='k')
             fout.write('{} {} {} {}'.format(cross_pt1[0],cross_pt1[1],cross_pt2[0],cross_pt2[1])+'\n')

   m.drawcoastlines()
   m.fillcontinents(color='lightgrey')
   #m.drawparallels(np.arange(-90.,120.,30.))
   #m.drawmeridians(np.arange(0.,360.,60.))
   if plot_title != 'None':
      plt.title(plot_title)

   if savefig:
      plt.savefig(fig_name)
      plt.clf()
   else:
      plt.show()
Пример #19
0
    def find_pierce_coor(self, plot='False'):
        import geopy
        from geopy.distance import VincentyDistance
        '''
      given an instance of the receiver function class this function
      returns latitude and longitude of all receiver side pierce points
      of Pds in a given depth range (the default range is 50 - 800 km)
      NOTE:
      be careful that ses3d typically uses colatitude, while
      this function returns latitude '''

        depth_range = np.arange(50, 800, 5)  #set range of pierce points

        #geodetic info
        bearing = self.az
        lon_s = self.ses3d_seismogram.sy
        lat_s = 90.0 - self.ses3d_seismogram.sx
        lon_r = self.ses3d_seismogram.ry
        lat_r = 90.0 - self.ses3d_seismogram.rx
        origin = geopy.Point(lat_s, lon_s)

        #find how far away the pierce point is
        model = TauPyModel(model='pyrolite_5km')

        for i in range(0, len(depth_range)):
            phase = 'P' + str(depth_range[i]) + 's'
            pierce = model.get_pierce_points(self.eq_depth,
                                             self.delta_deg,
                                             phase_list=[phase])
            points = pierce[0].pierce
            for j in range(0, len(points)):
                if points[j]['depth'] == depth_range[
                        i] and points[j]['dist'] * (180.0 / np.pi) > 25.0:
                    prc_dist = points[j]['dist'] * (180.0 / np.pi)
                    d_km = prc_dist * ((2 * np.pi * 6371.0 / 360.0))
                    destination = VincentyDistance(
                        kilometers=d_km).destination(origin, bearing)
                    lat = destination[0]
                    lon = destination[1]
                    value = 0
                    row = {
                        'depth': depth_range[i],
                        'dist': prc_dist,
                        'lat': lat,
                        'lon': lon,
                        'value': value
                    }
                    self.pierce_dict.append(row)

        if plot == 'True':
            m = Basemap(projection='hammer', lon_0=0)
            m.drawmapboundary()
            m.drawcoastlines()
            m.drawgreatcircle(lon_s,
                              lat_s,
                              lon_r,
                              lat_r,
                              linewidth=1,
                              color='b',
                              alpha=0.5)

            for i in range(len(self.pierce_dict)):
                x, y = m(self.pierce_dict[i]['lon'],
                         self.pierce_dict[i]['lat'])
                m.scatter(x, y, 5, marker='o', color='r')
            plt.show()