Example #1
0
        def match(self, lat, lon):
            if self.bBox is not None:
                b = self.bBox
                if b.minLat is not None and lat < b.minLat:
                    return False
                if b.maxLat is not None and lat > b.maxLat:
                    return False
                # date line crossing if minLon > maxLon
                if b.dateLineCrossing():
                    return lon >= b.minLon or lon <= b.maxLon
                if b.minLon is not None and lon < b.minLon:
                    return False
                if b.maxLon is not None and lon > b.maxLon:
                    return False
                return True
            elif self.bCircle:
                c = self.bCircle
                dist = Math.delazi(c.lat, c.lon, lat, lon)
                if c.minRad is not None and dist[0] < c.minRad:
                    return False
                if c.maxRad is not None and dist[0] > c.maxRad:
                    return False
                return True

            return False
Example #2
0
 def _getDistancesArrivalsSorted(self, org):
     # sort arrival list by distance
     dist_arr = []
     if self.distInKM:
         from seiscomp3 import Math
         for i in xrange(org.arrivalCount()):
             arr = org.arrival(i)
             dist_arr.append((Math.deg2km(arr.distance()), arr))
     else:
         for i in xrange(org.arrivalCount()):
             arr = org.arrival(i)
             dist_arr.append((arr.distance(), arr))
     dist_arr.sort()
     return dist_arr
Example #3
0
 def _getDistancesArrivalsSorted(self, org):
     # sort arrival list by distance
     dist_arr = []
     if self.distInKM:
         from seiscomp3 import Math
         for i in xrange(org.arrivalCount()):
             arr = org.arrival(i)
             dist_arr.append((Math.deg2km(arr.distance()), arr))
     else:
         for i in xrange(org.arrivalCount()):
             arr = org.arrival(i)
             dist_arr.append((arr.distance(), arr))
     dist_arr.sort()
     return dist_arr
Example #4
0
		def match(self, lat, lon):
			if self.bBox:
				b = self.bBox
				if b.minLat and lat < b.minLat: return False
				if b.maxLat and lat > b.maxLat: return False
				# date line crossing if minLon > maxLon
				if b.dateLineCrossing():
					return lon >= b.minLon or lon <= b.maxLon
				if b.minLon and lon < b.minLon: return False
				if b.maxLat and lon > b.maxLon: return False
				return True
			elif self.bCircle:
				c = self.bCircle
				dist = Math.delazi(c.lat, c.lon, lat, lon)
				return dist[0] <= c.maxRad and (
				       not c.minRad or dist[0] >= c.minRad)

			return False
Example #5
0
		def match(self, lat, lon):
			if self.bBox is not None:
				b = self.bBox
				if b.minLat is not None and lat < b.minLat: return False
				if b.maxLat is not None and lat > b.maxLat: return False
				# date line crossing if minLon > maxLon
				if b.dateLineCrossing():
					return lon >= b.minLon or lon <= b.maxLon
				if b.minLon is not None and lon < b.minLon: return False
				if b.maxLon is not None and lon > b.maxLon: return False
				return True
			elif self.bCircle:
				c = self.bCircle
				dist = Math.delazi(c.lat, c.lon, lat, lon)
				if c.minRad is not None and dist[0] < c.minRad: return False
				if c.maxRad is not None and dist[0] > c.maxRad: return False
				return True

			return False
Example #6
0
 def _getDistancesArrivalsSorted(self, org):
     # sort arrival list by distance
     dist_arr = []
     if self.distInKM:
         from seiscomp3 import Math
         for i in range(org.arrivalCount()):
             arr = org.arrival(i)
             try:
                 dist_arr.append((Math.deg2km(arr.distance()), arr))
             except ValueError:
                 pass
     else:
         for i in range(org.arrivalCount()):
             arr = org.arrival(i)
             try:
                 dist_arr.append((arr.distance(), arr))
             except ValueError:
                 pass
     return sorted(dist_arr, key=lambda a: a[0])
Example #7
0
    def getQuery(self, params):
        """Get a list of streams that satisfies the input parameters.

        This method is public and appends the necessary
        information to the streams that belong to the stations
        actually selected by __selectStations. It contains many
        columns, as it is the list to show in the construction of
        the request package.

        """

        try:
            start_year = int(params.get('start', 1980))
        except (TypeError, ValueError):
            raise wsgicomm.WIClientError, 'Error! Start year is invalid.'

        start_date = datetime.datetime(start_year, 1, 1, 0, 0, 0)

        # Build the end date in datetime format
        # Only year-wide windows are allowed here.
        try:
            end_year = int(params.get('end', datetime.datetime.now().year))
        except:
            raise wsgicomm.WIClientError, 'Error! End year is invalid.'

        end_date = datetime.datetime(end_year, 12, 31, 23, 59, 59)

        # Get the network
        # network = params.get('network')

        # Get the station
        station = params.get('station')

        # Get the sensortype
        sensortype = params.get('sensortype')
        if sensortype == 'all':
            sensortype = None

        # Get the preferred sample rate
        try:
            preferredsps = float(params.get('preferredsps'))
        except:
            preferredsps = None

        # Split the list of streams if any
        try:
            streams = params.get('streams').split(',')
        except wsgicomm.WIError:
            raise
        except:
            streams = None

        # Look at the attributes associated with every network type
        try:
            networktype = params.get('networktype')

            if (networktype == 'all') or (networktype is None):
                networktype = None
            else:
                for nettype in self.nettypes:
                    if networktype == nettype[0]:
                        break
                else:
                    raise Exception

        except:
            msg = 'Wrong value in parameter "networktype"'
            raise wsgicomm.WIClientError, msg

        # Check for latitude and longitude parameters
        try:
            latmin = float(params.get('minlat')) if 'minlat' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: minlat must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            latmax = float(params.get('maxlat')) if 'maxlat' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: maxlat must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            lonmin = float(params.get('minlon')) if 'minlon' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: minlon must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            lonmax = float(params.get('maxlon')) if 'maxlon' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: maxlon must be a float number.'
            raise wsgicomm.WIClientError, msg

        # Check for radius and azimuth parameters
        try:
            minradius = float(params.get('minradius')) if 'minradius' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: minradius must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            maxradius = float(params.get('maxradius')) if 'maxradius' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: maxradius must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            minazimuth = float(params.get('minazimuth')) if 'minazimuth' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: minazimuth must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            maxazimuth = float(params.get('maxazimuth')) if 'maxazimuth' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: maxazimuth must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            events = params.get('events', None)
        except:
            events = None

        # Try to check parameters for different modes of selecting stations
        # One or all stations have been selected and also lat/lon parameters
        if station and (latmin is not None or latmax is not None
                        or lonmin is not None or lonmax is not None):
            msg = 'Error: station and lat/lon parameters are incompatible.'
            raise wsgicomm.WIClientError, msg

        # One or all stations have been selected and also radius/azimuth params
        if station and (minradius is not None or maxradius is not None
                        or minazimuth is not None or maxazimuth is not None):
            msg = 'Error: station and radius/azimuth parameters are ' + \
                'incompatible.'
            raise wsgicomm.WIClientError, msg

        # Lat/lon parameters have been selected and also radius/azimuth
        if (latmin is not None or latmax is not None or lonmin is not None
                or lonmax is not None) and (minradius is not None
                                            or maxradius is not None
                                            or minazimuth is not None
                                            or maxazimuth is not None):
            msg = 'Error: lat/lon and radius/azimuth parameters are ' + \
                'incompatible.'
            raise wsgicomm.WIClientError, msg

        # These are the two lists to return
        stats = []

        # Filter and save indexes of stations in statsOK
        statsOK = self.__selectStations(params)

        # Just to make notation shorter
        ptNets = self.networks
        ptStats = self.stations

        if ('station' in params):
            # Builds a list from the selected stations
            for st in statsOK:
                parent_net = ptStats[st][0]

                (loc_ch,
                 restricted) = self.__buildStreamsList(st, streams, sensortype,
                                                       preferredsps,
                                                       start_date, end_date)

                if len(loc_ch):
                    stats.append(
                        ('%s-%s-%s-%s%s%s' %
                         (ptNets[parent_net][0], ptNets[parent_net][4],
                          ptStats[st][4], ptStats[st][8].year,
                          ptStats[st][8].month, ptStats[st][8].day),
                         ptNets[parent_net][0], ptStats[st][4], ptStats[st][5],
                         ptStats[st][6], ptNets[parent_net][7],
                         ptNets[parent_net][8], ptNets[parent_net][9],
                         ptNets[parent_net][10], loc_ch, restricted))

        elif (latmin is not None and latmax is not None and lonmin is not None
              and lonmax is not None):

            # statsOK is a set and therefore, there will be no repetitions
            for st in statsOK:
                # Pointer to the parent network
                parent_net = ptStats[st][0]

                # Filter by latitude
                if (ptStats[st][5] < latmin) or (ptStats[st][5] > latmax):
                    continue

                # Filter by longitude
                if (lonmin <= lonmax):
                    if (ptStats[st][6] < lonmin) or (ptStats[st][6] > lonmax):
                        continue
                else:
                    if (ptStats[st][6] < lonmin) and (ptStats[st][6] > lonmax):
                        continue

                (loc_ch,
                 restricted) = self.__buildStreamsList(st, streams, sensortype,
                                                       preferredsps,
                                                       start_date, end_date)

                if len(loc_ch):
                    stats.append(
                        ('%s-%s-%s-%s%s%s' %
                         (ptNets[parent_net][0], ptNets[parent_net][4],
                          ptStats[st][4], ptStats[st][8].year,
                          ptStats[st][8].month, ptStats[st][8].day),
                         ptNets[parent_net][0], ptStats[st][4], ptStats[st][5],
                         ptStats[st][6], ptNets[parent_net][7],
                         ptNets[parent_net][8], ptNets[parent_net][9],
                         ptNets[parent_net][10], loc_ch, restricted))

        elif events is not None:

            events = json.loads(events)

            for st in statsOK:
                # Pointer to the parent network
                parent_net = ptStats[st][0]

                # Retrieve latitude and longitude of station
                slat = ptStats[st][5]
                slon = ptStats[st][6]

                for evt in events:
                    # Retrieve latitude and longitude of event
                    lat = evt[0]
                    lon = evt[1]

                    # Calculate radial distance and azimuth
                    (dist, azi, other) = Math.delazi(slat, slon, lat, lon)

                    if (minradius < dist) and (dist < maxradius) and \
                       (minazimuth < azi) and (azi < maxazimuth):
                        (loc_ch, restricted) = \
                            self.__buildStreamsList(st, streams, sensortype,
                                                    preferredsps, start_date,
                                                    end_date)

                        if len(loc_ch):
                            stats.append(
                                ('%s-%s-%s-%s%s%s' %
                                 (ptNets[parent_net][0], ptNets[parent_net][4],
                                  ptStats[st][4], ptStats[st][8].year,
                                  ptStats[st][8].month, ptStats[st][8].day),
                                 ptNets[parent_net][0], ptStats[st][4],
                                 ptStats[st][5], ptStats[st][6],
                                 ptStats[st][11], ptNets[parent_net][8],
                                 ptNets[parent_net][9], ptNets[parent_net][10],
                                 loc_ch, restricted))

                        # Stop the loop through events and go for the
                        # next station
                        break

        else:
            msg = 'Error: not enough parameters have been given.'
            raise wsgicomm.WIClientError, msg

        stats.sort()

        stats.insert(0, ('key', 'netcode', 'statcode', 'latitude', 'longitude',
                         'restricted', 'netclass', 'archive', 'netoperator',
                         'streams', 'streams_restricted'))

        return stats
Example #8
0
    def sh2proc(self, file):
        ep = DataModel.EventParameters()
        origin = DataModel.Origin.Create()
        event = DataModel.Event.Create()

        origin.setCreationInfo(DataModel.CreationInfo())
        origin.creationInfo().setCreationTime(Core.Time.GMT())

        originQuality = None
        originCE = None
        latFound = False
        lonFound = False
        depthError = None
        originComments = {}

        # variables, reset after 'end of phase'
        pick = None
        stationMag = None
        staCode = None
        compCode = None
        stationMagBB = None

        amplitudeDisp = None
        amplitudeVel = None
        amplitudeSNR = None
        amplitudeBB = None

        magnitudeMB = None
        magnitudeML = None
        magnitudeMS = None
        magnitudeBB = None

        km2degFac = 1.0 / Math.deg2km(1.0)

        # read file line by line, split key and value at colon
        iLine = 0
        for line in file:
            iLine += 1
            a = line.split(':', 1)
            key = a[0].strip()
            keyLower = key.lower()
            value = None

            # empty line
            if len(keyLower) == 0:
                continue

            # end of phase
            elif keyLower == '--- end of phase ---':
                if pick is None:
                    Logging.warning('Line %i: found empty phase block' % iLine)
                    continue

                if staCode is None or compCode is None:
                    Logging.warning('Line %i: end of phase, stream code '
                                    'incomplete' % iLine)
                    continue

                if staCode not in self.streams:
                    Logging.warning('Line %i: end of phase, station code %s '
                                    'not found in inventory' % (iLine, staCode))
                    continue

                if compCode not in self.streams[staCode]:
                    Logging.warning('Line %i: end of phase, component %s of '
                                    'station %s not found in inventory' % (
                                        iLine, compCode, staCode))
                    continue

                streamID = self.streams[staCode][compCode]

                pick.setWaveformID(streamID)
                ep.add(pick)

                arrival.setPickID(pick.publicID())
                arrival.setPhase(phase)
                origin.add(arrival)

                if amplitudeSNR is not None:
                    amplitudeSNR.setPickID(pick.publicID())
                    amplitudeSNR.setWaveformID(streamID)
                    ep.add(amplitudeSNR)

                if amplitudeBB is not None:
                    amplitudeBB.setPickID(pick.publicID())
                    amplitudeBB.setWaveformID(streamID)
                    ep.add(amplitudeBB)

                if stationMagBB is not None:
                    stationMagBB.setWaveformID(streamID)
                    origin.add(stationMagBB)
                    stationMagContrib = DataModel.StationMagnitudeContribution()
                    stationMagContrib.setStationMagnitudeID(
                        stationMagBB.publicID())
                    if magnitudeBB is None:
                        magnitudeBB = DataModel.Magnitude.Create()
                    magnitudeBB.add(stationMagContrib)

                if stationMag is not None:
                    if stationMag.type() in ['mb', 'ML'] and amplitudeDisp is not None:
                        amplitudeDisp.setPickID(pick.publicID())
                        amplitudeDisp.setWaveformID(streamID)
                        amplitudeDisp.setPeriod(
                            DataModel.RealQuantity(ampPeriod))
                        amplitudeDisp.setType(stationMag.type())
                        ep.add(amplitudeDisp)

                    if stationMag.type() in ['Ms(BB)'] and amplitudeVel is not None:
                        amplitudeVel.setPickID(pick.publicID())
                        amplitudeVel.setWaveformID(streamID)
                        amplitudeVel.setPeriod(
                            DataModel.RealQuantity(ampPeriod))
                        amplitudeVel.setType(stationMag.type())
                        ep.add(amplitudeVel)

                    stationMag.setWaveformID(streamID)
                    origin.add(stationMag)

                    stationMagContrib = DataModel.StationMagnitudeContribution()
                    stationMagContrib.setStationMagnitudeID(
                        stationMag.publicID())

                    magType = stationMag.type()
                    if magType == 'ML':
                        if magnitudeML is None:
                            magnitudeML = DataModel.Magnitude.Create()
                        magnitudeML.add(stationMagContrib)

                    elif magType == 'Ms(BB)':
                        if magnitudeMS is None:
                            magnitudeMS = DataModel.Magnitude.Create()
                        magnitudeMS.add(stationMagContrib)

                    elif magType == 'mb':
                        if magnitudeMB is None:
                            magnitudeMB = DataModel.Magnitude.Create()
                        magnitudeMB.add(stationMagContrib)

                pick = None
                staCode = None
                compCode = None
                stationMag = None
                stationMagBB = None
                amplitudeDisp = None
                amplitudeVel = None
                amplitudeSNR = None
                amplitudeBB = None
                continue

            # empty key
            elif len(a) == 1:
                Logging.warning('Line %i: key without value' % iLine)
                continue

            value = a[1].strip()
            if pick is None:
                pick = DataModel.Pick.Create()
                arrival = DataModel.Arrival()

            try:
                ##############################################################
                # station parameters

                # station code
                if keyLower == 'station code':
                    staCode = value

                # pick time
                elif keyLower == 'onset time':
                    pick.setTime(DataModel.TimeQuantity(self.parseTime(value)))

                # pick onset type
                elif keyLower == 'onset type':
                    found = False
                    for onset in [DataModel.EMERGENT, DataModel.IMPULSIVE,
                                  DataModel.QUESTIONABLE]:
                        if value == DataModel.EPickOnsetNames_name(onset):
                            pick.setOnset(onset)
                            found = True
                            break
                    if not found:
                        raise Exception('Unsupported onset value')

                # phase code
                elif keyLower == 'phase name':
                    phase = DataModel.Phase()
                    phase.setCode(value)
                    pick.setPhaseHint(phase)

                # event type
                elif keyLower == 'event type':
                    evttype = EventTypes[value]
                    event.setType(evttype)
                    originComments[key] = value

                # filter ID
                elif keyLower == 'applied filter':
                    pick.setFilterID(value)

                # channel code, prepended by configured Channel prefix if only
                # one character is found
                elif keyLower == 'component':
                    compCode = value

                # pick evaluation mode
                elif keyLower == 'pick type':
                    found = False
                    for mode in [DataModel.AUTOMATIC, DataModel.MANUAL]:
                        if value == DataModel.EEvaluationModeNames_name(mode):
                            pick.setEvaluationMode(mode)
                            found = True
                            break
                    if not found:
                        raise Exception('Unsupported evaluation mode value')

                # pick author
                elif keyLower == 'analyst':
                    creationInfo = DataModel.CreationInfo()
                    creationInfo.setAuthor(value)
                    pick.setCreationInfo(creationInfo)

                # pick polarity
                # isn't tested
                elif keyLower == 'sign':
                    if value == 'positive':
                        sign = '0'  # positive
                    elif value == 'negative':
                        sign = '1'  # negative
                    else:
                        sign = '2'  # unknown
                    pick.setPolarity(float(sign))

                # arrival weight
                elif keyLower == 'weight':
                    arrival.setWeight(float(value))

                # arrival azimuth
                elif keyLower == 'theo. azimuth (deg)':
                    arrival.setAzimuth(float(value))

                # pick theo backazimuth
                elif keyLower == 'theo. backazimuth (deg)':
                    if pick.slownessMethodID() == 'corrected':
                        Logging.debug('Line %i: ignoring parameter: %s' % (
                                      iLine, key))
                    else:
                        pick.setBackazimuth(
                            DataModel.RealQuantity(float(value)))
                        pick.setSlownessMethodID('theoretical')

                # pick beam slowness
                elif keyLower == 'beam-slowness (sec/deg)':
                    if pick.slownessMethodID() == 'corrected':
                        Logging.debug('Line %i: ignoring parameter: %s' % (
                                      iLine, key))
                    else:
                        pick.setHorizontalSlowness(
                            DataModel.RealQuantity(float(value)))
                        pick.setSlownessMethodID('Array Beam')

                # pick beam backazimuth
                elif keyLower == 'beam-azimuth (deg)':
                    if pick.slownessMethodID() == 'corrected':
                        Logging.debug('Line %i: ignoring parameter: %s' % (
                                      iLine, key))
                    else:
                        pick.setBackazimuth(
                            DataModel.RealQuantity(float(value)))

                # pick epi slowness
                elif keyLower == 'epi-slowness (sec/deg)':
                    pick.setHorizontalSlowness(
                        DataModel.RealQuantity(float(value)))
                    pick.setSlownessMethodID('corrected')

                # pick epi backazimuth
                elif keyLower == 'epi-azimuth (deg)':
                    pick.setBackazimuth(DataModel.RealQuantity(float(value)))

                # arrival distance degree
                elif keyLower == 'distance (deg)':
                    arrival.setDistance(float(value))

                # arrival distance km, recalculates for degree
                elif keyLower == 'distance (km)':
                    if isinstance(arrival.distance(), float):
                        Logging.debug('Line %i: ignoring parameter: %s' % (
                                      iLine-1, 'distance (deg)'))
                    arrival.setDistance(float(value) * km2degFac)

                # arrival time residual
                elif keyLower == 'residual time':
                    arrival.setTimeResidual(float(value))

                # amplitude snr
                elif keyLower == 'signal/noise':
                    amplitudeSNR = DataModel.Amplitude.Create()
                    amplitudeSNR.setType('SNR')
                    amplitudeSNR.setAmplitude(
                        DataModel.RealQuantity(float(value)))

                # amplitude period
                elif keyLower.startswith('period'):
                    ampPeriod = float(value)

                # amplitude value for displacement
                elif keyLower == 'amplitude (nm)':
                    amplitudeDisp = DataModel.Amplitude.Create()
                    amplitudeDisp.setAmplitude(
                        DataModel.RealQuantity(float(value)))
                    amplitudeDisp.setUnit('nm')

                # amplitude value for velocity
                elif keyLower.startswith('vel. amplitude'):
                    amplitudeVel = DataModel.Amplitude.Create()
                    amplitudeVel.setAmplitude(
                        DataModel.RealQuantity(float(value)))
                    amplitudeVel.setUnit('nm/s')

                elif keyLower == 'bb amplitude (nm/sec)':
                    amplitudeBB = DataModel.Amplitude.Create()
                    amplitudeBB.setAmplitude(
                        DataModel.RealQuantity(float(value)))
                    amplitudeBB.setType('mB')
                    amplitudeBB.setUnit('nm/s')
                    amplitudeBB.setPeriod(DataModel.RealQuantity(ampBBPeriod))

                elif keyLower == 'bb period (sec)':
                    ampBBPeriod = float(value)

                elif keyLower == 'broadband magnitude':
                    magType = self.parseMagType('bb')
                    stationMagBB = DataModel.StationMagnitude.Create()
                    stationMagBB.setMagnitude(
                        DataModel.RealQuantity(float(value)))
                    stationMagBB.setType(magType)
                    stationMagBB.setAmplitudeID(amplitudeBB.publicID())

                # ignored
                elif keyLower == 'quality number':
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))

                # station magnitude value and type
                elif keyLower.startswith('magnitude '):
                    magType = self.parseMagType(key[10:])
                    stationMag = DataModel.StationMagnitude.Create()
                    stationMag.setMagnitude(
                        DataModel.RealQuantity(float(value)))

                    if len(magType) > 0:
                        stationMag.setType(magType)
                    if magType == 'mb':
                        stationMag.setAmplitudeID(amplitudeDisp.publicID())

                    elif magType == 'MS(BB)':
                        stationMag.setAmplitudeID(amplitudeVel.publicID())
                    else:
                        Logging.debug('Line %i: Magnitude Type not known %s.' % (
                                      iLine, magType))

                ###############################################################
                # origin parameters

                # event ID, added as origin comment later on
                elif keyLower == 'event id':
                    originComments[key] = value

                # magnitude value and type
                elif keyLower == 'mean bb magnitude':
                    magType = self.parseMagType('bb')
                    if magnitudeBB is None:
                        magnitudeBB = DataModel.Magnitude.Create()
                    magnitudeBB.setMagnitude(
                        DataModel.RealQuantity(float(value)))
                    magnitudeBB.setType(magType)

                elif keyLower.startswith('mean magnitude '):
                    magType = self.parseMagType(key[15:])

                    if magType == 'ML':
                        if magnitudeML is None:
                            magnitudeML = DataModel.Magnitude.Create()
                        magnitudeML.setMagnitude(
                            DataModel.RealQuantity(float(value)))
                        magnitudeML.setType(magType)

                    elif magType == 'Ms(BB)':
                        if magnitudeMS is None:
                            magnitudeMS = DataModel.Magnitude.Create()
                        magnitudeMS.setMagnitude(
                            DataModel.RealQuantity(float(value)))
                        magnitudeMS.setType(magType)

                    elif magType == 'mb':
                        if magnitudeMB is None:
                            magnitudeMB = DataModel.Magnitude.Create()
                        magnitudeMB.setMagnitude(
                            DataModel.RealQuantity(float(value)))
                        magnitudeMB.setType(magType)

                    else:
                        Logging.warning('Line %i: Magnitude type %s not defined yet.' % (
                                        iLine, magType))

                # latitude
                elif keyLower == 'latitude':
                    origin.latitude().setValue(float(value))
                    latFound = True
                elif keyLower == 'error in latitude (km)':
                    origin.latitude().setUncertainty(float(value))

                # longitude
                elif keyLower == 'longitude':
                    origin.longitude().setValue(float(value))
                    lonFound = True
                elif keyLower == 'error in longitude (km)':
                    origin.longitude().setUncertainty(float(value))

                # depth
                elif keyLower == 'depth (km)':
                    origin.setDepth(DataModel.RealQuantity(float(value)))
                    if depthError is not None:
                        origin.depth().setUncertainty(depthError)
                elif keyLower == 'depth type':
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))
                elif keyLower == 'error in depth (km)':
                    depthError = float(value)
                    try:
                        origin.depth().setUncertainty(depthError)
                    except Core.ValueException:
                        pass

                # time
                elif keyLower == 'origin time':
                    origin.time().setValue(self.parseTime(value))
                elif keyLower == 'error in origin time':
                    origin.time().setUncertainty(float(value))

                # location method
                elif keyLower == 'location method':
                    origin.setMethodID(str(value))

                # region table, added as origin comment later on
                elif keyLower == 'region table':
                    originComments[key] = value

                # region table, added as origin comment later on
                elif keyLower == 'region id':
                    originComments[key] = value

                # source region, added as origin comment later on
                elif keyLower == 'source region':
                    originComments[key] = value

                # used station count
                elif keyLower == 'no. of stations used':
                    if originQuality is None:
                        originQuality = DataModel.OriginQuality()
                    originQuality.setUsedStationCount(int(value))

                # ignored
                elif keyLower == 'reference location name':
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))

                # confidence ellipsoid major axis
                elif keyLower == 'error ellipse major':
                    if originCE is None:
                        originCE = DataModel.ConfidenceEllipsoid()
                    originCE.setSemiMajorAxisLength(float(value))

                # confidence ellipsoid minor axis
                elif keyLower == 'error ellipse minor':
                    if originCE is None:
                        originCE = DataModel.ConfidenceEllipsoid()
                    originCE.setSemiMinorAxisLength(float(value))

                # confidence ellipsoid rotation
                elif keyLower == 'error ellipse strike':
                    if originCE is None:
                        originCE = DataModel.ConfidenceEllipsoid()
                    originCE.setMajorAxisRotation(float(value))

                # azimuthal gap
                elif keyLower == 'max azimuthal gap (deg)':
                    if originQuality is None:
                        originQuality = DataModel.OriginQuality()
                    originQuality.setAzimuthalGap(float(value))

                # creation info author
                elif keyLower == 'author':
                    origin.creationInfo().setAuthor(value)

                # creation info agency
                elif keyLower == 'source of information':
                    origin.creationInfo().setAgencyID(value)

                # earth model id
                elif keyLower == 'velocity model':
                    origin.setEarthModelID(value)

                # standard error
                elif keyLower == 'rms of residuals (sec)':
                    if originQuality is None:
                        originQuality = DataModel.OriginQuality()
                    originQuality.setStandardError(float(value))

                # ignored
                elif keyLower == 'phase flags':
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))

                # ignored
                elif keyLower == 'location input params':
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))

                # missing keys
                elif keyLower == 'ampl&period source':
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))

                elif keyLower == 'location quality':
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))

                elif keyLower == 'reference latitude':
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))

                elif keyLower == 'reference longitude':
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))

                elif keyLower.startswith('amplitude time'):
                    Logging.debug('Line %i: ignoring parameter: %s' % (
                                  iLine, key))

                # unknown key
                else:
                    Logging.warning('Line %i: ignoring unknown parameter: %s'
                                    % (iLine, key))

            except ValueError as ve:
                Logging.warning('Line %i: can not parse %s value' % (
                                iLine, key))
            except Exception:
                Logging.error('Line %i: %s' % (iLine,
                                               str(traceback.format_exc())))
                return None

        # check
        if not latFound:
            Logging.warning('could not add origin, missing latitude parameter')
        elif not lonFound:
            Logging.warning(
                'could not add origin, missing longitude parameter')
        elif not origin.time().value().valid():
            Logging.warning(
                'could not add origin, missing origin time parameter')
        else:
            if magnitudeMB is not None:
                origin.add(magnitudeMB)
            if magnitudeML is not None:
                origin.add(magnitudeML)
            if magnitudeMS is not None:
                origin.add(magnitudeMS)
            if magnitudeBB is not None:
                origin.add(magnitudeBB)

            ep.add(event)
            ep.add(origin)

            if originQuality is not None:
                origin.setQuality(originQuality)

            if originCE is not None:
                uncertainty = DataModel.OriginUncertainty()
                uncertainty.setConfidenceEllipsoid(originCE)
                origin.setUncertainty(uncertainty)

            for k, v in originComments.items():
                comment = DataModel.Comment()
                comment.setId(k)
                comment.setText(v)
                origin.add(comment)

        return ep
Example #9
0
    def __timewindows_ev(self, streams, events, startphase, startoffset,
                         endphase, endoffset):
        """Helper function to calculate time windows related to events.

        Input: streams={list of stream keys}
               events={list of events} # [[lat, lon, depth, time],..]
               startphase={string}     # 'P' or 'S'
               startoffset={int}       # time in minutes to start time window.
                                       # POSITIVE if AFTER arrival of
                                       # 'startphase' at station.
               endphase={string}       # 'P' or 'S'
               endoffset={int}         # time in minutes to end time window.
                                       # POSITIVE if AFTER arrival of
                                       # 'endphase' at station.

        Output: list of start/end times per stream, AND estimated data volume,
                (start_time, end_time, net, sta, cha, loc, streamInfo['size'])

        NOTE 1: stream is a list of [net, sta, cha, loc] instead of nslc here!
        NOTE 2: There are many redundant time window computations for multiple
        streams at the same location
        """

        result = []

        for ev in events:
            try:
                if len(ev) != 4:
                    raise wsgicomm.WIClientError, "invalid event: " + str(ev)

                ev_lat = float(ev[0])
                ev_lon = float(ev[1])
                ev_dep = float(ev[2])
                ev_time = DateTimeAttr().fromxml(ev[3])

            except (TypeError, ValueError):
                raise wsgicomm.WIClientError, "invalid event: " + str(ev)

            for nscl in streams:
                try:
                    if len(nscl) != 4:
                        msg = "Invalid stream: " + str(nscl)
                        raise wsgicomm.WIClientError, msg

                    net = str(nscl[0])
                    sta = str(nscl[1])
                    cha = str(nscl[2])
                    loc = str(nscl[3])

                except (TypeError, ValueError):
                    msg = "Invalid stream: " + str(nscl)
                    raise wsgicomm.WIClientError, msg

                # we don't have actual time window yet, just use ev_time to
                # get the coordinates
                streamInfo = self.ic.getStreamInfo(ev_time, ev_time, net, sta,
                                                   cha, loc)

                if streamInfo is None:  # stream is not available
                    continue

                st_lat = streamInfo['latitude']
                st_lon = streamInfo['longitude']
                st_alt = streamInfo['elevation']

                start_time = None
                end_time = None

                # Assumption here is that compute() returns phases sorted by
                # time. Therefore breaking after the first gives the earliest
                # phase in the set defined in __isphase().
                # FIXME: Combine startphase and endphase logic into
                # function+loop?

                # Compute in delta the distance between event and station
                delta = Math.delazi(ev_lat, ev_lon, st_lat, st_lon)[0]
                # Threshold distance in degrees at which PKP arrives earlier
                # than P and friends (see Joachim's email - 14.08.2013)
                delta_threshold = 120

                try:
                    ttlist = self.ttt.compute(ev_lat, ev_lon, ev_dep, st_lat,
                                              st_lon, st_alt)
                except Exception, e:
                    msg = "/metadata/timewindows: exception from " + \
                        "ttt.compute(): " + str(e)
                    logs.error(msg)
                    continue

                try:
                    for tt in ttlist:
                        if (startphase == 'P') and (delta >= delta_threshold):
                            if (tt.phase.startswith('PKP')
                                    or tt.phase.startswith('PKiKP')):
                                start_time = ev_time + \
                                    datetime.timedelta(seconds=tt.time +
                                                       startoffset * 60)
                                break

                        elif ((startphase == 'S')
                              or ((startphase == 'P') and
                                  (delta < delta_threshold))):
                            if self.__isphase(tt.phase, startphase):
                                start_time = ev_time + datetime.timedelta(
                                    seconds=tt.time + startoffset * 60)
                                break
                        elif (startphase == 'OT'):
                            start_time = ev_time + datetime.timedelta(
                                seconds=startoffset * 60)
                        else:
                            msg = 'Wrong startphase received! Only "P", ' + \
                                '"S" and "OT" are implemented.'
                            raise wsgicomm.WIClientError, msg

                    for tt in ttlist:
                        if (endphase == 'P') and (delta >= delta_threshold):
                            if (tt.phase.startswith('PKP')
                                    or tt.phase.startswith('PKiKP')):
                                end_time = ev_time + datetime.timedelta(
                                    seconds=tt.time + endoffset * 60)
                                break

                        elif ((endphase == 'S')
                              or ((endphase == 'P') and
                                  (delta < delta_threshold))):
                            if self.__isphase(tt.phase, endphase):
                                end_time = ev_time + datetime.timedelta(
                                    seconds=tt.time + endoffset * 60)
                                break
                        elif (endphase == 'OT'):
                            end_time = ev_time + datetime.timedelta(
                                seconds=endoffset * 60)
                        else:
                            msg = 'Wrong endphase received! Only "P", ' + \
                                '"S" and "OT" are implemented.'
                            raise wsgicomm.WIClientError, msg

                except Exception, e:
                    logs.error("/metadata/timewindows: " + str(e))
                    continue

                if start_time is None:
                    msg = "/metadata/timewindows: did not find startphase " \
                        + "'%s' for %s" % (startphase, str((ev_lat, ev_lon,
                                                            ev_dep, st_lat,
                                                            st_lon, st_alt)))
                    logs.error(msg)

                if end_time is None:
                    msg = "/metadata/timewindows: did not find endphase " \
                        + "'%s' for %s" % (endphase, str((ev_lat, ev_lon,
                                                          ev_dep, st_lat,
                                                          st_lon, st_alt)))
                    logs.error(msg)

                if start_time is not None and end_time is not None:
                    # retry with actual time window
                    streamInfo = self.ic.getStreamInfo(start_time, end_time,
                                                       net, sta, cha, loc)

                    if streamInfo:
                        result.append((start_time, end_time, net, sta, cha,
                                       loc, streamInfo['size']))

                        if len(result) > self.max_lines:
                            msg = "Maximum request size exceeded"
                            raise wsgicomm.WIClientError, msg
Example #10
0
    def getQuery(self, params):
        """Get a list of streams that satisfies the input parameters.

        This method is public and appends the necessary
        information to the streams that belong to the stations
        actually selected by __selectStations. It contains many
        columns, as it is the list to show in the construction of
        the request package.

        """

        try:
            start_year = int(params.get('start', 1980))
        except (TypeError, ValueError):
            raise wsgicomm.WIClientError, 'Error! Start year is invalid.'

        start_date = datetime.datetime(start_year, 1, 1, 0, 0, 0)

        # Build the end date in datetime format
        # Only year-wide windows are allowed here.
        try:
            end_year = int(params.get('end', datetime.datetime.now().year))
        except:
            raise wsgicomm.WIClientError, 'Error! End year is invalid.'

        end_date = datetime.datetime(end_year, 12, 31, 23, 59, 59)

        # Get the network
        # network = params.get('network')

        # Get the station
        station = params.get('station')

        # Get the sensortype
        sensortype = params.get('sensortype')
        if sensortype == 'all':
            sensortype = None

        # Get the preferred sample rate
        try:
            preferredsps = float(params.get('preferredsps'))
        except:
            preferredsps = None

        # Split the list of streams if any
        try:
            streams = params.get('streams').split(',')
        except wsgicomm.WIError:
            raise
        except:
            streams = None

        # Look at the attributes associated with every network type
        try:
            networktype = params.get('networktype')

            if (networktype == 'all') or (networktype is None):
                networktype = None
            else:
                for nettype in self.nettypes:
                    if networktype == nettype[0]:
                        break
                else:
                    raise Exception

        except:
            msg = 'Wrong value in parameter "networktype"'
            raise wsgicomm.WIClientError, msg

        # Check for latitude and longitude parameters
        try:
            latmin = float(params.get('minlat')) if 'minlat' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: minlat must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            latmax = float(params.get('maxlat')) if 'maxlat' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: maxlat must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            lonmin = float(params.get('minlon')) if 'minlon' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: minlon must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            lonmax = float(params.get('maxlon')) if 'maxlon' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: maxlon must be a float number.'
            raise wsgicomm.WIClientError, msg

        # Check for radius and azimuth parameters
        try:
            minradius = float(params.get('minradius')) if 'minradius' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: minradius must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            maxradius = float(params.get('maxradius')) if 'maxradius' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: maxradius must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            minazimuth = float(params.get('minazimuth')) if 'minazimuth' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: minazimuth must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            maxazimuth = float(params.get('maxazimuth')) if 'maxazimuth' \
                in params else None
        except (TypeError, ValueError):
            msg = 'Error: maxazimuth must be a float number.'
            raise wsgicomm.WIClientError, msg

        try:
            events = params.get('events', None)
        except:
            events = None

        # Try to check parameters for different modes of selecting stations
        # One or all stations have been selected and also lat/lon parameters
        if station and (latmin is not None or latmax is not None or lonmin is
                        not None or lonmax is not None):
            msg = 'Error: station and lat/lon parameters are incompatible.'
            raise wsgicomm.WIClientError, msg

        # One or all stations have been selected and also radius/azimuth params
        if station and (minradius is not None or maxradius is not None or
                        minazimuth is not None or maxazimuth is not None):
            msg = 'Error: station and radius/azimuth parameters are ' + \
                'incompatible.'
            raise wsgicomm.WIClientError, msg

        # Lat/lon parameters have been selected and also radius/azimuth
        if (latmin is not None or latmax is not None or lonmin is not None or
                lonmax is not None) and (minradius is not None or maxradius is
                                         not None or minazimuth is not None or
                                         maxazimuth is not None):
            msg = 'Error: lat/lon and radius/azimuth parameters are ' + \
                'incompatible.'
            raise wsgicomm.WIClientError, msg

        # These are the two lists to return
        stats = []

        # Filter and save indexes of stations in statsOK
        statsOK = self.__selectStations(params)

        # Just to make notation shorter
        ptNets = self.networks
        ptStats = self.stations

        if ('station' in params):
            # Builds a list from the selected stations
            for st in statsOK:
                parent_net = ptStats[st][0]

                (loc_ch, restricted) = self.__buildStreamsList(st, streams,
                                                               sensortype,
                                                               preferredsps,
                                                               start_date,
                                                               end_date)

                if len(loc_ch):
                    stats.append(('%s-%s-%s-%s%s%s' % (ptNets[parent_net][0],
                                  ptNets[parent_net][4], ptStats[st][4],
                                  ptStats[st][8].year, ptStats[st][8].month,
                                  ptStats[st][8].day),  ptNets[parent_net][0],
                                  ptStats[st][4], ptStats[st][5],
                                  ptStats[st][6], ptNets[parent_net][7],
                                  ptNets[parent_net][8], ptNets[parent_net][9],
                                  ptNets[parent_net][10], loc_ch, restricted))

        elif (latmin is not None and latmax is not None and lonmin is not None
              and lonmax is not None):

            # statsOK is a set and therefore, there will be no repetitions
            for st in statsOK:
                # Pointer to the parent network
                parent_net = ptStats[st][0]

                # Filter by latitude
                if(ptStats[st][5] < latmin) or (ptStats[st][5] > latmax):
                    continue

                # Filter by longitude
                if(lonmin <= lonmax):
                    if (ptStats[st][6] < lonmin) or (ptStats[st][6] > lonmax):
                        continue
                else:
                    if (ptStats[st][6] < lonmin) and (ptStats[st][6] > lonmax):
                        continue

                (loc_ch, restricted) = self.__buildStreamsList(st, streams,
                                                               sensortype,
                                                               preferredsps,
                                                               start_date,
                                                               end_date)

                if len(loc_ch):
                    stats.append(('%s-%s-%s-%s%s%s' %
                                  (ptNets[parent_net][0],
                                   ptNets[parent_net][4], ptStats[st][4],
                                   ptStats[st][8].year, ptStats[st][8].month,
                                   ptStats[st][8].day),
                                  ptNets[parent_net][0],
                                  ptStats[st][4], ptStats[st][5],
                                  ptStats[st][6], ptNets[parent_net][7],
                                  ptNets[parent_net][8], ptNets[parent_net][9],
                                  ptNets[parent_net][10], loc_ch, restricted))

        elif events is not None:

            events = json.loads(events)

            for st in statsOK:
                # Pointer to the parent network
                parent_net = ptStats[st][0]

                # Retrieve latitude and longitude of station
                slat = ptStats[st][5]
                slon = ptStats[st][6]

                for evt in events:
                    # Retrieve latitude and longitude of event
                    lat = evt[0]
                    lon = evt[1]

                    # Calculate radial distance and azimuth
                    (dist, azi, other) = Math.delazi(slat, slon, lat, lon)

                    if (minradius < dist) and (dist < maxradius) and \
                       (minazimuth < azi) and (azi < maxazimuth):
                        (loc_ch, restricted) = \
                            self.__buildStreamsList(st, streams, sensortype,
                                                    preferredsps, start_date,
                                                    end_date)

                        if len(loc_ch):
                            stats.append(('%s-%s-%s-%s%s%s' %
                                          (ptNets[parent_net][0],
                                           ptNets[parent_net][4],
                                           ptStats[st][4],
                                           ptStats[st][8].year,
                                           ptStats[st][8].month,
                                           ptStats[st][8].day),
                                          ptNets[parent_net][0],
                                          ptStats[st][4], ptStats[st][5],
                                          ptStats[st][6],
                                          ptStats[st][11],
                                          ptNets[parent_net][8],
                                          ptNets[parent_net][9],
                                          ptNets[parent_net][10], loc_ch,
                                          restricted))

                        # Stop the loop through events and go for the
                        # next station
                        break

        else:
            msg = 'Error: not enough parameters have been given.'
            raise wsgicomm.WIClientError, msg

        stats.sort()

        stats.insert(0, ('key', 'netcode', 'statcode', 'latitude', 'longitude',
                         'restricted', 'netclass', 'archive', 'netoperator',
                         'streams', 'streams_restricted'))

        return stats
Example #11
0
    def __timewindows_ev(self, streams, events, startphase, startoffset,
                         endphase, endoffset):
        """Helper function to calculate time windows related to events.

        Input: streams={list of stream keys}
               events={list of events} # [[lat, lon, depth, time],..]
               startphase={string}     # 'P' or 'S'
               startoffset={int}       # time in minutes to start time window.
                                       # POSITIVE if AFTER arrival of
                                       # 'startphase' at station.
               endphase={string}       # 'P' or 'S'
               endoffset={int}         # time in minutes to end time window.
                                       # POSITIVE if AFTER arrival of
                                       # 'endphase' at station.

        Output: list of start/end times per stream, AND estimated data volume,
                (start_time, end_time, net, sta, cha, loc, streamInfo['size'])

        NOTE 1: stream is a list of [net, sta, cha, loc] instead of nslc here!
        NOTE 2: There are many redundant time window computations for multiple
        streams at the same location
        """

        result = []

        for ev in events:
            try:
                if len(ev) != 4:
                    raise wsgicomm.WIClientError, "invalid event: " + str(ev)

                ev_lat = float(ev[0])
                ev_lon = float(ev[1])
                ev_dep = float(ev[2])
                ev_time = DateTimeAttr().fromxml(ev[3])

            except (TypeError, ValueError):
                raise wsgicomm.WIClientError, "invalid event: " + str(ev)

            for nscl in streams:
                try:
                    if len(nscl) != 4:
                        msg = "Invalid stream: " + str(nscl)
                        raise wsgicomm.WIClientError, msg

                    net = str(nscl[0])
                    sta = str(nscl[1])
                    cha = str(nscl[2])
                    loc = str(nscl[3])

                except (TypeError, ValueError):
                    msg = "Invalid stream: " + str(nscl)
                    raise wsgicomm.WIClientError, msg

                # we don't have actual time window yet, just use ev_time to
                # get the coordinates
                streamInfo = self.ic.getStreamInfo(ev_time, ev_time, net, sta,
                                                   cha, loc)

                if streamInfo is None:  # stream is not available
                    continue

                st_lat = streamInfo['latitude']
                st_lon = streamInfo['longitude']
                st_alt = streamInfo['elevation']

                start_time = None
                end_time = None

                # Assumption here is that compute() returns phases sorted by
                # time. Therefore breaking after the first gives the earliest
                # phase in the set defined in __isphase().
                # FIXME: Combine startphase and endphase logic into
                # function+loop?

                # Compute in delta the distance between event and station
                delta = Math.delazi(ev_lat, ev_lon, st_lat, st_lon)[0]
                # Threshold distance in degrees at which PKP arrives earlier
                # than P and friends (see Joachim's email - 14.08.2013)
                delta_threshold = 120

                try:
                    ttlist = self.ttt.compute(ev_lat, ev_lon, ev_dep, st_lat,
                                              st_lon, st_alt)
                except Exception, e:
                    msg = "/metadata/timewindows: exception from " + \
                        "ttt.compute(): " + str(e)
                    logs.error(msg)
                    continue

                try:
                    for tt in ttlist:
                        if (startphase == 'P') and (delta >= delta_threshold):
                            if (tt.phase.startswith('PKP') or
                                    tt.phase.startswith('PKiKP')):
                                start_time = ev_time + \
                                    datetime.timedelta(seconds=tt.time +
                                                       startoffset * 60)
                                break

                        elif ((startphase == 'S') or
                              ((startphase == 'P') and
                               (delta < delta_threshold))):
                            if self.__isphase(tt.phase, startphase):
                                start_time = ev_time + datetime.timedelta(
                                    seconds=tt.time + startoffset * 60)
                                break
                        elif (startphase == 'OT'):
                            start_time = ev_time + datetime.timedelta(seconds=startoffset * 60)
                        else:
                            msg = 'Wrong startphase received! Only "P", ' + \
                                '"S" and "OT" are implemented.'
                            raise wsgicomm.WIClientError, msg

                    for tt in ttlist:
                        if (endphase == 'P') and (delta >= delta_threshold):
                            if (tt.phase.startswith('PKP') or
                                    tt.phase.startswith('PKiKP')):
                                end_time = ev_time + datetime.timedelta(
                                    seconds=tt.time + endoffset * 60)
                                break

                        elif ((endphase == 'S') or
                              ((endphase == 'P') and
                               (delta < delta_threshold))):
                            if self.__isphase(tt.phase, endphase):
                                end_time = ev_time + datetime.timedelta(
                                    seconds=tt.time + endoffset * 60)
                                break
                        elif (endphase == 'OT'):
                                end_time = ev_time + datetime.timedelta(seconds=endoffset * 60)
                        else:
                            msg = 'Wrong endphase received! Only "P", ' + \
                                '"S" and "OT" are implemented.'
                            raise wsgicomm.WIClientError, msg

                except Exception, e:
                    logs.error("/metadata/timewindows: " + str(e))
                    continue

                if start_time is None:
                    msg = "/metadata/timewindows: did not find startphase " \
                        + "'%s' for %s" % (startphase, str((ev_lat, ev_lon,
                                                            ev_dep, st_lat,
                                                            st_lon, st_alt)))
                    logs.error(msg)

                if end_time is None:
                    msg = "/metadata/timewindows: did not find endphase " \
                        + "'%s' for %s" % (endphase, str((ev_lat, ev_lon,
                                                          ev_dep, st_lat,
                                                          st_lon, st_alt)))
                    logs.error(msg)

                if start_time is not None and end_time is not None:
                    # retry with actual time window
                    streamInfo = self.ic.getStreamInfo(start_time, end_time,
                                                       net, sta, cha, loc)

                    if streamInfo:
                        result.append((start_time, end_time, net, sta, cha,
                                       loc, streamInfo['size']))

                        if len(result) > self.max_lines:
                            msg = "Maximum request size exceeded"
                            raise wsgicomm.WIClientError, msg