Example #1
0
    def _parse_second_line_origin(self, line, event, origin, magnitudes):
        magnitude_errors = []

        fields = self.fields['line_2']

        standard_error = line[fields['rms']].strip()
        time_uncertainty = line[fields['ot_error']].strip()
        max_horizontal_uncertainty = line[fields['s_major']].strip()
        min_horizontal_uncertainty = line[fields['s_minor']].strip()
        azimuth_max_horizontal_uncertainty = line[fields['az']].strip()
        depth_uncertainty = line[fields['depth_err']].strip()
        min_distance = line[fields['min_dist']].strip()
        max_distance = line[fields['max_dist']].strip()
        magnitude_errors.append(line[fields['mag_err_1']].strip())
        magnitude_errors.append(line[fields['mag_err_2']].strip())
        magnitude_errors.append(line[fields['mag_err_3']].strip())
        analysis_type = line[fields['antype']].strip().lower()
        location_method = line[fields['loctype']].strip().lower()
        event_type = line[fields['evtype']].strip().lower()

        try:
            origin.quality.standard_error = float(standard_error)
        except ValueError:
            pass

        try:
            origin.time_errors.uncertainty = float(time_uncertainty)
        except ValueError:
            pass

        try:
            uncertainty = OriginUncertainty()
            # Convert values from km to m
            min_value = float(min_horizontal_uncertainty) * 1000
            max_value = float(max_horizontal_uncertainty) * 1000
            azimuth_value = float(azimuth_max_horizontal_uncertainty)
            description = OriginUncertaintyDescription('uncertainty ellipse')

            uncertainty.min_horizontal_uncertainty = min_value
            uncertainty.max_horizontal_uncertainty = max_value
            uncertainty.azimuth_max_horizontal_uncertainty = azimuth_value
            uncertainty.preferred_description = description
            origin.origin_uncertainty = uncertainty
        except ValueError:
            pass

        try:
            # Convert value from km to m
            origin.depth_errors.uncertainty = float(depth_uncertainty) * 1000
        except ValueError:
            pass

        try:
            origin.quality.minimum_distance = float(min_distance)
            origin.quality.maximum_distance = float(max_distance)
        except ValueError:
            self._warn('Missing minimum/maximum distance')

        for i in range(2):
            try:
                mag_errors = magnitudes[i].mag_errors
                mag_errors.uncertainty = float(magnitude_errors[i])
            except (AttributeError, ValueError):
                pass

        # No match for 'g' (guess)
        # We map 'g' to 'manual' and create a comment for origin
        try:
            origin.evaluation_mode = EVALUATION_MODES[analysis_type]

            if analysis_type == 'g':
                # comment: 'GSE2.0:antype=g'
                text = 'GSE2.0:antype=g'
                comment = self._comment(text)
                origin.comments.append(comment)
        except KeyError:
            self._warn('Wrong analysis type')

        if location_method not in LOCATION_METHODS.keys():
            location_method = 'o'
        method = LOCATION_METHODS[location_method]
        method_id = "method/%s" % method
        origin.method_id = self._get_res_id(method_id)

        if event_type not in EVENT_TYPES.keys():
            event_type = 'uk'
            self._warn('Wrong or unknown event type')
        event_data = EVENT_TYPES[event_type]
        event.event_type_certainty, event.event_type = event_data

        # comment: 'GSE2.0:evtype=<evtype>'
        if event_type:
            text = 'GSE2.0:evtype=%s' % event_type
            comment = self._comment(text)
            event.comments.append(comment)
def __toOrigin(parser, origin_el):
    """
    Parses a given origin etree element.

    :type parser: :class:`~obspy.core.util.xmlwrapper.XMLParser`
    :param parser: Open XMLParser object.
    :type origin_el: etree.element
    :param origin_el: origin element to be parsed.
    :return: A ObsPy :class:`~obspy.core.event.Origin` object.
    """
    global CURRENT_TYPE

    origin = Origin()
    origin.resource_id = ResourceIdentifier(prefix="/".join([RESOURCE_ROOT, "origin"]))

    # I guess setting the program used as the method id is fine.
    origin.method_id = "%s/location_method/%s/1" % (RESOURCE_ROOT,
        parser.xpath2obj('program', origin_el))
    if str(origin.method_id).lower().endswith("none"):
        origin.method_id = None

    # Standard parameters.
    origin.time, origin.time_errors = \
        __toTimeQuantity(parser, origin_el, "time")
    origin.latitude, origin_latitude_error = \
        __toFloatQuantity(parser, origin_el, "latitude")
    origin.longitude, origin_longitude_error = \
        __toFloatQuantity(parser, origin_el, "longitude")
    origin.depth, origin.depth_errors = \
        __toFloatQuantity(parser, origin_el, "depth")

    if origin_longitude_error:
        origin_longitude_error = origin_longitude_error["uncertainty"]
    if origin_latitude_error:
        origin_latitude_error = origin_latitude_error["uncertainty"]

    # Figure out the depth type.
    depth_type = parser.xpath2obj("depth_type", origin_el)

    # Map Seishub specific depth type to the QuakeML depth type.
    if depth_type == "from location program":
        depth_type = "from location"
    if depth_type is not None:
        origin.depth_type = depth_type

    # XXX: CHECK DEPTH ORIENTATION!!

    if CURRENT_TYPE == "seiscomp3":
        origin.depth *= 1000
        if origin.depth_errors.uncertainty:
            origin.depth_errors.uncertainty *= 1000
    else:
        # Convert to m.
        origin.depth *= -1000
        if origin.depth_errors.uncertainty:
            origin.depth_errors.uncertainty *= 1000

    # Earth model.
    earth_mod = parser.xpath2obj('earth_mod', origin_el, str)
    if earth_mod:
        earth_mod = earth_mod.split()
        earth_mod = ",".join(earth_mod)
        origin.earth_model_id = "%s/earth_model/%s/1" % (RESOURCE_ROOT,
            earth_mod)

    if (origin_latitude_error is None or origin_longitude_error is None) and \
        CURRENT_TYPE not in ["seiscomp3", "toni"]:
        print "AAAAAAAAAAAAA"
        raise Exception

    if origin_latitude_error and origin_latitude_error:
        if CURRENT_TYPE in ["baynet", "obspyck"]:
            uncert = OriginUncertainty()
            if origin_latitude_error > origin_longitude_error:
                uncert.azimuth_max_horizontal_uncertainty = 0
            else:
                uncert.azimuth_max_horizontal_uncertainty = 90
            uncert.min_horizontal_uncertainty, \
                uncert.max_horizontal_uncertainty = \
                sorted([origin_longitude_error, origin_latitude_error])
            uncert.min_horizontal_uncertainty *= 1000.0
            uncert.max_horizontal_uncertainty *= 1000.0
            uncert.preferred_description = "uncertainty ellipse"
            origin.origin_uncertainty = uncert
        elif CURRENT_TYPE == "earthworm":
            uncert = OriginUncertainty()
            uncert.horizontal_uncertainty = origin_latitude_error
            uncert.horizontal_uncertainty *= 1000.0
            uncert.preferred_description = "horizontal uncertainty"
            origin.origin_uncertainty = uncert
        elif CURRENT_TYPE in ["seiscomp3", "toni"]:
            pass
        else:
            raise Exception

    # Parse the OriginQuality if applicable.
    if not origin_el.xpath("originQuality"):
        return origin

    origin_quality_el = origin_el.xpath("originQuality")[0]
    origin.quality = OriginQuality()
    origin.quality.associated_phase_count = \
        parser.xpath2obj("associatedPhaseCount", origin_quality_el, int)
    # QuakeML does apparently not distinguish between P and S wave phase
    # count. Some Seishub event files do.
    p_phase_count = parser.xpath2obj("P_usedPhaseCount", origin_quality_el,
                                     int)
    s_phase_count = parser.xpath2obj("S_usedPhaseCount", origin_quality_el,
                                     int)
    # Use both in case they are set.
    if p_phase_count is not None and s_phase_count is not None:
        phase_count = p_phase_count + s_phase_count
        # Also add two Seishub element file specific elements.
        origin.quality.p_used_phase_count = p_phase_count
        origin.quality.s_used_phase_count = s_phase_count
    # Otherwise the total usedPhaseCount should be specified.
    else:
        phase_count = parser.xpath2obj("usedPhaseCount",
                                       origin_quality_el, int)
    if p_phase_count is not None:
        origin.quality.setdefault("extra", AttribDict())
        origin.quality.extra.usedPhaseCountP = {'value': p_phase_count,
                                                'namespace': NAMESPACE}
    if s_phase_count is not None:
        origin.quality.setdefault("extra", AttribDict())
        origin.quality.extra.usedPhaseCountS = {'value': s_phase_count,
                                                'namespace': NAMESPACE}
    origin.quality.used_phase_count = phase_count

    associated_station_count = \
        parser.xpath2obj("associatedStationCount", origin_quality_el, int)
    used_station_count = parser.xpath2obj("usedStationCount",
        origin_quality_el, int)
    depth_phase_count = parser.xpath2obj("depthPhaseCount", origin_quality_el,
        int)
    standard_error = parser.xpath2obj("standardError", origin_quality_el,
        float)
    azimuthal_gap = parser.xpath2obj("azimuthalGap", origin_quality_el, float)
    secondary_azimuthal_gap = \
        parser.xpath2obj("secondaryAzimuthalGap", origin_quality_el, float)
    ground_truth_level = parser.xpath2obj("groundTruthLevel",
        origin_quality_el, str)
    minimum_distance = parser.xpath2obj("minimumDistance", origin_quality_el,
        float)
    maximum_distance = parser.xpath2obj("maximumDistance", origin_quality_el,
        float)
    median_distance = parser.xpath2obj("medianDistance", origin_quality_el,
        float)
    if minimum_distance is not None:
        minimum_distance = kilometer2degrees(minimum_distance)
    if maximum_distance is not None:
        maximum_distance = kilometer2degrees(maximum_distance)
    if median_distance is not None:
        median_distance = kilometer2degrees(median_distance)

    if associated_station_count is not None:
        origin.quality.associated_station_count = associated_station_count
    if used_station_count is not None:
        origin.quality.used_station_count = used_station_count
    if depth_phase_count is not None:
        origin.quality.depth_phase_count = depth_phase_count
    if standard_error is not None and not math.isnan(standard_error):
        origin.quality.standard_error = standard_error
    if azimuthal_gap is not None:
        origin.quality.azimuthal_gap = azimuthal_gap
    if secondary_azimuthal_gap is not None:
        origin.quality.secondary_azimuthal_gap = secondary_azimuthal_gap
    if ground_truth_level is not None:
        origin.quality.ground_truth_level = ground_truth_level
    if minimum_distance is not None:
        origin.quality.minimum_distance = minimum_distance
    if maximum_distance is not None:
        origin.quality.maximum_distance = maximum_distance
    if median_distance is not None and not math.isnan(median_distance):
        origin.quality.median_distance = median_distance

    return origin
def __toOrigin(parser, origin_el):
    """
    Parses a given origin etree element.

    :type parser: :class:`~obspy.core.util.xmlwrapper.XMLParser`
    :param parser: Open XMLParser object.
    :type origin_el: etree.element
    :param origin_el: origin element to be parsed.
    :return: A ObsPy :class:`~obspy.core.event.Origin` object.
    """
    global CURRENT_TYPE

    origin = Origin()
    origin.resource_id = ResourceIdentifier(
        prefix="/".join([RESOURCE_ROOT, "origin"]))

    # I guess setting the program used as the method id is fine.
    origin.method_id = "%s/location_method/%s/1" % (
        RESOURCE_ROOT, parser.xpath2obj('program', origin_el))
    if str(origin.method_id).lower().endswith("none"):
        origin.method_id = None

    # Standard parameters.
    origin.time, origin.time_errors = \
        __toTimeQuantity(parser, origin_el, "time")
    origin.latitude, origin_latitude_error = \
        __toFloatQuantity(parser, origin_el, "latitude")
    origin.longitude, origin_longitude_error = \
        __toFloatQuantity(parser, origin_el, "longitude")
    origin.depth, origin.depth_errors = \
        __toFloatQuantity(parser, origin_el, "depth")

    if origin_longitude_error:
        origin_longitude_error = origin_longitude_error["uncertainty"]
    if origin_latitude_error:
        origin_latitude_error = origin_latitude_error["uncertainty"]

    # Figure out the depth type.
    depth_type = parser.xpath2obj("depth_type", origin_el)

    # Map Seishub specific depth type to the QuakeML depth type.
    if depth_type == "from location program":
        depth_type = "from location"
    if depth_type is not None:
        origin.depth_type = depth_type

    # XXX: CHECK DEPTH ORIENTATION!!

    if CURRENT_TYPE == "seiscomp3":
        origin.depth *= 1000
        if origin.depth_errors.uncertainty:
            origin.depth_errors.uncertainty *= 1000
    else:
        # Convert to m.
        origin.depth *= -1000
        if origin.depth_errors.uncertainty:
            origin.depth_errors.uncertainty *= 1000

    # Earth model.
    earth_mod = parser.xpath2obj('earth_mod', origin_el, str)
    if earth_mod:
        earth_mod = earth_mod.split()
        earth_mod = ",".join(earth_mod)
        origin.earth_model_id = "%s/earth_model/%s/1" % (RESOURCE_ROOT,
                                                         earth_mod)

    if (origin_latitude_error is None or origin_longitude_error is None) and \
        CURRENT_TYPE not in ["seiscomp3", "toni"]:
        print "AAAAAAAAAAAAA"
        raise Exception

    if origin_latitude_error and origin_latitude_error:
        if CURRENT_TYPE in ["baynet", "obspyck"]:
            uncert = OriginUncertainty()
            if origin_latitude_error > origin_longitude_error:
                uncert.azimuth_max_horizontal_uncertainty = 0
            else:
                uncert.azimuth_max_horizontal_uncertainty = 90
            uncert.min_horizontal_uncertainty, \
                uncert.max_horizontal_uncertainty = \
                sorted([origin_longitude_error, origin_latitude_error])
            uncert.min_horizontal_uncertainty *= 1000.0
            uncert.max_horizontal_uncertainty *= 1000.0
            uncert.preferred_description = "uncertainty ellipse"
            origin.origin_uncertainty = uncert
        elif CURRENT_TYPE == "earthworm":
            uncert = OriginUncertainty()
            uncert.horizontal_uncertainty = origin_latitude_error
            uncert.horizontal_uncertainty *= 1000.0
            uncert.preferred_description = "horizontal uncertainty"
            origin.origin_uncertainty = uncert
        elif CURRENT_TYPE in ["seiscomp3", "toni"]:
            pass
        else:
            raise Exception

    # Parse the OriginQuality if applicable.
    if not origin_el.xpath("originQuality"):
        return origin

    origin_quality_el = origin_el.xpath("originQuality")[0]
    origin.quality = OriginQuality()
    origin.quality.associated_phase_count = \
        parser.xpath2obj("associatedPhaseCount", origin_quality_el, int)
    # QuakeML does apparently not distinguish between P and S wave phase
    # count. Some Seishub event files do.
    p_phase_count = parser.xpath2obj("P_usedPhaseCount", origin_quality_el,
                                     int)
    s_phase_count = parser.xpath2obj("S_usedPhaseCount", origin_quality_el,
                                     int)
    # Use both in case they are set.
    if p_phase_count is not None and s_phase_count is not None:
        phase_count = p_phase_count + s_phase_count
        # Also add two Seishub element file specific elements.
        origin.quality.p_used_phase_count = p_phase_count
        origin.quality.s_used_phase_count = s_phase_count
    # Otherwise the total usedPhaseCount should be specified.
    else:
        phase_count = parser.xpath2obj("usedPhaseCount", origin_quality_el,
                                       int)
    if p_phase_count is not None:
        origin.quality.setdefault("extra", AttribDict())
        origin.quality.extra.usedPhaseCountP = {
            'value': p_phase_count,
            'namespace': NAMESPACE
        }
    if s_phase_count is not None:
        origin.quality.setdefault("extra", AttribDict())
        origin.quality.extra.usedPhaseCountS = {
            'value': s_phase_count,
            'namespace': NAMESPACE
        }
    origin.quality.used_phase_count = phase_count

    associated_station_count = \
        parser.xpath2obj("associatedStationCount", origin_quality_el, int)
    used_station_count = parser.xpath2obj("usedStationCount",
                                          origin_quality_el, int)
    depth_phase_count = parser.xpath2obj("depthPhaseCount", origin_quality_el,
                                         int)
    standard_error = parser.xpath2obj("standardError", origin_quality_el,
                                      float)
    azimuthal_gap = parser.xpath2obj("azimuthalGap", origin_quality_el, float)
    secondary_azimuthal_gap = \
        parser.xpath2obj("secondaryAzimuthalGap", origin_quality_el, float)
    ground_truth_level = parser.xpath2obj("groundTruthLevel",
                                          origin_quality_el, str)
    minimum_distance = parser.xpath2obj("minimumDistance", origin_quality_el,
                                        float)
    maximum_distance = parser.xpath2obj("maximumDistance", origin_quality_el,
                                        float)
    median_distance = parser.xpath2obj("medianDistance", origin_quality_el,
                                       float)
    if minimum_distance is not None:
        minimum_distance = kilometer2degrees(minimum_distance)
    if maximum_distance is not None:
        maximum_distance = kilometer2degrees(maximum_distance)
    if median_distance is not None:
        median_distance = kilometer2degrees(median_distance)

    if associated_station_count is not None:
        origin.quality.associated_station_count = associated_station_count
    if used_station_count is not None:
        origin.quality.used_station_count = used_station_count
    if depth_phase_count is not None:
        origin.quality.depth_phase_count = depth_phase_count
    if standard_error is not None and not math.isnan(standard_error):
        origin.quality.standard_error = standard_error
    if azimuthal_gap is not None:
        origin.quality.azimuthal_gap = azimuthal_gap
    if secondary_azimuthal_gap is not None:
        origin.quality.secondary_azimuthal_gap = secondary_azimuthal_gap
    if ground_truth_level is not None:
        origin.quality.ground_truth_level = ground_truth_level
    if minimum_distance is not None:
        origin.quality.minimum_distance = minimum_distance
    if maximum_distance is not None:
        origin.quality.maximum_distance = maximum_distance
    if median_distance is not None and not math.isnan(median_distance):
        origin.quality.median_distance = median_distance

    return origin
Example #4
0
    def _parse_second_line_origin(self, line, event, origin, magnitudes):
        magnitude_errors = []

        fields = self.fields['line_2']

        standard_error = line[fields['rms']].strip()
        time_uncertainty = line[fields['ot_error']].strip()
        max_horizontal_uncertainty = line[fields['s_major']].strip()
        min_horizontal_uncertainty = line[fields['s_minor']].strip()
        azimuth_max_horizontal_uncertainty = line[fields['az']].strip()
        depth_uncertainty = line[fields['depth_err']].strip()
        min_distance = line[fields['min_dist']].strip()
        max_distance = line[fields['max_dist']].strip()
        magnitude_errors.append(line[fields['mag_err_1']].strip())
        magnitude_errors.append(line[fields['mag_err_2']].strip())
        magnitude_errors.append(line[fields['mag_err_3']].strip())
        analysis_type = line[fields['antype']].strip().lower()
        location_method = line[fields['loctype']].strip().lower()
        event_type = line[fields['evtype']].strip().lower()

        try:
            origin.quality.standard_error = float(standard_error)
        except ValueError:
            pass

        try:
            origin.time_errors.uncertainty = float(time_uncertainty)
        except ValueError:
            pass

        try:
            uncertainty = OriginUncertainty()
            # Convert values from km to m
            min_value = float(min_horizontal_uncertainty) * 1000
            max_value = float(max_horizontal_uncertainty) * 1000
            azimuth_value = float(azimuth_max_horizontal_uncertainty)
            description = OriginUncertaintyDescription('uncertainty ellipse')

            uncertainty.min_horizontal_uncertainty = min_value
            uncertainty.max_horizontal_uncertainty = max_value
            uncertainty.azimuth_max_horizontal_uncertainty = azimuth_value
            uncertainty.preferred_description = description
            origin.origin_uncertainty = uncertainty
        except ValueError:
            pass

        try:
            # Convert value from km to m
            origin.depth_errors.uncertainty = float(depth_uncertainty) * 1000
        except ValueError:
            pass

        try:
            origin.quality.minimum_distance = float(min_distance)
            origin.quality.maximum_distance = float(max_distance)
        except ValueError:
            self._warn('Missing minimum/maximum distance')

        for i in range(2):
            try:
                mag_errors = magnitudes[i].mag_errors
                mag_errors.uncertainty = float(magnitude_errors[i])
            except (AttributeError, ValueError):
                pass

        # No match for 'g' (guess)
        # We map 'g' to 'manual' and create a comment for origin
        try:
            origin.evaluation_mode = EVALUATION_MODES[analysis_type]

            if analysis_type == 'g':
                # comment: 'GSE2.0:antype=g'
                text = 'GSE2.0:antype=g'
                comment = self._comment(text)
                origin.comments.append(comment)
        except KeyError:
            self._warn('Wrong analysis type')

        if location_method not in LOCATION_METHODS.keys():
            location_method = 'o'
        method = LOCATION_METHODS[location_method]
        method_id = "method/%s" % method
        origin.method_id = self._get_res_id(method_id)

        if event_type not in EVENT_TYPES.keys():
            event_type = 'uk'
            self._warn('Wrong or unknown event type')
        event_data = EVENT_TYPES[event_type]
        event.event_type_certainty, event.event_type = event_data

        # comment: 'GSE2.0:evtype=<evtype>'
        if event_type:
            text = 'GSE2.0:evtype=%s' % event_type
            comment = self._comment(text)
            event.comments.append(comment)
    def _map_join2origin(self, db):
        """
        Return an Origin instance from an dict of CSS key/values
        
        Inputs
        ======
        db : dict of key/values of CSS fields related to the origin (see Join)

        Returns
        =======
        obspy.core.event.Origin

        Notes
        =====
        Any object that supports the dict 'get' method can be passed as
        input, e.g. OrderedDict, custom classes, etc.
        
        Join
        ----
        origin <- origerr (outer)

        """ 
        #-- Basic location ------------------------------------------
        origin = Origin()
        origin.latitude = db.get('lat')
        origin.longitude = db.get('lon')
        origin.depth = _km2m(db.get('depth'))
        origin.time = _utc(db.get('time'))
        origin.extra = {}
        
        #-- Quality -------------------------------------------------
        quality = OriginQuality(
            associated_phase_count = db.get('nass'),
            used_phase_count = db.get('ndef'),
            standard_error = db.get('sdobs'),
            )
        origin.quality = quality

        #-- Solution Uncertainties ----------------------------------
        # in CSS the ellipse is projected onto the horizontal plane
        # using the covariance matrix
        uncertainty = OriginUncertainty()
        a = _km2m(db.get('smajax'))
        b = _km2m(db.get('sminax'))
        s = db.get('strike')
        dep_u = _km2m(db.get('sdepth'))
        time_u = db.get('stime')

        uncertainty.max_horizontal_uncertainty = a
        uncertainty.min_horizontal_uncertainty = b
        uncertainty.azimuth_max_horizontal_uncertainty = s
        uncertainty.horizontal_uncertainty = a
        uncertainty.preferred_description = "horizontal uncertainty"

        if db.get('conf') is not None:
            uncertainty.confidence_level = db.get('conf') * 100.  

        if uncertainty.horizontal_uncertainty is not None:
            origin.origin_uncertainty = uncertainty

        #-- Parameter Uncertainties ---------------------------------
        if all([a, b, s]):
            n, e = _get_NE_on_ellipse(a, b, s)
            lat_u = _m2deg_lat(n)
            lon_u = _m2deg_lon(e, lat=origin.latitude)
            origin.latitude_errors = {'uncertainty': lat_u} 
            origin.longitude_errors = {'uncertainty': lon_u}
        if dep_u:
            origin.depth_errors = {'uncertainty': dep_u}
        if time_u:
            origin.time_errors = {'uncertainty': time_u}

        #-- Analyst-determined Status -------------------------------
        posted_author = _str(db.get('auth'))
        mode, status = self.get_event_status(posted_author)
        origin.evaluation_mode = mode
        origin.evaluation_status = status
        
        # Save etype per origin due to schema differences...
        css_etype = _str(db.get('etype'))
        # Compatible with future patch rename "_namespace" -> "namespace"
        origin.extra['etype'] = {
            'value': css_etype, 
            'namespace': CSS_NAMESPACE
            }

        origin.creation_info = CreationInfo(
            creation_time = _utc(db.get('lddate')),
            agency_id = self.agency, 
            version = db.get('orid'),
            author = posted_author,
            )
        origin.resource_id = self._rid(origin)
        return origin