def load_data(): inv = obspy.Inventory(networks=[], source="") # First read all station files. for filename in glob.glob("./stations/*.xml"): inv += obspy.read_inventory(filename) # Now read the waveform files. st = obspy.read("./waveforms/*.mseed") st.remove_response(inventory=inv, water_level=60) st.detrend("linear") st.taper(max_percentage=0.05) st.filter("bandpass", freqmin=0.001, freqmax=0.1, zerophase=True, corners=6) max_starttime = max(tr.stats.starttime for tr in st) min_endtime = min(tr.stats.endtime for tr in st) npts = int((min_endtime - max_starttime) / 2.0) for tr in st: tr.data = np.require(tr.data, requirements=["C_CONTIGUOUS"]) # Remove instrument response st.remove_response(inventory=inv) st.interpolate(sampling_rate=0.5, method="lanczos", starttime=max_starttime, npts=npts, a=12) return st
def __init__( self, filename, compression="gzip-3", shuffle=True, debug=False, mpi=None, mode="a", single_item_read_limit_in_mb=4096.0, format_version=None, ): # initialize ASDF super(baseASDF, self).__init__( filename = filename, compression=compression, shuffle=shuffle, debug=debug, mpi=mpi, mode=mode, single_item_read_limit_in_mb=single_item_read_limit_in_mb, format_version=format_version) #====================================== # initializations of other attributes #====================================== # range of station coverage try: limits_lonlat_param = self.auxiliary_data.Rfuncs['limits_lonlat'].parameters self.minlat = limits_lonlat_param['minlat'] self.maxlat = limits_lonlat_param['maxlat'] self.minlon = limits_lonlat_param['minlon'] self.maxlon = limits_lonlat_param['maxlon'] except: pass # station inventory; start/end date of the stations self.inv = obspy.Inventory() self.start_date = obspy.UTCDateTime('2599-01-01') self.end_date = obspy.UTCDateTime('1900-01-01') self.update_inv_info() return
def test_downloading_stations(self): split = { "https://example.com": "1234", "http://example2.com": "1234", "http://example3.com": "1234", "http://service.iris.edu": "1234" } with mock.patch("obspy.clients.fdsn.client.Client") as p: mock_instance = p.return_value mock_instance.get_stations_bulk.return_value = \ obspy.Inventory([], "") # Only accept test1 as a an argument. mock_instance.services = {"station": {"test1": True}} c = self._cls_object(debug=False, timeout=240) # test2 should not be passed on. c._download_stations(split=split, test1="a", test2="b") # Test initialization. self.assertEqual(p.call_count, 4) self.assertEqual(set(_i[0][0] for _i in p.call_args_list), set(split.keys())) self.assertEqual(set(_i[1]["debug"] for _i in p.call_args_list), set([False])) self.assertEqual(set(_i[1]["timeout"] for _i in p.call_args_list), set([240])) # Station download. wf_bulk = mock_instance.get_stations_bulk self.assertEqual(wf_bulk.call_count, 4) self.assertEqual(set(_i[0][0] for _i in wf_bulk.call_args_list), set(["test1=a\n1234"])) for _i in wf_bulk.call_args_list: self.assertEqual(_i[1], {})
def test_writing_network_before_1990(self): inv = obspy.Inventory(networks=[ Network(code="XX", start_date=obspy.UTCDateTime(1880, 1, 1))], source="") with io.BytesIO() as buf: inv.write(buf, format="stationxml") buf.seek(0, 0) inv2 = read_inventory(buf) assert inv.networks[0] == inv2.networks[0]
def _download_parallel(self, split, data_type, **kwargs): # Apply the provider filter. split = self._filter_requests(split) if not split: raise FDSNNoDataException( "Nothing remains to download after the provider " "inclusion/exclusion filters have been applied.") if data_type not in ["waveform", "station"]: # pragma: no cover raise ValueError("Invalid data type.") # One thread per data center. dl_requests = [] for k, v in split.items(): dl_requests.append({ "debug": self._debug, "timeout": self._timeout, "endpoint": k, "bulk_str": v, "data_type": data_type, "kwargs": kwargs, "credentials": self.credentials }) pool = ThreadPool(processes=len(dl_requests)) results = pool.map(_try_download_bulk, dl_requests) # Merge all results into a single object. if data_type == "waveform": collection = obspy.Stream() elif data_type == "station": collection = obspy.Inventory(networks=[], source="ObsPy FDSN Routing %s" % obspy.__version__) else: # pragma: no cover raise ValueError for _i in results: if not _i: continue collection += _i # Explitly close the thread pool as somehow this does not work # automatically under linux. See #2342. pool.close() return collection
def load_data(): inv = obspy.Inventory(networks=[], source="") # First read all station files. for filename in glob.glob("./stations/*.xml"): inv += obspy.read_inventory(filename) # Now read the waveform files. st = obspy.read("./waveforms/*.mseed") # Define Wood-Anderson Response paz_wa = { 'sensitivity': 2800, 'zeros': [0j], 'gain': 1, 'poles': [-6.2832 - 4.7124j, -6.2832 + 4.7124j] } #https://docs.obspy.org/tutorial/advanced_exercise/advanced_exercise.html st.remove_response(inventory=inv, water_level=60) # Remove instrument response st.simulate(paz_simulate=paz_wa, water_level=60) # Simulate Wood-Anderson st.detrend("linear") # Linear Detrend st.taper(max_percentage=0.05) # Taper #st.filter("bandpass", freqmin=0.001, freqmax=0.1, zerophase=True, corners=6) # Filter Response max_starttime = max(tr.stats.starttime for tr in st) min_endtime = min(tr.stats.endtime for tr in st) npts = int((min_endtime - max_starttime) / 0.04) for tr in st: tr.data = np.require(tr.data, requirements=["C_CONTIGUOUS"]) tr.data = tr.data * 1000 print('Data has been loaded') return st, inv
def test_information_from_other_namespaces_is_retained(): """ """ extra = obspy.core.AttribDict( { "my_tag": { "value": True, "namespace": "http://some-page.de/xmlns/1.0", "attrib": { "{http://some-page.de/xmlns/1.0}my_attrib1": "123.4", "{http://some-page.de/xmlns/1.0}my_attrib2": "567", }, }, "my_tag_2": { "value": "True", "namespace": "http://some-page.de/xmlns/1.0", }, } ) inv = obspy.Inventory( [ obspy.core.inventory.Network( "XX", stations=[ obspy.core.inventory.Station( code="YY", latitude=1.0, longitude=2.0, elevation=3.0 ) ], ) ], "XX", ) inv[0].extra = extra # Should survive the round trip. assert inv[0].extra == extra inv2 = isolate_and_merge_station(inv, network_id="XX", station_id="YY") assert inv2[0].extra == extra
def _make_inventory(self, df: pd.DataFrame): """ Loopy logic for creating the inventory form a dataframe. """ # get dataframe with correct columns/conditioning from input df = obsplus.stations_to_df(df).copy() # add responses (if requested) and drop response cols df["response"] = self._get_responses(df) df = df.drop(columns=self._drop_cols, errors="ignore") # warn if any unexpected columns are found in df self._maybe_warn_on_unexpected_columns(df) # Iterate networks and create stations networks = [] for net_code, net_df in self._groupby_if_exists(df, "network"): stations = [] for st_code, sta_df in self._groupby_if_exists(net_df, "station"): if not st_code[0]: continue channels = [] for ch_code, ch_df in self._groupby_if_exists(sta_df, "channel"): if not ch_code[0]: # skip empty channel lines continue chan_series = ch_df.iloc[0] kwargs = self._get_kwargs(chan_series, self.cha_map) # try to add the inventory channels.append(Channel(**kwargs)) kwargs = self._get_kwargs(sta_df.iloc[0], self.sta_map) self._add_dates(kwargs, channels) stations.append(Station(channels=channels, **kwargs)) kwargs = self._get_kwargs(net_df.iloc[0], self.net_map) self._add_dates(kwargs, stations) networks.append(Network(stations=stations, **kwargs)) return obspy.Inventory( networks=networks, source=f"ObsPlus_v{obsplus.__version__}" )
def get_inventory(): inv = obspy.Inventory(networks=[], source="") for filename in glob.glob("./stations/*.xml"): inv += obspy.read_inventory(filename) return inv
def make_gem_inventory(station_info, coords, response='default'): """ Create a station inventory for a Gem dataset. Parameters ---------- station_info: str or pandas.DataFrame file that contains a table with station definitions (columns for serial number, network, station, location, and channel) coords : pandas.DataFrame output of summarize_gps() response: str instrument response information (currently only 'default' is supported) Returns ------- obspy.Inventory containing station metadata for the dataset """ ## ensure that the provided station_info has all the necessary info, and fail if it doesn't station_info = _get_station_info(station_info) ## ensure that the coords info has all the necessary info, and fail if it doesn't if (type(coords) is not pd.DataFrame): raise Exception('invalid coords; must be pandas.DataFrame') elif ('SN' not in coords.keys()) and any([ key not in coords.keys() for key in ['network', 'station', 'location'] ]): raise Exception( "invalid coords; must contain key 'SN', or keys 'network', 'station', 'location'" ) elif any([key not in coords.keys() for key in ['lat', 'lon']]): raise Exception("invalid coords; must contain keys 'lat', 'lon'") ## create the inventory and loop through all the networks, stations, and locations in it inventory = obspy.Inventory() all_networks = _unique(station_info['network']) for network_name in all_networks: network = obspy.core.inventory.Network(network_name) ## loop through all the stations in the current network all_stations = _unique( station_info[station_info['network'] == network_name]['station']) for station_name in all_stations: station = obspy.core.inventory.Station(station_name, latitude=0, longitude=0, elevation=0) station.site.name = station_name ## loop through all the locations/channels in the current station all_locations = _unique(station_info[ (station_info['network'] == network_name) & (station_info['station'] == station_name)]['location']) for location_name in all_locations: ## find the serial number for this location SN = station_info[(station_info['network'] == network_name) & (station_info['station'] == station_name) & (station_info['location'] == location_name)]['SN'].iloc[0] ## find the coords line corresponding to this location if 'SN' in coords.keys(): line = coords[coords['SN'].astype(int) == int( SN)] # int just in case there's some type discrepancy else: line = coords[(coords['network'] == network_name) & (coords['station'] == station_name) & (coords['location'].astype(int) == int(location_name))] ## if no GPS info for this station is found, skip it if line.shape[0] == 0: print('No coords found for ' + SN + ', skipping') continue ## We need to extract the coordinate and times for this location. lat = line['lat'].iloc[0] lon = line['lon'].iloc[0] ## Check to see if the coords include start/end times. If so, pad ## them 1 hour to be safe. If not, assume the station is eternal. if all( [key in coords.keys() for key in ['starttime', 'endtime']]): t1 = obspy.UTCDateTime(line['starttime'].iloc[0]) - 3600 t2 = obspy.UTCDateTime(line['endtime'].iloc[0]) + 3600 else: t1 = obspy.UTCDateTime('1970-01-01T00:00:00') t2 = obspy.UTCDateTime('9999-12-31T23:59:59') ## Assume it's a gem v1.0--safe for now equipment = obspy.core.inventory.util.Equipment( serial_number=SN, model='Gem Infrasound Logger v1.0', description= 'Gem 1.0 (Infrasound), 0.039-27.1 Hz, 0.0035012 Pa/count') channel = obspy.core.inventory.Channel( 'HDF', location_code=location_name, latitude=lat, longitude=lon, elevation=0, depth=0, response=response, equipments=equipment, start_date=t1, end_date=t2, sample_rate=100, clock_drift_in_seconds_per_sample=0, types=['GEOPHYSICAL'], sensor=equipment) station.channels.append(channel) ## calculate the current station's coordinate as the mean of its locations, ## then append it to the network station.latitude = np.mean( [channel.latitude for channel in station.channels]) station.longitude = np.mean( [channel.longitude for channel in station.channels]) network.stations.append(station) ## append the current network to the inventory inventory.networks.append(network) return inventory
def empty_inventory(): return obspy.Inventory([], "unknown")
def df_to_inventory(df) -> obspy.Inventory: """ Create a simple inventory from a dataframe. The dataframe must have the same columns as the once produced by :func:`obsplus.stations_to_df`. """ def _make_key_mappings(cls): """ Create a mapping from columns in df to kwargs for cls. """ base_params = set(inspect.signature(cls).parameters) new_map = mapping_keys[cls] base_map = {x: x for x in base_params - set(new_map)} base_map.update(new_map) return base_map def _groupby_if_exists(df, columns): """ Groupby columns if they exist on dataframe, else return empty. """ cols = list(obsplus.utils.iterate(columns)) if not set(cols).issubset(df.columns): return # copy df and set missing start/end times to reasonable values # this is needed so they get included in a groupby df = df.copy() isnan = df.isna() if "start_date" in columns: df["start_date"] = df["start_date"].fillna(0) if "end_date" in columns: df["end_date"] = df["end_date"].fillna(LARGE_NUMBER) for ind, df_sub in df.groupby(cols): # replace NaN values if isnan.any().any(): df_sub[isnan.loc[df_sub.index]] = np.nan yield ind, df_sub def _get_kwargs(series, key_mapping): """ create the kwargs from a series and key mapping. """ out = {} for k, v in key_mapping.items(): # skip if requested kwarg is not in the series if v not in series: continue value = series[v] out[k] = value if not pd.isnull(value) else None return out # first get key_mappings net_map = _make_key_mappings(Network) sta_map = _make_key_mappings(Station) cha_map = _make_key_mappings(Channel) # next define columns groupbys should be performed on net_columns = ["network"] sta_columns = ["station", "start_date", "end_date"] cha_columns = ["channel", "location", "start_date", "end_date"] # Ensure input is a dataframe df = obsplus.stations_to_df(df) # replace # Iterate networks and create stations networks = [] for net_code, net_df in _groupby_if_exists(df, net_columns): stations = [] for st_code, sta_df in _groupby_if_exists(net_df, sta_columns): channels = [] for ch_code, ch_df in _groupby_if_exists(sta_df, cha_columns): kwargs = _get_kwargs(ch_df.iloc[0], cha_map) channels.append(Channel(**kwargs)) kwargs = _get_kwargs(sta_df.iloc[0], sta_map) stations.append(Station(channels=channels, **kwargs)) kwargs = _get_kwargs(net_df.iloc[0], net_map) networks.append(Network(stations=stations, **kwargs)) return obspy.Inventory(networks=networks, source=f"ObsPlus_v{obsplus.__version__}")
def df_to_inventory(df) -> obspy.Inventory: """ Create a station inventory from a dataframe. Parameters ---------- df A dataframe which must have the same columns as the once produced by :func:`obsplus.stations_to_df`. Notes ----- The dataframe can also contain columns named "sensor_keys" and "datalogger_keys" which will indicate the response information should be fetched suing obspy's ability to interact with the nominal response library. Each of these columns should either contain tuples or strings where the keys are separated by double underscores (__). """ def _make_key_mappings(cls): """ Create a mapping from columns in df to kwargs for cls. """ base_params = set(inspect.signature(cls).parameters) new_map = mapping_keys[cls] base_map = {x: x for x in base_params - set(new_map)} base_map.update(new_map) return base_map def _groupby_if_exists(df, columns): """ Groupby columns if they exist on dataframe, else return empty. """ cols = list(obsplus.utils.iterate(columns)) if not set(cols).issubset(df.columns): return # copy df and set missing start/end times to reasonable values # this is needed so they get included in a groupby df = df.copy() isnan = df.isna() default_start = pd.Timestamp(SMALLDT64) default_end = pd.Timestamp(LARGEDT64) if "start_date" in columns: df["start_date"] = df["start_date"].fillna(default_start) if "end_date" in columns: df["end_date"] = df["end_date"].fillna(default_end) for ind, df_sub in df.groupby(cols): # replace NaN values if isnan.any().any(): df_sub[isnan.loc[df_sub.index]] = np.nan yield ind, df_sub def _get_kwargs(series, key_mapping): """ create the kwargs from a series and key mapping. """ out = {} for k, v in key_mapping.items(): # skip if requested kwarg is not in the series if v not in series: continue value = series[v] value = value if not pd.isnull(value) else None # if the type needs to be cast to something else if k in type_mappings and value is not None: value = type_mappings[k](value) out[k] = value return out @lru_cache() def get_nrl(): """ Initiate a nominal response library object. """ from obspy.clients.nrl import NRL return NRL() @lru_cache() def get_response(datalogger_keys, sensor_keys): nrl = get_nrl() kwargs = dict(datalogger_keys=datalogger_keys, sensor_keys=sensor_keys) return nrl.get_response(**kwargs) def _get_resp_key(key): """ Get response keys from various types. """ if isinstance(key, str) or key is None: return tuple((key or "").split("__")) else: return tuple(key) def _maybe_add_response(series, channel_kwargs): """ Maybe add the response information if required columns exist. """ # bail out of required columns do not exist if not {"sensor_keys", "datalogger_keys"}.issubset(set(series.index)): return # determine if both required columns are populated, else bail out sensor_keys = _get_resp_key(series["sensor_keys"]) datalogger_keys = _get_resp_key(series["datalogger_keys"]) if not (sensor_keys and datalogger_keys): return # at this point all the required info for resp lookup should be there channel_kwargs["response"] = get_response(datalogger_keys, sensor_keys) # Deal with pandas dtype weirdness # TODO remove this when custom column functions are supported by DataFrame # Extractor (part of the big refactor in #131) for col in NSLC: df[col] = df[col].astype(str).str.replace(".0", "") # first get key_mappings net_map = _make_key_mappings(Network) sta_map = _make_key_mappings(Station) cha_map = _make_key_mappings(Channel) # next define columns groupbys should be performed on net_columns = ["network"] sta_columns = ["station", "start_date", "end_date"] cha_columns = ["channel", "location", "start_date", "end_date"] # Ensure input is a dataframe df = obsplus.stations_to_df(df) # Iterate networks and create stations networks = [] for net_code, net_df in _groupby_if_exists(df, net_columns): stations = [] for st_code, sta_df in _groupby_if_exists(net_df, sta_columns): channels = [] for ch_code, ch_df in _groupby_if_exists(sta_df, cha_columns): chan_series = ch_df.iloc[0] kwargs = _get_kwargs(chan_series, cha_map) # try to add the inventory _maybe_add_response(chan_series, kwargs) channels.append(Channel(**kwargs)) kwargs = _get_kwargs(sta_df.iloc[0], sta_map) stations.append(Station(channels=channels, **kwargs)) kwargs = _get_kwargs(net_df.iloc[0], net_map) networks.append(Network(stations=stations, **kwargs)) return obspy.Inventory(networks=networks, source=f"ObsPlus_v{obsplus.__version__}")
def dw_interfere(self, datadir, outdir = None, networks= [], channel='ZZ', chan_types=['LH', 'BH', 'HH'], \ alpha = 0.01, dthresh = 5., parallel=False, nprocess=None, subsize=1000, verbose=True, verbose2=False): """ compute three station direct wave interferometry ================================================================================================================= ::: input parameters ::: datadir - directory including data outdir - output directory channel - channel chan_types - types (also used as priorities) of channels (NOT implemented yet) alpha - threshhold percentage to determine stationary phase zone dtresh - threshhold difference in distance ( abs( abs(del_d_hyp) - del_d_ell) > dtresh ) parallel - run the xcorr parallelly or not nprocess - number of processes subsize - subsize of processing list, use to prevent lock in multiprocessing process ================================================================================================================= """ StationInv = obspy.Inventory() for staid in self.waveforms.list(): with warnings.catch_warnings(): warnings.simplefilter("ignore") StationInv += self.waveforms[staid].StationXML if outdir is None: outdir = datadir #--------------------------------- # prepare data #--------------------------------- print ('[%s] [DW_INTERFERE] preparing for three station direct wave interferometry' %datetime.now().isoformat().split('.')[0]) c3_lst = [] for staid1 in self.waveforms.list(): netcode1, stacode1 = staid1.split('.') with warnings.catch_warnings(): warnings.simplefilter("ignore") tmppos1 = self.waveforms[staid1].coordinates stla1 = tmppos1['latitude'] stlo1 = tmppos1['longitude'] for staid2 in self.waveforms.list(): netcode2, stacode2 = staid2.split('.') if staid1 >= staid2: continue if len(networks) > 0: if (not (netcode1 in networks)) and (not (netcode2 in networks)): continue with warnings.catch_warnings(): warnings.simplefilter("ignore") tmppos2 = self.waveforms[staid2].coordinates stla2 = tmppos2['latitude'] stlo2 = tmppos2['longitude'] c3_lst.append(_c3_funcs.c3_pair(datadir = datadir, outdir = outdir, stacode1 = stacode1, netcode1 = netcode1,\ stla1 = stla1, stlo1 = stlo1, stacode2 = stacode2, netcode2 = netcode2, stla2 = stla2, stlo2 = stlo2,\ channel = channel, chan_types = chan_types, StationInv = StationInv, alpha = alpha, \ dthresh = dthresh)) #=============================== # direct wave interferometry #=============================== print ('[%s] [DW_INTERFERE] computating... ' %datetime.now().isoformat().split('.')[0] ) # parallelized run if parallel: #----------------------------------------- # Computing xcorr with multiprocessing #----------------------------------------- if len(c3_lst) > subsize: Nsub = int(len(c3_lst)/subsize) for isub in range(Nsub): print ('[%s] [DW_INTERFERE] subset:' %datetime.now().isoformat().split('.')[0], isub, 'in', Nsub, 'sets') cur_c3Lst = c3_lst[isub*subsize:(isub+1)*subsize] CCUBE = partial(_c3_funcs.direct_wave_interfere_for_mp, verbose = verbose, verbose2 = verbose2) pool = multiprocessing.Pool(processes=nprocess) pool.map(CCUBE, cur_c3Lst) #make our results with a map call pool.close() #we are not adding any more processes pool.join() #tell it to wait until all threads are done before going on cur_c3Lst = c3_lst[(isub+1)*subsize:] CCUBE = partial(_c3_funcs.direct_wave_interfere_for_mp, verbose = verbose, verbose2 = verbose2) pool = multiprocessing.Pool(processes=nprocess) pool.map(CCUBE, cur_c3Lst) #make our results with a map call pool.close() #we are not adding any more processes pool.join() #tell it to wait until all threads are done before going on else: CCUBE = partial(_c3_funcs.direct_wave_interfere_for_mp, verbose = verbose, verbose2 = verbose2) pool = multiprocessing.Pool(processes=nprocess) pool.map(CCUBE, c3_lst) #make our results with a map call pool.close() #we are not adding any more processes pool.join() #tell it to wait until all threads are done before going on else: Nsuccess = 0 Nnodata = 0 for ilst in range(len(c3_lst)): if c3_lst[ilst].direct_wave_interfere(verbose = verbose, verbose2 = verbose2) > 0: Nsuccess+= 1 else: Nnodata += 1 print ('[%s] [DW_INTERFERE] computation ALL done: success/nodata: %d/%d' %(datetime.now().isoformat().split('.')[0], Nsuccess, Nnodata)) return
def make_gem_inventory(station_info, coords, response='default'): ## ensure that the provided station_info has all the necessary info, and fail if it doesn't station_info = _get_station_info(station_info) ## ensure that the coords info has all the necessary info, and fail if it doesn't if (type(coords) is not pd.DataFrame): raise Exception('invalid coords; must be pandas.DataFrame') elif ('SN' not in coords.keys()) and any([ key not in coords.keys() for key in ['network', 'station', 'location'] ]): raise Exception( "invalid coords; must contain key 'SN', or keys 'network', 'station', 'location'" ) elif any([key not in coords.keys() for key in ['lat', 'lon']]): raise Exception("invalid coords; must contain keys 'lat', 'lon'") ## create the inventory and loop through all the networks, stations, and locations in it inventory = obspy.Inventory() all_networks = _unique(station_info['network']) for network_name in all_networks: network = obspy.core.inventory.Network(network_name) ## loop through all the stations in the current network all_stations = _unique( station_info[station_info['network'] == network_name]['station']) for station_name in all_stations: station = obspy.core.inventory.Station(station_name, latitude=0, longitude=0, elevation=0) ## loop through all the locations/channels in the current station all_locations = _unique(station_info[ (station_info['network'] == network_name) & (station_info['station'] == station_name)]['location']) for location_name in all_locations: ## find the serial number for this location SN = station_info[(station_info['network'] == network_name) & (station_info['station'] == station_name) & (station_info['location'] == location_name)]['SN'].iloc[0] ## find the coords line corresponding to this location if 'SN' in coords.keys(): line = coords[coords['SN'] == SN] else: line = coords[(coords['network'] == network_name) & (coords['station'] == station_name) & (coords['location'] == location_name)] ## We need to extract the coordinate and times for this location. lat = line['lat'].iloc[0] lon = line['lon'].iloc[0] ## Check to see if the coords include start/end times. If so, pad ## them 1 hour to be safe. If not, assume the station is eternal. if all( [key in coords.keys() for key in ['starttime', 'endtime']]): t1 = obspy.UTCDateTime(line['starttime'].iloc[0]) - 3600 t2 = obspy.UTCDateTime(line['endtime'].iloc[0]) + 3600 else: t1 = obspy.UTCDateTime('1970-01-01T00:00:00') t2 = obspy.UTCDateTime('9999-12-31T23:59:59') ## Assume it's a gem v1.0--safe for now equipment = obspy.core.inventory.util.Equipment( serial_number=SN, model='Gem Infrasound Logger v1.0') channel = obspy.core.inventory.Channel( 'HDF', location_code=location_name, latitude=lat, longitude=lon, elevation=0, depth=0, response=response, equipments=equipment, start_date=t1, end_date=t2) station.channels.append(channel) ## calculate the current station's coordinate as the mean of its locations, ## then append it to the network station.latitude = np.mean( [channel.latitude for channel in station.channels]) station.longitude = np.mean( [channel.longitude for channel in station.channels]) network.stations.append(station) ## append the current network to the inventory inventory.networks.append(network) return inventory