diff --git a/geomagio/edge/EdgeFactory.py b/geomagio/edge/EdgeFactory.py new file mode 100644 index 0000000000000000000000000000000000000000..71503700cabd58e149ef1c81a38a493a0cfe1570 --- /dev/null +++ b/geomagio/edge/EdgeFactory.py @@ -0,0 +1,441 @@ +"""Factory that loads data from earthworm and writes to Edge.""" + +import obspy.core +from geomagio import TimeseriesFactory, TimeseriesFactoryException +from obspy import earthworm +from ObservatoryMetadata import ObservatoryMetadata + + +class EdgeFactory(TimeseriesFactory): + + def __init__(self, host=None, port=None, observatory=None, + channels=None, type=None, interval=None, ): + TimeseriesFactory.__init__(self, observatory, channels, type, interval) + self.client = earthworm.Client(host, port) + + def get_timeseries(self, starttime, endtime, observatory=None, + channels=None, type=None, interval=None): + """Get timeseries data + + Parameters + ---------- + observatory : str + observatory code. + starttime : obspy.core.UTCDateTime + time of first sample. + endtime : obspy.core.UTCDateTime + time of last sample. + channels : array_like + list of channels to load + type : {'variation', 'quasi-definitive'} + data type. + interval : {'minute', 'second'} + data interval. + + Returns + ------- + obspy.core.Stream + timeseries object with requested data. + + Raises + ------ + TimeseriesFactoryException + if invalid values are requested, or errors occur while + retrieving timeseries. + """ + observatory = observatory or self.observatory + channels = channels or self.channels + type = type or self.type + interval = interval or self.interval + channels = channels or self.channels + + timeseries = None + for channel in channels: + data = self._get_timeseries(starttime, endtime, observatory, + channel, type, interval) + if timeseries is None: + timeseries = data + else: + timeseries += data + + return timeseries + + def put_timeseries(self, starttime, endtime, observatory=None, + channels=None, type=None, interval=None): + """Put timeseries data + + Parameters + ---------- + observatory : str + observatory code. + starttime : obspy.core.UTCDateTime + time of first sample. + endtime : obspy.core.UTCDateTime + time of last sample. + channels : array_like + list of channels to load + type : {'variation', 'quasi-definitive'} + data type. + interval : {'minute', 'second'} + data interval. + + Returns + ------- + obspy.core.Stream + timeseries object with requested data. + + Raises + ------ + TimeseriesFactoryException + if invalid values are requested, or errors occur while + retrieving timeseries. + """ + raise NotImplementedError('"get_timeseries" not implemented') + + def get_edge_channel_codes(self, observatory, channels, type, interval): + """Get Edge channel(s) codes given single character channel(s) + + Parameters + ---------- + observatory : str + observatory code + channels : array_like + list of single character channels {H, E, D, Z, F} + type : str + data type {Definitive, Quasi-definitive, Variation} + interval : str + interval length {minute, second} + + Returns + ------- + array_like + list of corresponding edge channel names {MVH, SVH, MVE, SVE, ...} + """ + earthworm_channels = [] + for channel in channels: + earthworm_channels.append(self._get_edge_channel(observatory, + channel, type, interval)) + return earthworm_channels + + def get_interval_from_edge(self, channels): + """Get interval from edge style channel codes + + Parameters + ---------- + channels: array_like + list of edge channel codes (MVH, MVE, etc) + + Returns + ------- + channels: array_like + list of channel codes (H, E, D, Z, etc) + """ + interval = None + for channel in channels: + if interval is not None and interval is not channel[0]: + raise TimeseriesFactoryException( + 'Mixed interval values"%s" "%s"' % (interval, channel[0])) + interval = channel[0] + return self._get_interval_from_code(interval) + + def get_type_from_edge(self, location): + """Get type from edge location + + Parameters + ---------- + location: {R0, R1, Q0, D0} + the edge location code. + + Returns + ------- + type: {variation, quasi-definitive, definitive} + the type of data + """ + type = None + if 'location' == 'R0' or 'location' == 'R1': + type = 'variation' + elif 'location' == 'Q0': + type = 'quasi-definitive' + elif 'location' == 'D0': + type = 'definitive' + return type + + def get_channel_code_from_edge(self, channel): + """Get channel code from edge channel code. + + Parameters + ---------- + channel: str + An edge style channel code (MVH, MVE, etc) + + Returns + ------- + channel: str + A single character channel code (H, E, Z, F, etc) + + Raises + ------ + TimeseriesFactoryException + If input channel is invalid. + """ + if len(channel) == 3: + code = channel[2] + else: + raise TimeseriesFactoryException( + 'Unexpected Edge Channel"%s"' % channel) + return code + + def _get_edge_network(self, observatory, channel, type, interval): + """get edge network code. + + Parameters + ---------- + observatory : str + observatory code + channels : array_like + list of single character channels {H, E, D, Z, F} + type : str + data type {Definitive, Quasi-definitive, Variation} + interval : str + interval length {minute, second} + + Returns + ------- + network + always NT + """ + return 'NT' + + def _get_edge_station(self, observatory, channel, type, interval): + """get edge station. + + Parameters + ---------- + observatory : str + observatory code + channels : array_like + list of single character channels {H, E, D, Z, F} + type : str + data type {Definitive, Quasi-definitive, Variation} + interval : str + interval length {minute, second} + + Returns + ------- + station + the observatory is returned as the station + """ + return observatory + + def _get_edge_channel(self, observatory, channel, type, interval): + """get edge channel. + + Parameters + ---------- + observatory : str + observatory code + channels : array_like + list of single character channels {H, E, D, Z, F} + type : str + data type {Definitive, Quasi-definitive, Variation} + interval : str + interval length {minute, second} + + Returns + ------- + edge_channel + {MVH, MVE, MVD, etc} + """ + edge_interval_code = self._get_interval_code(interval) + edge_channel = None + if channel == 'D': + edge_channel = edge_interval_code + 'VD' + elif channel == 'E': + edge_channel = edge_interval_code + 'VE' + elif channel == 'F': + edge_channel = edge_interval_code + 'SF' + elif channel == 'H': + edge_channel = edge_interval_code + 'VH' + elif channel == 'Z': + edge_channel = edge_interval_code + 'VZ' + else: + raise TimeseriesFactoryException( + 'Unexpected channel code "%s"' % channel) + return edge_channel + + def _get_edge_location(self, observatory, channel, type, interval): + """get edge location. + + The edge location code is currently determined by the type + passed in. + + Parameters + ---------- + observatory : str + observatory code + channels : array_like + list of single character channels {H, E, D, Z, F} + type : str + data type {Definitive, Quasi-definitive, Variation} + interval : str + interval length {minute, second} + + Returns + ------- + location + returns an edge location code + """ + location = None + if type == 'variation': + location = 'R0' + elif type == 'quasi-definitive': + location = 'Q0' + elif type == 'definite': + location = 'D0' + return location + + def _get_edge_code_from_channel(self, channel): + """get edge code from channel. + + The second character of the edge channel code for geomag represents + the instrument type. Currently Variometer and Scalar are + supported. Which one is currently decided by the channel + passed in. + + Parameters + ---------- + observatory : str + observatory code + channels : array_like + list of single character channels {H, E, D, Z, F} + type : str + data type {Definitive, Quasi-definitive, Variation} + interval : str + interval length {minute, second} + + Returns + ------- + channel_code + partial channel code + """ + edge_channel = None + if channel == 'D': + edge_channel = 'VD' + elif channel == 'E': + edge_channel = 'VE' + elif channel == 'F': + edge_channel = 'SF' + elif channel == 'H': + edge_channel = 'VH' + elif channel == 'Z': + edge_channel = 'VZ' + else: + raise TimeseriesFactoryException( + 'Unexpected channel code "%s"' % channel) + return edge_channel + + def _get_interval_from_code(self, interval): + """get interval from edge Code. + + The first character of an Edge code represents the interval. + Currently minute and second are represented. + + Parameters + ---------- + observatory : str + observatory code + channels : array_like + list of single character channels {H, E, D, Z, F} + type : str + data type {Definitive, Quasi-definitive, Variation} + interval : str + interval length {minute, second} + + Returns + ------- + interval type + """ + interval_code = None + if 'M': + interval_code = 'minute' + elif 'S': + interval_code = 'second' + else: + raise TimeseriesFactoryException( + 'Unexpected interval code "%s' % interval) + return interval_code + + def _get_interval_code(self, interval): + """get edge interval code. + + Converts the metadata interval string, into an edge single character + edge code. + + Parameters + ---------- + observatory : str + observatory code + channels : array_like + list of single character channels {H, E, D, Z, F} + type : str + data type {Definitive, Quasi-definitive, Variation} + interval : str + interval length {minute, second} + + Returns + ------- + interval type + """ + interval_code = None + if interval == 'daily': + interval_code = 'D' + elif interval == 'hourly': + interval_code = 'H' + elif interval == 'minute': + interval_code = 'M' + elif interval == 'second': + interval_code = 'S' + else: + raise TimeseriesFactoryException( + 'Unexpected interval "%s"' % interval) + return interval_code + + def _get_timeseries(self, starttime, endtime, observatory, + channel, type, interval): + """get timeseries data for a single channel. + + Parameters + ---------- + starttime: obspy.core.UTCDateTime + the starttime of the requested data + endtime: obspy.core.UTCDateTime + the endtime of the requested data + observatory : str + observatory code + channels : array_like + list of single character channels {H, E, D, Z, F} + type : str + data type {Definitive, Quasi-definitive, Variation} + interval : str + interval length {minute, second} + + Returns + ------- + obspy.core.trace + timeseries trace of the requested channel data + """ + station = self._get_edge_station(observatory, channel, + type, interval) + location = self._get_edge_location(observatory, channel, + type, interval) + network = self._get_edge_network(observatory, channel, + type, interval) + channel = self._get_edge_channel(observatory, channel, + type, interval) + data = self.client.getWaveform(network, station, location, + channel, starttime, endtime) + stats = obspy.core.Stats(data[0].stats) + stats = ObservatoryMetadata().set_metadata(stats, observatory, + channel, type, interval) + data[0].stats = stats + return data diff --git a/geomagio/edge/EdgeFactory_test.py b/geomagio/edge/EdgeFactory_test.py new file mode 100644 index 0000000000000000000000000000000000000000..e9c50b6c6956c11aa34abf0115823882b53471a1 --- /dev/null +++ b/geomagio/edge/EdgeFactory_test.py @@ -0,0 +1,61 @@ +"""Tests for EdgeFactory.py""" + +from obspy.core.utcdatetime import UTCDateTime +from EdgeFactory import EdgeFactory +from nose.tools import assert_equals +from nose.tools import assert_raises +from geomagio import TimeseriesFactoryException + + +def test_get_edge_channel_codes(): + """geomagio.edge.EdgeFactory_test.test_get_edge_channel_codes() + """ + # 1) Call get_edge_channel_codes with minute, variation and H, + # expect MVH back + channels = EdgeFactory().get_edge_channel_codes('BOU', ('H'), 'variation', + 'minute') + assert_equals(channels, ['MVH'], 'Expect edge channel to equal MVH') + # 2) Call get_edge_channel_codes with second, variation and [H,D,Z,F], + # expect SVN, SVD, SVZ and SSF back + channels = EdgeFactory().get_edge_channel_codes('BOU', + ('H', 'D', 'Z', 'F'), 'variation', 'second') + assert_equals(channels[0], 'SVH', 'Expect edge channels to equal SVH') + assert_equals(channels[1], 'SVD', 'Expect edge channels to equal SVD') + assert_equals(channels[2], 'SVZ', 'Expect edge channels to equal SVZ') + assert_equals(channels[3], 'SSF', 'Expect edge channels to equal SSF') + + +def test_get_interval_from_edge(): + """geomagio.edge.EdgeFactory_test.test_get_interval_from_edge() + """ + # 1) Call get_interval_from_edge with Minute channels, get minute back. + assert_equals(EdgeFactory().get_interval_from_edge( + ('MVH', 'MVE')), 'minute') + # 2) Call get_interval_from_edge with Mixed channels, raise exception. + assert_raises(TimeseriesFactoryException, + EdgeFactory().get_interval_from_edge, + ('MVH', 'SVE')) + + +def test__get_edge_code_from_channel(): + """geomagio.edge.EdgeFactory_test.test__get_edge_code_from_channel() + """ + # Call private function _get_edge_code_from_channel, make certain + # it gets back the appropriate 2 character code. + assert_equals(EdgeFactory()._get_edge_code_from_channel('D'), 'VD') + assert_equals(EdgeFactory()._get_edge_code_from_channel('E'), 'VE') + assert_equals(EdgeFactory()._get_edge_code_from_channel('F'), 'SF') + assert_equals(EdgeFactory()._get_edge_code_from_channel('H'), 'VH') + assert_equals(EdgeFactory()._get_edge_code_from_channel('Z'), 'VZ') + + +# def test_get_timeseries(): +def dont_get_timeseries(): + """geomagio.edge.EdgeFactory_test.test_get_timeseries()""" + # Call get_timeseries, and test stats for comfirmation that it came back. + edge_factory = EdgeFactory() + timeseries = edge_factory.get_timeseries( + UTCDateTime(2015, 3, 1, 0, 0, 0), UTCDateTime(2015, 3, 1, 1, 0, 0), + 'BOU', ('H'), 'variation', 'minute') + assert_equals(timeseries.select(channel='MVH')[0].stats.station, + 'BOU', 'Expect timeseries to have stats') diff --git a/geomagio/edge/ObservatoryMetadata.py b/geomagio/edge/ObservatoryMetadata.py new file mode 100644 index 0000000000000000000000000000000000000000..8d9c50f300d7da4dc7619d0172d5a8dd67fe0fc2 --- /dev/null +++ b/geomagio/edge/ObservatoryMetadata.py @@ -0,0 +1,379 @@ +"""Factory that loads metadata for an observatory""" + + +# default metadata for the 14 USGS observatories. +DefaultMetadata = {'BOU': + {'network': 'NT', + 'station': 'BOU', + 'channel': 'H', + 'station_name': 'Boulder', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 40.137, + 'geodetic_longitude': 254.764, + 'elevation': 1682, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 7406, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'BRW': + {'network': 'NT', + 'station': 'BRW', + 'channel': 'H', + 'station_name': 'Barrow', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 71.322, + 'geodetic_longitude': 203.378, + 'elevation': 12, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 16000, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'BSL': + {'network': 'NT', + 'station': 'BSL', + 'channel': 'H', + 'station_name': 'Stennis Space Center', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 30.350, + 'geodetic_longitude': 270.365, + 'elevation': 8, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 1530, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'CMO': + {'network': 'NT', + 'station': 'CMO', + 'channel': 'H', + 'station_name': 'College', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 64.874, + 'geodetic_longitude': 212.140, + 'elevation': 197, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 16876, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'DED': + {'network': 'NT', + 'station': 'DED', + 'channel': 'H', + 'station_name': 'Deadhorse', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 70.356, + 'geodetic_longitude': 211.207, + 'elevation': 10, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 13200, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'FRD': + {'network': 'NT', + 'station': 'FRD', + 'channel': 'H', + 'station_name': 'Fredericksburg', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 38.205, + 'geodetic_longitude': 282.627, + 'elevation': 69, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 210942, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'FRN': + {'network': 'NT', + 'station': 'FRN', + 'channel': 'H', + 'station_name': 'Fresno', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 37.091, + 'geodetic_longitude': 240.282, + 'elevation': 331, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 9250, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'GUA': + {'network': 'NT', + 'station': 'GUA', + 'channel': 'H', + 'station_name': 'Guam', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 13.588, + 'geodetic_longitude': 144.867, + 'elevation': 140, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 1157, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'HON': + {'network': 'NT', + 'station': 'HON', + 'channel': 'H', + 'station_name': 'Honolulu', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 21.316, + 'geodetic_longitude': 202.000, + 'elevation': 4, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 6920, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'SHU': + {'network': 'NT', + 'station': 'SHU', + 'channel': 'H', + 'station_name': 'Shumagin', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 55.348, + 'geodetic_longitude': 199.538, + 'elevation': 80, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 13974, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'SIT': + {'network': 'NT', + 'station': 'SIT', + 'channel': 'H', + 'station_name': 'Sitka', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 57.058, + 'geodetic_longitude': 224.674, + 'elevation': 24, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 16523, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'SJG': + {'network': 'NT', + 'station': 'SJG', + 'channel': 'H', + 'station_name': 'San Juan', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 18.113, + 'geodetic_longitude': 293.849, + 'elevation': 424, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 209800, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '}, +'TUC': + {'network': 'NT', + 'station': 'TUC', + 'channel': 'H', + 'station_name': 'Tucson', + 'agency_name': 'United States Geological Survey (USGS)', + 'geodetic_latitude': 32.174, + 'geodetic_longitude': 249.267, + 'elevation': 946, + 'sensor_orientation': 'HDZF', + 'sensor_sampling_rate': '0.01 second', + 'data_type': 'variation', + 'data_interval': 'minute', + 'data_interval_type': 'filtered 1-minute (00:15-01:45)', + 'declination_base': 7258, + 'is_intermagnet': False, + 'condtions_of_use': 'The Conditions of Use for data provided through ' + + 'INTERMAGNET and acknowledgement templates can be found at ' + + 'www.intermagnet.org', + 'filter_comments': 'Vector 1-minute values are computed from 1-second' + + 'values using the INTERMAGNET gaussian filter centered on the ' + + 'minute. Scalar 1-minute values are computed from 1-second values ' + + 'using the INTERMAGNET gaussian filter centered on the minute. ', + 'comments': ' # This data file was constructed by the Golden GIN. Final ' + + 'data will be available on the INTERMAGNET DVD. Go to ' + + 'www.intermagnet.org for details on obtaining this product. '} +} + + +class ObservatoryMetadata(object): + """Helper class for providing all the metadata needed for a geomag + timeseries. + Notes + ----- + Currently the only method is set_metadata. Eventually this will probably + pull from a database, or maybe a config file. + """ + + def set_metadata(self, stats, observatory, channel, type, interval): + """Set timeseries metadata (aka a traces stats) + + Parameters + ---------- + stats : obspy.core.trace.stats + the class associated with a given obspy trace, which contains + it's metadata + observatory : string + the observatory code to look up. + type : {'variation', 'quasi-definitive'} + data type. + interval : {'minute', 'second'} + data interval. + + Returns + ------- + obspy.core.trace.stats + the combined stats and the default metadata. + """ + static_stats = DefaultMetadata['BOU'] + for key in static_stats.keys(): + if key not in stats: + stats[key] = static_stats[key] + return stats diff --git a/geomagio/edge/ObservatoryMetadata_test.py b/geomagio/edge/ObservatoryMetadata_test.py new file mode 100644 index 0000000000000000000000000000000000000000..933765859bb9cdb5ac275b9707db56513b4c3cfd --- /dev/null +++ b/geomagio/edge/ObservatoryMetadata_test.py @@ -0,0 +1,25 @@ +"""Tests for ObservatoryMetadata.py""" + +from ObservatoryMetadata import ObservatoryMetadata +from nose.tools import assert_equals +import obspy.core + + +def test_set_metadata(): + """geomagio.edge.ObservatoryMetadata_test.test_set_metadata() + """ + # Test set_metadata by passing in a stats class, and looking + # for parameters that are both passed in, and aquired from the default + # metadata. + observatorymetadata = ObservatoryMetadata() + stats = obspy.core.Stats() + stats.channel = 'MVH' + stats.location = 'R0' + stats.data_interval = 'second' + stats.data_type = 'quasi-definitive' + stats = observatorymetadata.set_metadata(stats, 'BOU', 'H', + 'quasi-definitive', 'second') + assert_equals(stats['channel'], 'MVH') + assert_equals(stats['data_interval'], 'second') + assert_equals(stats['data_type'], 'quasi-definitive') + assert_equals(stats['declination_base'], 7406) diff --git a/geomagio/edge/__init__.py b/geomagio/edge/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e2c3fdf9321b5d8d45d538b87c1b579588725e04 --- /dev/null +++ b/geomagio/edge/__init__.py @@ -0,0 +1,13 @@ +"""IO Module for Edge Format + +Based on documentation at: + http://www.ngdc.noaa.gov/IAGA/vdat/iagaformat.html +""" + +from EdgeFactory import EdgeFactory +from ObservatoryMetadata import ObservatoryMetadata + +__all__ = [ + 'EdgeFactory', + 'ObservatoryMetadata', +]