diff --git a/docs/algorithms/DeltaF_usage.md b/docs/algorithms/DeltaF_usage.md index ff93d774601967b7c784293904ca7a715d5dfb44..beb0b2d023fea4777daa0dd9f54a11fe1e2a6769 100644 --- a/docs/algorithms/DeltaF_usage.md +++ b/docs/algorithms/DeltaF_usage.md @@ -6,7 +6,7 @@ and a scalar total-field measurement made by independent sensors. Read more about the [DeltaF Algorithm](./DeltaF.md). -`geomag.py --deltaf {geo, obs, obsd}` +`geomag.py --algorithm deltaf [--deltaf-from {geo, obs, obsd}]` ### Reference Frames @@ -21,7 +21,7 @@ about the [DeltaF Algorithm](./DeltaF.md). To compute DeltaF from HEZF data for Tucson observatory: ``` geomag.py \ - --deltaf obs \ + --algorithm deltaf \ --observatory TUC \ --type variation \ --interval minute \ diff --git a/docs/algorithms/XYZ_usage.md b/docs/algorithms/XYZ_usage.md index b01fdd8be4834f4ed1884bb1840e3faa61b2613d..d154887f83005f19203821eb40d9c7504fc37992 100644 --- a/docs/algorithms/XYZ_usage.md +++ b/docs/algorithms/XYZ_usage.md @@ -5,7 +5,7 @@ The XYZ Algorithm rotates between `geographic`, `observatory`, and `magnetic`, channel orientations. Read more about the [XYZ Algorithm](./XYZ.md). -`geomag.py --xyz {geo, mag, obs, obsd} {geo, mag, obs, obsd}` +`geomag.py --algorithm xyz [--xyz-from {geo,mag,obs,obsd}] [--xyz-to {geo,mag,obs,obsd}]` ### Reference Frames @@ -30,7 +30,7 @@ There are 3 reference frames in this library. To convert HEZF data in pcdcp files to XYZF for Tucson observatory for all of March 2013 output to iaga2002 files: - geomag.py --xyz obs geo --observatory TUC \ + geomag.py --algorithm xyz --observatory TUC \ --starttime 2013-03-01T00:00:00Z --endtime 2013-03-31T23:59:00Z \ --input-pcdcp-url file://data-pcdcp/./%(OBS)s%(year)s%(julian)s.%(i)s \ --output-iaga-url file://data-iaga/./$(obs)s%(Y)s%(j)s.%(i)s \ diff --git a/docs/api.md b/docs/api.md index 15c8df354c0b47fbcd11445a1c0b5e87fd246910..61ef90e0570f4a0b4ee1d6c40ff292ee792f3c71 100644 --- a/docs/api.md +++ b/docs/api.md @@ -44,11 +44,11 @@ Exception base class is `geomagio.TimeseriesFactoryException`. ## Algorithms -Base class is `geomagio.Algorithm` -Exception base class is `geomagio.AlgorithmException` +Base class is `geomagio.algorithm.Algorithm` +Exception base class is `geomagio.algorithm.AlgorithmException` -- Delta F `geomagio.DeltaFAlgorithm` -- XYZ `geomagio.XYZAlgorithm` +- Delta F `geomagio.algorithm.DeltaFAlgorithm` +- XYZ `geomagio.algorithm.XYZAlgorithm` ## Example @@ -60,7 +60,7 @@ The following example: - Plots the data using matplotlib ```python -from geomagio import XYZAlgorithm +from geomagio.algorithm import XYZAlgorithm from geomagio.edge import EdgeFactory from obspy.core import UTCDateTime diff --git a/docs/usage.md b/docs/usage.md index bc28f80a448391409d1e1fc8e20c6e32147c23a4..a0bc321e649eef05c34694469449a2133f452330 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -68,10 +68,12 @@ There are flags to specify certain algorithms should be run against the data. #### XYZ #### -`--xyz {geo, mag, obs, obsd} {geo, mag, obs, obsd}` +`--algorithm xyz` +`--xyz-from {geo, mag, obs, obsd}` (default is `obs`) +`--xyz-to {geo, mag, obs, obsd}` (default is `geo`) #### [XYZ Usage](./algorithms/XYZ_usage.md) #### -Rotate data from HEZ or HDZ to XYZ and back. +Rotate data from HEZ (obs) or HDZ (mag) to XYZ (geo) and back. Extensive explanation of all input and output methods: [IO Methods](./io.md) diff --git a/geomagio/Controller.py b/geomagio/Controller.py index 60094a11700cabdb4f778fa1120c73b3b74b507b..f6142619a289060adf0cb79ee185c355775277c9 100644 --- a/geomagio/Controller.py +++ b/geomagio/Controller.py @@ -4,7 +4,7 @@ import argparse import sys from obspy.core import UTCDateTime -from Algorithm import Algorithm +from algorithm import algorithms import TimeseriesUtility from TimeseriesFactoryException import TimeseriesFactoryException from Util import ObjectView @@ -14,9 +14,6 @@ import iaga2002 import pcdcp import imfv283 -from DeltaFAlgorithm import DeltaFAlgorithm -from XYZAlgorithm import XYZAlgorithm - class Controller(object): """Controller for geomag algorithms. @@ -301,17 +298,8 @@ def main(args): else: print >> sys.stderr, "Missing required output directive" - if args.xyz is not None: - algorithm = XYZAlgorithm(informat=args.xyz[0], - outformat=args.xyz[1]) - elif args.deltaf is not None: - algorithm = DeltaFAlgorithm(informat=args.deltaf) - else: - # TODO get smarter on inchannels/outchannels since input doesn't always - # need to use the --inchannels argument, but might (as in iaga2002), - # get it from the file. - algorithm = Algorithm(inchannels=args.inchannels, - outchannels=args.outchannels or args.inchannels) + algorithm = algorithms[args.algorithm]() + algorithm.configure(args) # TODO check for unused arguments. @@ -481,14 +469,11 @@ def parse_args(args): help='Edge IP #. See --output-edge-* for other optional arguments') # Algorithms group - algorithm_group = parser.add_mutually_exclusive_group() - algorithm_group.add_argument('--xyz', - nargs=2, - choices=['geo', 'mag', 'obs', 'obsd'], - help='Enter the geomagnetic orientation(s) you want to read from' + - ' and to respectfully.') - algorithm_group.add_argument('--deltaf', - choices=['geo', 'obs', 'obsd'], - help='Enter the geomagnetic orientation you want to read from') + parser.add_argument('--algorithm', + choices=[k for k in algorithms], + default='default') + + for k in algorithms: + algorithms[k].add_arguments(parser) return parser.parse_args(args) diff --git a/geomagio/__init__.py b/geomagio/__init__.py index 4b0f6a79f4f91a58d04ef4f4e7a9fd595ba840de..9e086ee633914218db2d191bafdd1a54bc6f4b4a 100644 --- a/geomagio/__init__.py +++ b/geomagio/__init__.py @@ -4,19 +4,14 @@ Geomag Algorithm Module import ChannelConverter import StreamConverter -from Algorithm import Algorithm -from AlgorithmException import AlgorithmException from Controller import Controller from ObservatoryMetadata import ObservatoryMetadata from TimeseriesFactory import TimeseriesFactory from TimeseriesFactoryException import TimeseriesFactoryException import TimeseriesUtility import Util -from XYZAlgorithm import XYZAlgorithm __all__ = [ - 'Algorithm', - 'AlgorithmException', 'ChannelConverter', 'Controller', 'DeltaFAlgorithm', diff --git a/geomagio/Algorithm.py b/geomagio/algorithm/Algorithm.py similarity index 79% rename from geomagio/Algorithm.py rename to geomagio/algorithm/Algorithm.py index bd7699089ba45eb8da9bd2e7085c057fb341efe1..fed7196b967c626b31472c0ed62abe94b1025365 100644 --- a/geomagio/Algorithm.py +++ b/geomagio/algorithm/Algorithm.py @@ -1,6 +1,6 @@ """Algorithm Interface.""" -import TimeseriesUtility +from .. import TimeseriesUtility class Algorithm(object): @@ -91,3 +91,25 @@ class Algorithm(object): endtime < input_gap[2]): return False return True + + @classmethod + def add_arguments(cls, parser): + """Add command line arguments to argparse parser. + + Parameters + ---------- + parser: ArgumentParser + command line argument parser + """ + pass + + def configure(self, arguments): + """Configure algorithm using comand line arguments. + + Parameters + ---------- + arguments: Namespace + parsed command line arguments + """ + self._inchannels = arguments.inchannels + self._outchannels = arguments.outchannels or arguments.inchannels diff --git a/geomagio/AlgorithmException.py b/geomagio/algorithm/AlgorithmException.py similarity index 100% rename from geomagio/AlgorithmException.py rename to geomagio/algorithm/AlgorithmException.py diff --git a/geomagio/DeltaFAlgorithm.py b/geomagio/algorithm/DeltaFAlgorithm.py similarity index 66% rename from geomagio/DeltaFAlgorithm.py rename to geomagio/algorithm/DeltaFAlgorithm.py index d0619dee63ae90534ec4034063c383219cc90947..616c83d87db39049276edba93466343cfad1cbe8 100644 --- a/geomagio/DeltaFAlgorithm.py +++ b/geomagio/algorithm/DeltaFAlgorithm.py @@ -4,7 +4,7 @@ from Algorithm import Algorithm from AlgorithmException import AlgorithmException -import StreamConverter as StreamConverter +from .. import StreamConverter # List of channels by geomagnetic observatory orientation. # geo represents a geographic north/south orientation @@ -27,10 +27,10 @@ class DeltaFAlgorithm(Algorithm): will be converting from. """ - def __init__(self, informat=None): + def __init__(self, informat='obs'): Algorithm.__init__(self, inchannels=CHANNELS[informat], outchannels=['G']) - self.informat = informat + self._informat = informat def check_stream(self, timeseries): """checks a stream to make certain all the required channels @@ -61,10 +61,35 @@ class DeltaFAlgorithm(Algorithm): """ self.check_stream(timeseries) out_stream = None - - if self.informat == 'geo': + informat = self._informat + if informat == 'geo': out_stream = StreamConverter.get_deltaf_from_geo(timeseries) - elif self.informat == 'obs' or self.informat == 'obsd': + elif informat == 'obs' or informat == 'obsd': out_stream = StreamConverter.get_deltaf_from_obs(timeseries) return out_stream + + @classmethod + def add_arguments(cls, parser): + """Add command line arguments to argparse parser. + + Parameters + ---------- + parser: ArgumentParser + command line argument parser + """ + parser.add_argument('--deltaf-from', + choices=['geo', 'obs', 'obsd'], + default='obs', + help='Geomagnetic orientation to read from') + + def configure(self, arguments): + """Configure algorithm using comand line arguments. + + Parameters + ---------- + arguments: Namespace + parsed command line arguments + """ + self._informat = arguments.deltaf_from + self._inchannels = CHANNELS[self._informat] diff --git a/geomagio/XYZAlgorithm.py b/geomagio/algorithm/XYZAlgorithm.py similarity index 62% rename from geomagio/XYZAlgorithm.py rename to geomagio/algorithm/XYZAlgorithm.py index 12c3a1e0cc195558843a0decc8443d2a214faac6..64d1e91587b64f396125bdb98327c5cb7f2c74c2 100644 --- a/geomagio/XYZAlgorithm.py +++ b/geomagio/algorithm/XYZAlgorithm.py @@ -5,7 +5,7 @@ from Algorithm import Algorithm from AlgorithmException import AlgorithmException -import StreamConverter as StreamConverter +from .. import StreamConverter # List of channels by geomagnetic observatory orientation. # geo represents a geographic north/south orientation @@ -33,11 +33,11 @@ class XYZAlgorithm(Algorithm): be converting to. """ - def __init__(self, informat=None, outformat=None): + def __init__(self, informat='obs', outformat='geo'): Algorithm.__init__(self, inchannels=CHANNELS[informat], outchannels=CHANNELS[outformat]) - self.informat = informat - self.outformat = outformat + self._informat = informat + self._outformat = outformat def check_stream(self, timeseries): """checks an stream to make certain all the required channels @@ -69,36 +69,69 @@ class XYZAlgorithm(Algorithm): """ self.check_stream(timeseries) out_stream = None - if self.outformat == 'geo': - if self.informat == 'geo': + informat = self._informat + outformat = self._outformat + if outformat == 'geo': + if informat == 'geo': out_stream = timeseries - elif self.informat == 'mag': + elif informat == 'mag': out_stream = StreamConverter.get_geo_from_mag(timeseries) - elif self.informat == 'obs' or self.informat == 'obsd': + elif informat == 'obs' or informat == 'obsd': out_stream = StreamConverter.get_geo_from_obs(timeseries) - elif self.outformat == 'mag': - if self.informat == 'geo': + elif outformat == 'mag': + if informat == 'geo': out_stream = StreamConverter.get_mag_from_geo(timeseries) - elif self.informat == 'mag': + elif informat == 'mag': out_stream = timeseries - elif self.informat == 'obs' or self.informat == 'obsd': + elif informat == 'obs' or informat == 'obsd': out_stream = StreamConverter.get_mag_from_obs(timeseries) - elif self.outformat == 'obs': - if self.informat == 'geo': + elif outformat == 'obs': + if informat == 'geo': out_stream = StreamConverter.get_obs_from_geo(timeseries) - elif self.informat == 'mag': + elif informat == 'mag': out_stream = StreamConverter.get_obs_from_mag(timeseries) - elif self.informat == 'obs' or self.informat == 'obsd': + elif informat == 'obs' or informat == 'obsd': out_stream = StreamConverter.get_obs_from_obs(timeseries, include_e=True) - elif self.outformat == 'obsd': - if self.informat == 'geo': + elif outformat == 'obsd': + if informat == 'geo': out_stream = StreamConverter.get_obs_from_geo(timeseries, include_d=True) - elif self.informat == 'mag': + elif informat == 'mag': out_stream = StreamConverter.get_obs_from_mag(timeseries, include_d=True) - elif self.informat == 'obs' or self.informat == 'obsd': + elif informat == 'obs' or informat == 'obsd': out_stream = StreamConverter.get_obs_from_obs(timeseries, include_d=True) return out_stream + + @classmethod + def add_arguments(cls, parser): + """Add command line arguments to argparse parser. + + Parameters + ---------- + parser: ArgumentParser + command line argument parser + """ + parser.add_argument('--xyz-from', + choices=['geo', 'mag', 'obs', 'obsd'], + default='obs', + help='Geomagnetic orientation to read from') + parser.add_argument('--xyz-to', + choices=['geo', 'mag', 'obs', 'obsd'], + default='geo', + help='Geomagnetic orientation to convert to') + + def configure(self, arguments): + """Configure algorithm using comand line arguments. + + Parameters + ---------- + arguments: Namespace + parsed command line arguments + """ + self._informat = arguments.xyz_from + self._outformat = arguments.xyz_to + self._inchannels = CHANNELS[self._informat] + self._outchannels = CHANNELS[self._outformat] diff --git a/geomagio/algorithm/__init__.py b/geomagio/algorithm/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..caaabb0c7a2ab733eb7cd9b3405a27aa00a2ecd3 --- /dev/null +++ b/geomagio/algorithm/__init__.py @@ -0,0 +1,28 @@ +""" +Geomag Algorithms module +""" + +# base classes +from Algorithm import Algorithm +from AlgorithmException import AlgorithmException +# algorithms +from DeltaFAlgorithm import DeltaFAlgorithm +from XYZAlgorithm import XYZAlgorithm + + +# algorithms is used by Controller to auto generate arguments +algorithms = { + 'identity': Algorithm, + 'deltaf': DeltaFAlgorithm, + 'xyz': XYZAlgorithm +} + + +__all__ = [ + # base classes + 'Algorithm', + 'AlgorithmException', + # algorithms + 'DeltaFAlgorithm', + 'XYZAlgorithm' +] diff --git a/setup.py b/setup.py index 0257b0d1df189943db32736561b7b92692d60446..84ef2911c87c6b82a32c55c9aaa286b5052151c1 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ setup( url='https://github.com/usgs/geomag-algorithms', packages=[ 'geomagio', + 'geomagio.algorithm', 'geomagio.iaga2002', 'geomagio.imfv283', 'geomagio.edge', diff --git a/test/Controller_test.py b/test/Controller_test.py index e407a9ecaa9463508a72b8cdea09fc083842e542..4b1992c98daa32abac7c47ffa35f9c806f773465 100644 --- a/test/Controller_test.py +++ b/test/Controller_test.py @@ -1,5 +1,6 @@ #! /usr/bin/env python -from geomagio import Algorithm, Controller, TimeseriesFactory +from geomagio import Controller, TimeseriesFactory +from geomagio.algorithm import Algorithm from nose.tools import assert_is_instance diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/Algorithm_test.py b/test/algorithm_test/Algorithm_test.py similarity index 95% rename from test/Algorithm_test.py rename to test/algorithm_test/Algorithm_test.py index cf4d2e3cbf249b8a50b4b75068abcb28c881a9ae..8ce878f1dd34cd6561cd9010d120d0d242c614c7 100644 --- a/test/Algorithm_test.py +++ b/test/algorithm_test/Algorithm_test.py @@ -2,7 +2,7 @@ from obspy.core.stream import Stream from nose.tools import assert_equals from nose.tools import assert_is_instance -from geomagio import Algorithm +from geomagio.algorithm import Algorithm def test_algorithm_process(): diff --git a/test/XYZAlgorithm_test.py b/test/algorithm_test/XYZAlgorithm_test.py similarity index 92% rename from test/XYZAlgorithm_test.py rename to test/algorithm_test/XYZAlgorithm_test.py index b84f87198174e311879f46789c64a792d1dbdbbb..0ffcfb3ec543c6c1d8875c76798473bc4906a97c 100644 --- a/test/XYZAlgorithm_test.py +++ b/test/algorithm_test/XYZAlgorithm_test.py @@ -2,8 +2,8 @@ from obspy.core.stream import Stream from nose.tools import assert_equals from nose.tools import assert_is -from geomagio import XYZAlgorithm -from StreamConverter_test import __create_trace +from geomagio.algorithm import XYZAlgorithm +from ..StreamConverter_test import __create_trace def test_xyzalgorithm_process(): diff --git a/test/algorithm_test/__init__.py b/test/algorithm_test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/edge_test/__init__.py b/test/edge_test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/iaga2002_test/__init__.py b/test/iaga2002_test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/imfv283_test/__init__.py b/test/imfv283_test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/pcdcp_test/__init__.py b/test/pcdcp_test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391