Skip to content
Snippets Groups Projects
IMFJSONWriter.py 7.34 KiB
Newer Older
  • Learn to ignore specific revisions
  • from __future__ import absolute_import
    
    from collections import OrderedDict
    
    from io import BytesIO
    
    from datetime import datetime
    import json
    
    from .. import ChannelConverter, TimeseriesUtility
    from ..TimeseriesFactoryException import TimeseriesFactoryException
    
    
    class IMFJSONWriter(object):
    
        """JSON writer.
        """
    
        def write(self, out, timeseries, channels, **kwargs):
    
            """Write timeseries to json 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
    
            kwargs
                request : query string
    
            Raises
            ------
            TimeseriesFactoryException
                if there is a missing channel.
    
            file_dict = OrderedDict()
    
            request = kwargs.get('request')
            for channel in channels:
                if timeseries.select(channel=channel).count() == 0:
                    raise TimeseriesFactoryException(
                        'Missing channel "%s" for output, available channels %s' %
                        (channel, str(TimeseriesUtility.get_channels(timeseries))))
            stats = timeseries[0].stats
    
            file_dict['type'] = 'Timeseries'
            file_dict['metadata'] = self._format_metadata(stats, channels)
    
            if request:
    
                base = 'http://geomag.usgs.gov/ws/edge/?'
                file_dict['metadata']['url'] = base + request
            file_dict['times'] = self._format_times(timeseries, channels)
            file_dict['values'] = self._format_data(timeseries, channels, stats)
            formatted_timeseries = json.dumps(file_dict,
                    ensure_ascii=True).encode('utf8')
            out.write(str(formatted_timeseries))
    
        def _format_data(self, timeseries, channels, stats):
            """Format all data lines.
    
            Parameters
            ----------
            timeseries : obspy.core.Stream
                stream containing traces with channel listed in channels
            channels : sequence
                list and order of channel values to output.
            stats: obspy.core.trace.stats
                holds the observatory metadata
    
            Returns
            -------
            array_like
                an array containing dictionaries of data.
            """
            if timeseries.select(channel='D'):
                d = timeseries.select(channel='D')
                d[0].data = ChannelConverter.get_minutes_from_radians(d[0].data)
            values = []
            for c in channels:
                value_dict = OrderedDict()
                trace = timeseries.select(channel=c)[0]
                value_dict['id'] = c
                value_dict = OrderedDict()
                value_dict['element'] = c
                if 'network' in stats:
                    value_dict['network'] = stats.network
                value_dict['station'] = stats.station
                if 'channel' in stats:
                    edge_channel = trace.stats.channel
                else:
                    edge_channel = c
                value_dict['channel'] = edge_channel
                if 'location' in stats:
                    value_dict['location'] = stats.location
                # TODO: Add flag metadata
                values += [value_dict]
                data = np.copy(trace.data)
                data[np.isnan(data)] = None
                value_dict['values'] = data.tolist()
            return values
    
    
        def _format_metadata(self, stats, channels):
    
            """Format metadata for json file and update dictionary
    
    
            Parameters
            ----------
            stats: obspy.core.trace.stats
                holds the observatory metadata
            channels: array_like
                channels to be reported.
    
    
            Returns
            -------
            dictionary
                a dictionary containing metadata.
    
            metadata_dict = OrderedDict()
            intermag = OrderedDict()
            imo = OrderedDict()
            imo['iaga_code'] = stats.station
    
            if 'station_name' in stats:
    
                imo['name'] = stats.station_name
    
            coords = [None] * 3
            if 'geodetic_longitude' in stats:
                coords[0] = str(stats.geodetic_longitude)
            if 'geodetic_latitude' in stats:
                coords[1] = str(stats.geodetic_latitude)
            if 'elevation' in stats:
                coords[2] = str(stats.elevation)
    
            imo['coordinates'] = coords
            intermag['imo'] = imo
            intermag['reported_orientation'] = ''.join(channels)
    
            if 'sensor_orientation' in stats:
    
                intermag['sensor_orientation'] = stats.sensor_orientation
    
            if 'data_type' in stats:
    
                intermag['data_type'] = stats.data_type
    
            if 'sampling_rate' in stats:
                if stats.sampling_rate == 1. / 60.:
                    rate = 60
                elif stats.sampling_rate == 1. / 3600.:
                    rate = 3600
                elif stats.sampling_rate == 1. / 86400.:
                    rate = 86400
                else:
                    rate = 1
    
                intermag['sampling_period'] = str(rate)
    
            if 'sensor_sampling_rate' in stats:
    
                sampling = 1 / stats.sensor_sampling_rate
                intermag['digital_sampling_rate'] = str(sampling)
    
            metadata_dict['intermagnet'] = intermag
            metadata_dict['status'] = 200
    
            generated = datetime.utcnow()
            metadata_dict['generated'] = generated.strftime("%Y-%m-%dT%H:%M:%SZ")
    
    
        def _format_times(self, timeseries, channels):
    
            """Format times for json file and update dictionary
    
    
            Parameters
            ----------
    
            timeseries : obspy.core.Stream
                stream containing traces with channel listed in channels
    
            channels: array_like
                channels to be reported.
    
    
            Returns
            -------
            array_like
                an array containing formatted strings of time data.
    
            """
            times = []
            traces = [timeseries.select(channel=c)[0] for c in channels]
            starttime = float(traces[0].stats.starttime)
            delta = traces[0].stats.delta
            for i in range(len(traces[0].data)):
                times.append(self._format_time_string(
                    datetime.utcfromtimestamp(starttime + i * delta)))
    
    
        def _format_time_string(self, time):
    
            """Format one datetime object.
    
    
            Parameters
            ----------
            time : datetime
                timestamp for values
    
            Returns
            -------
            unicode
                formatted time.
            """
            tt = time.timetuple()
            return '{0.tm_year:0>4d}-{0.tm_mon:0>2d}-{0.tm_mday:0>2d}T' \
    
                    '{0.tm_hour:0>2d}:{0.tm_min:0>2d}:{0.tm_sec:0>2d}.{1:0>3d}Z' \
                    ''.format(tt, int(time.microsecond / 1000))
    
    
        @classmethod
        def format(self, timeseries, channels, **kwargs):
            """Get a json formatted string.
    
            Calls write() with a BytesIO, and returns the output.
    
            Parameters
            ----------
    
            timeseries : obspy.core.Stream
                stream containing traces with channel listed in channels
            channels: array_like
                channels to be written from timeseries object
    
            kwargs
                request : query string
    
            Returns
            -------
            unicode
             json formatted string.
            """
            request = kwargs.get('request')
            out = BytesIO()
    
            writer = IMFJSONWriter()
            writer.write(out, timeseries, channels, request=request)
    
            return out.getvalue()