Beispiel #1
0
def _read_channel(instrumentation_register, cha_element, _ns):

    """
    reads channel element from sc3ml format

    :param instrumentation_register: register of instrumentation metadata
    :param cha_element: channel element
    :param _ns: namespace
    """

    code = cha_element.get("code")

    # Information is also kept within the parent <sensorLocation> element
    sen_loc_element = cha_element.getparent()
    location_code = sen_loc_element.get("code")

    # get site info from the <sensorLocation> element
    longitude = _read_floattype(sen_loc_element, _ns("longitude"), Longitude,
                                datum=True)
    latitude = _read_floattype(sen_loc_element, _ns("latitude"), Latitude,
                               datum=True)
    elevation = _read_floattype(sen_loc_element, _ns("elevation"), Distance,
                                unit=True)
    depth = _read_floattype(cha_element, _ns("depth"), Distance,
                            unit=True)

    # Set values to 0 if they are is missing (see #1816)
    if longitude is None:
        msg = "Sensor is missing longitude information, using 0.0"
        warnings.warn(msg)
        longitude = 0
    if latitude is None:
        msg = "Sensor is missing latitude information, using 0.0"
        warnings.warn(msg)
        latitude = 0
    if elevation is None:
        msg = "Sensor is missing elevation information, using 0.0"
        warnings.warn(msg)
        elevation = 0
    if depth is None:
        msg = "Channel is missing depth information, using 0.0"
        warnings.warn(msg)
        depth = 0

    channel = obspy.core.inventory.Channel(
        code=code, location_code=location_code, latitude=latitude,
        longitude=longitude, elevation=elevation, depth=depth)

    # obtain the sensorID and link to particular publicID <sensor> element
    # in the inventory base node
    sensor_id = cha_element.get("sensor")
    sensor_element = instrumentation_register["sensors"].get(sensor_id)

    # obtain the poles and zeros responseID and link to particular
    # <responsePAZ> publicID element in the inventory base node
    if (sensor_element is not None and
       sensor_element.get("response") is not None):

        response_id = sensor_element.get("response")
        response_elements = []

        for resp_element in instrumentation_register["responses"].values():
            found_response = resp_element.get(response_id)
            if found_response is not None:
                response_elements.append(found_response)

        if len(response_elements) == 0:
            msg = ("Could not find response tag with public ID "
                   "'{}'.".format(response_id))
            raise obspy.ObsPyException(msg)
        elif len(response_elements) > 1:
            msg = ("Found multiple matching response tags with the same "
                   "public ID '{}'.".format(response_id))
            raise obspy.ObsPyException(msg)
        response_element = response_elements[0]
    else:
        response_element = None

    # obtain the dataloggerID and link to particular <responsePAZ> publicID
    # element in the inventory base node
    datalogger_id = cha_element.get("datalogger")
    data_log_element = \
        instrumentation_register["dataloggers"].get(datalogger_id)

    channel.restricted_status = _get_restricted_status(cha_element, _ns)

    # There is no further information in the attributes of <stream>
    # Start and end date are included as tags instead
    channel.start_date = _tag2obj(cha_element, _ns("start"), obspy.UTCDateTime)
    channel.end_date = _tag2obj(cha_element, _ns("end"), obspy.UTCDateTime)

    # Determine sample rate (given is a numerator, denominator)
    # Assuming numerator is # samples and denominator is # seconds
    numerator = _tag2obj(cha_element, _ns("sampleRateNumerator"), int)
    denominator = _tag2obj(cha_element, _ns("sampleRateDenominator"), int)

    # If numerator is non-zero and denominator zero, will raise
    # ZeroDivisionError.
    rate = numerator / denominator if numerator != 0 else 0

    channel.sample_rate_ratio_number_samples = numerator
    channel.sample_rate_ratio_number_seconds = denominator
    channel.sample_rate = _read_float_var(rate, SampleRate)

    if sensor_element is not None:
        channel.sensor = _read_sensor(sensor_element, _ns)
    if data_log_element is not None:
        channel.data_logger = _read_datalogger(data_log_element, _ns)
        temp = _read_floattype(data_log_element, _ns("maxClockDrift"),
                               ClockDrift)
        if temp is not None:
            if channel.sample_rate != 0.0:
                channel.clock_drift_in_seconds_per_sample = \
                    _read_float_var(temp / channel.sample_rate, ClockDrift)
            else:
                msg = "Clock drift division by sample rate of 0: " \
                      "using sec/sample"
                warnings.warn(msg)
                channel.sample_rate = temp

    channel.azimuth = _read_floattype(cha_element, _ns("azimuth"), Azimuth)
    channel.dip = _read_floattype(cha_element, _ns("dip"), Dip)
    match = re.search(r'{([^}]*)}', cha_element.tag)
    if match:
        namespace = match.group(1)
    else:
        namespace = _get_schema_namespace('0.9')
    channel.extra = {'format': {
        'value': _tag2obj(cha_element, _ns("format"), str),
        # storage format of channel not supported by StationXML1.1 anymore,
        # keep it as a foreign tag to be nice if anybody needs to access it
        'namespace': namespace}}

    if channel.sample_rate == 0.0:
        msg = "Something went hopelessly wrong, found sampling-rate of 0!"
        warnings.warn(msg)

    # Begin to collect digital/analogue filter chains
    # This information is stored as an array in the datalogger element
    response_fir_id = []
    response_paz_id = []
    if data_log_element is not None:
        # Find the decimation element with a particular num/denom
        decim_element = data_log_element.find(_ns(
            "decimation[@sampleRateDenominator='" +
            str(int(denominator)) + "'][@sampleRateNumerator='" +
            str(int(numerator)) + "']"))
        analogue_filter_chain = _tag2obj(decim_element,
                                         _ns("analogueFilterChain"), str)
        if analogue_filter_chain is not None:
            response_paz_id = analogue_filter_chain.split(" ")
        digital_filter_chain = _tag2obj(decim_element,
                                        _ns("digitalFilterChain"), str)
        if digital_filter_chain is not None:
            response_fir_id = digital_filter_chain.split(" ")

    channel.response = _read_response(instrumentation_register['responses'],
                                      sensor_element, response_element,
                                      cha_element, data_log_element, _ns,
                                      channel.sample_rate,
                                      response_fir_id, response_paz_id)

    return channel
Beispiel #2
0
def _read_sc3ml(path_or_file_object):
    """
    Function for reading a stationXML file.

    :param path_or_file_object: File name or file like object.
    """
    root = etree.parse(path_or_file_object).getroot()

    # Code can be used for version 0.7, 0.8, and 0.9
    for version in SCHEMA_VERSION:
        namespace = _get_schema_namespace(version)
        if root.find("{%s}%s" % (namespace, "Inventory")) is not None:
            break
    else:
        raise ValueError("Schema version not supported.")

    def _ns(tagname):
        return "{%s}%s" % (namespace, tagname)

    # This needs to be tested, did not find an inventory
    # with the journal entry.
    journal = root.find(_ns("Journaling"))
    if journal is not None:
        entry = journal.find(_ns("entry"))
        if entry is not None:
            created = _tag2obj(entry, _ns("created"), obspy.UTCDateTime)
            sender = _tag2obj(entry, _ns("sender"), str)
    else:
        created = None
        sender = "ObsPy Inventory"

    # Set source to this script
    source = "sc3ml import"
    module = None
    module_uri = None

    # Find the inventory root element. (Only finds the first. We expect only
    # one, so any more than that will be ignored.)
    inv_element = root.find(_ns("Inventory"))

    # Pre-generate a dictionary of the sensors, dataloggers and responses to
    # avoid costly linear search when parsing network nodes later.
    # Register sensors
    sensors = {}
    for sensor_element in inv_element.findall(_ns("sensor")):
        public_id = sensor_element.get("publicID")
        if public_id:
            if public_id in sensors:
                msg = ("Found multiple matching sensor tags with the same "
                       "publicID '{}'.".format(public_id))
                raise obspy.ObsPyException(msg)
            else:
                sensors[public_id] = sensor_element
    # Register dataloggers
    dataloggers = {}
    for datalogger_element in inv_element.findall(_ns("datalogger")):
        public_id = datalogger_element.get("publicID")
        if public_id:
            if public_id in dataloggers:
                msg = ("Found multiple matching datalogger tags with the same "
                       "publicID '{}'.".format(public_id))
                raise obspy.ObsPyException(msg)
            else:
                dataloggers[public_id] = datalogger_element
    # Register reponses
    responses = {
        "responsePAZ": {},
        "responsePolynomial": {},
        "responseFIR": {},
        "responseIIR": {}
    }
    for response_type, all_elements in responses.items():
        for response_element in inv_element.findall(_ns(response_type)):
            public_id = response_element.get("publicID")
            if public_id:
                if public_id in all_elements:
                    msg = ("Found multiple matching {} tags with the same "
                           "publicID '{}'.".format(response_type, public_id))
                    raise obspy.ObsPyException(msg)
                else:
                    all_elements[public_id] = response_element
    # Organize all the collection instrument information into a unified
    # intrumentation register.
    instrumentation_register = {
        "sensors": sensors,
        "dataloggers": dataloggers,
        "responses": responses
    }

    # Collect all networks from the sc3ml inventory
    networks = []
    for net_element in inv_element.findall(_ns("network")):
        networks.append(_read_network(instrumentation_register,
                                      net_element, _ns))

    return obspy.core.inventory.Inventory(networks=networks, source=source,
                                          sender=sender, created=created,
                                          module=module, module_uri=module_uri)
Beispiel #3
0
def _read_channel(inventory_root, cha_element, _ns):
    """
    reads channel element from sc3ml format

    :param sta_element: channel element
    :param _ns: namespace
    """

    code = cha_element.get("code")

    # Information is also kept within the parent <sensorLocation> element
    sen_loc_element = cha_element.getparent()
    location_code = sen_loc_element.get("code")

    # get site info from the <sensorLocation> element
    longitude = _read_floattype(sen_loc_element,
                                _ns("longitude"),
                                Longitude,
                                datum=True)
    latitude = _read_floattype(sen_loc_element,
                               _ns("latitude"),
                               Latitude,
                               datum=True)
    elevation = _read_floattype(sen_loc_element,
                                _ns("elevation"),
                                Distance,
                                unit=True)
    depth = _read_floattype(cha_element, _ns("depth"), Distance, unit=True)

    # Set values to 0 if they are is missing (see #1816)
    if longitude is None:
        msg = "Sensor is missing longitude information, using 0.0"
        warnings.warn(msg)
        longitude = 0
    if latitude is None:
        msg = "Sensor is missing latitude information, using 0.0"
        warnings.warn(msg)
        latitude = 0
    if elevation is None:
        msg = "Sensor is missing elevation information, using 0.0"
        warnings.warn(msg)
        elevation = 0
    if depth is None:
        msg = "Channel is missing depth information, using 0.0"
        warnings.warn(msg)
        depth = 0

    channel = obspy.core.inventory.Channel(code=code,
                                           location_code=location_code,
                                           latitude=latitude,
                                           longitude=longitude,
                                           elevation=elevation,
                                           depth=depth)

    # obtain the sensorID and link to particular publicID <sensor> element
    # in the inventory base node
    sensor_id = cha_element.get("sensor")
    sensor_element = inventory_root.find(
        _ns("sensor[@publicID='" + sensor_id + "']"))
    # obtain the poles and zeros responseID and link to particular
    # <responsePAZ> publicID element in the inventory base node
    if (sensor_element is not None
            and sensor_element.get("response") is not None):

        response_id = sensor_element.get("response")
        response_elements = []

        for resp_type in ['responsePAZ', 'responsePolynomial']:
            search = "{}[@publicID='{}']".format(resp_type, response_id)
            response_elements += inventory_root.findall(_ns(search))
        if len(response_elements) == 0:
            msg = ("Could not find response tag with public ID "
                   "'{}'.".format(response_id))
            raise obspy.ObsPyException(msg)
        elif len(response_elements) > 1:
            msg = ("Found multiple matching response tags with the same "
                   "public ID '{}'.".format(response_id))
            raise obspy.ObsPyException(msg)
        response_element = response_elements[0]
    else:
        response_element = None

    # obtain the dataloggerID and link to particular <responsePAZ> publicID
    # element in the inventory base node
    datalogger_id = cha_element.get("datalogger")
    search = "datalogger[@publicID='" + datalogger_id + "']"
    data_log_element = inventory_root.find(_ns(search))

    channel.restricted_status = _get_restricted_status(cha_element, _ns)

    # There is no further information in the attributes of <stream>
    # Start and end date are included as tags instead
    channel.start_date = _tag2obj(cha_element, _ns("start"), obspy.UTCDateTime)
    channel.end_date = _tag2obj(cha_element, _ns("end"), obspy.UTCDateTime)

    # Determine sample rate (given is a numerator, denominator)
    # Assuming numerator is # samples and denominator is # seconds
    numerator = _tag2obj(cha_element, _ns("sampleRateNumerator"), int)
    denominator = _tag2obj(cha_element, _ns("sampleRateDenominator"), int)

    rate = numerator / denominator

    channel.sample_rate_ratio_number_samples = numerator
    channel.sample_rate_ratio_number_seconds = denominator
    channel.sample_rate = _read_float_var(rate, SampleRate)

    if sensor_element is not None:
        channel.sensor = _read_sensor(sensor_element, _ns)
    if data_log_element is not None:
        channel.data_logger = _read_datalogger(data_log_element, _ns)
        temp = _read_floattype(data_log_element, _ns("maxClockDrift"),
                               ClockDrift)
        if temp is not None:
            if channel.sample_rate != 0.0:
                channel.clock_drift_in_seconds_per_sample = \
                    _read_float_var(temp / channel.sample_rate, ClockDrift)
            else:
                msg = "Clock drift division by sample rate of 0: " \
                      "using sec/sample"
                warnings.warn(msg)
                channel.sample_rate = temp

    channel.azimuth = _read_floattype(cha_element, _ns("azimuth"), Azimuth)
    channel.dip = _read_floattype(cha_element, _ns("dip"), Dip)
    channel.storage_format = _tag2obj(cha_element, _ns("format"), str)

    if channel.sample_rate == 0.0:
        msg = "Something went hopelessly wrong, found sampling-rate of 0!"
        warnings.warn(msg)

    # Begin to collect digital/analogue filter chains
    # This information is stored as an array in the datalogger element
    response_fir_id = []
    response_paz_id = []
    if data_log_element is not None:
        # Find the decimation element with a particular num/denom
        decim_element = data_log_element.find(
            _ns("decimation[@sampleRateDenominator='" + str(int(denominator)) +
                "'][@sampleRateNumerator='" + str(int(numerator)) + "']"))
        analogue_filter_chain = _tag2obj(decim_element,
                                         _ns("analogueFilterChain"), str)
        if analogue_filter_chain is not None:
            response_paz_id = analogue_filter_chain.split(" ")
        digital_filter_chain = _tag2obj(decim_element,
                                        _ns("digitalFilterChain"), str)
        if digital_filter_chain is not None:
            response_fir_id = digital_filter_chain.split(" ")

    channel.response = _read_response(inventory_root, sensor_element,
                                      response_element, cha_element,
                                      data_log_element, _ns,
                                      channel.sample_rate, response_fir_id,
                                      response_paz_id)

    return channel