Esempio n. 1
0
    def get(self, event, iteration):
        """
        Returns the window manager instance for a given event and iteration.

        :param event_name: The name of the event.
        :param iteration_name: The name of the iteration.
        """
        event = self.comm.events.get(event)
        iteration = self.comm.iterations.get(iteration)
        event_name = event["event_name"]
        iteration_name = iteration.name

        if not self.comm.events.has_event(event_name):
            msg = "Event '%s' not known." % event_name
            raise LASIFNotFoundError(msg)

        if not self.comm.iterations.has_iteration(iteration_name):
            msg = "Iteration '%s' not known." % iteration_name
            raise LASIFNotFoundError(msg)

        iteration = self.comm.iterations.get(iteration_name)
        if event_name not in iteration.events:
            msg = "Event '%s' not part of iteration '%s'." % (event_name,
                                                              iteration_name)
            raise ValueError(msg)

        folder = os.path.join(
            self._folder, event_name,
            self.comm.iterations.get_long_iteration_name(iteration_name))
        return WindowGroupManager(folder,
                                  iteration_name,
                                  event_name,
                                  comm=self.comm)
Esempio n. 2
0
    def get_project_function(self, fct_type):
        """
        Helper importing the project specific function.

        :param fct_type: The desired function.
        """
        # Cache to avoid repeated imports.
        if fct_type in self.__project_function_cache:
            return self.__project_function_cache[fct_type]

        # type / filename map
        fct_type_map = {
            "window_picking_function": "window_picking_function.py",
            "preprocessing_function": "preprocessing_function.py",
            "data_svd_selection": "data_svd_selection.py",
            "process_synthetics": "process_synthetics.py",
            "source_time_function": "source_time_function.py",
            "instaseis_synthetics_function":
            "instaseis_synthetics_function.py",
            "stf_deconvolution": "stf_deconvolution.py",
        }

        if fct_type not in fct_type:
            msg = "Function '%s' not found. Available types: %s" % (
                fct_type, str(list(fct_type_map.keys())))
            raise LASIFNotFoundError(msg)

        filename = os.path.join(self.paths["functions"],
                                fct_type_map[fct_type])
        if not os.path.exists(filename):
            msg = "No file '%s' in existence." % filename
            raise LASIFNotFoundError(msg)

        fct_template = imp.load_source("_lasif_fct_template", filename)
        try:
            fct = getattr(fct_template, fct_type)
        except AttributeError:
            raise LASIFNotFoundError(
                "Could not find function %s in file '%s'" %
                (fct_type, filename))

        if not callable(fct):
            raise LASIFError("Attribute %s in file '%s' is not a function." %
                             (fct_type, filename))

        # Add to cache.
        self.__project_function_cache[fct_type] = fct
        return fct
Esempio n. 3
0
    def __init__(self, comm, iteration, event):
        self.comm = comm
        self.event = self.comm.events.get(event)
        self.iteration = self.comm.iterations.get(iteration)

        self.event_name = self.event["event_name"]

        if self.event_name not in self.iteration.events:
            msg = "Event '%s' not part of iteration '%s'." % (
                self.event_name, self.iteration.name)
            raise LASIFNotFoundError(msg)

        # Get all stations defined for the given iteration and event.
        stations = set(
            self.iteration.events[self.event_name]["stations"].keys())

        # Only use those stations that actually have processed and synthetic
        # data available! Especially synthetics might not always be available.
        processed = comm.waveforms.get_metadata_processed(
            self.event_name, self.iteration.processing_tag)
        synthetics = comm.waveforms.get_metadata_synthetic(
            self.event_name, self.iteration)
        processed = set(
            ["%s.%s" % (_i["network"], _i["station"]) for _i in processed])
        synthetics = set(
            ["%s.%s" % (_i["network"], _i["station"]) for _i in synthetics])
        self.stations = tuple(
            sorted(stations.intersection(processed).intersection(synthetics)))

        self._current_index = -1
Esempio n. 4
0
    def get_available_synthetics(self, event_name):
        """
        Returns the available synthetics for a given event.

        :param event_name: The event name.
        """
        data_dir = os.path.join(self._synthetics_folder, event_name)
        if not os.path.exists(data_dir):
            raise LASIFNotFoundError("No synthetic data for event '%s'." %
                                     event_name)
        iterations = []
        for folder in os.listdir(data_dir):
            if not os.path.isdir(os.path.join(
                    self._synthetics_folder, event_name, folder)) \
                    or not fnmatch.fnmatch(folder, "ITERATION_*"):
                continue
            iterations.append(folder)

        # Make sure the iterations also contain the event and the stations.
        its = []
        for iteration in iterations:
            try:
                it = self.comm.iterations.get(iteration)
            except LASIFNotFoundError:
                continue
            if event_name not in it.events:
                continue
            its.append(it.name)
        return its
Esempio n. 5
0
    def __what_is_this_station_file(self, file_path, filetype):
        ft_map = {
            "dataless_seed": "SEED",
            "resp": "RESP",
            "stationxml": "StationXML"
        }
        info = self.comm.stations.get_details_for_filename(file_path)
        if info is None:
            raise LASIFNotFoundError("File '%s' is not valid station file." %
                                     file_path)

        info = [
            "\t%s | %s - %s | Lat/Lng/Ele/Dep: %s/%s/%s/%s" %
            (_i["channel_id"], str(_i["start_date"]),
             str(_i["end_date"]) if _i["end_date"] else "--",
             "%.2f" % _i["latitude"] if _i["latitude"] is not None else "--",
             "%.2f" % _i["longitude"] if _i["longitude"] is not None else "--",
             "%.2f" % _i["elevation_in_m"] if _i["elevation_in_m"] is not None
             else "--", "%.2f" % _i["local_depth_in_m"]
             if _i["local_depth_in_m"] is not None else "--") for _i in info
        ]

        return ("The %s file contains information about %i channel%s:\n%s" %
                (ft_map[filetype], len(info), "s" if len(info) > 1 else "",
                 "\n".join(info)))
Esempio n. 6
0
    def get_channel_filename(self, channel_id, time):
        """
        Returns the absolute path of the file storing the information for the
        given channel and time combination.

        :param channel_id: The id of the channel.
        :type channel_id: str
        :param time: The time at which to retrieve the information.
        :type time: ``int`` or :class:`~obspy.core.utcdatetime.UTCDateTime`

        >>> import obspy
        >>> comm = getfixture('stations_comm')

        It works with :class:`~obspy.core.utcdatetime.UTCDateTime` objects

        >>> comm.stations.get_channel_filename(  # doctest: +ELLIPSIS
        ...     "IU.ANMO.10.BHZ", obspy.UTCDateTime(2012, 3, 14))
        u'/.../IRIS_single_channel_with_response.xml'

        and timestamps.

        >>> comm.stations.get_channel_filename(  # doctest: +ELLIPSIS
        ...     "IU.ANMO.10.BHZ", 1331683200)
        u'/.../IRIS_single_channel_with_response.xml'
        """
        filename = self._station_cache.get_station_filename(channel_id, time)
        if filename is None:
            raise LASIFNotFoundError(
                "Could not find a station file for channel '%s' at %s." % (
                    channel_id, str(time)))
        return filename
Esempio n. 7
0
 def _get_waveforms(self,
                    event_name,
                    station_id,
                    data_type,
                    tag_or_iteration=None):
     waveform_cache = self.get_waveform_cache(event_name, data_type,
                                              tag_or_iteration)
     network, station = station_id.split(".")
     files = waveform_cache.get_files_for_station(network, station)
     if len(files) == 0:
         raise LASIFNotFoundError("No '%s' waveform data found for event "
                                  "'%s' and station '%s'." %
                                  (data_type, event_name, station_id))
     if data_type in ["raw", "processed"]:
         # Sort files by location.
         locations = {
             key: list(value)
             for key, value in itertools.groupby(
                 files, key=lambda x: x["location"])
         }
         keys = sorted(locations.keys())
         if len(keys) != 1:
             msg = ("Found %s waveform data from %i locations for event "
                    "'%s' and station '%s': %s. Will only use data from "
                    "location '%s'." %
                    (data_type, len(keys), event_name, station_id,
                     ", ".join(["'%s'" % _i for _i in keys]), keys[0]))
             warnings.warn(msg, LASIFWarning)
         files = locations[keys[0]]
     st = obspy.Stream()
     for single_file in files:
         st += obspy.read(single_file["filename"])
     st.sort()
     return st
Esempio n. 8
0
    def get_metadata_raw(self, event_name):
        """
        Returns the available metadata at the channel level for the raw
        waveforms and the given event_name.

        :param event_name: The name of the event.
        :returns: A list of dictionaries, each describing channel level data
            at a particular point in time.

        In most instances, the ``latitude``, ``longitude``,
        ``elevation_in_m``, and ``local_depth_in_m`` values will be
        ``None`` as station information is usually retrieved from the
        station metadata file. SAC files are an exception.

        >>> import pprint
        >>> comm = getfixture('waveforms_comm')
        >>> pprint.pprint(sorted(comm.waveforms.get_metadata_raw(
        ...     "GCMT_event_TURKEY_Mag_5.1_2010-3-24-14-11"),
        ...     key=lambda x: x["channel_id"])) \
        # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
        [{'channel': u'BHE',
          'channel_id': u'HL.ARG..BHE',
          'elevation_in_m': None,
          'endtime': UTCDateTime(2010, 3, 24, 15, 11, 30, 974999),
          'filename': u'/.../HL.ARG..BHE.mseed',
          'latitude': None,
          'local_depth_in_m': None,
          'location': u'',
          'longitude': None,
          'network': u'HL',
          'starttime': UTCDateTime(2010, 3, 24, 14, 6, 31, 24999),
          'station': u'ARG'},
         {...},
        ...]

        Each dictionary will have the following keys.

        >>> sorted(comm.waveforms.get_metadata_raw(
        ...     "GCMT_event_TURKEY_Mag_5.1_2010-3-24-14-11")[0].keys()) \
        # doctest: +NORMALIZE_WHITESPACE
        ['channel', 'channel_id', 'elevation_in_m', 'endtime',
         'filename', 'latitude', 'local_depth_in_m', 'location',
         'longitude', 'network', 'starttime', 'station']

        A :class:`~lasif.LASIFNotFoundError` will be raised, if no raw
        waveform data is found for the specified event.

        >>> comm.waveforms.get_metadata_raw("RandomEvent")
        Traceback (most recent call last):
            ...
        LASIFNotFoundError: ...
        """
        waveform_cache = self.get_waveform_cache(event_name,
                                                 data_type="raw")
        values = waveform_cache.get_values()
        if not values:
            msg = "No data for event '%s' found." % event_name
            raise LASIFNotFoundError(msg)
        return self._convert_timestamps(waveform_cache.get_values())
Esempio n. 9
0
    def get(self, iteration_name):
        """
        Returns an iteration object.

        :param iteration_name: The name of the iteration to retrieve.

        >>> comm = getfixture('iterations_comm')
        >>> comm.iterations.get("1")  # doctest: +ELLIPSIS
        <lasif.iteration_xml.Iteration object at ...>
        >>> print comm.iterations.get("1")  \
        # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
        LASIF Iteration
            Name: 1
            ...

        A :class:`~lasif.LASIFNotFoundError` will be raised, if the
        iteration is not known.

        >>> comm.iterations.get("99")
        Traceback (most recent call last):
            ...
        LASIFNotFoundError: ...


        It also works with the long iteration name and event an existing
        iteration object. This makes it simple to use, one path for all
        possibilities.
        >>> it = comm.iterations.get("ITERATION_1")
        >>> it  # doctest: +ELLIPSIS
        <lasif.iteration_xml.Iteration object at ...>
        >>> comm.iterations.get(it)
        <lasif.iteration_xml.Iteration object at ...>
        """
        # Make it work with both the long and short version of the iteration
        # name, and existing iteration object.
        try:
            iteration_name = str(iteration_name.iteration_name)
        except AttributeError:
            iteration_name = str(iteration_name)
        iteration_name = iteration_name.lstrip("ITERATION_")

        # Access cache.
        if iteration_name in self.__cached_iterations:
            return self.__cached_iterations[iteration_name]

        it_dict = self.get_iteration_dict()
        if iteration_name not in it_dict:
            msg = "Iteration '%s' not found." % iteration_name
            raise LASIFNotFoundError(msg)

        from lasif.iteration_xml import Iteration
        it = Iteration(it_dict[iteration_name],
                       stf_fct=self.comm.project.get_project_function(
                           "source_time_function"))

        # Store in cache.
        self.__cached_iterations[iteration_name] = it

        return it
Esempio n. 10
0
 def get(self, iteration, event):
     iteration = self.comm.iterations.get(iteration)
     kernel_dir = os.path.join(self._folder, iteration.long_name, event)
     if not os.path.exists(kernel_dir) or not os.path.isdir(kernel_dir):
         raise LASIFNotFoundError("Kernel for iteration %s and event %s "
                                  "not found" %
                                  (iteration.long_name, event))
     return kernel_dir
Esempio n. 11
0
def select_component_from_stream(st, component):
    """
    Helper function selecting a component from a Stream an raising the proper
    error if not found.

    This is a bit more flexible then stream.select() as it works with single
    letter channels and lowercase channels.
    """
    component = component.upper()
    component = [tr for tr in st if tr.stats.channel[-1].upper() == component]
    if not component:
        raise LASIFNotFoundError("Component %s not found in Stream." %
                                 component)
    elif len(component) > 1:
        raise LASIFNotFoundError("More than 1 Trace with component %s found "
                                 "in Stream." % component)
    return component[0]
Esempio n. 12
0
    def get_waveform_stf(self, event_name, tag_or_iteration, component="Z"):
        """
        Gets the stf waveform for the given event and iteration and component as a
        :class:`~obspy.core.stream.Stream` object.

        :param event_name: The name of the event.
        :param tag: The processing tag
        :param component: The stf component 'Z', 'E' or 'N'
        """

        import glob
        if (component != 'Z') and (component != 'E') and (component != 'N'):
            msg = (
                "Invalid data component '%s'. Component should be E, N, or Z." %
                component)
            raise ValueError(msg)

        data_type = "stf"
        tag_or_iteration = \
            self.comm.iterations.get(tag_or_iteration).long_name

        data_path = self.get_waveform_folder(event_name, data_type,
                                             tag_or_iteration)
        if not tag_or_iteration:
            msg = "Long iteration name must be given for stf data."
            raise ValueError(msg)
            if not os.path.exists(data_path):
                msg = ("No stf data for event '%s' and iteration '%s' "
                       "found." % (event_name, tag_or_iteration))
                raise LASIFNotFoundError(msg)

        list_file = glob.glob(os.path.join(data_path, "stf_%s*" % component))
        if len(list_file) > 1:
            msg = (
                "More than one stf data file for event '%s' and iteration '%s' and component %s "
                "found." %
                (event_name, tag_or_iteration, component))
            raise LASIFNotFoundError(msg)
        else:
            try:
                stf = obspy.read(list_file[0])
                return stf
            except BaseException:
                msg = ("Cannot read stf file %s" % list_file[0])
                raise LASIFNotFoundError(msg)
Esempio n. 13
0
    def get(self, event_name):
        """
        Get information about one event.

        This function uses multiple cache layers and is thus very cheap to
        call.

        :type event_name: str
        :param event_name: The name of the event.
        :rtype: dict

        >>> comm = getfixture('events_comm')
        >>> comm.events.get('GCMT_event_TURKEY_Mag_5.9_2011-5-19-20-15') \
        # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
        {'m_tp': -2.17e+17, 'm_tt': 8.92e+17, 'depth_in_km': 7.0,
        'event_name': u'GCMT_event_TURKEY_Mag_5.9_2011-5-19-20-15',
        'region': u'TURKEY', 'longitude': 29.1,
        'filename': u'/.../GCMT_event_TURKEY_Mag_5.9_2011-5-19-20-15.xml',
        'm_rr': -8.07e+17, 'magnitude': 5.9, 'magnitude_type': u'Mwc',
        'latitude': 39.15,
        'origin_time': UTCDateTime(2011, 5, 19, 20, 15, 22, 900000),
        'm_rp': -5.3e+16, 'm_pp': -8.5e+16, 'm_rt': 2.8e+16}

        The moment tensor components are in ``Nm``. The dictionary will
        contain the following keys:

        >>> sorted(comm.events.get(
        ...     'GCMT_event_TURKEY_Mag_5.9_2011-5-19-20-15').keys()) \
        # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
         ['depth_in_km', 'event_name', 'filename', 'latitude', 'longitude',
          'm_pp', 'm_rp', 'm_rr', 'm_rt', 'm_tp', 'm_tt', 'magnitude',
          'magnitude_type', 'origin_time', 'region']

        It also works with an existing event dictionary. This eases calling
        the function under certain circumstances.

        >>> ev = comm.events.get('GCMT_event_TURKEY_Mag_5.9_2011-5-19-20-15')
        >>> ev == comm.events.get(ev)
        True
        """
        # Make sure  it also works with existing event dictionaries. This
        # has the potential to simplify lots of code.
        try:
            event_name = event_name["event_name"]
        except (KeyError, TypeError):
            pass

        if event_name not in self.__event_info_cache:
            raise LASIFNotFoundError("Event '%s' not known to LASIF." %
                                     event_name)

        return self.__event_info_cache[event_name]
Esempio n. 14
0
    def assert_has_boxfile(self, iteration, event):
        """
        Makes sure the kernel in question has a boxfile. Otherwise it will
        search all models until it finds one with the same dimensions and
        copy the boxfile.

        :param iteration: The iteration.
        :param event: The event name.
        """
        kernel_dir = self.get(iteration=iteration, event=event)
        boxfile = os.path.join(kernel_dir, "boxfile")
        if os.path.exists(boxfile):
            return

        boxfile_found = False

        # Find all vp gradients.
        vp_gradients = glob.glob(os.path.join(kernel_dir, "grad_csv_*"))
        file_count = len(vp_gradients)
        filesize = list(set([os.path.getsize(_i) for _i in vp_gradients]))
        if len(filesize) != 1:
            msg = ("The grad_cp_*_* files in '%s' do not all have "
                   "identical size.") % kernel_dir
            raise ValueError(msg)
        filesize = filesize[0]
        # Now loop over all model directories until a fitting one if found.
        for model_name in self.comm.models.list():
            model_dir = self.comm.models.get(model_name)
            # Use the lambda parameter files. One could also use any of the
            # others.
            lambda_files = glob.glob(os.path.join(model_dir, "lambda*"))
            if len(lambda_files) != file_count:
                continue
            l_filesize = list(set([os.path.getsize(_i)
                                   for _i in lambda_files]))
            if len(l_filesize) != 1 or l_filesize[0] != filesize:
                continue
            model_boxfile = os.path.join(model_dir, "boxfile")
            if not os.path.exists(model_boxfile):
                continue
            boxfile_found = True
            boxfile = model_boxfile
            break
        if boxfile_found is not True:
            msg = (
                "Could not find a suitable boxfile for the kernel stored "
                "in '%s'. Please either copy a suitable one to this "
                "directory or add a model with the same dimension to LASIF. "
                "LASIF will then be able to figure out the dimensions of it.")
            raise LASIFNotFoundError(msg)
        print("Copied boxfile from '%s' to '%s'." % (model_dir, kernel_dir))
        shutil.copyfile(boxfile, os.path.join(kernel_dir, "boxfile"))
Esempio n. 15
0
    def list_for_event(self, event_name):
        """
        List of all iterations with windows for an event.

        :param event_name: The name of the event.
        """
        event_folder = os.path.join(self._folder, event_name)
        if not os.path.exists(event_folder):
            msg = "No windows for event '%s'." % event_name
            raise LASIFNotFoundError(msg)

        return sorted([_i.lstrip("ITERATION_")
                       for _i in os.listdir(event_folder) if
                       os.path.isdir(os.path.join(event_folder, _i)) and
                       _i.startswith("ITERATION_")])
Esempio n. 16
0
    def get_metadata_synthetic(self, event_name, long_iteration_name):
        """
        Get the synthetics metadata.

        :param event_name: The name of the event.
        :param long_iteration_name: The long form of the iteration name.
        :param station_id: The id of the station in the form ``NET.STA``.
        """
        # Assure the iteration actually contains the event.
        it = self.comm.iterations.get(long_iteration_name)
        if event_name not in it.events:
            raise LASIFNotFoundError(
                "Iteration '%s' does not contain event '%s'." %
                (it.name, event_name))
        waveform_cache = self.get_waveform_cache(
            event_name,
            data_type="synthetic",
            tag_or_iteration=long_iteration_name)
        values = waveform_cache.get_values()
        if not values:
            msg = ("No synthetic data for event '%s' and iteration '%s' "
                   "found." % (event_name, long_iteration_name))
            raise LASIFNotFoundError(msg)
        return self._convert_timestamps(waveform_cache.get_values())
Esempio n. 17
0
    def get_coordinates_for_station(self, event_name, station_id):
        """
        Get the coordinates for one station.

        Must be in sync with :meth:`~.get_all_stations_for_event`.
        """
        event = self.comm.events.get(event_name)

        # Collect information from all the different places.
        waveform = self.comm.waveforms.get_metadata_raw_for_station(
            event_name, station_id)[0]
        station_coordinates = self.comm.stations.get_all_channels_at_time(
            event["origin_time"])

        try:
            stat_coords = station_coordinates[waveform["channel_id"]]
        except KeyError:
            # No station file for channel.
            raise LASIFNotFoundError("Station '%s' has no available "
                                     "station file." % station_id)

        # First attempt to retrieve from the station files.
        if stat_coords["latitude"] is not None:
            return stat_coords
        # Then from the waveform metadata in the case of a sac file.
        elif waveform["latitude"] is not None:
            return waveform
        # The last resort is a new query via the inventory database.
        coords = self.comm.inventory_db.get_coordinates(station_id)
        if coords["latitude"]:
            return coords
        else:
            # No station file for channel.
            raise LASIFNotFoundError("Coordinates could not be deduced for "
                                     "station '%s' and event '%s'." %
                                     (station_id, event_name))
Esempio n. 18
0
    def get_metadata_processed(self, event_name, tag):
        """
        Get the processed metadata.

        :param event_name: The name of the event.
        :param tag: The processing tag.
        """
        waveform_cache = self.get_waveform_cache(event_name,
                                                 data_type="processed",
                                                 tag_or_iteration=tag)
        values = waveform_cache.get_values()
        if not values:
            msg = "No data for event '%s' and processing tag '%s' found." % \
                  (event_name, tag)
            raise LASIFNotFoundError(msg)
        return self._convert_timestamps(waveform_cache.get_values())
Esempio n. 19
0
    def get_available_processing_tags(self, event_name):
        """
        Returns the available processing tags for a given event.

        :param event_name: The event name.
        """
        data_dir = os.path.join(self._data_folder, event_name)
        if not os.path.exists(data_dir):
            raise LASIFNotFoundError("No data for event '%s'." % event_name)
        tags = []
        for tag in os.listdir(data_dir):
            # Only interested in preprocessed data.
            if not tag.startswith("preprocessed") or \
                    tag.endswith("_cache.sqlite"):
                continue
            tags.append(tag)
        return tags
Esempio n. 20
0
    def get_metadata_raw_for_station(self, event_name, station_id):
        """
        Returns the available metadata at the channel level for the raw
        waveforms and the given event_name at a certain station.

        Same as :meth:`~.get_metadata_raw` just for only a single station.

        :param event_name: The name of the event.
        :param station_id: The station id.
        :returns: A list of dictionaries, each describing channel level data
            at a particular point in time.
        """
        waveform_cache = self.get_waveform_cache(event_name, data_type="raw")
        network_id, station_id = station_id.split(".")
        values = waveform_cache.get_files_for_station(network_id, station_id)
        if not values:
            msg = "No data for event '%s' and station '%s' found." % (
                event_name, station_id)
            raise LASIFNotFoundError(msg)
        return self._convert_timestamps(values)
Esempio n. 21
0
    def get_metadata_processed_for_station(self, event_name, tag, station_id):
        """
        Get the processed metadata for a single station.

        Same as :meth:`~.get_metadata_processed` but for a single station.

        :param event_name: The name of the event.
        :param tag: The processing tag.
        :param station_id: The id of the station in the form ``NET.STA``.
        """
        waveform_cache = self.get_waveform_cache(event_name,
                                                 data_type="processed",
                                                 tag_or_iteration=tag)
        network_id, station_id = station_id.split(".")
        values = waveform_cache.get_files_for_station(network_id, station_id)
        if not values:
            msg = "No processed data for event '%s', tag '%s', and station " \
                  "'%s' found." % (event_name, tag, station_id)
            raise LASIFNotFoundError(msg)
        return self._convert_timestamps(values)
Esempio n. 22
0
    def get_metadata_synthetic_for_station(self, event_name,
                                           long_iteration_name, station_id):
        """
        Get the synthetics metadata for a single station.

        Same as :meth:`~.get_metadata_synthetic` but for a single station.

        :param event_name: The name of the event.
        :param long_iteration_name: The long form of the iteration name.
        :param station_id: The id of the station in the form ``NET.STA``.
        """
        waveform_cache = self.get_waveform_cache(
            event_name, data_type="synthetic",
            tag_or_iteration=long_iteration_name)
        network_id, station_id = station_id.split(".")
        values = waveform_cache.get_files_for_station(network_id, station_id)
        if not values:
            msg = "No synthetic data for event '%s', iteration '%s', " \
                  "and station '%s' found." % (event_name, long_iteration_name,
                                               station_id)
            raise LASIFNotFoundError(msg)
        return self._convert_timestamps(values)
Esempio n. 23
0
    def what_is(self, path):
        """
        Debug function returning a string with information about the file.
        Useful as a debug function and to figure out what LASIF is doing.

        :param path: The path to the file.
        """
        path = os.path.normpath(os.path.abspath(path))

        # File does not exist.
        if not os.path.exists(path):
            raise LASIFNotFoundError("Path '%s' does not exist." % path)
        # File not part of the project.
        if os.path.commonprefix([path, self.comm.project.paths["root"]]) \
                != self.comm.project.paths["root"]:
            raise LASIFError("File '%s' is not part of the LASIF project." %
                             path)

        # Split in dir an folder to ease the rest.
        if os.path.isdir(path):
            return self.__what_is_this_folder(path)
        else:
            return self.__what_is_this_file(path)
Esempio n. 24
0
    def get_waveform_cache(self,
                           event_name,
                           data_type,
                           tag_or_iteration=None,
                           dont_update=False):
        """
        :param event_name: The name of the event.
        :param data_type: The data type.
        :param tag_or_iteration: If processed data, the tag, if synthetic
            data, the iteration.
        :param dont_update: If True, an existing cache will not be updated
            but returned as is. If it does not exist, it will be updated
            regardless.
        """
        if data_type == "synthetic":
            tag_or_iteration = \
                self.comm.iterations.get(tag_or_iteration).long_name

        data_path = self.get_waveform_folder(event_name, data_type,
                                             tag_or_iteration)
        if data_type == "raw":
            if not os.path.exists(data_path):
                msg = "No data for event '%s' found." % event_name
                raise LASIFNotFoundError(msg)
            label = "Raw"
        elif data_type == "processed":
            if not tag_or_iteration:
                msg = "Tag must be given for processed data."
                raise ValueError(msg)
            if not os.path.exists(data_path):
                msg = ("No data for event '%s' and processing tag '%s' "
                       "found." % (event_name, tag_or_iteration))
                raise LASIFNotFoundError(msg)
            label = "Processed %s" % event_name
        elif data_type == "synthetic":
            if not tag_or_iteration:
                msg = "Long iteration name must be given for synthetic data."
                raise ValueError(msg)
            if not os.path.exists(data_path):
                msg = ("No synthetic data for event '%s' and iteration '%s' "
                       "found." % (event_name, tag_or_iteration))
                raise LASIFNotFoundError(msg)
            label = "Synthetic %s" % event_name
        else:
            raise ValueError("Invalid data type '%s'." % data_type)

        waveform_db_file = data_path + "_cache" + os.path.extsep + "sqlite"
        if waveform_db_file in self.__cache:
            return self.__cache[waveform_db_file]
        if dont_update is True and os.path.exists(waveform_db_file):
            cache = WaveformCache(cache_db_file=waveform_db_file,
                                  root_folder=self.comm.project.paths["root"],
                                  waveform_folder=data_path,
                                  pretty_name="%s Waveform Cache" % label,
                                  read_only=True)
        elif data_type == "synthetic" \
                and not os.path.exists(waveform_db_file) \
                and os.listdir(data_path):
            # If it is synthetic, read a file and assume all other files
            # have the same length. This has the huge advantage that the
            # files no longer have to be opened but only the filename has to
            # be parsed. Only works for SES3D files.
            files = sorted(os.listdir(data_path))
            filename = os.path.join(data_path, files[len(files) // 2])
            tr = obspy.read(filename)[0]
            synthetic_info = {
                "starttime_timestamp": tr.stats.starttime.timestamp,
                "endtime_timestamp": tr.stats.endtime.timestamp
            }

            cache = WaveformCache(cache_db_file=waveform_db_file,
                                  root_folder=self.comm.project.paths["root"],
                                  waveform_folder=data_path,
                                  pretty_name="%s Waveform Cache" % label,
                                  read_only=self.comm.project.read_only_caches,
                                  synthetic_info=synthetic_info)
        else:
            cache = WaveformCache(cache_db_file=waveform_db_file,
                                  root_folder=self.comm.project.paths["root"],
                                  waveform_folder=data_path,
                                  pretty_name="%s Waveform Cache" % label,
                                  read_only=self.comm.project.read_only_caches)
        self.__cache[waveform_db_file] = cache
        return cache
Esempio n. 25
0
    def create_successive_iteration(self,
                                    existing_iteration_name,
                                    new_iteration_name,
                                    create_folders=True):
        """
        Create an iteration based on an existing one.

        It will take all settings in one iteration and transfers them to
        another iteration. Any comments will be deleted.

        :param existing_iteration_name: Name of the iteration to be used as
            a template.
        :param new_iteration_name: Name of the new iteration.
        :param create_folders: Create the folders for the next iteration's
            synthetic waveforms

        Note that the ``create_folders=False`` argument is only used here
        for testing purposes. In most cases you will want this to be ``True``.

        >>> comm = getfixture('iterations_comm')
        >>> comm.iterations.has_iteration("3")
        False
        >>> comm.iterations.create_successive_iteration("1", "3",
        ...                                             create_folders=False)
        >>> comm.iterations.has_iteration("3")
        True

        Comments of an iteration will be stripped.

        >>> comm.iterations.get("1").comments
        ['Some', 'random comments']
        >>> comm.iterations.get("3").comments
        []

        >>> os.remove(comm.iterations.get_iteration_dict()["3"])

        If the iteration template does not exist, a
        :class:`~lasif.LASIFNotFoundError` will be raised.

        >>> comm.iterations.create_successive_iteration("99", "100")
        Traceback (most recent call last):
            ...
        LASIFNotFoundError: ...

        A ``ValueError`` will be raised if the new iteration already exists.

        >>> comm.iterations.create_successive_iteration("1", "2")
        Traceback (most recent call last):
            ...
        ValueError: ...
        """
        it_dict = self.get_iteration_dict()
        if existing_iteration_name not in it_dict:
            msg = "Iteration %s does not exists." % existing_iteration_name
            raise LASIFNotFoundError(msg)
        if new_iteration_name in it_dict:
            msg = "Iteration %s already exists." % new_iteration_name
            raise ValueError(msg)

        from lasif.iteration_xml import Iteration

        existing_iteration = Iteration(
            it_dict[existing_iteration_name],
            stf_fct=self.comm.project.get_project_function(
                "source_time_function"))

        # Clone the old iteration, delete any comments and change the name.
        existing_iteration.comments = []
        existing_iteration.iteration_name = new_iteration_name
        self.save_iteration(existing_iteration)

        if create_folders:
            self.create_synthetics_folder_for_iteration(new_iteration_name)
            self.create_stf_folder_for_iteration(new_iteration_name)
Esempio n. 26
0
    def calculate_adjoint_source(self, event_name, iteration_name, channel_id,
                                 starttime, endtime, taper, taper_percentage,
                                 ad_src_type):
        """
        Calculates an adjoint source for a single window.

        :param event_name: The name of the event.
        :param iteration_name: The name of the iteration.
        :param channel_id: The channel id in the form NET.STA.NET.CHA.
        :param starttime: The starttime of the window.
        :param endtime: The endtime of the window.
        :param taper: How to taper the window.
        :param taper_percentage: The taper percentage at one end as a
            decimal number ranging from 0.0 to 0.5 for a full width taper.
        :param ad_src_type: The type of adjoint source. Currently supported
            are ``"TimeFrequencyPhaseMisfitFichtner2008"`` and ``"L2Norm"``.
        """
        iteration = self.comm.iterations.get(iteration_name)
        iteration_name = iteration.long_name
        event = self.comm.events.get(event_name)
        event_name = event["event_name"]

        folder = os.path.join(self._folder, event_name, iteration_name)
        if not os.path.exists(folder):
            os.makedirs(folder)
        filename = os.path.join(
            folder, "%s_%s_%s_%s_%.2f_%s" %
            (channel_id, str(starttime), str(endtime), str(taper),
             taper_percentage, ad_src_type))

        if os.path.exists(filename):
            adsrc = joblib.load(filename)
            if not self._validate_return_value(adsrc):
                os.remove(filename)
            else:
                return adsrc

        if ad_src_type not in MISFIT_MAPPING:
            raise LASIFAdjointSourceCalculationError(
                "Adjoint source type '%s' not supported. Supported types: %s" %
                (ad_src_type, ", ".join(MISFIT_MAPPING.keys())))

        waveforms = self.comm.query.get_matching_waveforms(
            event=event_name,
            iteration=iteration_name,
            station_or_channel_id=channel_id)
        data = waveforms.data
        synth = waveforms.synthetics

        if len(data) != 1:
            raise LASIFNotFoundError(
                "Data not found for event '%s', iteration '%s', and channel "
                "'%s'." % (event_name, iteration_name, channel_id))
        if len(synth) != 1:
            raise LASIFNotFoundError(
                "Synthetics not found for event '%s', iteration '%s', "
                "and channel '%s'." % (event_name, iteration_name, channel_id))
        data = data[0]
        synth = synth[0]

        # Make sure they are equal enough.
        if abs(data.stats.starttime - synth.stats.starttime) > 0.1:
            raise LASIFAdjointSourceCalculationError(
                "Starttime not similar enough")
        if data.stats.npts != synth.stats.npts:
            raise LASIFAdjointSourceCalculationError(
                "Differing number of samples")
        if abs(data.stats.delta - synth.stats.delta) / data.stats.delta > \
                0.01:
            raise LASIFAdjointSourceCalculationError(
                "Sampling rate not similar enough.")

        original_stats = copy.deepcopy(data.stats)

        for trace in [data, synth]:
            trace.trim(starttime, endtime)
            trace.taper(type=taper.lower(), max_percentage=taper_percentage)
            trace.trim(original_stats.starttime,
                       original_stats.endtime,
                       pad=True,
                       fill_value=0.0)

        #  make time axis
        t = np.linspace(0, (original_stats.npts - 1) * original_stats.delta,
                        original_stats.npts)

        #  set data and synthetics, compute actual misfit
        t = np.require(t, dtype="float64", requirements="C")
        data_d = np.require(data.data, dtype="float64", requirements="C")
        synth_d = np.require(synth.data, dtype="float64", requirements="C")

        process_parameters = iteration.get_process_params()

        #  compute misfit and adjoint source
        adsrc = MISFIT_MAPPING[ad_src_type](
            t, data_d, synth_d, 1.0 / process_parameters["lowpass"],
            1.0 / process_parameters["highpass"])

        # Recreate dictionary for clarity.
        ret_val = {
            "adjoint_source": adsrc["adjoint_source"],
            "misfit_value": adsrc["misfit_value"],
            "details": adsrc["details"]
        }

        if not self._validate_return_value(ret_val):
            raise LASIFAdjointSourceCalculationError(
                "Could not calculate adjoint source due to mismatching types.")

        joblib.dump(ret_val, filename)
        return ret_val
Esempio n. 27
0
    def discover_available_data(self, event_name, station_id):
        """
        Discovers the available data for one event at a certain station.

        Will raise a :exc:`~lasif.LASIFNotFoundError` if no raw data is
        found for the given event and station combination.

        :type event_name: str
        :param event_name: The name of the event.
        :type station_id: str
        :param station_id: The id of the station in question.

        :rtype: dict
        :returns: Return a dictionary with "processed" and "synthetic" keys.
            Both values will be a list of strings. In the case of "processed"
            it will be a list of all available preprocessing tags. In the case
            of the synthetics it will be a list of all iterations for which
            synthetics are available.
        """
        if not self.comm.events.has_event(event_name):
            msg = "Event '%s' not found in project." % event_name
            raise LASIFNotFoundError(msg)
        # Attempt to get the station coordinates. This ensures availability
        # of the raw data.
        self.get_coordinates_for_station(event_name, station_id)

        def get_components(waveform_cache):
            return sorted([_i["channel"][-1] for _i in waveform_cache],
                          reverse=True)

        raw = self.comm.waveforms.get_metadata_raw_for_station(
            event_name, station_id)
        raw_comps = get_components(raw)

        # Collect all tags and iteration names.
        all_files = {
            "raw": {
                "raw": raw_comps
            },
            "processed": {},
            "synthetic": {}
        }

        # Get the available synthetic and processing tags.
        proc_tags = self.comm.waveforms.get_available_processing_tags(
            event_name)

        for tag in proc_tags:
            try:
                procs = self.comm.waveforms.get_metadata_processed_for_station(
                    event_name, tag, station_id)
            except LASIFNotFoundError:
                continue
            comps = get_components(procs)
            if not comps:
                continue
            all_files["processed"][tag] = comps

        iterations = self.comm.waveforms.get_available_synthetics(event_name)
        synthetic_coordinates_mapping = {
            "X": "N",
            "Y": "E",
            "Z": "Z",
            "N": "N",
            "E": "E"
        }
        for it in iterations:
            try:
                its = self.comm.waveforms.get_metadata_synthetic_for_station(
                    event_name, it, station_id)
            except LASIFNotFoundError:
                continue
            comps = get_components(its)
            if not comps:
                continue
            comps = [synthetic_coordinates_mapping[i] for i in comps]
            all_files["synthetic"][it] = sorted(comps, reverse=True)
        return all_files
Esempio n. 28
0
 def get(self, model_name):
     model_dir = os.path.join(self._folder, model_name)
     if not os.path.exists(model_dir) or not os.path.isdir(model_dir):
         raise LASIFNotFoundError("Model '%s' not known." % model_name)
     return model_dir
Esempio n. 29
0
    def select_windows_for_station(self, event, iteration, station, **kwargs):
        """
        Selects windows for the given event, iteration, and station. Will
        delete any previously existing windows for that station if any.

        :param event: The event.
        :param iteration: The iteration.
        :param station: The station id in the form NET.STA.
        """
        from lasif.utils import select_component_from_stream

        # Load project specific window selection function.
        select_windows = self.comm.project.get_project_function(
            "window_picking_function")

        event = self.comm.events.get(event)
        iteration = self.comm.iterations.get(iteration)
        data = self.comm.query.get_matching_waveforms(event, iteration,
                                                      station)

        process_params = iteration.get_process_params()
        minimum_period = 1.0 / process_params["lowpass"]
        maximum_period = 1.0 / process_params["highpass"]

        window_group_manager = self.comm.windows.get(event, iteration)
        # Delete the windows for this stations.
        window_group_manager.delete_windows_for_station(station)

        found_something = False
        for component in ["E", "N", "Z"]:
            try:
                data_tr = select_component_from_stream(data.data, component)
                synth_tr = select_component_from_stream(
                    data.synthetics, component)
            except LASIFNotFoundError:
                continue
            found_something = True

            windows = select_windows(data_tr,
                                     synth_tr,
                                     event["latitude"],
                                     event["longitude"],
                                     event["depth_in_km"],
                                     data.coordinates["latitude"],
                                     data.coordinates["longitude"],
                                     minimum_period=minimum_period,
                                     maximum_period=maximum_period,
                                     iteration=iteration,
                                     **kwargs)
            if not windows:
                continue

            window_group = window_group_manager.get(data_tr.id)
            for starttime, endtime in windows:
                window_group.add_window(starttime=starttime, endtime=endtime)
            window_group.write()

        if found_something is False:
            raise LASIFNotFoundError(
                "No matching data found for event '%s', iteration '%s', and "
                "station '%s'." %
                (event["event_name"], iteration.name, station))