def getWaveform(self, network, station, location, channel, starttime, endtime, format="MSEED"): """ Retrieves waveform data from the NERIES Web service and returns a ObsPy Stream object. :type network: str :param network: Network code, e.g. ``'BW'``. :type station: str :param station: Station code, e.g. ``'MANZ'``. :type location: str :param location: Location code, e.g. ``'01'``. Location code may contain wild cards. :type channel: str :param channel: Channel code, e.g. ``'EHE'``. . Channel code may contain wild cards. :type starttime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param starttime: Start date and time. :type endtime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param endtime: End date and time. :type format: ``'FSEED'`` or ``'MSEED'``, optional :param format: Output format. Either as full SEED (``'FSEED'``) or Mini-SEED (``'MSEED'``) volume. Defaults to ``'MSEED'``. :return: ObsPy :class:`~obspy.core.stream.Stream` object. .. rubric:: Example >>> from obspy.neries import Client >>> client = Client(user='******') >>> dt = UTCDateTime("2009-04-01T00:00:00") >>> st = client.getWaveform("NL", "WIT", "", "BH*", dt, dt+30) >>> print st # doctest: +ELLIPSIS 3 Trace(s) in Stream: NL.WIT..BHZ | 2009-04-01T00:00:00.010200Z - ... | 40.0 Hz, 1201 samples NL.WIT..BHN | 2009-04-01T00:00:00.010200Z - ... | 40.0 Hz, 1201 samples NL.WIT..BHE | 2009-04-01T00:00:00.010200Z - ... | 40.0 Hz, 1201 samples """ tf = NamedTemporaryFile() self.saveWaveform(tf._fileobj, network, station, location, channel, starttime, endtime, format=format) # read stream using obspy.mseed tf.seek(0) try: stream = read(tf.name, 'MSEED') except: stream = Stream() tf.close() # remove temporary file: try: os.remove(tf.name) except: pass # trim stream stream.trim(starttime, endtime) return stream
def test_read_and_write(self): """ Writes, reads and compares files created via libgse2. """ gse2file = os.path.join(self.path, 'loc_RNON20040609200559.z') with open(gse2file, 'rb') as f: header, data = libgse2.read(f) with NamedTemporaryFile() as f: # raises "UserWarning: Bad value in GSE2 header field" with warnings.catch_warnings(): warnings.simplefilter('ignore', UserWarning) libgse2.write(header, data, f) f.flush() with open(f.name, 'rb') as f2: newheader, newdata = libgse2.read(f2) self.assertEqual(header, newheader) np.testing.assert_equal(data, newdata)
def test_merge_sac_obspy_headers(self): """ Test that manually setting a set of SAC headers not related to validity or reference time on Trace.stats.sac is properly merged with the Trace.stats header. Issue 1285. """ tr = Trace(data=np.arange(30)) o = 10.0 tr.stats.sac = {'o': o} with NamedTemporaryFile() as tf: tempfile = tf.name tr.write(tempfile, format='SAC') tr1 = read(tempfile)[0] self.assertEqual(tr1.stats.starttime, tr.stats.starttime) self.assertEqual(tr1.stats.sac.o, o)
def test_valid_sac_from_minimal_existing_sac_header(self): """ An incomplete manually-produced SAC header should still produce a valid SAC file, including values from the ObsPy header. Issue 1204. """ tr = Trace(np.arange(100)) t = UTCDateTime() tr.stats.starttime = t tr.stats.station = 'AAA' tr.stats.network = 'XX' tr.stats.channel = 'BHZ' tr.stats.location = '00' tr.stats.sac = AttribDict() tr.stats.sac.iztype = 9 tr.stats.sac.nvhdr = 6 tr.stats.sac.leven = 1 tr.stats.sac.lovrok = 1 tr.stats.sac.iftype = 1 tr.stats.sac.stla = 1. tr.stats.sac.stlo = 2. with NamedTemporaryFile() as tf: tempfile = tf.name tr.write(tempfile, format='SAC') tr1 = read(tempfile)[0] # starttime made its way to SAC file nztimes, microsecond = utcdatetime_to_sac_nztimes(t) self.assertEqual(tr1.stats.sac.nzyear, nztimes['nzyear']) self.assertEqual(tr1.stats.sac.nzjday, nztimes['nzjday']) self.assertEqual(tr1.stats.sac.nzhour, nztimes['nzhour']) self.assertEqual(tr1.stats.sac.nzmin, nztimes['nzmin']) self.assertEqual(tr1.stats.sac.nzsec, nztimes['nzsec']) self.assertEqual(tr1.stats.sac.nzmsec, nztimes['nzmsec']) self.assertEqual(tr1.stats.sac.kstnm, 'AAA') self.assertEqual(tr1.stats.sac.knetwk, 'XX') self.assertEqual(tr1.stats.sac.kcmpnm, 'BHZ') self.assertEqual(tr1.stats.sac.khole, '00') self.assertEqual(tr1.stats.sac.iztype, 9) self.assertEqual(tr1.stats.sac.nvhdr, 6) self.assertEqual(tr1.stats.sac.leven, 1) self.assertEqual(tr1.stats.sac.lovrok, 1) self.assertEqual(tr1.stats.sac.iftype, 1) self.assertEqual(tr1.stats.sac.stla, 1.0) self.assertEqual(tr1.stats.sac.stlo, 2.0)
def test_write_with_date_time_before_1970(self): """ Write an stream via libmseed with a datetime before 1970. This test depends on the platform specific localtime()/gmtime() function. """ # create trace tr = Trace(data=np.empty(1000)) tr.stats.starttime = UTCDateTime("1969-01-01T00:00:00") # write file with NamedTemporaryFile() as tf: tempfile = tf.name _write_mseed(Stream([tr]), tempfile, format="MSEED") # read again stream = _read_mseed(tempfile) stream.verify()
def test_saveWaveform(self): """ Testing simple waveform file save method. """ # file identical to file retrieved via web interface client = Client() start = UTCDateTime("2010-02-27T06:30:00") end = UTCDateTime("2010-02-27T06:31:00") origfile = os.path.join(self.path, 'data', 'IU.ANMO.00.BHZ.mseed') with NamedTemporaryFile() as tf: tempfile = tf.name client.saveWaveform(tempfile, "IU", "ANMO", "00", "BHZ", start, end) self.assertTrue(filecmp.cmp(origfile, tempfile)) # no data raises an exception self.assertRaises(Exception, client.saveWaveform, "YY", "XXXX", "00", "BHZ", start, end)
def test_invalidEncoding(self): """ An invalid encoding should raise an exception. """ npts = 6000 np.random.seed(815) # make test reproducible with NamedTemporaryFile() as tf: tempfile = tf.name data = np.random.randint(-1000, 1000, npts).astype(np.int32) st = Stream([Trace(data=data)]) # Writing should fail with invalid record lengths. # Wrong number. self.assertRaises(ValueError, _write_mseed, st, tempfile, format="MSEED", encoding=2) # Wrong Text. self.assertRaises(ValueError, _write_mseed, st, tempfile, format="MSEED", encoding='FLOAT_64')
def test_writing_new_sampling_rate(self): """ Setting a new sample rate works. """ file = os.path.join(self.path, '1.sgy_first_trace') segy = _read_segy(file) segy.stats.textual_file_header = \ _patch_header(segy.stats.textual_file_header) segy[0].stats.sampling_rate = 20 with NamedTemporaryFile() as tf: outfile = tf.name _write_segy(segy, outfile) new_segy = _read_segy(outfile) self.assertEqual(new_segy[0].stats.sampling_rate, 20) # The same with the Seismic Unix file. file = os.path.join(self.path, '1.su_first_trace') _read_su(file)
def process_GET(self, request): """ Function that will be called upon receiving a GET request for the aforementioned URL. """ # Parse the given parameters. event_id = request.args0.get("event", None) channel_id = request.args0.get("channel_id", None) station_id = request.args0.get("station_id", None) tag = request.args0.get("tag", "") format = request.args0.get("format", None) # An event id is obviously needed. if event_id is None: msg = ("No event parameter passed. Every waveform " "is bound to an existing event.") raise InvalidParameterError(msg) if event_id is not None and not event_exists(event_id, self.env): msg = "The given event resource name '%s' " % event_id msg += "is not known to SeisHub." raise InvalidParameterError(msg) # Returns different things based on parameter combinations. # Return all waveforms available for a given event. if channel_id is None and station_id is None and event_id is not None: return self.getListForEvent(event_id, request) # Return all waveforms available for a given event and station id. elif station_id is not None and event_id is not None: return self.getListForStationAndEvent(event_id, station_id, request) # At this step format will mean a waveform output format. acceptable_formats = ["mseed", "sac", "gse2", "segy", "raw", "json"] if format and format.lower() not in acceptable_formats: msg = "'%s' is an unsupported format. Supported formats: %s" % \ (format, ", ".join(acceptable_formats)) raise InvalidParameterError(msg) if channel_id is None: msg = ("To download a waveform, 'channel_id' to be specified.") raise InvalidParameterError(msg) split_channel = channel_id.split(".") if len(split_channel) != 4: msg = "Invalid 'channel_id'. Needs to be NET.STA.LOC.CHAN." raise InvalidParameterError(msg) network, station, location, channel = split_channel session = self.env.db.session(bind=self.env.db.engine) station_id = get_station_id(network, station, session) if station_id is False: session.close() msg = "Could not find station %s.%s in the database" % \ (network, station) raise InvalidParameterError(msg) query = session.query(WaveformChannelObject)\ .join(ChannelObject)\ .filter(WaveformChannelObject.event_resource_id == event_id)\ .filter(WaveformChannelObject.tag == tag)\ .filter(ChannelObject.location == location)\ .filter(ChannelObject.channel == channel)\ .filter(ChannelObject.station_id == station_id) try: result = query.one() except sqlalchemy.orm.exc.NoResultFound: session.close() msg = "No matching data found in the database." raise NotFoundError(msg) if format and format.lower() == "raw": with open(result.filepath.filepath, "rb") as open_file: data = open_file.read() # Set the corresponding headers. request.setHeader("content-type", "application/octet-stream") filename = os.path.basename(result.filepath.filepath)\ .encode("utf-8") request.setHeader("content-disposition", "attachment; filename=%s" % filename) return data chan = result.channel stat = chan.station network = stat.network station = stat.station location = chan.location channel = chan.channel starttime = UTCDateTime(result.starttime) if result.starttime else None endtime = UTCDateTime(result.endtime) if result.endtime else None default_format = result.format # Read and filter the file. st = read(result.filepath.filepath).select(network=network, station=station, location=location, channel=channel) session.close() # Now attempt to find the correct trace in case of more then one trace. # This should enable multicomponent files. selected_trace = None for tr in st: if (starttime and abs(tr.stats.starttime - starttime) > 1) or \ (endtime and abs(tr.stats.endtime - endtime) > 1): continue selected_trace = tr break if selected_trace is None: msg = "Could not find the corresponding waveform file." raise InternalServerError(msg) # Deal with json format conversion. if format and format == "json": output = { "channel": selected_trace.id, "sampling_rate": selected_trace.stats.sampling_rate, "npts": selected_trace.stats.npts, "data": [] } time = selected_trace.stats.starttime delta = selected_trace.stats.delta for value in selected_trace.data: output["data"].append([time.isoformat(), float(value)]) time += delta request.setHeader('content-type', 'application/json; charset=UTF-8') return json.dumps(output) # XXX: Fix some ObsPy modules to be able to write to memory files. tempfile = NamedTemporaryFile() if format: default_format = format selected_trace.write(tempfile.name, format=default_format) with open(tempfile.name, "rb") as open_file: data = open_file.read() tempfile.close() os.remove(tempfile.name) # Set the corresponding headers. request.setHeader("content-type", "application/octet-stream") filename = "%s.%s" % (selected_trace.id, default_format.lower()) filename = filename.encode("utf-8") request.setHeader("content-disposition", "attachment; filename=%s" % filename) return data