def surf_4100_to_inv(location_file, response_inv, plot=False): """ Combine the xyz Homestake locations and MMF calibration responses into an Inventory object for the 4100L """ converter = SURF_converter() sta_df = pd.read_csv(location_file) inv = Inventory() serial_map = {'GMF1': '21010', 'GMF2': '21015', 'GMF3': '21027'} inv.networks = [Network(code='CB')] for _, row in sta_df.iterrows(): print(row) sta_code = row['Sensor name'] # Station location # Convert from SURF coords to lat lon, but keep local for actual use lon, lat, elev = converter.to_lonlat( (row['x_ft'] * 0.3048, row['y_ft'] * 0.3048, row['z_ft'] * 0.3048)) print(lon, lat, elev) # Just leave as zero here and convert HMC feet elevation to m depth = 0.0 # Save HMC coords to custom attributes of Station and Channel extra = AttribDict({ 'hmc_east': { 'value': row['x_ft'], 'namespace': 'smi:local/hmc' }, 'hmc_north': { 'value': row['y_ft'], 'namespace': 'smi:local/hmc' }, 'hmc_elev': { 'value': row['z_ft'] * 0.3048, 'namespace': 'smi:local/hmc' } }) if sta_code.startswith('TS'): # Hydrophone or CASSM, wet well if 'SS' in sta_code: # Cassm (Y for unspecified instrument) chan_code = 'XY1' chans = [ Channel(code=chan_code, location_code='', latitude=lat, longitude=lon, elevation=elev, depth=depth, response=Response()) ] else: # Hydrophone (D), Downhole (H) per SEED manual chan_code = 'XDH' chans = [ Channel(code=chan_code, location_code='', latitude=lat, longitude=lon, elevation=elev, depth=depth, response=Response()) ] elif 'S' in sta_code: # Grouted CASSM chan_code = 'XY1' chans = [ Channel(code=chan_code, location_code='', latitude=lat, longitude=lon, elevation=elev, depth=depth, response=Response()) ] else: # Grouted accelerometer chans = [] try: serial = serial_map[sta_code] except KeyError: serial = '9999' for chan_code in ['XNX', 'XNY', 'XNZ']: # Set samp_rate to 40 kHz so that Nyquist is below max shake f chan = Channel(code=chan_code, location_code='', latitude=lat, longitude=lon, elevation=elev, depth=0., sample_rate=40000., sensor=Equipment( type='IEPE Accelerometer', description='Piezoelectric accelerometer', manufacturer='MMF', model='KS943B.100', serial_number=serial)) # Apply exact response for the three tested sensors, # ...otherwise use the average avg_resp = response_inv.select( station='AVG', channel=chan_code)[0][0][0].response chan.response = avg_resp chans.append(chan) sta = Station(code=sta_code, latitude=chans[0].latitude, longitude=chans[0].longitude, elevation=chans[0].elevation, channels=chans) sta.extra = extra inv[0].stations.append(sta) return inv
def surf_stations_to_inv(excel_file, debug=0): """ Take Petrs orientation excel file for the hydrophones/accelerometers and build an inventory for later use. :param excel_file: path to Petr's excel file (formatting hard-coded) :return: obspy.core.Inventory """ # Call coordinate converter converter = SURF_converter() sta_df = pd.read_excel(excel_file, skiprows=[0, 1, 2, 3], header=1, nrows=90) # Assemble dictionary of {station: {channel: infoz}} # Create dict before, then build inventory from channel level upwards sta_dict = {} extra_dict = {} for i, row in sta_df.iterrows(): # Station location # Convert from SURF coords to lat lon, but keep local for actual use lon, lat, elev = converter.to_lonlat( (row['Easting(m)'], row['Northing(m)'], row['Elev(m)'])) # Correct for arbitrary zero 'depth' of 130m elev -= 130 # Already accounted for in the elevation but will include here as its # ...a required arg for Channel() depth = row['Depth (m)'] # Save HMC coords to custom attributes of Station and Channel extra = AttribDict({ 'hmc_east': { 'value': row['Easting(m)'], 'namespace': 'smi:local/hmc' }, 'hmc_north': { 'value': row['Northing(m)'], 'namespace': 'smi:local/hmc' }, 'hmc_elev': { 'value': row['Elev(m)'], # extra will preserve absolute elev 'namespace': 'smi:local/hmc' } }) # Sort out azimuth and dip for this channel (if it exists) if not np.isnan(row['Sx']): # TODO Something is real effed here. Answers are right though. dip_rad = np.arcsin(-row['Sz']) az_rad = np.arcsin(row['Sx'] / np.cos(dip_rad)) dip = np.rad2deg(dip_rad) az = np.rad2deg(az_rad) # Force positive if az < 0: az += 360. # Correct if row['Sx'] < 0 and row['Sy'] < 0: az -= 270. az = 270. - az elif row['Sy'] < 0: az = 180 - az if debug > 0: print(np.array((row['Sx'], row['Sy'], row['Sz']))) print(az, dip) if row['Sensor'].endswith(('Z', 'X', 'Y')): chan = 'XN{}'.format(row['Sensor'][-1]) # Geophones if row['Sensor'].startswith('G'): continue # Accelerometers else: no = row['Sensor'].split('_')[1] sta_name = '{}{}'.format(row['Desc'], no) if sta_name in ['OB14', 'OT17', 'PDT2', 'PDT5', 'PSB8', 'PST11']: # These are geode stations only, skip continue channel = Channel(code=chan, location_code='', latitude=lat, longitude=lon, elevation=elev, depth=depth, azimuth=az, dip=dip, response=Response()) # channel.extra = extra elif row['Sensor'].startswith('Hydro'): chan = 'XN1' sta_name = '{}{}'.format(row['Desc'], row['Sensor'].split('-')[-1].zfill(2)) channel = Channel(code=chan, location_code='', latitude=lat, longitude=lon, elevation=elev, depth=depth, response=Response()) extra_dict[sta_name] = extra # channel.extra = extra if sta_name in sta_dict.keys(): sta_dict[sta_name].append(channel) else: sta_dict[sta_name] = [channel] # Now loop station dict to create inventory stas = [] for nm, chans in sta_dict.items(): station = Station(code=nm, latitude=chans[0].latitude, longitude=chans[0].longitude, elevation=chans[0].elevation, channels=chans) station.extra = extra_dict[nm] stas.append(station) # Build inventory inventory = Inventory(networks=[Network(code='SV', stations=stas)], source='SURF') return inventory
def fsb_to_inv(path, orientations=False, debug=0): """ Take excel file of sensor locations and build an Inventory :param path: Path to excel spreadsheet :param orientations: False or dict of orientation info :param debug: :return: """ inventory = Inventory() inventory.networks = [Network(code='FS')] converter = FSB_converter() sens_dict = read_fsb_asbuilt(path) # Assemble dictionary of {station: {channel: infoz}} # Create dict before, then build inventory from channel level upwards sta_dict = {} extra_dict = {} for sta, loc in sens_dict.items(): # Station location # Convert from SURF coords to lat lon, but keep local for actual use lon, lat, elev = converter.to_lonlat((loc[0], loc[1], loc[2])) depth = 0.0 # Until we do any orientations? # Save HMC coords to custom attributes of Station and Channel extra = AttribDict({ 'ch1903_east': { 'value': loc[0], 'namespace': 'smi:local/hmc' }, 'ch1903_north': { 'value': loc[1], 'namespace': 'smi:local/hmc' }, 'ch1903_elev': { 'value': loc[2], # extra will preserve absolute elev 'namespace': 'smi:local/hmc' } }) # Not yet implemented; Pass orientations dict when we do if orientations: # TODO Something is real effed here. Answers are right though. dip_rad = np.arcsin(-orientations[sta]['Sz']) az_rad = np.arcsin(orientations[sta]['Sx'] / np.cos(dip_rad)) dip = np.rad2deg(dip_rad) az = np.rad2deg(az_rad) # Force positive if az < 0: az += 360. # Correct if orientations[sta]['Sx'] < 0 and orientations[sta]['Sy'] < 0: az -= 270. az = 270. - az elif orientations[sta]['Sy'] < 0: az = 180 - az if debug > 0: print( np.array((orientations[sta]['Sx'], orientations[sta]['Sy'], orientations[sta]['Sz']))) print(az, dip) try: if orientations[sta]['Sensor'].endswith(('Z', 'X', 'Y')): chan = 'XN{}'.format(orientations[sta]['Sensor'][-1]) # Geophones if orientations[sta]['Sensor'].startswith('G'): no = orientations[sta]['Sensor'][-3] # Accelerometers else: no = orientations[sta]['Sensor'].split('_')[1] sta_name = '{}{}'.format(orientations[sta]['Desc'], no) channel = Channel(code=chan, location_code='', latitude=lat, longitude=lon, elevation=elev, depth=depth, azimuth=az, dip=dip, response=Response()) # channel.extra = extra elif orientations[sta]['Sensor'].startswith('Hydro'): chan = 'XN1' sta_name = '{}{}'.format( orientations[sta]['Desc'], orientations[sta]['Sensor'].split('-')[-1].zfill(2)) channel = Channel(code=chan, location_code='', latitude=lat, longitude=lon, elevation=elev, depth=depth, response=Response()) except TypeError as e: sta_name = sta if sta in fsb_accelerometers: channels = [] for chan in ['XNZ', 'XNX', 'XNY']: channels.append( Channel(code=chan, location_code='', latitude=lat, longitude=lon, elevation=elev, depth=depth, response=Response())) else: channel = Channel(code='XN1', location_code='', latitude=lat, longitude=lon, elevation=elev, depth=depth, response=Response()) channels = [channel] extra_dict[sta_name] = extra sta_dict[sta_name] = channels for nm, chans in sta_dict.items(): station = Station(code=nm, latitude=chans[0].latitude, longitude=chans[0].longitude, elevation=chans[0].elevation, channels=chans) station.extra = extra_dict[nm] inventory[0].stations.append(station) return inventory