Ejemplo n.º 1
0
def model_prediction_sensitivity(engine, *args, **kwargs):
    '''
    Calculate the model prediction Covariance Sensitivity Kernel.
    (numerical derivation with respect to the input source parameter(s))
    Following Duputel et al. 2014

    :Input:
    :py:class:'engine'
    source_parms = list of parameters with respect to which the kernel
                   is being calculated e.g. ['strike', 'dip', 'depth']
    !!!
    NEEDS to have seismosizer source object parameter variable name convention
    !!!
    (see seismosizer.source.keys())

    calculate_model_prediction_sensitivity(request, source_params, **kwargs)
    calculate_model_prediction_sensitivity(sources,
                                             targets, source_params, **kwargs)

    Returns traces in a list[parameter][targets] for each station and channel
    as specified in the targets. The location code of each trace is placed to
    show the respective source parameter.
    '''

    if len(args) not in (0, 1, 2, 3):
        raise gf.BadRequest('invalid arguments')

    if len(args) == 2:
        kwargs['request'] = args[0]
        kwargs['source_params'] = args[1]

    elif len(args) == 3:
        kwargs.update(gf.Request.args2kwargs(args[0:1]))
        kwargs['source_params'] = args[2]

    request = kwargs.pop('request', None)
    nprocs = kwargs.pop('nprocs', 1)
    source_params = kwargs.pop('source_params', None)
    h = kwargs.pop('h', None)

    if request is None:
        request = gf.Request(**kwargs)

    if h is None:
        h = num.ones(len(source_params)) * 1e-1

    # create results list
    sensitivity_param_list = []
    sensitivity_param_trcs = []

    for i in xrange(len(source_params)):
        sensitivity_param_list.append([0] * len(request.targets))
        sensitivity_param_trcs.append([0] * len(request.targets))

    for ref_source in request.sources:
        par_count = 0
        for param in source_params:
            print param, 'with h = ', h[par_count]
            calc_source_p2h = ref_source.clone()
            calc_source_ph = ref_source.clone()
            calc_source_mh = ref_source.clone()
            calc_source_m2h = ref_source.clone()

            setattr(calc_source_p2h, param,
                    ref_source[param] + (2 * h[par_count]))
            setattr(calc_source_ph, param, ref_source[param] + (h[par_count]))
            setattr(calc_source_mh, param, ref_source[param] - (h[par_count]))
            setattr(calc_source_m2h, param,
                    ref_source[param] - (2 * h[par_count]))

            calc_sources = [
                calc_source_p2h, calc_source_ph, calc_source_mh,
                calc_source_m2h
            ]

            response = engine.process(sources=calc_sources,
                                      targets=request.targets,
                                      nprocs=nprocs)

            for k in xrange(len(request.targets)):
                # zero padding if necessary
                trc_lengths = num.array(
                    [len(response.results_list[i][k].trace.data) for i in \
                                        range(len(response.results_list))])
                Id = num.where(trc_lengths != trc_lengths.max())

                for l in Id[0]:
                    response.results_list[l][k].trace.data = num.concatenate(
                        (response.results_list[l][k].trace.data,
                         num.zeros(trc_lengths.max() - trc_lengths[l])))

                # calculate numerical partial derivative for
                # each source and target
                sensitivity_param_list[par_count][k] = (
                        sensitivity_param_list[par_count][k] + (\
                            - response.results_list[0][k].trace.data + \
                            8 * response.results_list[1][k].trace.data - \
                            8 * response.results_list[2][k].trace.data + \
                                response.results_list[3][k].trace.data) / \
                            (12 * h[par_count])
                                                       )

            par_count = par_count + 1

    # form traces from sensitivities
    par_count = 0
    for param in source_params:
        for k in xrange(len(request.targets)):
            sensitivity_param_trcs[par_count][k] = trace.Trace(
                network=request.targets[k].codes[0],
                station=request.targets[k].codes[1],
                ydata=sensitivity_param_list[par_count][k],
                deltat=response.results_list[0][k].trace.deltat,
                tmin=response.results_list[0][k].trace.tmin,
                channel=request.targets[k].codes[3],
                location=param)

        par_count = par_count + 1

    return sensitivity_param_trcs
Ejemplo n.º 2
0
    def call(self):
        '''Main work routine of the snuffling.'''
        self.cleanup()

        # get time range visible in viewer
        viewer = self.get_viewer()

        event = viewer.get_active_event()
        if event:
            event, stations = self.get_active_event_and_stations(
                missing='warn')
        else:
            # event = model.Event(lat=self.lat, lon=self.lon)
            event = model.Event(lat=0., lon=0.)
            stations = []

        stations = self.get_stations()

        s2c = {}
        for traces in self.chopper_selected_traces(fallback=True,
                                                   mode='visible'):
            for tr in traces:
                net, sta, loc, cha = tr.nslc_id
                ns = net, sta
                if ns not in s2c:
                    s2c[ns] = set()

                s2c[ns].add((loc, cha))

        if not stations:
            stations = []
            for (lat, lon) in [(5., 0.), (-5., 0.)]:
                s = model.Station(station='(%g, %g)' % (lat, lon),
                                  lat=lat,
                                  lon=lon)
                stations.append(s)
                viewer.add_stations(stations)

        for s in stations:
            ns = s.nsl()[:2]
            if ns not in s2c:
                s2c[ns] = set()

            for cha in 'NEZ':
                s2c[ns].add(('', cha))

        source = gf.RectangularSource(time=event.time + self.time,
                                      lat=event.lat,
                                      lon=event.lon,
                                      north_shift=self.north_km * km,
                                      east_shift=self.east_km * km,
                                      depth=self.depth_km * km,
                                      magnitude=self.magnitude,
                                      strike=self.strike,
                                      dip=self.dip,
                                      rake=self.rake,
                                      length=self.length,
                                      width=self.width,
                                      nucleation_x=self.nucleation_x,
                                      velocity=self.velocity,
                                      stf=self.get_stf())

        source.regularize()

        m = EventMarker(source.pyrocko_event())
        self.add_marker(m)

        targets = []

        if self.store_id == '<not loaded yet>':
            self.fail('Select a GF Store first')

        for station in stations:

            nsl = station.nsl()
            if nsl[:2] not in s2c:
                continue

            for loc, cha in s2c[nsl[:2]]:

                target = gf.Target(codes=(station.network, station.station,
                                          loc + '-syn', cha),
                                   quantity='displacement',
                                   lat=station.lat,
                                   lon=station.lon,
                                   depth=station.depth,
                                   store_id=self.store_id,
                                   optimization='enable',
                                   interpolation='nearest_neighbor')

                _, bazi = source.azibazi_to(target)

                if cha.endswith('T'):
                    dip = 0.
                    azi = bazi + 270.
                elif cha.endswith('R'):
                    dip = 0.
                    azi = bazi + 180.
                elif cha.endswith('1'):
                    dip = 0.
                    azi = 0.
                elif cha.endswith('2'):
                    dip = 0.
                    azi = 90.
                else:
                    dip = None
                    azi = None

                target.azimuth = azi
                target.dip = dip

                targets.append(target)

        req = gf.Request(sources=[source], targets=targets)

        req.regularize()

        try:
            resp = self.get_engine().process(req)
        except (gf.meta.OutOfBounds, gf.store_ext.StoreExtError) as e:
            self.fail(e)

        traces = resp.pyrocko_traces()

        if self.waveform_type.startswith('Velocity'):
            for tr in traces:
                tr.set_ydata(num.diff(tr.ydata) / tr.deltat)

        elif self.waveform_type.startswith('Acceleration'):
            for tr in traces:
                tr.set_ydata(num.diff(num.diff(tr.ydata)) / tr.deltat**2)

        if self.waveform_type.endswith('[nm]') or \
                self.waveform_type.endswith('[nm/s]') or \
                self.waveform_type.endswith('[nm/s^2]'):

            for tr in traces:
                tr.set_ydata(tr.ydata * 1e9)

        self.add_traces(traces)