Skip to content
Snippets Groups Projects
Commit 25d8edab authored by Hal Simpson's avatar Hal Simpson
Browse files

added more pydoc style comments

parent c179f540
No related branches found
No related tags found
No related merge requests found
#! /usr/bin/env python #! /usr/bin/env python
"""Converts iaga2002 files from one coordinate system to another.
Inputs
------
informat: string
The input format/coordinate system of the input file.
geo: geographic coordinate system (xyzf)
mag: magnetic north coordinate system (hdzf)
obs: observatory coordinate system (hezf)
obsd: observatory coordinate system (hdzf)
outformat: string
The ouput format/coordinate system of the output file.
geo: geographic coordinate system (xyzf)
mag: magnetic north coordinate system (hdzf)
obs: observatory coordinate system (hezf or hdzf)
infile: string
the filename of the Iaga2002 file to be read from
outfile: string
the filename of a new Iaga2002 file to be read to
"""
import argparse import argparse
import sys import sys
...@@ -42,6 +21,71 @@ from obspy.core.utcdatetime import UTCDateTime ...@@ -42,6 +21,71 @@ from obspy.core.utcdatetime import UTCDateTime
def main(): def main():
"""command line factory for geomag algorithms
Inputs
------
--input: string
the type of data for input
currently either iaga or edge.
--output: string
the type of data for ouput
currently either iaga or edge.
--starttime: string
formatted as a obspy.core.UTCDateTime object
the starttime for data input/output
--endtime: string
formatted as a obspy.core.UTCDateTime object
the endtime for data input/output
--observatory:string
--channels: array_like
list of channels
--type: string
data type
--invterval: string
data interval.
--algorithm: string
name of an algorithm to use.
--xyz-informat: string
The input format/coordinate system of the input file.
geo: geographic coordinate system (xyzf)
mag: magnetic north coordinate system (hdzf)
obs: observatory coordinate system (hezf)
obsd: observatory coordinate system (hdzf)
--xyz-outformat: string
The ouput format/coordinate system of the output file.
geo: geographic coordinate system (xyzf)
mag: magnetic north coordinate system (hdzf)
obs: observatory coordinate system (hezf or hdzf)
--input_iaga_magweb: boolean
indicates to use http://magweb.cr.usgs.gov/data/magnetometer/ as the
source of iaga2002 files.
--input_iaga_url: string
url of iaga2002 files to use as the data source.
--input-iaga-urltemplate: string
template for the subdirectories that files are found in.
example: %(OBS)s/%(interval)s%(type)s/
--input-iaga-filetemplate: string
template for the file name
example: %(obs)s%(ymd)s%(t)s%(i)s.%(i)s
--input-iaga-file: string
the filename of the Iaga2002 file to be read from
--input-iaga-stdin: boolean
indicates the file will be coming from stdin
--output_iaga_file: string
the filename of a new Iaga2002 file to be read to
--output-iaga-url: string
url of directory to write output files in.
--output-iaga-urltemplate: string
template for the subdirectories that files are to be written in.
example: %(OBS)s/%(interval)s%(type)s/
--output-iaga-filetemplate: string
template for the file name
example: %(obs)s%(ymd)s%(t)s%(i)s.%(i)s
--output-iaga-stdout: boolen
indicates output will go to stdout
"""
args = parse_args() args = parse_args()
...@@ -119,6 +163,13 @@ def main(): ...@@ -119,6 +163,13 @@ def main():
controller.run(UTCDateTime(args.starttime), UTCDateTime(args.endtime)) controller.run(UTCDateTime(args.starttime), UTCDateTime(args.endtime))
def parse_args(): def parse_args():
"""parse input arguments
Returns
-------
argparse.Namespace
dictionary like object containing arguments.
"""
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Use @ to read commands from a file.', description='Use @ to read commands from a file.',
fromfile_prefix_chars='@',) fromfile_prefix_chars='@',)
......
"""Algorithm Interface."""
class Algorithm(object): class Algorithm(object):
"""An algorithm processes a stream of timeseries to produce new timeseries. """Base class for geomag algorithms
Parameters
----------
channels: array_like
the list of channels to be processed.
Notes
-----
An algorithm processes a stream of timeseries to produce new timeseries.
""" """
def __init__(self, channels=None): def __init__(self, channels=None):
...@@ -9,7 +19,7 @@ class Algorithm(object): ...@@ -9,7 +19,7 @@ class Algorithm(object):
pass pass
def process(self, stream): def process(self, stream):
"""Process a chunk of data. """Process a stream of data.
Parameters Parameters
---------- ----------
...@@ -24,7 +34,21 @@ class Algorithm(object): ...@@ -24,7 +34,21 @@ class Algorithm(object):
return stream.copy() return stream.copy()
def get_input_channels(self): def get_input_channels(self):
"""Get input channels
Returns
-------
array_like
list of channels the algorithm needs to operate.
"""
return self._channels return self._channels
def get_output_channels(self): def get_output_channels(self):
"""Get output channels
Returns
-------
array_like
list of channels the algorithm will be returning.
"""
return self._channels return self._channels
#! /usr/bin/env python """Conrtoller class for geomag algorithms"""
"""Converts iaga2002 files from one coordinate system to another.
Inputs class Controller(object):
------ """Controller for geomag algorithms.
Parameters
----------
inputFactory: TimeseriesFactory inputFactory: TimeseriesFactory
the factory that will read in timeseries data
outputFactory: TimeseriesFactory outputFactory: TimeseriesFactory
algorithm: Algorithm the factory that will output the timeseries data
""" algorithm: the algorithm(s) that will take procees the timeseries data
"""
class Controller(object):
def __init__(self, inputFactory, outputFactory, algorithm=None): def __init__(self, inputFactory, outputFactory, algorithm=None):
self._inputFactory = inputFactory self._inputFactory = inputFactory
...@@ -18,6 +19,15 @@ class Controller(object): ...@@ -18,6 +19,15 @@ class Controller(object):
self._outputFactory = outputFactory self._outputFactory = outputFactory
def run(self, starttime, endtime): def run(self, starttime, endtime):
"""run an algorithm as setup up by the main script.
Parameters
----------
starttime : UTCDateTime
time of first sample to be worked on.
endtime : UTCDateTime
time of last sample to be worked on.
"""
input_channels = self._algorithm.get_input_channels() input_channels = self._algorithm.get_input_channels()
timeseries = self._inputFactory.get_timeseries(starttime, endtime, timeseries = self._inputFactory.get_timeseries(starttime, endtime,
channels=input_channels) channels=input_channels)
......
#! /usr/bin/env python """Algorithm that converts from one geomagnetic coordinate system to a
related coordinate system.
"""Takes a timeseries stream in, and returns a converted timeseries stream out
""" """
from Algorithm import Algorithm from Algorithm import Algorithm
import StreamConverter as StreamConverter import StreamConverter as StreamConverter
# static containing the standard output types for iaga2002 files. # List of channels by geomagnetic observatory orientation.
# geo represents a geographic north/south orientation
# mag represents the (calculated)instantaneous mangnetic north orientation
# obs represents the sensor orientation aligned close to the mag orientation
# obsd is the same as obs, but with D(declination) instead of E (e/w vector)
CHANNELS = { CHANNELS = {
'geo': ['X', 'Y', 'Z', 'F'], 'geo': ['X', 'Y', 'Z', 'F'],
'mag': ['H', 'D', 'Z', 'F'], 'mag': ['H', 'D', 'Z', 'F'],
...@@ -17,6 +20,17 @@ CHANNELS = { ...@@ -17,6 +20,17 @@ CHANNELS = {
class XYZAlgorithm(Algorithm): class XYZAlgorithm(Algorithm):
"""Algorithm for converting data, probably inapproprately named XYZ.
Parameters
----------
informat: str
the code that represents the incoming data form that the Algorithm
will be converting from.
outformat: str
the code that represents what form the incoming data will
be converting to.
"""
def __init__(self, informat=None, outformat=None): def __init__(self, informat=None, outformat=None):
Algorithm.__init__(self) Algorithm.__init__(self)
...@@ -24,14 +38,14 @@ class XYZAlgorithm(Algorithm): ...@@ -24,14 +38,14 @@ class XYZAlgorithm(Algorithm):
self.outformat = outformat self.outformat = outformat
def check_stream(self, timeseries, channels): def check_stream(self, timeseries, channels):
"""checks an input stream to make certain all the required channels """checks an stream to make certain all the required channels
exist. exist.
Parameters Parameters
---------- ----------
timeseries: obspy.core.Stream timeseries: obspy.core.Stream
stream that was read in. stream to be checked.
channels: array channels: array_like
channels that are expected in stream. channels that are expected in stream.
""" """
for channel in channels: for channel in channels:
...@@ -41,9 +55,23 @@ class XYZAlgorithm(Algorithm): ...@@ -41,9 +55,23 @@ class XYZAlgorithm(Algorithm):
return True return True
def get_input_channels(self): def get_input_channels(self):
"""Get input channels
Returns
-------
array_like
list of channels the algorithm needs to operate.
"""
return CHANNELS[self.informat] return CHANNELS[self.informat]
def get_output_channels(self): def get_output_channels(self):
"""Get output channels
Returns
-------
array_like
list of channels the algorithm will be returning.
"""
return CHANNELS[self.outformat] return CHANNELS[self.outformat]
def process(self, timeseries): def process(self, timeseries):
......
"""Factory that loads data from earthworm and writes to Edge.""" """Factory that loads data from earthworm and writes to Edge.
EdgeFactory uses obspy earthworm class to read data from any
earthworm standard Waveserver using the obspy getWaveform call.
Writing will be implemented with Edge specific capabilities,
to take advantage of it's newer realtime abilities.
Edge is the USGS earthquake hazard centers replacement for earthworm.
"""
import obspy.core import obspy.core
from obspy.core.utcdatetime import UTCDateTime from obspy.core.utcdatetime import UTCDateTime
...@@ -9,6 +18,22 @@ from ObservatoryMetadata import ObservatoryMetadata ...@@ -9,6 +18,22 @@ from ObservatoryMetadata import ObservatoryMetadata
class EdgeFactory(TimeseriesFactory): class EdgeFactory(TimeseriesFactory):
"""TimeseriesFactory for Edge related data.
Parameters
----------
host: str
a string representing the IP number of the host to connect to.
port: integer
the port number the waveserver is listening on.
observatoryMetadata: ObservatoryMetadata object
an ObservatoryMetadata object used to replace the default
ObservatoryMetadata.
See Also
--------
TimeseriesFactory
"""
def __init__(self, host=None, port=None, observatory=None, def __init__(self, host=None, port=None, observatory=None,
channels=None, type=None, interval=None, channels=None, type=None, interval=None,
...@@ -24,12 +49,12 @@ class EdgeFactory(TimeseriesFactory): ...@@ -24,12 +49,12 @@ class EdgeFactory(TimeseriesFactory):
Parameters Parameters
---------- ----------
observatory : str
observatory code.
starttime : obspy.core.UTCDateTime starttime : obspy.core.UTCDateTime
time of first sample. time of first sample.
endtime : obspy.core.UTCDateTime endtime : obspy.core.UTCDateTime
time of last sample. time of last sample.
observatory : str
observatory code.
channels : array_like channels : array_like
list of channels to load list of channels to load
type : {'variation', 'quasi-definitive'} type : {'variation', 'quasi-definitive'}
...@@ -294,7 +319,22 @@ class EdgeFactory(TimeseriesFactory): ...@@ -294,7 +319,22 @@ class EdgeFactory(TimeseriesFactory):
observatory, channel, type, interval) observatory, channel, type, interval)
return data return data
def _clean_timeseries(self, timeseries, starttime, endtime, channels): def _clean_timeseries(self, timeseries, starttime, endtime):
"""Realigns timeseries data so the start and endtimes are the same
as what was originally asked for, even if the data was during
a gap.
Parameters
----------
timeseries: obspy.core.stream
The timeseries stream as returned by the call to getWaveform
starttime: obspy.core.UTCDateTime
the starttime of the requested data
endtime: obspy.core.UTCDateTime
the endtime of the requested data
Notes: the original timeseries object is changed.
"""
for trace in timeseries: for trace in timeseries:
trace_starttime = UTCDateTime(trace.stats.starttime) trace_starttime = UTCDateTime(trace.stats.starttime)
trace_endtime = UTCDateTime(trace.stats.endtime) trace_endtime = UTCDateTime(trace.stats.endtime)
...@@ -312,13 +352,32 @@ class EdgeFactory(TimeseriesFactory): ...@@ -312,13 +352,32 @@ class EdgeFactory(TimeseriesFactory):
numpy.full(cnt, numpy.nan, dtype=numpy.float64)]) numpy.full(cnt, numpy.nan, dtype=numpy.float64)])
trace.stats.endttime = endtime trace.stats.endttime = endtime
def _post_process(self, stream, starttime, endtime, channels): def _post_process(self, timeseries, starttime, endtime, channels):
for trace in stream: """Post process a timeseries stream after the raw data is
is fetched from a waveserver. Specifically changes
any MaskedArray to a ndarray with nans representing gaps.
Then calls _clean_timeseries to deal with gaps at the
beggining or end of the streams.
Parameters
----------
timeseries: obspy.core.stream
The timeseries stream as returned by the call to getWaveform
starttime: obspy.core.UTCDateTime
the starttime of the requested data
endtime: obspy.core.UTCDateTime
the endtime of the requested data
channels: array_like
list of channels to load
Notes: the original timeseries object is changed.
"""
for trace in timeseries:
if isinstance(trace.data, numpy.ma.MaskedArray): if isinstance(trace.data, numpy.ma.MaskedArray):
trace.data.set_fill_value(numpy.nan) trace.data.set_fill_value(numpy.nan)
trace.data = trace.data.filled() trace.data = trace.data.filled()
self._clean_timeseries(stream, starttime, endtime, channels) self._clean_timeseries(timeseries, starttime, endtime)
# TODO add in test for missing channel, if so, make it all nans? # TODO add in test for missing channel, if so, make it all nans?
def _set_metadata(self, stream, observatory, channel, type, interval): def _set_metadata(self, stream, observatory, channel, type, interval):
......
...@@ -15,14 +15,38 @@ class IAGA2002Writer(object): ...@@ -15,14 +15,38 @@ class IAGA2002Writer(object):
self.empty_value = empty_value self.empty_value = empty_value
def write(self, out, timeseries, channels): def write(self, out, timeseries, channels):
"""write timeseries to iaga file
Parameters
----------
out: file object
file object to be written to. could be stdout
timeseries: obspy.core.stream
timeseries object with data to be written
channels: array_like
channels to be written from timeseries object
"""
stats = timeseries[0].stats stats = timeseries[0].stats
out.write(self._format_headers(stats, channels)) out.write(self._format_headers(stats, channels))
out.write(self._format_comments(stats)) out.write(self._format_comments(stats))
out.write(self._format_channels(channels, stats.station)) out.write(self._format_channels(channels, stats.station))
out.write(self._format_data(timeseries, channels)) out.write(self._format_data(timeseries, channels))
pass
def _format_headers(self, stats, channels): def _format_headers(self, stats, channels):
"""format headers for IAGA2002 file
Parameters
----------
stats: obspy.core.trace.stats
holds the observatory metadata
channels: array_like
channels to be reported.
Returns
-------
array_like
an array containing formatted strings of header data.
"""
buf = [] buf = []
buf.append(self._format_header('Format', 'IAGA-2002')) buf.append(self._format_header('Format', 'IAGA-2002'))
buf.append(self._format_header('Source of Data', stats.agency_name)) buf.append(self._format_header('Source of Data', stats.agency_name))
...@@ -44,7 +68,18 @@ class IAGA2002Writer(object): ...@@ -44,7 +68,18 @@ class IAGA2002Writer(object):
return ''.join(buf) return ''.join(buf)
def _format_comments(self, stats): def _format_comments(self, stats):
# build comments """format comments for IAGA2002 file
Parameters
----------
stats: obspy.core.trace.stats
holds the observatory metadata
Returns
-------
array_like
an array containing formatted strings of header data.
"""
comments = [] comments = []
if 'declination_base' in stats: if 'declination_base' in stats:
comments.append('DECBAS {:<8d}' comments.append('DECBAS {:<8d}'
...@@ -71,11 +106,36 @@ class IAGA2002Writer(object): ...@@ -71,11 +106,36 @@ class IAGA2002Writer(object):
return ''.join(buf) return ''.join(buf)
def _format_header(self, name, value): def _format_header(self, name, value):
"""format headers for IAGA2002 file
Parameters
----------
name: str
the name to be written
value: str
the value to written.
Returns
-------
str
a string formatted to be a single header line in an IAGA2002 file
"""
prefix = ' ' prefix = ' '
suffix = ' |\n' suffix = ' |\n'
return ''.join((prefix, name.ljust(23), value.ljust(44), suffix)) return ''.join((prefix, name.ljust(23), value.ljust(44), suffix))
def _format_comment(self, comment): def _format_comment(self, comment):
"""format header for IAGA2002 file
Parameters
----------
comment: str
a single comment to be broken formatted if needed.
Returns
-------
str
a string formatted to be a single comment in an IAGA2002 file.
"""
buf = [] buf = []
prefix = ' # ' prefix = ' # '
suffix = ' |\n' suffix = ' |\n'
......
"""Factory that loads IAGA2002 Files.""" """Factory to load IAGA2002 files from an input StreamIAGA2002Factory."""
from IAGA2002Factory import IAGA2002Factory from IAGA2002Factory import IAGA2002Factory
# pattern for iaga 2002 file names
class StreamIAGA2002Factory(IAGA2002Factory): class StreamIAGA2002Factory(IAGA2002Factory):
"""Timeseries Factory for IAGA2002 formatted files loaded via a stream.
normally either a single file, or stdio.
Parameters
----------
stream: file object
io stream, normally either a file, or stdio
See Also
--------
IAGA2002Factory
Timeseriesfactory
"""
def __init__(self, stream, observatory=None, channels=None, def __init__(self, stream, observatory=None, channels=None,
type=None, interval=None): type=None, interval=None):
IAGA2002Factory.__init__(self, None, observatory, channels, IAGA2002Factory.__init__(self, None, observatory, channels,
...@@ -14,8 +25,20 @@ class StreamIAGA2002Factory(IAGA2002Factory): ...@@ -14,8 +25,20 @@ class StreamIAGA2002Factory(IAGA2002Factory):
def get_timeseries(self, starttime, endtime, observatory=None, def get_timeseries(self, starttime, endtime, observatory=None,
channels=None, type=None, interval=None): channels=None, type=None, interval=None):
"""Implements get_timeseries
Notes: Calls IAGA2002Factory.parse_string in place of
IAGA2002Factory.get_timeseries.
"""
return IAGA2002Factory.parse_string(self, self._stream) return IAGA2002Factory.parse_string(self, self._stream)
def put_timeseries(self, timeseries, starttime=None, endtime=None, def put_timeseries(self, timeseries, starttime=None, endtime=None,
channels=None, type=None, interval=None): channels=None, type=None, interval=None):
"""Implements put_timeseries
Notes: Calls IAGA2002Factory.write_file in place of
IAGA2002Factory.get_timeseries. This can result in a
non-standard IAGA2002 file, specifically one of longer then
expected length.
"""
IAGA2002Factory.write_file(self, self._stream, timeseries, channels) IAGA2002Factory.write_file(self, self._stream, timeseries, channels)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment