Esempio n. 1
0
class ToyProblem(Problem):
    problem_parameters = [
        Parameter('north', 'm', label='North'),
        Parameter('east', 'm', label='East'),
        Parameter('depth', 'm', label='Depth')
    ]

    ranges = Dict.T(String.T(), gf.Range.T())

    targets = List.T(ToyTarget.T())
    base_source = ToySource.T()

    def __init__(self, **kwargs):
        Problem.__init__(self, **kwargs)
        self._xtargets = None
        self._obs_distances = None

    def pack(self, source):
        return num.array([source.north, source.east, source.depth],
                         dtype=num.float)

    def _setup_modelling(self):
        if self._xtargets is None:
            self._xtargets = num.array([(t.north, t.east, t.depth)
                                        for t in self.targets],
                                       dtype=num.float)

            self._obs_distances = num.array(
                [t.obs_distance for t in self.targets], dtype=num.float)

    def misfits(self, x, mask=None):
        self._setup_modelling()
        distances = num.sqrt(
            num.sum((x[num.newaxis, :] - self._xtargets)**2, axis=1))

        misfits = num.zeros((self.ntargets, 2))
        misfits[:, 0] = num.abs(distances - self._obs_distances)
        misfits[:, 1] = num.ones(self.ntargets) \
            * num.mean(num.abs(self._obs_distances))
        return misfits

    def misfits_many(self, xs):
        self._setup_modelling()
        distances = num.sqrt(
            num.sum(
                (xs[:, num.newaxis, :] - self._xtargets[num.newaxis, :])**2,
                axis=2))

        misfits = num.zeros((xs.shape[0], self.ntargets, 2))

        misfits[:, :,
                0] = num.abs(distances - self._obs_distances[num.newaxis, :])

        misfits[:, :, 1] = num.mean(num.abs(self._obs_distances))

        return misfits

    def xref(self):
        base_source = self.base_source
        return num.array(
            [base_source.north, base_source.east, base_source.depth])

    def extract(self, xs, i):
        if xs.ndim == 1:
            return self.extract(xs[num.newaxis, :], i)[0]

        if i < self.nparameters:
            return xs[:, i]
        else:
            return self.make_dependant(
                xs, self.dependants[i - self.nparameters].name)
Esempio n. 2
0
    def testOptionalDefault(self):

        from pyrocko.guts_array import Array, array_equal
        import numpy as num
        assert_ae = num.testing.assert_almost_equal

        def array_equal_noneaware(a, b):
            if a is None:
                return b is None
            elif b is None:
                return a is None
            else:
                return array_equal(a, b)

        data = [
            ('a', Int.T(), [None, 0, 1, 2], ['aerr', 0, 1, 2]),
            ('b', Int.T(optional=True), [None, 0, 1, 2], [None, 0, 1, 2]),
            ('c', Int.T(default=1), [None, 0, 1, 2], [1, 0, 1, 2]),
            ('d', Int.T(default=1, optional=True), [None, 0, 1,
                                                    2], [1, 0, 1, 2]),
            ('e', List.T(Int.T()), [None, [], [1], [2]], [[], [], [1], [2]]),
            ('f', List.T(Int.T(), optional=True), [None, [], [1],
                                                   [2]], [None, [], [1], [2]]),
            ('g', List.T(Int.T(), default=[1]), [None, [], [1], [2]], [[1], [],
                                                                       [1],
                                                                       [2]]),
            ('h', List.T(Int.T(), default=[1],
                         optional=True), [None, [], [1], [2]], [[1], [], [1],
                                                                [2]]),
            ('i', Tuple.T(2, Int.T()), [None, (1, 2)], ['err', (1, 2)]),
            ('j', Tuple.T(2, Int.T(),
                          optional=True), [None, (1, 2)], [None, (1, 2)]),
            ('k', Tuple.T(2, Int.T(),
                          default=(1, 2)), [None, (1, 2), (3, 4)], [(1, 2),
                                                                    (1, 2),
                                                                    (3, 4)]),
            ('l', Tuple.T(2, Int.T(), default=(1, 2),
                          optional=True), [None, (1, 2), (3, 4)], [(1, 2),
                                                                   (1, 2),
                                                                   (3, 4)]),
            ('i2', Tuple.T(None, Int.T()), [None, (1, 2)], [(), (1, 2)]),
            ('j2', Tuple.T(None, Int.T(),
                           optional=True), [None, (),
                                            (3, 4)], [None, (), (3, 4)]),
            ('k2', Tuple.T(None, Int.T(), default=(1, )), [None, (),
                                                           (3, 4)], [(1, ), (),
                                                                     (3, 4)]),
            ('l2', Tuple.T(None, Int.T(), default=(1, ),
                           optional=True), [None, (), (3, 4)], [(1, ), (),
                                                                (3, 4)]),
            ('m', Array.T(shape=(None, ), dtype=num.int, serialize_as='list'),
             [num.arange(0), num.arange(2)], [num.arange(0),
                                              num.arange(2)]),
            ('n',
             Array.T(shape=(None, ),
                     dtype=num.int,
                     serialize_as='list',
                     optional=True), [None, num.arange(0),
                                      num.arange(2)],
             [None, num.arange(0), num.arange(2)]),
            ('o',
             Array.T(shape=(None, ),
                     dtype=num.int,
                     serialize_as='list',
                     default=num.arange(2)),
             [None, num.arange(0),
              num.arange(2), num.arange(3)
              ], [num.arange(2),
                  num.arange(0),
                  num.arange(2),
                  num.arange(3)]),
            ('p',
             Array.T(shape=(None, ),
                     dtype=num.int,
                     serialize_as='list',
                     default=num.arange(2),
                     optional=True),
             [None, num.arange(0),
              num.arange(2), num.arange(3)
              ], [num.arange(2),
                  num.arange(0),
                  num.arange(2),
                  num.arange(3)]),
            ('q', Dict.T(String.T(), Int.T()), [None, {}, {
                'a': 1
            }], [{}, {}, {
                'a': 1
            }]),
            ('r', Dict.T(String.T(), Int.T(),
                         optional=True), [None, {}, {
                             'a': 1
                         }], [None, {}, {
                             'a': 1
                         }]),
            ('s', Dict.T(String.T(), Int.T(),
                         default={'a': 1}), [None, {}, {
                             'a': 1
                         }], [{
                             'a': 1
                         }, {}, {
                             'a': 1
                         }]),
            ('t', Dict.T(String.T(), Int.T(), default={'a': 1},
                         optional=True), [None, {}, {
                             'a': 1
                         }], [{
                             'a': 1
                         }, {}, {
                             'a': 1
                         }]),
        ]

        for k, t, vals, exp, in data:
            last = [None]

            class A(Object):
                def __init__(self, **kwargs):
                    last[0] = len(kwargs)
                    Object.__init__(self, **kwargs)

                v = t

            A.T.class_signature()

            for v, e in zip(vals, exp):
                if isinstance(e, str) and e == 'aerr':
                    with self.assertRaises(ArgumentError):
                        if v is not None:
                            a1 = A(v=v)
                        else:
                            a1 = A()

                    continue
                else:
                    if v is not None:
                        a1 = A(v=v)
                    else:
                        a1 = A()

                if isinstance(e, str) and e == 'err':
                    with self.assertRaises(ValidationError):
                        a1.validate()
                else:
                    a1.validate()
                    a2 = load_string(dump(a1))
                    if isinstance(e, num.ndarray):
                        assert last[0] == int(not (array_equal_noneaware(
                            t.default(), a1.v) and t.optional))
                        assert_ae(a1.v, e)
                        assert_ae(a1.v, e)
                    else:
                        assert last[0] == int(not (
                            t.default() == a1.v and t.optional))
                        self.assertEqual(a1.v, e)
                        self.assertEqual(a2.v, e)
Esempio n. 3
0
class results_dict(Object):
    medians = Dict.T(String.T(), Float.T())
    means = Dict.T(String.T(), Float.T())
    st_devs = Dict.T(String.T(), Float.T())
    n_ev = Dict.T(String.T(), Int.T())
Esempio n. 4
0
class GNSSCampaignMisfitResult(MisfitResult):
    """Carries the observations for a target and corresponding synthetics. """
    statics_syn = Dict.T(optional=True,
                         help='Synthetic gnss surface displacements')
    statics_obs = Dict.T(optional=True,
                         help='Observed gnss surface displacements')
Esempio n. 5
0
 class Y(Object):
     xs = Dict.T(X.T(), X.T(), default={X(a=2): X(a=3)})
Esempio n. 6
0
class PolygonMaskConfig(PluginConfig):
    polygons = Dict.T(optional=True, default={})
    applied = Bool.T(default=True)
Esempio n. 7
0
class Event(Location):
    '''Seismic event representation

    :param lat: latitude of hypocenter (default 0.0)
    :param lon: longitude of hypocenter (default 0.0)
    :param time: origin time as float in seconds after '1970-01-01 00:00:00
    :param name: event identifier as string (optional)
    :param depth: source depth (optional)
    :param magnitude: magnitude of event (optional)
    :param region: source region (optional)
    :param catalog: name of catalog that lists this event (optional)
    :param moment_tensor: moment tensor as
        :py:class:`moment_tensor.MomentTensor` instance (optional)
    :param duration: source duration as float (optional)
    :param tags: list of tags describing event (optional)
    :param extras: dictionary for user defined event attributes (optional).
        Keys must be strings, values must be YAML serializable.
    '''

    time = Timestamp.T(default=util.str_to_time('1970-01-01 00:00:00'))
    depth = Float.T(optional=True)
    name = String.T(default='', optional=True, yamlstyle="'")
    magnitude = Float.T(optional=True)
    magnitude_type = String.T(optional=True, yamlstyle="'")
    region = Unicode.T(optional=True, yamlstyle="'")
    catalog = String.T(optional=True, yamlstyle="'")
    moment_tensor = moment_tensor.MomentTensor.T(optional=True)
    duration = Float.T(optional=True)
    tags = List.T(Tag.T(), default=[])
    extras = Dict.T(String.T(), Any.T(), default={})

    def __init__(self,
                 lat=0.,
                 lon=0.,
                 north_shift=0.,
                 east_shift=0.,
                 time=0.,
                 name='',
                 depth=None,
                 elevation=None,
                 magnitude=None,
                 magnitude_type=None,
                 region=None,
                 load=None,
                 loadf=None,
                 catalog=None,
                 moment_tensor=None,
                 duration=None,
                 tags=None,
                 extras=None):

        if tags is None:
            tags = []

        if extras is None:
            extras = {}

        vals = None
        if load is not None:
            vals = Event.oldload(load)
        elif loadf is not None:
            vals = Event.oldloadf(loadf)

        if vals:
            lat, lon, north_shift, east_shift, time, name, depth, magnitude, \
                magnitude_type, region, catalog, moment_tensor, duration, \
                tags = vals

        Location.__init__(self,
                          lat=lat,
                          lon=lon,
                          north_shift=north_shift,
                          east_shift=east_shift,
                          time=time,
                          name=name,
                          depth=depth,
                          elevation=elevation,
                          magnitude=magnitude,
                          magnitude_type=magnitude_type,
                          region=region,
                          catalog=catalog,
                          moment_tensor=moment_tensor,
                          duration=duration,
                          tags=tags,
                          extras=extras)

    def time_as_string(self):
        return util.time_to_str(self.time)

    def set_name(self, name):
        self.name = name

    def olddump(self, filename):
        file = open(filename, 'w')
        self.olddumpf(file)
        file.close()

    def olddumpf(self, file):
        if self.extras:
            raise EventExtrasDumpError(
                'Event user-defined extras attributes cannot be dumped in the '
                '"basic" event file format. Use '
                'dump_events(..., format="yaml").')

        file.write('name = %s\n' % self.name)
        file.write('time = %s\n' % util.time_to_str(self.time))

        if self.lat != 0.0:
            file.write('latitude = %.12g\n' % self.lat)
        if self.lon != 0.0:
            file.write('longitude = %.12g\n' % self.lon)

        if self.north_shift != 0.0:
            file.write('north_shift = %.12g\n' % self.north_shift)
        if self.east_shift != 0.0:
            file.write('east_shift = %.12g\n' % self.east_shift)

        if self.magnitude is not None:
            file.write('magnitude = %g\n' % self.magnitude)
            file.write('moment = %g\n' %
                       moment_tensor.magnitude_to_moment(self.magnitude))
        if self.magnitude_type is not None:
            file.write('magnitude_type = %s\n' % self.magnitude_type)
        if self.depth is not None:
            file.write('depth = %.10g\n' % self.depth)
        if self.region is not None:
            file.write('region = %s\n' % self.region)
        if self.catalog is not None:
            file.write('catalog = %s\n' % self.catalog)
        if self.moment_tensor is not None:
            m = self.moment_tensor.m()
            sdr1, sdr2 = self.moment_tensor.both_strike_dip_rake()
            file.write(
                ('mnn = %g\nmee = %g\nmdd = %g\nmne = %g\nmnd = %g\nmed = %g\n'
                 'strike1 = %g\ndip1 = %g\nrake1 = %g\n'
                 'strike2 = %g\ndip2 = %g\nrake2 = %g\n') %
                ((m[0, 0], m[1, 1], m[2, 2], m[0, 1], m[0, 2], m[1, 2]) +
                 sdr1 + sdr2))

        if self.duration is not None:
            file.write('duration = %g\n' % self.duration)

        if self.tags:
            file.write('tags = %s\n' % ', '.join(self.tags))

    @staticmethod
    def unique(events,
               deltat=10.,
               group_cmp=(lambda a, b: cmp(a.catalog, b.catalog))):
        groups = Event.grouped(events, deltat)

        events = []
        for group in groups:
            if group:
                group.sort(group_cmp)
                events.append(group[-1])

        return events

    @staticmethod
    def grouped(events, deltat=10.):
        events = list(events)
        groups = []
        for ia, a in enumerate(events):
            groups.append([])
            haveit = False
            for ib, b in enumerate(events[:ia]):
                if abs(b.time - a.time) < deltat:
                    groups[ib].append(a)
                    haveit = True
                    break

            if not haveit:
                groups[ia].append(a)

        groups = [g for g in groups if g]
        groups.sort(key=lambda g: sum(e.time for e in g) // len(g))
        return groups

    @staticmethod
    def dump_catalog(events, filename=None, stream=None):
        if filename is not None:
            file = open(filename, 'w')
        else:
            file = stream
        try:
            i = 0
            for ev in events:

                ev.olddumpf(file)

                file.write('--------------------------------------------\n')
                i += 1

        finally:
            if filename is not None:
                file.close()

    @staticmethod
    def oldload(filename):
        with open(filename, 'r') as file:
            return Event.oldloadf(file)

    @staticmethod
    def oldloadf(file):
        d = {}
        try:
            for line in file:
                if line.lstrip().startswith('#'):
                    continue

                toks = line.split(' = ', 1)
                if len(toks) == 2:
                    k, v = toks[0].strip(), toks[1].strip()
                    if k in ('name', 'region', 'catalog', 'magnitude_type'):
                        d[k] = v
                    if k in (('latitude longitude magnitude depth duration '
                              'north_shift east_shift '
                              'mnn mee mdd mne mnd med strike1 dip1 rake1 '
                              'strike2 dip2 rake2 duration').split()):
                        d[k] = float(v)
                    if k == 'time':
                        d[k] = util.str_to_time(v)
                    if k == 'tags':
                        d[k] = [x.strip() for x in v.split(',')]

                if line.startswith('---'):
                    d['have_separator'] = True
                    break

        except Exception as e:
            raise FileParseError(e)

        if not d:
            raise EOF()

        if 'have_separator' in d and len(d) == 1:
            raise EmptyEvent()

        mt = None
        m6 = [d[x] for x in 'mnn mee mdd mne mnd med'.split() if x in d]
        if len(m6) == 6:
            mt = moment_tensor.MomentTensor(m=moment_tensor.symmat6(*m6))
        else:
            sdr = [d[x] for x in 'strike1 dip1 rake1'.split() if x in d]
            if len(sdr) == 3:
                moment = 1.0
                if 'moment' in d:
                    moment = d['moment']
                elif 'magnitude' in d:
                    moment = moment_tensor.magnitude_to_moment(d['magnitude'])

                mt = moment_tensor.MomentTensor(strike=sdr[0],
                                                dip=sdr[1],
                                                rake=sdr[2],
                                                scalar_moment=moment)

        return (d.get('latitude', 0.0), d.get('longitude', 0.0),
                d.get('north_shift', 0.0), d.get('east_shift', 0.0),
                d.get('time', 0.0), d.get('name', ''), d.get('depth', None),
                d.get('magnitude', None), d.get('magnitude_type',
                                                None), d.get('region', None),
                d.get('catalog', None), mt, d.get('duration',
                                                  None), d.get('tags', []))

    @staticmethod
    def load_catalog(filename):

        file = open(filename, 'r')

        try:
            while True:
                try:
                    ev = Event(loadf=file)
                    yield ev
                except EmptyEvent:
                    pass

        except EOF:
            pass

        file.close()

    def get_hash(self):
        e = self
        if isinstance(e.time, util.hpfloat):
            stime = util.time_to_str(e.time, format='%Y-%m-%d %H:%M:%S.6FRAC')
        else:
            stime = util.time_to_str(e.time, format='%Y-%m-%d %H:%M:%S.3FRAC')

        s = float_or_none_to_str

        to_hash = ', '.join((stime, s(e.lat), s(e.lon), s(e.depth),
                             float_or_none_to_str(e.magnitude, 5),
                             str(e.catalog), str(e.name or ''), str(e.region)))

        return ehash(to_hash)

    def human_str(self):
        s = [
            'Latitude [deg]: %g' % self.lat,
            'Longitude [deg]: %g' % self.lon,
            'Time [UTC]: %s' % util.time_to_str(self.time)
        ]

        if self.name:
            s.append('Name: %s' % self.name)

        if self.depth is not None:
            s.append('Depth [km]: %g' % (self.depth / 1000.))

        if self.magnitude is not None:
            s.append('Magnitude [%s]: %3.1f' %
                     (self.magnitude_type or 'M?', self.magnitude))

        if self.region:
            s.append('Region: %s' % self.region)

        if self.catalog:
            s.append('Catalog: %s' % self.catalog)

        if self.moment_tensor:
            s.append(str(self.moment_tensor))

        return '\n'.join(s)
Esempio n. 8
0
class rota_ev_by_stat(Object):
    station = Tuple.T(3, String.T())
    ev_rota = Dict.T(String.T(), Int.T())
Esempio n. 9
0
class IFC(common.HasPaths):
    '''Image function contribution.'''

    name = String.T()
    weight = Float.T(
        default=1.0,
        help='global weight for this IFC')

    weights = Dict.T(
                String.T(help='NSL regular expression identifying stations'),
                Float.T(help='weighting factor'),
                optional=True,
                help='weight selected traces')

    fmin = Float.T()
    fmax = Float.T()
    shifter = shifter.Shifter.T(optional=True)

    trace_selector = TraceSelector.T(
        optional=True, help='select traces to be treated by this IFC')

    def __init__(self, *args, **kwargs):
        common.HasPaths.__init__(self, *args, **kwargs)
        self.shifter.t_tolerance = 1./(self.fmax * 2.)

    def setup(self, config):
        if self.shifter:
            self.shifter.setup(config)

    def get_table(self, grid, receivers):
        return self.shifter.get_table(grid, receivers)

    def get_tpad(self):
        return 4. / self.fmin

    def get_fsmooth(self):
        return self.fmin

    def prescan(self, p):
        pass

    def deltat_cf_is_available(self, deltat_cf):
        return False

    def preprocess(self, trs, wmin, wmax, tpad_new, deltat_cf):
        pass

    def get_weights(self, nsls):
        if self.weights is None:
            return num.ones(len(nsls), dtype=num.float)

        else:
            weights = num.empty(len(nsls))
            selectors = self.weights.keys()
            for insl, nsl in enumerate(nsls):
                weights[insl] = 1.
                for selector in selectors:
                    if util.match_nslc(selector, nsl):
                        weights[insl] = self.weights[selector]
                        break
            return weights
Esempio n. 10
0
class VersionInfo(Object):
    grond_version = String.T(yamlstyle="'")
    dependencies = Dict.T(String.T(), String.T(yamlstyle="'"))
Esempio n. 11
0
class dict_stats_rota(Object):
    CorrectAngl_perStat_median = Dict.T(String.T(), Float.T())
    CorrectAngl_perStat_mean = Dict.T(String.T(), Float.T())
    CorrectAngl_perStat_stdd = Dict.T(String.T(), Float.T())
    n_events = Dict.T(String.T(), Int.T())
Esempio n. 12
0
class Problem(Object):
    '''
    Base class for objective function setup.

    Defines the *problem* to be solved by the optimiser.
    '''
    name = String.T()
    ranges = Dict.T(String.T(), gf.Range.T())
    dependants = List.T(Parameter.T())
    norm_exponent = Int.T(default=2)
    base_source = gf.Source.T(optional=True)
    targets = List.T(MisfitTarget.T())
    target_groups = List.T(TargetGroup.T())
    grond_version = String.T(optional=True)
    nthreads = Int.T(default=1)

    def __init__(self, **kwargs):
        Object.__init__(self, **kwargs)

        if self.grond_version is None:
            self.grond_version = __version__

        self._target_weights = None
        self._engine = None
        self._family_mask = None

        if hasattr(self, 'problem_waveform_parameters') and self.has_waveforms:
            self.problem_parameters =\
                self.problem_parameters + self.problem_waveform_parameters

        self.check()

    @classmethod
    def get_plot_classes(cls):
        from . import plot
        return plot.get_plot_classes()

    def check(self):
        paths = set()
        for grp in self.target_groups:
            if grp.path == 'all':
                continue
            if grp.path in paths:
                raise ValueError('Path %s defined more than once! In %s'
                                 % (grp.path, grp.__class__.__name__))
            paths.add(grp.path)
        logger.debug('TargetGroup check OK.')

    def copy(self):
        o = copy.copy(self)
        o._target_weights = None
        return o

    def set_target_parameter_values(self, x):
        nprob = len(self.problem_parameters)
        for target in self.targets:
            target.set_parameter_values(x[nprob:nprob+target.nparameters])
            nprob += target.nparameters

    def get_parameter_dict(self, model, group=None):
        params = []
        for ip, p in enumerate(self.parameters):
            if group in p.groups or group is None:
                params.append((p.name, model[ip]))
        return ADict(params)

    def get_parameter_array(self, d):
        arr = num.zeros(self.nparameters, dtype=num.float)
        for ip, p in enumerate(self.parameters):
            if p.name in d.keys():
                arr[ip] = d[p.name]
        return arr

    def dump_problem_info(self, dirname):
        fn = op.join(dirname, 'problem.yaml')
        util.ensuredirs(fn)
        guts.dump(self, filename=fn)

    def dump_problem_data(
            self, dirname, x, misfits, chains=None,
            sampler_context=None):

        fn = op.join(dirname, 'models')
        if not isinstance(x, num.ndarray):
            x = num.array(x)
        with open(fn, 'ab') as f:
            x.astype('<f8').tofile(f)

        fn = op.join(dirname, 'misfits')
        with open(fn, 'ab') as f:
            misfits.astype('<f8').tofile(f)

        if chains is not None:
            fn = op.join(dirname, 'chains')
            with open(fn, 'ab') as f:
                chains.astype('<f8').tofile(f)

        if sampler_context is not None:
            fn = op.join(dirname, 'choices')
            with open(fn, 'ab') as f:
                num.array(sampler_context, dtype='<i8').tofile(f)

    def name_to_index(self, name):
        pnames = [p.name for p in self.combined]
        return pnames.index(name)

    @property
    def parameters(self):
        target_parameters = []
        for target in self.targets:
            target_parameters.extend(target.target_parameters)
        return self.problem_parameters + target_parameters

    @property
    def parameter_names(self):
        return [p.name for p in self.combined]

    @property
    def dependant_names(self):
        return [p.name for p in self.dependants]

    @property
    def nparameters(self):
        return len(self.parameters)

    @property
    def ntargets(self):
        return len(self.targets)

    @property
    def nwaveform_targets(self):
        return len(self.waveform_targets)

    @property
    def nsatellite_targets(self):
        return len(self.satellite_targets)

    @property
    def ngnss_targets(self):
        return len(self.gnss_targets)

    @property
    def nmisfits(self):
        nmisfits = 0
        for target in self.targets:
            nmisfits += target.nmisfits
        return nmisfits

    @property
    def ndependants(self):
        return len(self.dependants)

    @property
    def ncombined(self):
        return len(self.parameters) + len(self.dependants)

    @property
    def combined(self):
        return self.parameters + self.dependants

    @property
    def satellite_targets(self):
        return [t for t in self.targets
                if isinstance(t, SatelliteMisfitTarget)]

    @property
    def gnss_targets(self):
        return [t for t in self.targets
                if isinstance(t, GNSSCampaignMisfitTarget)]

    @property
    def waveform_targets(self):
        return [t for t in self.targets
                if isinstance(t, WaveformMisfitTarget)]

    @property
    def has_satellite(self):
        if self.satellite_targets:
            return True
        return False

    @property
    def has_waveforms(self):
        if self.waveform_targets:
            return True
        return False

    def set_engine(self, engine):
        self._engine = engine

    def get_engine(self):
        return self._engine

    def get_gf_store(self, target):
        if self.get_engine() is None:
            raise GrondError('Cannot get GF Store, modelling is not set up!')
        return self.get_engine().get_store(target.store_id)

    def random_uniform(self, xbounds, rstate, fixed_magnitude=None):
        if fixed_magnitude is not None:
            raise GrondError(
                'Setting fixed magnitude in random model generation not '
                'supported for this type of problem.')

        x = rstate.uniform(0., 1., self.nparameters)
        x *= (xbounds[:, 1] - xbounds[:, 0])
        x += xbounds[:, 0]
        return x

    def preconstrain(self, x):
        return x

    def extract(self, xs, i):
        if xs.ndim == 1:
            return self.extract(xs[num.newaxis, :], i)[0]

        if i < self.nparameters:
            return xs[:, i]
        else:
            return self.make_dependant(
                xs, self.dependants[i-self.nparameters].name)

    def get_target_weights(self):
        if self._target_weights is None:
            self._target_weights = num.concatenate(
               [target.get_combined_weight() for target in self.targets])

        return self._target_weights

    def get_target_residuals(self):
        pass

    def inter_family_weights(self, ns):
        exp, root = self.get_norm_functions()

        family, nfamilies = self.get_family_mask()

        ws = num.zeros(self.nmisfits)
        for ifamily in range(nfamilies):
            mask = family == ifamily
            ws[mask] = 1.0 / root(num.nansum(exp(ns[mask])))

        return ws

    def inter_family_weights2(self, ns):
        '''
        :param ns: 2D array with normalization factors ``ns[imodel, itarget]``
        :returns: 2D array ``weights[imodel, itarget]``
        '''

        exp, root = self.get_norm_functions()
        family, nfamilies = self.get_family_mask()

        ws = num.zeros(ns.shape)
        for ifamily in range(nfamilies):
            mask = family == ifamily
            ws[:, mask] = (1.0 / root(
                num.nansum(exp(ns[:, mask]), axis=1)))[:, num.newaxis]

        return ws

    def get_reference_model(self):
        model = num.zeros(self.nparameters)
        model_source_params = self.pack(self.base_source)
        model[:model_source_params.size] = model_source_params
        return model

    def get_parameter_bounds(self):
        out = []
        for p in self.problem_parameters:
            r = self.ranges[p.name]
            out.append((r.start, r.stop))

        for target in self.targets:
            for p in target.target_parameters:
                r = target.target_ranges[p.name_nogroups]
                out.append((r.start, r.stop))

        return num.array(out, dtype=num.float)

    def get_dependant_bounds(self):
        return num.zeros((0, 2))

    def get_combined_bounds(self):
        return num.vstack((
            self.get_parameter_bounds(),
            self.get_dependant_bounds()))

    def raise_invalid_norm_exponent(self):
        raise GrondError('Invalid norm exponent: %f' % self.norm_exponent)

    def get_norm_functions(self):
        if self.norm_exponent == 2:
            def sqr(x):
                return x**2

            return sqr, num.sqrt

        elif self.norm_exponent == 1:
            def noop(x):
                return x

            return noop, num.abs

        else:
            self.raise_invalid_norm_exponent()

    def combine_misfits(
            self, misfits,
            extra_weights=None,
            extra_residuals=None,
            extra_correlated_weights=dict(),
            get_contributions=False):

        '''
        Combine misfit contributions (residuals) to global or bootstrap misfits

        :param misfits: 3D array ``misfits[imodel, iresidual, 0]`` are the
            misfit contributions (residuals) ``misfits[imodel, iresidual, 1]``
            are the normalisation contributions. It is also possible to give
            the misfit and normalisation contributions for a single model as
            ``misfits[iresidual, 0]`` and misfits[iresidual, 1]`` in which
            case, the first dimension (imodel) of the result will be stipped
            off.

        :param extra_weights: if given, 2D array of extra weights to be applied
            to the contributions, indexed as
            ``extra_weights[ibootstrap, iresidual]``.

        :param extra_residuals: if given, 2D array of perturbations to be added
            to the residuals, indexed as
            ``extra_residuals[ibootstrap, iresidual]``.

        :param extra_correlated_weights: if a dictionary of
            ``imisfit: correlated weight matrix`` is passed a correlated
            weight matrix is applied to the misfit and normalisation values.
            `imisfit` is the starting index in the misfits vector the
            correlated weight matrix applies to.

        :param get_contributions: get the weighted and perturbed contributions
            (don't do the sum).

        :returns: if no *extra_weights* or *extra_residuals* are given, a 1D
            array indexed as ``misfits[imodel]`` containing the global misfit
            for each model is returned, otherwise a 2D array
            ``misfits[imodel, ibootstrap]`` with the misfit for every model and
            weighting/residual set is returned.
        '''
        if misfits.ndim == 2:
            misfits = misfits[num.newaxis, :, :]
            return self.combine_misfits(
                misfits, extra_weights, extra_residuals,
                extra_correlated_weights, get_contributions)[0, ...]

        if extra_weights is None and extra_residuals is None:
            return self.combine_misfits(
                misfits, False, False,
                extra_correlated_weights, get_contributions)[:, 0]

        assert misfits.ndim == 3
        assert not num.any(extra_weights) or extra_weights.ndim == 2
        assert not num.any(extra_residuals) or extra_residuals.ndim == 2

        if self.norm_exponent != 2 and extra_correlated_weights:
            raise GrondError('Correlated weights can only be used '
                             ' with norm_exponent=2')

        exp, root = self.get_norm_functions()

        nmodels = misfits.shape[0]
        nmisfits = misfits.shape[1]  # noqa

        mf = misfits[:, num.newaxis, :, :].copy()

        if num.any(extra_residuals):
            mf = mf + extra_residuals[num.newaxis, :, :, num.newaxis]

        res = mf[..., 0]
        norms = mf[..., 1]

        for imisfit, corr_weight_mat in extra_correlated_weights.items():

            jmisfit = imisfit + corr_weight_mat.shape[0]

            for imodel in range(nmodels):
                corr_res = res[imodel, :, imisfit:jmisfit]
                corr_norms = norms[imodel, :, imisfit:jmisfit]

                res[imodel, :, imisfit:jmisfit] = \
                    correlated_weights(corr_res, corr_weight_mat)

                norms[imodel, :, imisfit:jmisfit] = \
                    correlated_weights(corr_norms, corr_weight_mat)

        # Apply normalization family weights (these weights depend on
        # on just calculated correlated norms!)
        weights_fam = \
            self.inter_family_weights2(norms[:, 0, :])[:, num.newaxis, :]

        weights_fam = exp(weights_fam)

        res = exp(res)
        norms = exp(norms)

        res *= weights_fam
        norms *= weights_fam

        weights_tar = self.get_target_weights()[num.newaxis, num.newaxis, :]
        if num.any(extra_weights):
            weights_tar = weights_tar * extra_weights[num.newaxis, :, :]

        weights_tar = exp(weights_tar)

        res = res * weights_tar
        norms = norms * weights_tar

        if get_contributions:
            return res / num.nansum(norms, axis=2)[:, :, num.newaxis]

        result = root(
            num.nansum(res, axis=2) /
            num.nansum(norms, axis=2))

        assert result[result < 0].size == 0
        return result

    def make_family_mask(self):
        family_names = set()
        families = num.zeros(self.nmisfits, dtype=num.int)

        idx = 0
        for itarget, target in enumerate(self.targets):
            family_names.add(target.normalisation_family)
            families[idx:idx + target.nmisfits] = len(family_names) - 1
            idx += target.nmisfits

        return families, len(family_names)

    def get_family_mask(self):
        if self._family_mask is None:
            self._family_mask = self.make_family_mask()

        return self._family_mask

    def evaluate(self, x, mask=None, result_mode='full', targets=None,
                 nthreads=0):
        source = self.get_source(x)
        engine = self.get_engine()

        self.set_target_parameter_values(x)

        if mask is not None and targets is not None:
            raise ValueError('Mask cannot be defined with targets set.')
        targets = targets if targets is not None else self.targets

        for target in targets:
            target.set_result_mode(result_mode)

        modelling_targets = []
        t2m_map = {}
        for itarget, target in enumerate(targets):
            t2m_map[target] = target.prepare_modelling(engine, source, targets)
            if mask is None or mask[itarget]:
                modelling_targets.extend(t2m_map[target])

        u2m_map = {}
        for imtarget, mtarget in enumerate(modelling_targets):
            if mtarget not in u2m_map:
                u2m_map[mtarget] = []

            u2m_map[mtarget].append(imtarget)

        modelling_targets_unique = list(u2m_map.keys())

        resp = engine.process(source, modelling_targets_unique,
                              nthreads=nthreads)
        modelling_results_unique = list(resp.results_list[0])

        modelling_results = [None] * len(modelling_targets)

        for mtarget, mresult in zip(
                modelling_targets_unique, modelling_results_unique):

            for itarget in u2m_map[mtarget]:
                modelling_results[itarget] = mresult

        imt = 0
        results = []
        for itarget, target in enumerate(targets):
            nmt_this = len(t2m_map[target])
            if mask is None or mask[itarget]:
                result = target.finalize_modelling(
                    engine, source,
                    t2m_map[target],
                    modelling_results[imt:imt+nmt_this])

                imt += nmt_this
            else:
                result = gf.SeismosizerError(
                    'target was excluded from modelling')

            results.append(result)

        return results

    def misfits(self, x, mask=None, nthreads=0):
        results = self.evaluate(
            x, mask=mask, result_mode='sparse', nthreads=nthreads)
        misfits = num.full((self.nmisfits, 2), num.nan)

        imisfit = 0
        for target, result in zip(self.targets, results):
            if isinstance(result, MisfitResult):
                misfits[imisfit:imisfit+target.nmisfits, :] = result.misfits

            imisfit += target.nmisfits

        return misfits

    def forward(self, x):
        source = self.get_source(x)
        engine = self.get_engine()

        plain_targets = []
        for target in self.targets:
            plain_targets.extend(target.get_plain_targets(engine, source))

        resp = engine.process(source, plain_targets)

        results = []
        for target, result in zip(plain_targets, resp.results_list[0]):
            if isinstance(result, gf.SeismosizerError):
                logger.debug(
                    '%s.%s.%s.%s: %s' % (target.codes + (str(result),)))
            else:
                results.append(result)

        return results

    def get_random_model(self, ntries_limit=100):
        xbounds = self.get_parameter_bounds()

        for _ in range(ntries_limit):
            x = self.random_uniform(xbounds, rstate=g_rstate)
            try:
                return self.preconstrain(x)

            except Forbidden:
                pass

        raise GrondError(
            'Could not find any suitable candidate sample within %i tries' % (
                ntries_limit))
Esempio n. 13
0
class BeamForming(Object):
    station_c = Station.T(optional=True)
    bazi = Float.T()
    slow = Float.T()
    diff_dt_treat = String.T(help='how to handle differing sampling rates:'
                             ' oversample(default) or downsample')
    normalize_std = Bool.T()
    post_normalize = Bool.T()
    t_shifts = Dict.T(String.T(), Float.T())

    def __init__(self,
                 stations,
                 traces,
                 normalize=True,
                 post_normalize=False,
                 diff_dt_treat='oversample'):
        self.stations = stations
        self.c_lat_lon_z = self.center_lat_lon(stations)
        self.traces = traces
        self.diff_dt_treat = diff_dt_treat
        self.normalize_std = normalize
        self.post_normalize = post_normalize
        self.station_c = None
        self.diff_dt_treat = diff_dt_treat

    def process(self,
                event,
                timing,
                bazi=None,
                slow=None,
                restitute=False,
                *args,
                **kwargs):
        '''
      :param timing: CakeTiming. Uses the definition without the offset.
      :param fn_dump_center: filename to where center stations shall be dumped
      :param fn_beam: filename of beam trace
      :param model: earthmodel to use(optional)
      :param earthmodel to use(optional)
      :param network: network code(optional)
      :param station: station code(optional)
        '''
        logger.debug('start beam forming')
        stations = self.stations
        network_code = kwargs.get('responses', None)
        network_code = kwargs.get('network', '')
        station_code = kwargs.get('station', 'STK')
        c_station_id = (network_code, station_code)

        lat_c, lon_c, z_c = self.c_lat_lon_z

        self.station_c = Station(lat=float(lat_c),
                                 lon=float(lon_c),
                                 elevation=float(z_c),
                                 depth=0.,
                                 name='Array Center',
                                 network=c_station_id[0],
                                 station=c_station_id[1][:5])
        fn_dump_center = kwargs.get('fn_dump_center', 'array_center.pf')
        fn_beam = kwargs.get('fn_beam', 'beam.mseed')
        if event:
            mod = cake.load_model(crust2_profile=(event.lat, event.lon))
            dist = ortho.distance_accurate50m(event, self.station_c)
            ray = timing.t(mod, (event.depth, dist), get_ray=True)
            if ray is None:
                logger.error(
                    'None of defined phases available at beam station:\n %s' %
                    self.station_c)
                return
            else:
                b = ortho.azimuth(self.station_c, event)
                if b >= 0.:
                    self.bazi = b
                elif b < 0.:
                    self.bazi = 360. + b
                self.slow = ray.p / (cake.r2d * cake.d2m)
        else:
            self.bazi = bazi
            self.slow = slow

        logger.info(
            'stacking %s with slowness %1.4f s/km at back azimut %1.1f '
            'degrees' %
            ('.'.join(c_station_id), self.slow * cake.km, self.bazi))

        lat0 = num.array([lat_c] * len(stations))
        lon0 = num.array([lon_c] * len(stations))
        lats = num.array([s.lat for s in stations])
        lons = num.array([s.lon for s in stations])
        ns, es = ortho.latlon_to_ne_numpy(lat0, lon0, lats, lons)
        theta = num.float(self.bazi * num.pi / 180.)
        R = num.array([[num.cos(theta), -num.sin(theta)],
                       [num.sin(theta), num.cos(theta)]])
        distances = R.dot(num.vstack((es, ns)))[1]
        channels = set()
        self.stacked = {}
        num_stacked = {}
        self.t_shifts = {}
        self.shifted_traces = []
        taperer = trace.CosFader(xfrac=0.05)
        if self.diff_dt_treat == 'downsample':
            self.traces.sort(key=lambda x: x.deltat)
        elif self.diff_dt_treat == 'oversample':
            dts = [t.deltat for t in self.traces]
            for tr in self.traces:
                tr.resample(min(dts))

        for tr in self.traces:
            if tr.nslc_id[:2] == c_station_id:
                continue
            tr = tr.copy(data=True)
            tr.ydata = tr.ydata.astype(
                num.float64) - tr.ydata.mean(dtype=num.float64)
            tr.taper(taperer)
            try:
                stack_trace = self.stacked[tr.channel]
                num_stacked[tr.channel] += 1
            except KeyError:
                stack_trace = tr.copy(data=True)
                stack_trace.set_ydata(num.zeros(len(stack_trace.get_ydata())))

                stack_trace.set_codes(network=c_station_id[0],
                                      station=c_station_id[1],
                                      location='',
                                      channel=tr.channel)

                self.stacked[tr.channel] = stack_trace
                channels.add(tr.channel)
                num_stacked[tr.channel] = 1

            nslc_id = tr.nslc_id

            try:
                stats = filter(
                    lambda x: util.match_nslc('%s.%s.%s.*' % x.nsl(), nslc_id),
                    stations)

                stat = stats[0]
            except IndexError:
                break

            i = stations.index(stat)
            d = distances[i]
            t_shift = d * self.slow
            tr.shift(t_shift)
            #stat = viewer.get_station(tr.nslc_id[:2])
            self.t_shifts[tr.nslc_id[:2]] = t_shift
            if self.normalize_std:
                tr.ydata = tr.ydata / tr.ydata.std()

            if num.abs(tr.deltat - stack_trace.deltat) > 0.000001:
                if self.diff_dt_treat == 'downsample':
                    stack_trace.downsample_to(tr.deltat)
                elif self.diff_dt_treat == 'upsample':
                    raise Exception(
                        'something went wrong with the upsampling, previously')
            stack_trace.add(tr)

            #tr.set_station('%s_s' % tr.station)
            self.shifted_traces.append(tr)

        if self.post_normalize:
            for ch, tr in self.stacked.items():
                tr.set_ydata(tr.get_ydata() / num_stacked[ch])
        #for ch, tr in self.stacked.items():
        #    if num_stacked[ch]>1:
        #        self.add_trace(tr)
        self.save_station(fn_dump_center)
        self.checked_nslc([stack_trace])
        self.save(stack_trace, fn_beam)
        #trace.snuffle(self.shifted_traces)
        return self.shifted_traces

    def checked_nslc(self, trs):
        for tr in trs:
            oldids = tr.nslc_id
            n, s, l, c = oldids
            tr.set_codes(network=n[:2],
                         station=s[:5],
                         location=l[:2],
                         channel=c[:3])
            newids = tr.nslc_id
            if cmp(oldids, newids) != 0:
                logger.warn('nslc id truncated: %s to %s' %
                            ('.'.join(oldids), '.'.join(newids)))

    def snuffle(self):
        '''Scrutinize the shifted traces.'''
        from pyrocko import snuffler
        snuffler.snuffle(self.shifted_traces)

    def center_lat_lon(self, stations):
        '''Calculate a mean geographical centre of the array
        using spherical earth'''

        lats = num.zeros(len(stations))
        lons = num.zeros(len(stations))
        elevations = num.zeros(len(stations))
        depths = num.zeros(len(stations))
        for i, s in enumerate(stations):
            lats[i] = s.lat * torad
            lons[i] = s.lon * torad
            depths[i] = s.depth
            elevations[i] = s.elevation

        z = num.mean(elevations - depths)
        return (lats.mean() * 180 / num.pi, lons.mean() * 180 / num.pi, z)

    def plot(self, fn='beam_shifts.png'):
        stations = self.stations
        stations.append(self.station_c)
        res = to_cartesian(stations, self.station_c)
        center_xyz = res[self.station_c.nsl()[:2]]
        x = num.zeros(len(res))
        y = num.zeros(len(res))
        z = num.zeros(len(res))
        sizes = num.zeros(len(res))
        stat_labels = []
        i = 0
        for nsl, xyz in res.items():
            x[i] = xyz[0]
            y[i] = xyz[1]
            z[i] = xyz[2]

            try:
                sizes[i] = self.t_shifts[nsl[:2]]
                stat_labels.append('%s' % ('.'.join(nsl)))
            except AttributeError:
                self.fail('Run the snuffling first')
            except KeyError:
                stat_labels.append('%s' % ('.'.join(nsl)))
                continue
            finally:
                i += 1

        x /= 1000.
        y /= 1000.
        z /= 1000.
        xmax = x.max()
        xmin = x.min()
        ymax = y.max()
        ymin = y.min()

        fig = plt.figure()
        cax = fig.add_axes([0.85, 0.2, 0.05, 0.5])
        ax = fig.add_axes([0.10, 0.1, 0.70, 0.7])
        ax.set_aspect('equal')
        cmap = cm.get_cmap('bwr')
        ax.scatter(x,
                   y,
                   c=sizes,
                   s=200,
                   cmap=cmap,
                   vmax=num.max(sizes),
                   vmin=-num.max(sizes))
        for i, lab in enumerate(stat_labels):
            ax.text(x[i], y[i], lab, size=14)

        x = x[num.where(sizes == 0.)]
        y = y[num.where(sizes == 0.)]
        ax.scatter(x, y, c='black', alpha=0.4, s=200)

        ax.arrow(center_xyz[0] / 1000.,
                 center_xyz[1] / 1000.,
                 -num.sin(self.bazi / 180. * num.pi),
                 -num.cos(self.bazi / 180. * num.pi),
                 head_width=0.2,
                 head_length=0.2)
        ax.set_ylabel("N-S [km]")
        ax.set_xlabel("E-W [km]")
        ColorbarBase(cax,
                     cmap=cmap,
                     norm=Normalize(vmin=sizes.min(), vmax=sizes.max()))
        logger.debug('finished plotting %s' % fn)
        fig.savefig(fn)

    def save(self, traces, fn='beam.pf'):
        io.save(traces, fn)

    def save_station(self, fn):
        dump_stations([self.station_c], fn)
Esempio n. 14
0
class ProblemConfig(Object):
    """
    Config for inversion problem to setup.
    """
    mode = String.T(default='geometry',
                    help='Problem to solve: "geometry", "static","kinematic"')
    n_faults = Int.T(default=1, help='Number of Sub-faults to solve for')
    datasets = List.T(default=['geodetic'])
    hyperparameters = Dict.T(
        help='Hyperparameters to weight different types of datasets.')
    priors = List.T(Parameter.T())

    def init_vars(self):

        variables = self.select_variables()

        self.priors = []
        for variable in variables:
            self.priors.append(
                Parameter(
                    name=variable,
                    lower=num.ones(self.n_faults, dtype=num.float) * \
                        default_bounds[variable][0],
                    upper=num.ones(self.n_faults, dtype=num.float) * \
                        default_bounds[variable][1],
                    testvalue=num.ones(self.n_faults, dtype=num.float) * \
                        num.mean(default_bounds[variable]))
                               )

    def select_variables(self):
        """
        Return model variables depending on problem config.
        """

        if self.mode not in modes:
            raise ValueError('Problem mode %s not implemented' % self.mode)

        if self.mode == 'geometry':
            if 'geodetic' in self.datasets:
                variables = geo_vars_geometry
            if 'seismic' in self.datasets:
                variables = joint_vars_geometry

        elif self.mode == 'static':
            variables = static_dist_vars

        elif self.mode == 'kinematic':
            variables = kinematic_dist_vars
            if 'seismic' not in self.datasets:
                logger.error('A kinematic model cannot be resolved with'
                             'geodetic data only.')
                raise Exception('Kinematic model not resolvable with only'
                                'geodetic data!')

        return variables

    def validate_priors(self):
        """
        Check if priors and their test values do not contradict!
        """
        for param in self.priors:
            param()

        logger.info('All parameter-priors ok!')

    def validate_hypers(self):
        """
        Check if hyperparameters and their test values do not contradict!
        """
        if self.hyperparameters is not None:
            for hp in self.hyperparameters.itervalues():
                hp()

            logger.info('All hyper-parameters ok!')

        else:
            logger.info('No hyper-parameters defined!')
Esempio n. 15
0
class dict_stats(Object):
    """
    Dict for all stations + their flat freq ranges
    """
    FlatFreqRanges = Dict.T(String.T(), List.T(Tuple.T(2, Float.T())))
    MeanMedianR_FlatRanges = Dict.T(String.T(), List.T(Float.T()))
Esempio n. 16
0
class Gains(Object):
    trace_gains_mean = Dict.T(String.T(), Float.T())
    trace_gains_median = Dict.T(String.T(), Float.T())
    trace_gains_stdev = Dict.T(String.T(), Float.T())
    n_ev_used = Dict.T(String.T(), Int.T())
    ref_stats = String.T(optional=True)
Esempio n. 17
0
class ProblemConfig(Object):
    """
    Config for optimization problem to setup.
    """
    mode = StringChoice.T(
        choices=['geometry', 'static', 'kinematic', 'interseismic'],
        default='geometry',
        help='Problem to solve: "geometry", "static", "kinematic",'
        ' "interseismic"',
    )
    source_type = StringChoice.T(
        default='RectangularSource',
        choices=source_names,
        help='Source type to optimize for. Options: %s' %
        (', '.join(name for name in source_names)))
    stf_type = StringChoice.T(
        default='HalfSinusoid',
        choices=stf_names,
        help='Source time function type to use. Options: %s' %
        (', '.join(name for name in stf_names)))
    decimation_factors = Dict.T(
        default=None,
        optional=True,
        help='Determines the reduction of discretization of an extended'
        ' source.')
    n_sources = Int.T(default=1, help='Number of Sub-sources to solve for')
    datatypes = List.T(default=['geodetic'])
    hyperparameters = Dict.T(
        help='Hyperparameters to weight different types of datatypes.')
    priors = Dict.T(help='Priors of the variables in question.')

    def init_vars(self, variables=None):
        """
        Initiate priors based on the problem mode and datatypes.

        Parameters
        ----------
        variables : list
            of str of variable names to initialise
        """
        if variables is None:
            variables = self.select_variables()

        self.priors = OrderedDict()
        for variable in variables:
            if variable in block_vars:
                nvars = 1
            else:
                nvars = self.n_sources

            lower = default_bounds[variable][0]
            upper = default_bounds[variable][1]
            self.priors[variable] = \
                Parameter(
                    name=variable,
                    lower=num.ones(
                        nvars,
                        dtype=tconfig.floatX) * lower,
                    upper=num.ones(
                        nvars,
                        dtype=tconfig.floatX) * upper,
                    testvalue=num.ones(
                        nvars,
                        dtype=tconfig.floatX) * (lower + (upper / 5.)))

    def select_variables(self):
        """
        Return model variables depending on problem config.
        """

        if self.mode not in modes_catalog.keys():
            raise ValueError('Problem mode %s not implemented' % self.mode)

        vars_catalog = modes_catalog[self.mode]

        variables = []
        for datatype in self.datatypes:
            if datatype in vars_catalog.keys():
                if self.mode == 'geometry':
                    if self.source_type in vars_catalog[datatype].keys():
                        source = vars_catalog[datatype][self.source_type]
                        svars = set(source.keys())

                        if isinstance(source(),
                                      (PyrockoRS, gf.ExplosionSource)):
                            svars.discard('magnitude')

                        variables += utility.weed_input_rvs(
                            svars, self.mode, datatype)
                    else:
                        raise ValueError('Source Type not supported for type'
                                         ' of problem, and datatype!')

                    if datatype == 'seismic':
                        if self.stf_type in stf_catalog.keys():
                            stf = stf_catalog[self.stf_type]
                            variables += utility.weed_input_rvs(
                                set(stf.keys()), self.mode, datatype)
                else:
                    variables += vars_catalog[datatype]
            else:
                raise ValueError(
                    'Datatype %s not supported for type of'
                    ' problem! Supported datatype are: %s' %
                    (datatype, ', '.join('"%s"' % d
                                         for d in vars_catalog.keys())))

        unique_variables = utility.unique_list(variables)

        if len(unique_variables) == 0:
            raise Exception('Mode and datatype combination not implemented'
                            ' or not resolvable with given datatypes.')

        return unique_variables

    def set_decimation_factor(self):
        """
        Determines the reduction of discretization of an extended source.
        Influences yet only the RectangularSource.
        """
        if self.source_type == 'RectangularSource':
            self.decimation_factors = {}
            for datatype in self.datatypes:
                self.decimation_factors[datatype] = \
                    default_decimation_factors[datatype]
        else:
            self.decimation_factors = None

    def validate_priors(self):
        """
        Check if priors and their test values do not contradict!
        """
        for param in self.priors.itervalues():
            param.validate_bounds()

        logger.info('All parameter-priors ok!')

    def validate_hypers(self):
        """
        Check if hyperparameters and their test values do not contradict!
        """
        if self.hyperparameters is not None:
            for hp in self.hyperparameters.itervalues():
                hp.validate_bounds()

            logger.info('All hyper-parameters ok!')

        else:
            logger.info('No hyper-parameters defined!')
Esempio n. 18
0
class Map(Object):
    lat = Float.T(optional=True)
    lon = Float.T(optional=True)
    radius = Float.T(optional=True)
    width = Float.T(default=20.)
    height = Float.T(default=14.)
    margins = List.T(Float.T())
    illuminate = Bool.T(default=True)
    skip_feature_factor = Float.T(default=0.02)
    show_grid = Bool.T(default=False)
    show_topo = Bool.T(default=True)
    show_topo_scale = Bool.T(default=False)
    show_center_mark = Bool.T(default=False)
    show_rivers = Bool.T(default=True)
    illuminate_factor_land = Float.T(default=0.5)
    illuminate_factor_ocean = Float.T(default=0.25)
    color_wet = Tuple.T(3, Int.T(), default=(216, 242, 254))
    color_dry = Tuple.T(3, Int.T(), default=(172, 208, 165))
    topo_resolution_min = Float.T(
        default=40., help='minimum resolution of topography [dpi]')
    topo_resolution_max = Float.T(
        default=200., help='maximum resolution of topography [dpi]')
    replace_topo_color_only = FloatTile.T(
        optional=True,
        help='replace topo color while keeping topographic shading')
    topo_cpt_wet = String.T(default='light_sea')
    topo_cpt_dry = String.T(default='light_land')
    axes_layout = String.T(optional=True)
    custom_cities = List.T(City.T())
    gmt_config = Dict.T(String.T(), String.T())
    comment = String.T(optional=True)

    def __init__(self, **kwargs):
        Object.__init__(self, **kwargs)
        self._gmt = None
        self._scaler = None
        self._widget = None
        self._corners = None
        self._wesn = None
        self._minarea = None
        self._coastline_resolution = None
        self._rivers = None
        self._dems = None
        self._have_topo_land = None
        self._have_topo_ocean = None
        self._jxyr = None
        self._prep_topo_have = None
        self._labels = []

    def save(self,
             outpath,
             resolution=75.,
             oversample=2.,
             size=None,
             width=None,
             height=None):
        '''Save the image.

        Save the image to *outpath*. The format is determined by the filename
        extension. Formats are handled as follows: ``'.eps'`` and ``'.ps'``
        produce EPS and PS, respectively, directly with GMT. If the file name
        ends with ``'.pdf'``, GMT output is fed through ``gmtpy-epstopdf`` to
        create a PDF file. For any other filename extension, output is first
        converted to PDF with ``gmtpy-epstopdf``, then with ``pdftocairo`` to
        PNG with a resolution oversampled by the factor *oversample* and
        finally the PNG is downsampled and converted to the target format with
        ``convert``. The resolution of rasterized target image can be
        controlled either by *resolution* in DPI or by specifying *width* or
        *height* or *size*, where the latter fits the image into a square with
        given side length.'''

        gmt = self.gmt
        self.draw_labels()
        self.draw_axes()
        if self.show_topo and self.show_topo_scale:
            self._draw_topo_scale()

        gmt = self._gmt
        if outpath.endswith('.eps'):
            tmppath = gmt.tempfilename() + '.eps'
        elif outpath.endswith('.ps'):
            tmppath = gmt.tempfilename() + '.ps'
        else:
            tmppath = gmt.tempfilename() + '.pdf'

        gmt.save(tmppath)

        if any(outpath.endswith(x) for x in ('.eps', '.ps', '.pdf')):
            shutil.copy(tmppath, outpath)
        else:
            convert_graph(tmppath,
                          outpath,
                          resolution=resolution,
                          oversample=oversample,
                          size=size,
                          width=width,
                          height=height)

    @property
    def scaler(self):
        if self._scaler is None:
            self._setup_geometry()

        return self._scaler

    @property
    def wesn(self):
        if self._wesn is None:
            self._setup_geometry()

        return self._wesn

    @property
    def widget(self):
        if self._widget is None:
            self._setup()

        return self._widget

    @property
    def layout(self):
        if self._layout is None:
            self._setup()

        return self._layout

    @property
    def jxyr(self):
        if self._jxyr is None:
            self._setup()

        return self._jxyr

    @property
    def pxyr(self):
        if self._pxyr is None:
            self._setup()

        return self._pxyr

    @property
    def gmt(self):
        if self._gmt is None:
            self._setup()

        if self._have_topo_ocean is None:
            self._draw_background()

        return self._gmt

    def _setup(self):
        if not self._widget:
            self._setup_geometry()

        self._setup_lod()
        self._setup_gmt()

    def _setup_geometry(self):
        wpage, hpage = self.width, self.height
        ml, mr, mt, mb = self._expand_margins()
        wpage -= ml + mr
        hpage -= mt + mb

        wreg = self.radius * 2.0
        hreg = self.radius * 2.0
        if wpage >= hpage:
            wreg *= wpage / hpage
        else:
            hreg *= hpage / wpage

        self._corners = corners(self.lon, self.lat, wreg, hreg)
        west, east, south, north = extent(self.lon, self.lat, wreg, hreg, 10)

        x, y, z = ((west, east), (south, north), (-6000., 4500.))

        xax = gmtpy.Ax(mode='min-max', approx_ticks=4.)
        yax = gmtpy.Ax(mode='min-max', approx_ticks=4.)
        zax = gmtpy.Ax(mode='min-max',
                       inc=1000.,
                       label='Height',
                       scaled_unit='km',
                       scaled_unit_factor=0.001)

        scaler = gmtpy.ScaleGuru(data_tuples=[(x, y, z)], axes=(xax, yax, zax))

        par = scaler.get_params()

        west = par['xmin']
        east = par['xmax']
        south = par['ymin']
        north = par['ymax']

        self._wesn = west, east, south, north
        self._scaler = scaler

    def _setup_lod(self):
        w, e, s, n = self._wesn
        if self.radius > 1500. * km:
            coastline_resolution = 'i'
            rivers = False
        else:
            coastline_resolution = 'f'
            rivers = True

        self._minarea = (self.skip_feature_factor * self.radius / km)**2

        self._coastline_resolution = coastline_resolution
        self._rivers = rivers

        self._prep_topo_have = {}
        self._dems = {}

        cm2inch = gmtpy.cm / gmtpy.inch

        dmin = 2.0 * self.radius * m2d / (self.topo_resolution_max *
                                          (self.height * cm2inch))
        dmax = 2.0 * self.radius * m2d / (self.topo_resolution_min *
                                          (self.height * cm2inch))

        for k in ['ocean', 'land']:
            self._dems[k] = topo.select_dem_names(k, dmin, dmax, self._wesn)
            if self._dems[k]:
                logger.debug('using topography dataset %s for %s' %
                             (','.join(self._dems[k]), k))

    def _expand_margins(self):
        if len(self.margins) == 0 or len(self.margins) > 4:
            ml = mr = mt = mb = 2.0
        elif len(self.margins) == 1:
            ml = mr = mt = mb = self.margins[0]
        elif len(self.margins) == 2:
            ml = mr = self.margins[0]
            mt = mb = self.margins[1]
        elif len(self.margins) == 4:
            ml, mr, mt, mb = self.margins

        return ml, mr, mt, mb

    def _setup_gmt(self):
        w, h = self.width, self.height
        scaler = self._scaler

        gmtconf = dict(TICK_PEN='1.25p',
                       TICK_LENGTH='0.2c',
                       ANNOT_FONT_PRIMARY='1',
                       ANNOT_FONT_SIZE_PRIMARY='12p',
                       LABEL_FONT='1',
                       LABEL_FONT_SIZE='12p',
                       CHAR_ENCODING='ISOLatin1+',
                       BASEMAP_TYPE='fancy',
                       PLOT_DEGREE_FORMAT='D',
                       PAPER_MEDIA='Custom_%ix%i' %
                       (w * gmtpy.cm, h * gmtpy.cm),
                       GRID_PEN_PRIMARY='thinnest/0/50/0',
                       DOTS_PR_INCH='1200',
                       OBLIQUE_ANNOTATION='6')

        gmtconf.update(
            (k.upper(), v) for (k, v) in self.gmt_config.iteritems())

        gmt = gmtpy.GMT(config=gmtconf)

        layout = gmt.default_layout()

        layout.set_fixed_margins(*[x * cm for x in self._expand_margins()])

        widget = layout.get_widget()
        # widget['J'] = ('-JT%g/%g' % (self.lon, self.lat)) + '/%(width)gp'
        # widget['J'] = ('-JA%g/%g' % (self.lon, self.lat)) + '/%(width)gp'
        widget['P'] = widget['J']
        widget['J'] = ('-JA%g/%g' % (self.lon, self.lat)) + '/%(width_m)gm'
        # widget['J'] = ('-JE%g/%g' % (self.lon, self.lat)) + '/%(width)gp'
        # scaler['R'] = '-R%(xmin)g/%(xmax)g/%(ymin)g/%(ymax)g'
        scaler['R'] = '-R%g/%g/%g/%gr' % self._corners

        aspect = gmtpy.aspect_for_projection(*(widget.J() + scaler.R()))
        widget.set_aspect(aspect)

        self._gmt = gmt
        self._layout = layout
        self._widget = widget
        self._jxyr = self._widget.JXY() + self._scaler.R()
        self._pxyr = self._widget.PXY() + [
            '-R%g/%g/%g/%g' % (0, widget.width(), 0, widget.height())
        ]
        self._have_drawn_axes = False
        self._have_drawn_labels = False

    def _draw_background(self):
        self._have_topo_land = False
        self._have_topo_ocean = False
        if self.show_topo:
            self._have_topo = self._draw_topo()

        self._draw_basefeatures()

    def _get_topo_tile(self, k):
        t = None
        demname = None
        for dem in self._dems[k]:
            t = topo.get(dem, self._wesn)
            demname = dem
            if t is not None:
                break

        if not t:
            raise NoTopo()

        return t, demname

    def _prep_topo(self, k):
        gmt = self._gmt
        t, demname = self._get_topo_tile(k)

        if demname not in self._prep_topo_have:

            grdfile = gmt.tempfilename()
            gmtpy.savegrd(t.x(),
                          t.y(),
                          t.data,
                          filename=grdfile,
                          naming='lonlat')

            if self.illuminate:
                if k == 'ocean':
                    factor = self.illuminate_factor_ocean
                else:
                    factor = self.illuminate_factor_land

                ilumfn = gmt.tempfilename()
                gmt.grdgradient(grdfile,
                                N='e%g' % factor,
                                A=-45,
                                G=ilumfn,
                                out_discard=True)

                ilumargs = ['-I%s' % ilumfn]
            else:
                ilumargs = []

            if self.replace_topo_color_only:
                t2 = self.replace_topo_color_only
                grdfile2 = gmt.tempfilename()

                gmtpy.savegrd(t2.x(),
                              t2.y(),
                              t2.data,
                              filename=grdfile2,
                              naming='lonlat')

                gmt.grdsample(grdfile2,
                              G=grdfile,
                              Q='l',
                              I='%g/%g' % (t.dx, t.dy),
                              R=grdfile,
                              out_discard=True)

                gmt.grdmath(grdfile,
                            '0.0',
                            'AND',
                            '=',
                            grdfile2,
                            out_discard=True)

                grdfile = grdfile2

            self._prep_topo_have[demname] = grdfile, ilumargs

        return self._prep_topo_have[demname]

    def _draw_topo(self):
        widget = self._widget
        scaler = self._scaler
        gmt = self._gmt
        cres = self._coastline_resolution
        minarea = self._minarea

        JXY = widget.JXY()
        R = scaler.R()

        try:
            grdfile, ilumargs = self._prep_topo('ocean')
            gmt.pscoast(D=cres, S='c', A=minarea, *(JXY + R))
            gmt.grdimage(grdfile,
                         C=topo.cpt(self.topo_cpt_wet),
                         *(ilumargs + JXY + R))
            gmt.pscoast(Q=True, *(JXY + R))
            self._have_topo_ocean = True
        except NoTopo:
            self._have_topo_ocean = False

        try:
            grdfile, ilumargs = self._prep_topo('land')
            gmt.pscoast(D=cres, G='c', A=minarea, *(JXY + R))
            gmt.grdimage(grdfile,
                         C=topo.cpt(self.topo_cpt_dry),
                         *(ilumargs + JXY + R))
            gmt.pscoast(Q=True, *(JXY + R))
            self._have_topo_land = True
        except NoTopo:
            self._have_topo_land = False

    def _draw_topo_scale(self, label='Elevation [km]'):
        dry = read_cpt(topo.cpt(self.topo_cpt_dry))
        wet = read_cpt(topo.cpt(self.topo_cpt_wet))
        combi = cpt_merge_wet_dry(wet, dry)
        for level in combi.levels:
            level.vmin /= km
            level.vmax /= km

        topo_cpt = self.gmt.tempfilename()
        write_cpt(combi, topo_cpt)

        (w, h), (xo, yo) = self.widget.get_size()
        self.gmt.psscale(
            D='%gp/%gp/%gp/%gph' %
            (xo + 0.5 * w, yo - 2.0 * gmtpy.cm, w, 0.5 * gmtpy.cm),
            C=topo_cpt,
            B='1:%s:' % label)

    def _draw_basefeatures(self):
        gmt = self._gmt
        cres = self._coastline_resolution
        rivers = self._rivers
        minarea = self._minarea

        color_wet = self.color_wet
        color_dry = self.color_dry

        if self.show_rivers and rivers:
            rivers = ['-Ir/0.25p,%s' % gmtpy.color(self.color_wet)]
        else:
            rivers = []

        fill = {}
        if not self._have_topo_land:
            fill['G'] = color_dry

        if not self._have_topo_ocean:
            fill['S'] = color_wet

        gmt.pscoast(D=cres,
                    W='thinnest,%s' %
                    gmtpy.color(darken(gmtpy.color_tup(color_dry))),
                    A=minarea,
                    *(rivers + self._jxyr),
                    **fill)

    def _draw_axes(self):
        gmt = self._gmt
        scaler = self._scaler
        widget = self._widget

        if self.axes_layout is None:
            if self.lat > 0.0:
                axes_layout = 'WSen'
            else:
                axes_layout = 'WseN'
        else:
            axes_layout = self.axes_layout

        scale_km = gmtpy.nice_value(self.radius / 5.) / 1000.

        if self.show_center_mark:
            gmt.psxy(in_rows=[[self.lon, self.lat]],
                     S='c20p',
                     W='2p,black',
                     *self._jxyr)

        if self.show_grid:
            btmpl = ('%(xinc)gg%(xinc)g:%(xlabel)s:/'
                     '%(yinc)gg%(yinc)g:%(ylabel)s:')
        else:
            btmpl = '%(xinc)g:%(xlabel)s:/%(yinc)g:%(ylabel)s:'

        gmt.psbasemap(B=(btmpl % scaler.get_params()) + axes_layout,
                      L=('x%gp/%gp/%g/%g/%gk' %
                         (6. / 7 * widget.width(), widget.height() / 7.,
                          self.lon, self.lat, scale_km)),
                      *self._jxyr)

        if self.comment:
            fontsize = self.gmt.to_points(
                self.gmt.gmt_config['LABEL_FONT_SIZE'])

            _, east, south, _ = self._wesn
            gmt.pstext(in_rows=[[1, 0, fontsize, 0, 0, 'BR', self.comment]],
                       N=True,
                       R=(0, 1, 0, 1),
                       D='%gp/%gp' % (-fontsize * 0.2, fontsize * 0.3),
                       *widget.PXY())

    def draw_axes(self):
        if not self._have_drawn_axes:
            self._draw_axes()
            self._have_drawn_axes = True

    def _have_coastlines(self):
        gmt = self._gmt
        cres = self._coastline_resolution
        minarea = self._minarea

        checkfile = gmt.tempfilename()

        gmt.pscoast(M=True,
                    D=cres,
                    W='thinnest/black',
                    A=minarea,
                    out_filename=checkfile,
                    *self._jxyr)

        with open(checkfile, 'r') as f:
            for line in f:
                ls = line.strip()
                if ls.startswith('#') or ls.startswith('>') or ls == '':
                    continue
                plon, plat = [float(x) for x in ls.split()]
                if point_in_region((plon, plat), self._wesn):
                    return True

        return False

    def project(self, lats, lons):
        onepoint = False
        if isinstance(lats, float) and isinstance(lons, float):
            lats = [lats]
            lons = [lons]
            onepoint = True

        j, _, _, r = self.jxyr
        (xo, yo) = self.widget.get_size()[1]
        f = StringIO()
        self.gmt.mapproject(j, r, in_columns=(lons, lats), out_stream=f, D='p')
        f.seek(0)
        data = num.loadtxt(f, ndmin=2)
        xs, ys = data.T
        if onepoint:
            xs = xs[0]
            ys = ys[0]
        return xs, ys

    def _draw_labels(self):
        if self._labels:
            fontsize = self.gmt.to_points(
                self.gmt.gmt_config['LABEL_FONT_SIZE'])

            n = len(self._labels)

            lons, lats, texts, sx, sy, styles = zip(*self._labels)

            sx = num.array(sx, dtype=num.float)
            sy = num.array(sy, dtype=num.float)

            j, _, _, r = self.jxyr
            f = StringIO()
            self.gmt.mapproject(j,
                                r,
                                in_columns=(lons, lats),
                                out_stream=f,
                                D='p')
            f.seek(0)
            data = num.loadtxt(f, ndmin=2)
            xs, ys = data.T
            dxs = num.zeros(n)
            dys = num.zeros(n)

            g = gmtpy.GMT()
            g.psbasemap('-G0', finish=True, *(j, r))
            l, b, r, t = g.bbox()
            h = (t - b)
            w = (r - l)

            for i in xrange(n):
                g = gmtpy.GMT()
                g.pstext(in_rows=[[0, 0, fontsize, 0, 1, 'BL', texts[i]]],
                         finish=True,
                         R=(0, 1, 0, 1),
                         J='x10p',
                         N=True,
                         **styles[i])

                fn = g.tempfilename()
                g.save(fn)

                (_, stderr) = Popen([
                    'gs', '-q', '-dNOPAUSE', '-dBATCH', '-r720',
                    '-sDEVICE=bbox', fn
                ],
                                    stderr=PIPE).communicate()

                dx, dy = None, None
                for line in stderr.splitlines():
                    if line.startswith('%%HiResBoundingBox:'):
                        l, b, r, t = [float(x) for x in line.split()[-4:]]
                        dx, dy = r - l, t - b

                dxs[i] = dx
                dys[i] = dy

            la = num.logical_and
            anchors_ok = (
                la(xs + sx + dxs < w, ys + sy + dys < h),
                la(xs - sx - dxs > 0., ys - sy - dys > 0.),
                la(xs + sx + dxs < w, ys - sy - dys > 0.),
                la(xs - sx - dxs > 0., ys + sy + dys < h),
            )

            arects = [(xs, ys, xs + sx + dxs, ys + sy + dys),
                      (xs - sx - dxs, ys - sy - dys, xs, ys),
                      (xs, ys - sy - dys, xs + sx + dxs, ys),
                      (xs - sx - dxs, ys, xs, ys + sy + dys)]

            def no_points_in_rect(xs, ys, xmin, ymin, xmax, ymax):
                xx = not num.any(
                    la(la(xmin < xs, xs < xmax), la(ymin < ys, ys < ymax)))
                return xx

            for i in xrange(n):
                for ianch in xrange(4):
                    anchors_ok[ianch][i] &= no_points_in_rect(
                        xs, ys, *[xxx[i] for xxx in arects[ianch]])

            anchor_choices = []
            anchor_take = []
            for i in xrange(n):
                choices = [
                    ianch for ianch in xrange(4) if anchors_ok[ianch][i]
                ]
                anchor_choices.append(choices)
                if choices:
                    anchor_take.append(choices[0])
                else:
                    anchor_take.append(None)

            def roverlaps(a, b):
                return (a[0] < b[2] and b[0] < a[2] and a[1] < b[3]
                        and b[1] < a[3])

            def cost(anchor_take):
                noverlaps = 0
                for i in xrange(n):
                    for j in xrange(n):
                        if i != j:
                            i_take = anchor_take[i]
                            j_take = anchor_take[j]
                            if i_take is None or j_take is None:
                                continue
                            r_i = [xxx[i] for xxx in arects[i_take]]
                            r_j = [xxx[j] for xxx in arects[j_take]]
                            if roverlaps(r_i, r_j):
                                noverlaps += 1

                return noverlaps

            cur_cost = cost(anchor_take)
            imax = 30
            while cur_cost != 0 and imax > 0:
                for i in xrange(n):
                    for t in anchor_choices[i]:
                        anchor_take_new = list(anchor_take)
                        anchor_take_new[i] = t
                        new_cost = cost(anchor_take_new)
                        if new_cost < cur_cost:
                            anchor_take = anchor_take_new
                            cur_cost = new_cost

                imax -= 1

            while cur_cost != 0:
                for i in xrange(n):
                    anchor_take_new = list(anchor_take)
                    anchor_take_new[i] = None
                    new_cost = cost(anchor_take_new)
                    if new_cost < cur_cost:
                        anchor_take = anchor_take_new
                        cur_cost = new_cost
                        break

            anchor_strs = ['BL', 'TR', 'TL', 'BR']

            for i in xrange(n):
                ianchor = anchor_take[i]
                if ianchor is not None:
                    anchor = anchor_strs[ianchor]
                    yoff = [-sy[i], sy[i]][anchor[0] == 'B']
                    xoff = [-sx[i], sx[i]][anchor[1] == 'L']
                    row = (lons[i], lats[i], fontsize, 0, 1, anchor, texts[i])
                    self.gmt.pstext(in_rows=[row],
                                    D='%gp/%gp' % (xoff, yoff),
                                    *self.jxyr,
                                    **styles[i])

    def draw_labels(self):
        if not self._have_drawn_labels:
            self._draw_labels()
            self._have_drawn_labels = True

    def add_label(self, lat, lon, text, offset_x=5., offset_y=5., style={}):
        self._labels.append((lon, lat, text, offset_x, offset_y, style))

    def cities_in_region(self):
        from pyrocko import geonames
        cities = list(
            geonames.load('cities1000.zip',
                          'cities1000.txt',
                          region=self.wesn,
                          minpop=0))

        cities.extend(self.custom_cities)
        cities.sort(key=lambda x: x.population)

        return cities

    def draw_cities(
        self,
        exact=None,
        include=[],
        exclude=['City of London'],  # duplicate entry in geonames
        nmax_soft=10,
        psxy_style=dict(S='s5p', G='black')):

        cities = self.cities_in_region()

        if exact is not None:
            cities = [c for c in cities if c.name in exact]
            minpop = None
        else:
            cities = [c for c in cities if c.name not in exclude]
            minpop = 10**3
            for minpop_new in [1e3, 3e3, 1e4, 3e4, 1e5, 3e5, 1e6, 3e6, 1e7]:
                cities_new = [c for c in cities if c.population > minpop_new]

                if len(cities_new) == 0 or (len(cities_new) < 3
                                            and len(cities) < nmax_soft * 2):
                    break

                cities = cities_new
                minpop = minpop_new
                if len(cities) <= nmax_soft:
                    break

        if cities:
            lats = [c.lat for c in cities]
            lons = [c.lon for c in cities]

            self.gmt.psxy(in_columns=(lons, lats), *self.jxyr, **psxy_style)

            for c in cities:
                try:
                    text = c.name.encode('iso-8859-1')
                except UnicodeEncodeError:
                    text = c.asciiname

                self.add_label(c.lat, c.lon, text)

        self._cities_minpop = minpop
Esempio n. 19
0
class Problem(Object):
    '''
    Base class for objective function setup.

    Defines the *problem* to be solved by the optimiser.
    '''
    name = String.T()
    ranges = Dict.T(String.T(), gf.Range.T())
    dependants = List.T(Parameter.T())
    norm_exponent = Int.T(default=2)
    base_source = gf.Source.T(optional=True)
    targets = List.T(MisfitTarget.T())
    target_groups = List.T(TargetGroup.T())
    grond_version = String.T(optional=True)

    def __init__(self, **kwargs):
        Object.__init__(self, **kwargs)

        if self.grond_version is None:
            self.grond_version = __version__

        self._target_weights = None
        self._engine = None
        self._family_mask = None

        if hasattr(self, 'problem_waveform_parameters') and self.has_waveforms:
            self.problem_parameters =\
                self.problem_parameters + self.problem_waveform_parameters

    @classmethod
    def get_plot_classes(cls):
        from . import plot
        return plot.get_plot_classes()

    def get_engine(self):
        return self._engine

    def copy(self):
        o = copy.copy(self)
        o._target_weights = None
        return o

    def set_target_parameter_values(self, x):
        nprob = len(self.problem_parameters)
        for target in self.targets:
            target.set_parameter_values(x[nprob:nprob + target.nparameters])
            nprob += target.nparameters

    def get_parameter_dict(self, model, group=None):
        params = []
        for ip, p in enumerate(self.parameters):
            if group in p.groups or group is None:
                params.append((p.name, model[ip]))
        return ADict(params)

    def get_parameter_array(self, d):
        arr = num.zeros(self.nparameters, dtype=num.float)
        for ip, p in enumerate(self.parameters):
            if p.name in d.keys():
                arr[ip] = d[p.name]
        return arr

    def dump_problem_info(self, dirname):
        fn = op.join(dirname, 'problem.yaml')
        util.ensuredirs(fn)
        guts.dump(self, filename=fn)

    def dump_problem_data(self,
                          dirname,
                          x,
                          misfits,
                          bootstraps=None,
                          accept=None,
                          ibootstrap_choice=None,
                          ibase=None):

        fn = op.join(dirname, 'models')
        if not isinstance(x, num.ndarray):
            x = num.array(x)
        with open(fn, 'ab') as f:
            x.astype('<f8').tofile(f)

        fn = op.join(dirname, 'misfits')
        with open(fn, 'ab') as f:
            misfits.astype('<f8').tofile(f)

        if bootstraps is not None:
            fn = op.join(dirname, 'bootstraps')
            with open(fn, 'ab') as f:
                bootstraps.astype('<f8').tofile(f)

        if None not in (ibootstrap_choice, ibase):
            fn = op.join(dirname, 'choices')
            with open(fn, 'ab') as f:
                num.array((ibootstrap_choice, ibase), dtype='<i8').tofile(f)

        if accept is not None:
            fn = op.join(dirname, 'accepted')
            with open(fn, 'ab') as f:
                accept.astype('<i1').tofile(f)

    def name_to_index(self, name):
        pnames = [p.name for p in self.combined]
        return pnames.index(name)

    @property
    def parameters(self):
        target_parameters = []
        for target in self.targets:
            target_parameters.extend(target.target_parameters)
        return self.problem_parameters + target_parameters

    @property
    def parameter_names(self):
        return [p.name for p in self.combined]

    @property
    def dependant_names(self):
        return [p.name for p in self.dependants]

    @property
    def nparameters(self):
        return len(self.parameters)

    @property
    def ntargets(self):
        return len(self.targets)

    @property
    def nwaveform_targets(self):
        return len(self.waveform_targets)

    @property
    def nsatellite_targets(self):
        return len(self.satellite_targets)

    @property
    def ngnss_targets(self):
        return len(self.gnss_targets)

    @property
    def nmisfits(self):
        nmisfits = 0
        for target in self.targets:
            nmisfits += target.nmisfits
        return nmisfits

    @property
    def ndependants(self):
        return len(self.dependants)

    @property
    def ncombined(self):
        return len(self.parameters) + len(self.dependants)

    @property
    def combined(self):
        return self.parameters + self.dependants

    @property
    def satellite_targets(self):
        return [
            t for t in self.targets if isinstance(t, SatelliteMisfitTarget)
        ]

    @property
    def gnss_targets(self):
        return [
            t for t in self.targets if isinstance(t, GNSSCampaignMisfitTarget)
        ]

    @property
    def waveform_targets(self):
        return [t for t in self.targets if isinstance(t, WaveformMisfitTarget)]

    @property
    def has_satellite(self):
        if self.satellite_targets:
            return True
        return False

    @property
    def has_waveforms(self):
        if self.waveform_targets:
            return True
        return False

    def set_engine(self, engine):
        self._engine = engine

    def random_uniform(self, xbounds):
        x = num.random.uniform(0., 1., self.nparameters)
        x *= (xbounds[:, 1] - xbounds[:, 0])
        x += xbounds[:, 0]
        return x

    def preconstrain(self, x):
        return x

    def extract(self, xs, i):
        if xs.ndim == 1:
            return self.extract(xs[num.newaxis, :], i)[0]

        if i < self.nparameters:
            return xs[:, i]
        else:
            return self.make_dependant(
                xs, self.dependants[i - self.nparameters].name)

    def get_target_weights(self):
        if self._target_weights is None:
            self._target_weights = num.concatenate(
                [target.get_combined_weight() for target in self.targets])

        return self._target_weights

    def get_target_residuals(self):
        pass

    def inter_family_weights(self, ns):
        exp, root = self.get_norm_functions()

        family, nfamilies = self.get_family_mask()

        ws = num.zeros(self.nmisfits)
        for ifamily in range(nfamilies):
            mask = family == ifamily
            ws[mask] = 1.0 / root(num.nansum(exp(ns[mask])))

        return ws

    def inter_family_weights2(self, ns):
        '''
        :param ns: 2D array with normalization factors ``ns[imodel, itarget]``
        :returns: 2D array ``weights[imodel, itarget]``
        '''

        exp, root = self.get_norm_functions()

        family, nfamilies = self.get_family_mask()
        ws = num.zeros(ns.shape)
        for ifamily in range(nfamilies):
            mask = family == ifamily
            ws[:, mask] = (
                1.0 / root(num.nansum(exp(ns[:, mask]), axis=1)))[:,
                                                                  num.newaxis]
        return ws

    def get_reference_model(self, expand=False):
        if expand:
            src_params = self.pack(self.base_source)
            ref = num.zeros(self.nparameters)
            ref[:src_params.size] = src_params
        else:
            ref = self.pack(self.base_source)
        return ref

    def get_parameter_bounds(self):
        out = []
        for p in self.problem_parameters:
            r = self.ranges[p.name]
            out.append((r.start, r.stop))

        for target in self.targets:
            for p in target.target_parameters:
                r = target.target_ranges[p.name_nogroups]
                out.append((r.start, r.stop))

        return num.array(out, dtype=num.float)

    def get_dependant_bounds(self):
        return num.zeros((0, 2))

    def get_combined_bounds(self):
        return num.vstack(
            (self.get_parameter_bounds(), self.get_dependant_bounds()))

    def raise_invalid_norm_exponent(self):
        raise GrondError('invalid norm exponent' % self.norm_exponent)

    def get_norm_functions(self):
        if self.norm_exponent == 2:

            def sqr(x):
                return x**2

            return sqr, num.sqrt

        elif self.norm_exponent == 1:

            def noop(x):
                return x

            return noop, num.abs

        else:
            self.raise_invalid_norm_exponent()

    def combine_misfits(self,
                        misfits,
                        extra_weights=None,
                        extra_residuals=None,
                        get_contributions=False):
        '''
        Combine misfit contributions (residuals) to global or bootstrap misfits

        :param misfits: 3D array ``misfits[imodel, iresidual, 0]`` are the
            misfit contributions (residuals) ``misfits[imodel, iresidual, 1]``
            are the normalisation contributions. It is also possible to give
            the misfit and normalisation contributions for a single model as
            ``misfits[iresidual, 0]`` and misfits[iresidual, 1]`` in which
            case, the first dimension (imodel) of the result will be stipped
            off.

        :param extra_weights: if given, 2D array of extra weights to be applied
            to the contributions, indexed as
            ``extra_weights[ibootstrap, iresidual]``.

        :param extra_residuals: if given, 2D array of perturbations to be added
            to the residuals, indexed as
            ``extra_residuals[ibootstrap, iresidual]``.

        :param get_contributions: get the weighted and perturbed contributions
            (don't do the sum).

        :returns: if no *extra_weights* or *extra_residuals* are given, a 1D
            array indexed as ``misfits[imodel]`` containing the global misfit
            for each model is returned, otherwise a 2D array
            ``misfits[imodel, ibootstrap]`` with the misfit for every model and
            weighting/residual set is returned.
        '''

        exp, root = self.get_norm_functions()

        if misfits.ndim == 2:
            misfits = misfits[num.newaxis, :, :]
            return self.combine_misfits(misfits, extra_weights,
                                        extra_residuals,
                                        get_contributions)[0, ...]

        assert misfits.ndim == 3
        assert extra_weights is None or extra_weights.ndim == 2
        assert extra_residuals is None or extra_residuals.ndim == 2

        if extra_weights is not None or extra_residuals is not None:
            if extra_weights is not None:
                w = extra_weights[num.newaxis, :, :] \
                    * self.get_target_weights()[num.newaxis, num.newaxis, :] \
                    * self.inter_family_weights2(
                        misfits[:, :, 1])[:, num.newaxis, :]
            else:
                w = 1.0

            if extra_residuals is not None:
                r = extra_residuals[num.newaxis, :, :]
            else:
                r = 0.0

            if get_contributions:
                return exp(w*(misfits[:, num.newaxis, :, 0]+r)) \
                    / num.nansum(
                        exp(w*misfits[:, num.newaxis, :, 1]),
                        axis=2)[:, :, num.newaxis]

            res = root(
                num.nansum(exp(w * (misfits[:, num.newaxis, :, 0] + r)),
                           axis=2) /
                num.nansum(exp(w * (misfits[:, num.newaxis, :, 1])), axis=2))
            assert res[res < 0].size == 0
            return res
        else:
            w = self.get_target_weights()[num.newaxis, :] \
                * self.inter_family_weights2(misfits[:, :, 1])

            r = self.get_target_weights()[num.newaxis, :] \
                * self.inter_family_weights2(misfits[:, :, 1])

            if get_contributions:
                return exp(w*misfits[:, :, 0]) \
                    / num.nansum(
                        exp(w*misfits[:, :, 1]),
                        axis=1)[:, num.newaxis]

            return root(
                num.nansum(exp(w * misfits[:, :, 0]), axis=1) /
                num.nansum(exp(w * misfits[:, :, 1]), axis=1))

    def make_family_mask(self):
        family_names = set()
        families = num.zeros(self.nmisfits, dtype=num.int)

        idx = 0
        for itarget, target in enumerate(self.targets):
            family_names.add(target.normalisation_family)
            families[idx:idx + target.nmisfits] = len(family_names) - 1
            idx += target.nmisfits

        return families, len(family_names)

    def get_family_mask(self):
        if self._family_mask is None:
            self._family_mask = self.make_family_mask()

        return self._family_mask

    def evaluate(self, x, mask=None, result_mode='full', targets=None):
        source = self.get_source(x)
        engine = self.get_engine()

        self.set_target_parameter_values(x)

        if mask is not None and targets is not None:
            raise ValueError('mask cannot be defined with targets set')
        targets = targets if targets is not None else self.targets

        for target in targets:
            target.set_result_mode(result_mode)

        modelling_targets = []
        t2m_map = {}
        for itarget, target in enumerate(targets):
            t2m_map[target] = target.prepare_modelling(engine, source, targets)
            if mask is None or mask[itarget]:
                modelling_targets.extend(t2m_map[target])

        u2m_map = {}
        for imtarget, mtarget in enumerate(modelling_targets):
            if mtarget not in u2m_map:
                u2m_map[mtarget] = []

            u2m_map[mtarget].append(imtarget)

        modelling_targets_unique = list(u2m_map.keys())

        resp = engine.process(source, modelling_targets_unique)
        modelling_results_unique = list(resp.results_list[0])

        modelling_results = [None] * len(modelling_targets)

        for mtarget, mresult in zip(modelling_targets_unique,
                                    modelling_results_unique):

            for itarget in u2m_map[mtarget]:
                modelling_results[itarget] = mresult

        imt = 0
        results = []
        for itarget, target in enumerate(targets):
            nmt_this = len(t2m_map[target])
            if mask is None or mask[itarget]:
                result = target.finalize_modelling(
                    engine, source, t2m_map[target],
                    modelling_results[imt:imt + nmt_this])

                imt += nmt_this
            else:
                result = gf.SeismosizerError(
                    'target was excluded from modelling')

            results.append(result)

        return results

    def misfits(self, x, mask=None):
        results = self.evaluate(x, mask=mask, result_mode='sparse')
        misfits = num.full((self.nmisfits, 2), num.nan)

        imisfit = 0
        for target, result in zip(self.targets, results):
            if isinstance(result, MisfitResult):
                misfits[imisfit:imisfit + target.nmisfits, :] = result.misfits

            imisfit += target.nmisfits

        return misfits

    def forward(self, x):
        source = self.get_source(x)
        engine = self.get_engine()

        plain_targets = []
        for target in self.targets:
            plain_targets.extend(target.get_plain_targets(engine, source))

        resp = engine.process(source, plain_targets)

        results = []
        for target, result in zip(plain_targets, resp.results_list[0]):
            if isinstance(result, gf.SeismosizerError):
                logger.debug('%s.%s.%s.%s: %s' % (target.codes +
                                                  (str(result), )))
            else:
                results.append(result)

        return results

    def get_random_model(self):
        xbounds = self.get_parameter_bounds()

        while True:
            x = self.random_uniform(xbounds)
            try:
                return self.preconstrain(x)

            except Forbidden:
                pass
Esempio n. 20
0
class DataProvider(Object):
    use = List.T(String.T())
    timings = Dict.T(String.T(), Timings.T())

    def __init__(self, channels='SHZ', use=None, timings=None):
        self.use = use or []
        self.timings = timings or {}
        iris_arrays = {
            'YKA': ('CN', 'YKA*', '', channels),
            #'ESK': [('IM', 'EKB?', '', channels),
            #        ('IM', 'EKR*', '', channels)],
            #'ESK1': ('IM', 'EKA?', '', channels),
            'ILAR': ('IM', 'IL*', '', channels),
            'IMAR': ('IM', 'IM0?', '', channels),
            #'NIA': ('IM', 'I56H?', '', channels),
            #'PFIA': [('IM', 'I57H?', '', channels),
            #         ('IM', 'I57L?', '', channels)],
            'BMA': ('IM', 'BM0?', '', channels),
            'BCA': ('IM', 'BC0?', '', channels),
            #'HIA': ('IM', 'I59H?', '', channels),
            'NVAR': ('IM', 'NV*', '', channels),
            'PDAR': [('IM', 'PD0*', '', channels),
                     ('IM', 'PD1*', '', channels)],
            'TXAR': ('IM', 'TX*', '', channels),
            #'Pilbara': ('AU', 'PSA*', '', channels),
            'AliceSprings': ('AU', 'AS*', '', channels),
            #'GERES': [('IM', 'GEA?', '', channels),
            #         ('IM', 'GEB?', '', channels),
            #         ('IM', 'GEC?', '', channels),
            #         ('IM', 'GED?', '', channels)],
            # Diego Garcia Hydroacoustic array noqa
            'DGHAland': ('IM', 'I52H?', '', channels),
            'DGHAS': ('IM', 'H08S?', '', channels),
            'DGHAN': ('IM', 'H08N?', '', channels),
            # Tristan da Cunha. channels: BDF. noqa
            #'TDC': [('IM', 'H09N?', '', channels),
            #        ('IM', 'I49H?', '', channels)],
            #'NarroginIA': ('IM', 'I04H?', '', channels),
            #'CocosIslands': ('IM', 'I06H?', '', channels),
            'Warramunga': ('IM', 'I07H?', '', channels),
            #'BermudaIA': ('IM', 'I51H?', '', channels),
            #'FairbanksIA': ('IM', 'I53H?', '', channels)
        }

        geofon_arrays = {
            'ROHRBACH': ('6A', 'V*', '', channels),
            'AntaOffshore': ('GR', 'I27L?', '*', channels),
            'AntaOnshore': ('AW', 'VNA*', '*', channels),
            #'NORES': [('NO', 'NA*', '*', channels),
            #('NO', 'NB*', '*', channels),
            #('NO', 'NC*', '*', channels)]}
        }
        bgr_arrays = {
            'GERES': [('GR', 'GEA?', '*', channels),
                      ('GR', 'GEB?', '*', channels),
                      ('GR', 'GEC?', '*', channels),
                      ('GR', 'GED?', '*', channels)],
        }

        self.providers = {
            'iris': iris_arrays,
            'geofon': geofon_arrays,
            'bgr': bgr_arrays
        }

    def download(self,
                 event,
                 directory='array_data',
                 timing=None,
                 length=None,
                 want='all',
                 force=False,
                 prefix=False,
                 dump_config=False,
                 get_responses=False):
        """:param want: either 'all' or ID as string or list of IDs as strings
        """
        use = []
        #ts = {}
        unit = 'M'
        if all([timing, length]) is None:
            raise Exception('Define one of "timing" and "length"')
        prefix = prefix or ''
        directory = pjoin(prefix, directory)
        if not os.path.isdir(directory):
            os.mkdir(directory)
        pzresponses = {}
        logger.info('download data: %s at %sN %sE' %
                    (event.name, event.lat, event.lon))
        for site, array_data_provder in self.providers.items():
            logger.info('requesting data from site %s' % site)
            for array_id, codes in array_data_provder.items():
                if array_id not in want and want != ['all']:
                    continue
                sub_directory = pjoin(directory, array_id)
                logger.info("%s" % array_id)
                codes = array_data_provder[array_id]
                if not isinstance(codes, list):
                    codes = [codes]
                selection = [
                    c + tuple((event.time, event.time + 1000.)) for c in codes
                ]
                logger.debug('selection: %s' % selection)
                try:
                    #    if site=='bgr':
                    #        st = ws.station(url='http://eida.bgr.de/', selection=selection)
                    #    else:
                    #        st = ws.station(site=site, selection=selection)
                    st = ws.station(site=site, selection=selection)
                except ws.EmptyResult as e:
                    logging.error('No results: %s %s. skip' % (e, array_id))
                    continue
                except ValueError as e:
                    logger.error(e)
                    logger.error('...skipping...')
                    continue

                stations = st.get_pyrocko_stations()
                min_dist = min(
                    [ortho.distance_accurate50m(s, event) for s in stations])
                max_dist = max(
                    [ortho.distance_accurate50m(s, event) for s in stations])

                mod = cake.load_model(crust2_profile=(event.lat, event.lon))
                if length:
                    tstart = 0.
                    tend = length
                elif timing:
                    tstart = timing[0].t(mod, (event.depth, min_dist))
                    tend = timing[1].t(mod, (event.depth, max_dist))
                selection = [
                    c + tuple((event.time + tstart, event.time + tend))
                    for c in codes
                ]
                try:
                    d = ws.dataselect(site=site, selection=selection)
                    store.remake_dir(sub_directory, force)
                    store.remake_dir(pjoin(sub_directory, 'responses'), force)
                    fn = pjoin(sub_directory, 'traces.mseed')
                    with open(fn, 'w') as f:
                        f.write(d.read())
                        f.close()
                    if get_responses:
                        trs = io.load(fn, getdata=False)
                        logger.info('Request responses from %s' % site)
                        if progressbar:
                            pb = progressbar.ProgressBar(
                                maxval=len(trs)).start()
                        for i_tr, tr in enumerate(trs):
                            try:
                                st = ws.station(site=site,
                                                selection=selection,
                                                level='response')
                                pzresponse = st.get_pyrocko_response(
                                    nslc=tr.nslc_id,
                                    timespan=(tr.tmin, tr.tmax),
                                    fake_input_units=unit)
                                pzresponse.regularize()
                            except fdsnstation.NoResponseInformation as e:
                                logger.warn("no response information: %s" % e)
                                pzresponse = None
                                pass
                            except fdsnstation.MultipleResponseInformation as e:
                                logger.warn("MultipleResponseInformation: %s" %
                                            e)
                                pzresponse = None
                                pass
                            pzresponses[tr.nslc_id] = pzresponse
                            pzresponses[tr.nslc_id].dump(filename=pjoin(
                                sub_directory, 'responses', 'resp_%s.yaml' %
                                '.'.join(tr.nslc_id)))
                            if progressbar:
                                pb.update(i_tr)
                        if progressbar:
                            pb.finish()
                    model.dump_stations(stations,
                                        pjoin(sub_directory, 'stations.pf'))

                    if timing:
                        t = Timings(list(timing))
                        self.timings[array_id] = t
                    if array_id not in use and array_id not in self.use:
                        use.append(array_id)
                except ws.EmptyResult as e:
                    logging.error('%s on %s' % (e, array_id))

        self.use.extend(use)
Esempio n. 21
0
class ProblemConfig(Object):
    """
    Config for optimization problem to setup.
    """
    mode = StringChoice.T(
        choices=['geometry', 'ffi', 'interseismic'],
        default='geometry',
        help='Problem to solve: "geometry", "ffi",'
        ' "interseismic"',
    )
    mode_config = ModeConfig.T(
        optional=True, help='Global optimization mode specific parameters.')
    source_type = StringChoice.T(
        default='RectangularSource',
        choices=source_names,
        help='Source type to optimize for. Options: %s' %
        (', '.join(name for name in source_names)))
    stf_type = StringChoice.T(
        default='HalfSinusoid',
        choices=stf_names,
        help='Source time function type to use. Options: %s' %
        (', '.join(name for name in stf_names)))
    decimation_factors = Dict.T(
        default=None,
        optional=True,
        help='Determines the reduction of discretization of an extended'
        ' source.')
    n_sources = Int.T(default=1, help='Number of Sub-sources to solve for')
    datatypes = List.T(default=['geodetic'])
    dataset_specific_residual_noise_estimation = Bool.T(
        default=False,
        help='If set, for EACH DATASET specific hyperparameter estimation.'
        'For seismic data: n_hypers = nstations * nchannels.'
        'For geodetic data: n_hypers = nimages (SAR) or '
        'nstations * ncomponents (GPS).'
        'If false one hyperparameter for each DATATYPE and '
        'displacement COMPONENT.')
    hyperparameters = Dict.T(
        default=OrderedDict(),
        help='Hyperparameters to estimate the noise in different'
        ' types of datatypes.')
    priors = Dict.T(default=OrderedDict(),
                    help='Priors of the variables in question.')
    hierarchicals = Dict.T(
        default=OrderedDict(),
        help='Hierarchical parameters that affect the posterior'
        ' likelihood, but do not affect the forward problem.'
        ' Implemented: Temporal station corrections, orbital'
        ' ramp estimation')

    def __init__(self, **kwargs):

        mode = 'mode'
        mode_config = 'mode_config'
        if mode in kwargs:
            omode = kwargs[mode]

            if omode == 'ffi':
                if mode_config not in kwargs:
                    kwargs[mode_config] = FFIConfig()

        Object.__init__(self, **kwargs)

    def init_vars(self, variables=None, nvars=None):
        """
        Initiate priors based on the problem mode and datatypes.

        Parameters
        ----------
        variables : list
            of str of variable names to initialise
        """
        if variables is None:
            variables = self.select_variables()

        self.priors = OrderedDict()

        for variable in variables:

            if nvars is None:
                if variable in block_vars:
                    nvars = 1
                else:
                    nvars = self.n_sources

            lower = default_bounds[variable][0]
            upper = default_bounds[variable][1]
            self.priors[variable] = \
                Parameter(
                    name=variable,
                    lower=num.ones(
                        nvars,
                        dtype=tconfig.floatX) * lower,
                    upper=num.ones(
                        nvars,
                        dtype=tconfig.floatX) * upper,
                    testvalue=num.ones(
                        nvars,
                        dtype=tconfig.floatX) * (lower + (upper / 5.)))

    def set_vars(self, bounds_dict):
        """
        Set variable bounds to given bounds.
        """
        for variable, bounds in bounds_dict.items():
            if variable in self.priors.keys():
                param = self.priors[variable]
                param.lower = num.atleast_1d(bounds[0])
                param.upper = num.atleast_1d(bounds[1])
                param.testvalue = num.atleast_1d(num.mean(bounds))
            else:
                logger.warning('Prior for variable %s does not exist!'
                               ' Bounds not updated!' % variable)

    def select_variables(self):
        """
        Return model variables depending on problem config.
        """

        if self.mode not in modes_catalog.keys():
            raise ValueError('Problem mode %s not implemented' % self.mode)

        vars_catalog = modes_catalog[self.mode]

        variables = []
        for datatype in self.datatypes:
            if datatype in vars_catalog.keys():
                if self.mode == 'geometry':
                    if self.source_type in vars_catalog[datatype].keys():
                        source = vars_catalog[datatype][self.source_type]
                        svars = set(source.keys())

                        if isinstance(source(),
                                      (PyrockoRS, gf.ExplosionSource)):
                            svars.discard('magnitude')

                        variables += utility.weed_input_rvs(
                            svars, self.mode, datatype)
                    else:
                        raise ValueError('Source Type not supported for type'
                                         ' of problem, and datatype!')

                    if datatype == 'seismic':
                        if self.stf_type in stf_catalog.keys():
                            stf = stf_catalog[self.stf_type]
                            variables += utility.weed_input_rvs(
                                set(stf.keys()), self.mode, datatype)
                else:
                    variables += vars_catalog[datatype]
            else:
                raise ValueError(
                    'Datatype %s not supported for type of'
                    ' problem! Supported datatype are: %s' %
                    (datatype, ', '.join('"%s"' % d
                                         for d in vars_catalog.keys())))

        unique_variables = utility.unique_list(variables)

        if len(unique_variables) == 0:
            raise Exception('Mode and datatype combination not implemented'
                            ' or not resolvable with given datatypes.')

        return unique_variables

    def get_slip_variables(self):
        """
        Return a list of slip variable names defined in the ProblemConfig.
        """
        if self.mode == 'ffi':
            return [
                var for var in static_dist_vars if var in self.priors.keys()
            ]
        elif self.mode == 'geometry':
            return [
                var for var in ['slip', 'magnitude']
                if var in self.priors.keys()
            ]
        elif self.mode == 'interseismic':
            return ['bl_amplitude']

    def set_decimation_factor(self):
        """
        Determines the reduction of discretization of an extended source.
        Influences yet only the RectangularSource.
        """
        if self.source_type == 'RectangularSource':
            self.decimation_factors = {}
            for datatype in self.datatypes:
                self.decimation_factors[datatype] = \
                    default_decimation_factors[datatype]
        else:
            self.decimation_factors = None

    def validate_priors(self):
        """
        Check if priors and their test values do not contradict!
        """
        for param in self.priors.itervalues():
            param.validate_bounds()

        logger.info('All parameter-priors ok!')

    def validate_hypers(self):
        """
        Check if hyperparameters and their test values do not contradict!
        """
        if self.hyperparameters is not None:
            for hp in self.hyperparameters.itervalues():
                hp.validate_bounds()

            logger.info('All hyper-parameters ok!')

        else:
            logger.info('No hyper-parameters defined!')

    def validate_hierarchicals(self):
        """
        Check if hierarchicals and their test values do not contradict!
        """
        if self.hierarchicals is not None:
            for hp in self.hierarchicals.itervalues():
                hp.validate_bounds()

            logger.info('All hierarchical-parameters ok!')

        else:
            logger.info('No hyper-parameters defined!')

    def get_test_point(self):
        """
        Returns dict with test point
        """
        test_point = {}
        for varname, var in self.priors.items():
            test_point[varname] = var.testvalue

        for varname, var in self.hyperparameters.items():
            test_point[varname] = var.testvalue

        for varname, var in self.hierarchicals.items():
            test_point[varname] = var.testvalue

        return test_point
Esempio n. 22
0
class MisfitTarget(Object):

    manual_weight = Float.T(
        default=1.0,
        help='Relative weight of this target')
    analyser_results = Dict.T(
        gf.StringID.T(),
        AnalyserResult.T(),
        help='Dictionary of analyser results')
    normalisation_family = gf.StringID.T(
        optional=True,
        help='Normalisation family of this misfit target')
    path = gf.StringID.T(
        help='A path identifier used for plotting')
    misfit_config = MisfitConfig.T(
        default=MisfitConfig.D(),
        help='Misfit configuration')
    bootstrap_weights = Array.T(
        dtype=num.float,
        serialize_as='base64',
        optional=True)
    bootstrap_residuals = Array.T(
        dtype=num.float,
        serialize_as='base64',
        optional=True)

    can_bootstrap_weights = False
    can_bootstrap_residuals = False

    def __init__(self, **kwargs):
        Object.__init__(self, **kwargs)
        self.parameters = []

        self._ds = None
        self._result_mode = 'sparse'

        self._combined_weight = None
        self._target_parameters = None
        self._target_ranges = None

        self._combined_weight = None

    @classmethod
    def get_plot_classes(cls):
        return []

    def set_dataset(self, ds):
        self._ds = ds

    def get_dataset(self):
        return self._ds

    @property
    def nmisfits(self):
        return 1

    @property
    def nparameters(self):
        if self._target_parameters is None:
            return 0
        return len(self._target_parameters)

    @property
    def target_parameters(self):
        if self._target_parameters is None:
            self._target_parameters = copy.deepcopy(self.parameters)
            for p in self._target_parameters:
                p.set_groups([self.string_id()])
        return self._target_parameters

    @property
    def target_ranges(self):
        return {}

    def set_parameter_values(self, model):
        for i, p in enumerate(self.parameters):
            self.parameter_values[p.name_nogroups] = model[i]

    def set_result_mode(self, result_mode):
        self._result_mode = result_mode

    def post_process(self, engine, source, statics):
        raise NotImplementedError()

    def get_combined_weight(self):
        if self._combined_weight is None:
            self._combined_weight = num.ones(1, dtype=num.float)
        return self._combined_weight

    def set_bootstrap_weights(self, weights):
        self.bootstrap_weights = weights

    def get_bootstrap_weights(self):
        if self.bootstrap_weights is None:
            raise Exception('Bootstrap weights have not been set!')
        nbootstraps = self.bootstrap_weights.size // self.nmisfits
        return self.bootstrap_weights.reshape(nbootstraps, self.nmisfits)

    def init_bootstrap_residuals(self, nbootstrap, rstate=None):
        raise NotImplementedError

    def set_bootstrap_residuals(self, residuals):
        self.bootstrap_residuals = residuals

    def get_bootstrap_residuals(self):
        if self.bootstrap_residuals is None:
            raise Exception('Bootstrap residuals have not been set!')
        nbootstraps = self.bootstrap_residuals.size // self.nmisfits
        return self.bootstrap_residuals.reshape(nbootstraps, self.nmisfits)

    def prepare_modelling(self, engine, source, targets):
        return []

    def finalize_modelling(
            self, engine, source, modelling_targets, modelling_results):

        raise NotImplemented('must be overloaded in subclass')
Esempio n. 23
0
 class B(Object):
     a_list = List.T(A.T())
     a_tuple = Tuple.T(3, A.T())
     a_dict = Dict.T(Int.T(), A.T())
     b = Float.T()
Esempio n. 24
0
class SyntheticTest(Object):
    inject_solution = Bool.T(default=False)
    respect_data_availability = Bool.T(default=False)
    real_noise_scale = Float.T(default=0.0)
    white_noise_scale = Float.T(default=0.0)
    relative_white_noise_scale = Float.T(default=0.0)
    random_response_scale = Float.T(default=0.0)
    real_noise_toffset = Float.T(default=-3600.)
    random_seed = Int.T(optional=True)
    x = Dict.T(String.T(), Float.T())

    def __init__(self, **kwargs):
        Object.__init__(self, **kwargs)
        self._problem = None
        self._synthetics = None

    def set_problem(self, problem):
        self._problem = problem
        self._synthetics = None

    def get_problem(self):
        if self._problem is None:
            raise SyntheticWaveformNotAvailable(
                'SyntheticTest.set_problem() has not been called yet')

        return self._problem

    def get_x(self):
        problem = self.get_problem()
        if self.x:
            x = problem.preconstrain(
                problem.get_parameter_array(self.x))

        else:
            x = problem.preconstrain(
                problem.pack(
                    problem.base_source))

        return x

    def get_synthetics(self):
        problem = self.get_problem()
        if self._synthetics is None:
            x = self.get_x()
            results = problem.forward(x)
            synthetics = {}
            for iresult, result in enumerate(results):
                tr = result.trace.pyrocko_trace()
                tfade = tr.tmax - tr.tmin
                tr_orig = tr.copy()
                tr.extend(tr.tmin - tfade, tr.tmax + tfade)
                rstate = num.random.RandomState(
                    (self.random_seed or 0) + iresult)

                if self.random_response_scale != 0:
                    tf = RandomResponse(scale=self.random_response_scale)
                    tf.set_random_state(rstate)
                    tr = tr.transfer(
                        tfade=tfade,
                        transfer_function=tf)

                if self.white_noise_scale != 0.0:
                    u = rstate.normal(
                        scale=self.white_noise_scale,
                        size=tr.data_len())

                    tr.ydata += u

                if self.relative_white_noise_scale != 0.0:
                    u = rstate.normal(
                        scale=self.relative_white_noise_scale * num.std(
                            tr_orig.ydata),
                        size=tr.data_len())

                    tr.ydata += u

                synthetics[result.trace.codes] = tr

            self._synthetics = synthetics

        return self._synthetics

    def get_waveform(self, nslc, tmin, tmax, tfade=0., freqlimits=None):
        synthetics = self.get_synthetics()
        if nslc not in synthetics:
            s = 'no synthetics for %s available' % '.'.join(nslc)
            logger.warn(s)
            from grond.dataset import NotFound
            raise NotFound(s)

        tr = synthetics[nslc]
        tr.extend(tmin - tfade * 2.0, tmax + tfade * 2.0)

        tr = tr.transfer(
            tfade=tfade,
            freqlimits=freqlimits)

        tr.chop(tmin, tmax)
        return tr
Esempio n. 25
0
 class A(Object):
     d = Dict.T(Int.T(), Float.T())
Esempio n. 26
0
class MisfitTarget(Object):

    manual_weight = Float.T(
        default=1.0,
        help='Relative weight of this target')
    analyser_results = Dict.T(
        gf.StringID.T(),
        AnalyserResult.T(),
        help='Dictionary of analyser results')
    normalisation_family = gf.StringID.T(
        optional=True,
        help='Normalisation family of this misfit target')
    path = gf.StringID.T(
        help='A path identifier used for plotting')
    misfit_config = MisfitConfig.T(
        default=MisfitConfig.D(),
        help='Misfit configuration')
    bootstrap_weights = Array.T(
        dtype=num.float,
        serialize_as='base64',
        optional=True)
    bootstrap_residuals = Array.T(
        dtype=num.float,
        serialize_as='base64',
        optional=True)

    can_bootstrap_weights = False
    can_bootstrap_residuals = False

    plot_misfits_cumulative = True

    def __init__(self, **kwargs):
        Object.__init__(self, **kwargs)
        self.parameters = []

        self._ds = None
        self._result_mode = 'sparse'

        self._combined_weight = None
        self._target_parameters = None
        self._target_ranges = None

        self._combined_weight = None

    @classmethod
    def get_plot_classes(cls):
        return []

    def set_dataset(self, ds):
        self._ds = ds

    def get_dataset(self):
        return self._ds

    def string_id(self):
        return str(self.path)

    def misfits_string_ids(self):
        raise NotImplementedError('%s does not implement misfits_string_id'
                                  % self.__class__.__name__)

    @property
    def nmisfits(self):
        return 1

    def noise_weight_matrix(self):
        return num.array([[1]])

    @property
    def nparameters(self):
        if self._target_parameters is None:
            return 0
        return len(self._target_parameters)

    @property
    def target_parameters(self):
        if self._target_parameters is None:
            self._target_parameters = copy.deepcopy(self.parameters)
            for p in self._target_parameters:
                p.set_groups([self.string_id()])
        return self._target_parameters

    @property
    def target_ranges(self):
        return {}

    def set_parameter_values(self, model):
        for i, p in enumerate(self.parameters):
            self.parameter_values[p.name_nogroups] = model[i]

    def set_result_mode(self, result_mode):
        self._result_mode = result_mode

    def post_process(self, engine, source, statics):
        raise NotImplementedError()

    def get_combined_weight(self):
        if self._combined_weight is None:
            self._combined_weight = num.ones(1, dtype=num.float)
        return self._combined_weight

    def get_correlated_weights(self, nthreads=0):
        pass

    def set_bootstrap_weights(self, weights):
        self.bootstrap_weights = weights

    def get_bootstrap_weights(self):
        if self.bootstrap_weights is None:
            raise Exception('Bootstrap weights have not been set!')
        nbootstraps = self.bootstrap_weights.size // self.nmisfits
        return self.bootstrap_weights.reshape(nbootstraps, self.nmisfits)

    def init_bootstrap_residuals(self, nbootstrap, rstate=None, nthreads=0):
        raise NotImplementedError()

    def set_bootstrap_residuals(self, residuals):
        self.bootstrap_residuals = residuals

    def get_bootstrap_residuals(self):
        if self.bootstrap_residuals is None:
            raise Exception('Bootstrap residuals have not been set!')
        nbootstraps = self.bootstrap_residuals.size // self.nmisfits
        return self.bootstrap_residuals.reshape(nbootstraps, self.nmisfits)

    def prepare_modelling(self, engine, source, targets):
        ''' Prepare modelling target

        This function shall return a list of :class:`pyrocko.gf.Target`
        for forward modelling in the :class:`pyrocko.gf.LocalEngine`.
        '''
        return [self]

    def finalize_modelling(
            self, engine, source, modelling_targets, modelling_results):
        ''' Manipulate modelling before misfit calculation

        This function can be overloaded interact with the modelling results.
        '''
        return modelling_results[0]
Esempio n. 27
0
class Map(Object):
    lat = Float.T(optional=True)
    lon = Float.T(optional=True)
    radius = Float.T(optional=True)
    width = Float.T(default=20.)
    height = Float.T(default=14.)
    margins = List.T(Float.T())
    illuminate = Bool.T(default=True)
    skip_feature_factor = Float.T(default=0.02)
    show_grid = Bool.T(default=False)
    show_topo = Bool.T(default=True)
    show_scale = Bool.T(default=False)
    show_topo_scale = Bool.T(default=False)
    show_center_mark = Bool.T(default=False)
    show_rivers = Bool.T(default=True)
    show_plates = Bool.T(default=False)
    show_boundaries = Bool.T(default=False)
    illuminate_factor_land = Float.T(default=0.5)
    illuminate_factor_ocean = Float.T(default=0.25)
    color_wet = Tuple.T(3, Int.T(), default=(216, 242, 254))
    color_dry = Tuple.T(3, Int.T(), default=(172, 208, 165))
    color_boundaries = Tuple.T(3, Int.T(), default=(1, 1, 1))
    topo_resolution_min = Float.T(
        default=40.,
        help='minimum resolution of topography [dpi]')
    topo_resolution_max = Float.T(
        default=200.,
        help='maximum resolution of topography [dpi]')
    replace_topo_color_only = FloatTile.T(
        optional=True,
        help='replace topo color while keeping topographic shading')
    topo_cpt_wet = String.T(default='light_sea')
    topo_cpt_dry = String.T(default='light_land')
    axes_layout = String.T(optional=True)
    custom_cities = List.T(City.T())
    gmt_config = Dict.T(String.T(), String.T())
    comment = String.T(optional=True)

    def __init__(self, gmtversion='newest', **kwargs):
        Object.__init__(self, **kwargs)
        self._gmt = None
        self._scaler = None
        self._widget = None
        self._corners = None
        self._wesn = None
        self._minarea = None
        self._coastline_resolution = None
        self._rivers = None
        self._dems = None
        self._have_topo_land = None
        self._have_topo_ocean = None
        self._jxyr = None
        self._prep_topo_have = None
        self._labels = []
        self._area_labels = []
        self._gmtversion = gmtversion

    def save(self, outpath, resolution=75., oversample=2., size=None,
             width=None, height=None, psconvert=False):

        '''
        Save the image.

        Save the image to ``outpath``. The format is determined by the filename
        extension. Formats are handled as follows: ``'.eps'`` and ``'.ps'``
        produce EPS and PS, respectively, directly with GMT. If the file name
        ends with ``'.pdf'``, GMT output is fed through ``gmtpy-epstopdf`` to
        create a PDF file. For any other filename extension, output is first
        converted to PDF with ``gmtpy-epstopdf``, then with ``pdftocairo`` to
        PNG with a resolution oversampled by the factor ``oversample`` and
        finally the PNG is downsampled and converted to the target format with
        ``convert``. The resolution of rasterized target image can be
        controlled either by ``resolution`` in DPI or by specifying ``width``
        or ``height`` or ``size``, where the latter fits the image into a
        square with given side length. To save transparency use
        ``psconvert=True``.
        '''

        gmt = self.gmt
        self.draw_labels()
        self.draw_axes()
        if self.show_topo and self.show_topo_scale:
            self._draw_topo_scale()

        gmt.save(outpath, resolution=resolution, oversample=oversample,
                 size=size, width=width, height=height, psconvert=psconvert)

    @property
    def scaler(self):
        if self._scaler is None:
            self._setup_geometry()

        return self._scaler

    @property
    def wesn(self):
        if self._wesn is None:
            self._setup_geometry()

        return self._wesn

    @property
    def widget(self):
        if self._widget is None:
            self._setup()

        return self._widget

    @property
    def layout(self):
        if self._layout is None:
            self._setup()

        return self._layout

    @property
    def jxyr(self):
        if self._jxyr is None:
            self._setup()

        return self._jxyr

    @property
    def pxyr(self):
        if self._pxyr is None:
            self._setup()

        return self._pxyr

    @property
    def gmt(self):
        if self._gmt is None:
            self._setup()

        if self._have_topo_ocean is None:
            self._draw_background()

        return self._gmt

    def _setup(self):
        if not self._widget:
            self._setup_geometry()

        self._setup_lod()
        self._setup_gmt()

    def _setup_geometry(self):
        wpage, hpage = self.width, self.height
        ml, mr, mt, mb = self._expand_margins()
        wpage -= ml + mr
        hpage -= mt + mb

        wreg = self.radius * 2.0
        hreg = self.radius * 2.0
        if wpage >= hpage:
            wreg *= wpage/hpage
        else:
            hreg *= hpage/wpage

        self._wreg = wreg
        self._hreg = hreg

        self._corners = corners(self.lon, self.lat, wreg, hreg)
        west, east, south, north = extent(self.lon, self.lat, wreg, hreg, 10)

        x, y, z = ((west, east), (south, north), (-6000., 4500.))

        xax = gmtpy.Ax(mode='min-max', approx_ticks=4.)
        yax = gmtpy.Ax(mode='min-max', approx_ticks=4.)
        zax = gmtpy.Ax(mode='min-max', inc=1000., label='Height',
                       scaled_unit='km', scaled_unit_factor=0.001)

        scaler = gmtpy.ScaleGuru(data_tuples=[(x, y, z)], axes=(xax, yax, zax))

        par = scaler.get_params()

        west = par['xmin']
        east = par['xmax']
        south = par['ymin']
        north = par['ymax']

        self._wesn = west, east, south, north
        self._scaler = scaler

    def _setup_lod(self):
        w, e, s, n = self._wesn
        if self.radius > 1500.*km:
            coastline_resolution = 'i'
            rivers = False
        else:
            coastline_resolution = 'f'
            rivers = True

        self._minarea = (self.skip_feature_factor * self.radius/km)**2

        self._coastline_resolution = coastline_resolution
        self._rivers = rivers

        self._prep_topo_have = {}
        self._dems = {}

        cm2inch = gmtpy.cm/gmtpy.inch

        dmin = 2.0 * self.radius * m2d / (self.topo_resolution_max *
                                          (self.height * cm2inch))
        dmax = 2.0 * self.radius * m2d / (self.topo_resolution_min *
                                          (self.height * cm2inch))

        for k in ['ocean', 'land']:
            self._dems[k] = topo.select_dem_names(k, dmin, dmax, self._wesn)
            if self._dems[k]:
                logger.debug('using topography dataset %s for %s'
                             % (','.join(self._dems[k]), k))

    def _expand_margins(self):
        if len(self.margins) == 0 or len(self.margins) > 4:
            ml = mr = mt = mb = 2.0
        elif len(self.margins) == 1:
            ml = mr = mt = mb = self.margins[0]
        elif len(self.margins) == 2:
            ml = mr = self.margins[0]
            mt = mb = self.margins[1]
        elif len(self.margins) == 4:
            ml, mr, mt, mb = self.margins

        return ml, mr, mt, mb

    def _setup_gmt(self):
        w, h = self.width, self.height
        scaler = self._scaler

        if gmtpy.is_gmt5(self._gmtversion):
            gmtconf = dict(
                MAP_TICK_PEN_PRIMARY='1.25p',
                MAP_TICK_PEN_SECONDARY='1.25p',
                MAP_TICK_LENGTH_PRIMARY='0.2c',
                MAP_TICK_LENGTH_SECONDARY='0.6c',
                FONT_ANNOT_PRIMARY='12p,1,black',
                FONT_LABEL='12p,1,black',
                PS_CHAR_ENCODING='ISOLatin1+',
                MAP_FRAME_TYPE='fancy',
                FORMAT_GEO_MAP='D',
                PS_MEDIA='Custom_%ix%i' % (
                    w*gmtpy.cm,
                    h*gmtpy.cm),
                PS_PAGE_ORIENTATION='portrait',
                MAP_GRID_PEN_PRIMARY='thinnest,0/50/0',
                MAP_ANNOT_OBLIQUE='6')
        else:
            gmtconf = dict(
                TICK_PEN='1.25p',
                TICK_LENGTH='0.2c',
                ANNOT_FONT_PRIMARY='1',
                ANNOT_FONT_SIZE_PRIMARY='12p',
                LABEL_FONT='1',
                LABEL_FONT_SIZE='12p',
                CHAR_ENCODING='ISOLatin1+',
                BASEMAP_TYPE='fancy',
                PLOT_DEGREE_FORMAT='D',
                PAPER_MEDIA='Custom_%ix%i' % (
                    w*gmtpy.cm,
                    h*gmtpy.cm),
                GRID_PEN_PRIMARY='thinnest/0/50/0',
                DOTS_PR_INCH='1200',
                OBLIQUE_ANNOTATION='6')

        gmtconf.update(
            (k.upper(), v) for (k, v) in self.gmt_config.items())

        gmt = gmtpy.GMT(config=gmtconf, version=self._gmtversion)

        layout = gmt.default_layout()

        layout.set_fixed_margins(*[x*cm for x in self._expand_margins()])

        widget = layout.get_widget()
        widget['P'] = widget['J']
        widget['J'] = ('-JA%g/%g' % (self.lon, self.lat)) + '/%(width)gp'
        scaler['R'] = '-R%g/%g/%g/%gr' % self._corners

        # aspect = gmtpy.aspect_for_projection(
        #     gmt.installation['version'], *(widget.J() + scaler.R()))

        aspect = self._map_aspect(jr=widget.J() + scaler.R())
        widget.set_aspect(aspect)

        self._gmt = gmt
        self._layout = layout
        self._widget = widget
        self._jxyr = self._widget.JXY() + self._scaler.R()
        self._pxyr = self._widget.PXY() + [
            '-R%g/%g/%g/%g' % (0, widget.width(), 0, widget.height())]
        self._have_drawn_axes = False
        self._have_drawn_labels = False

    def _draw_background(self):
        self._have_topo_land = False
        self._have_topo_ocean = False
        if self.show_topo:
            self._have_topo = self._draw_topo()

        self._draw_basefeatures()

    def _get_topo_tile(self, k):
        t = None
        demname = None
        for dem in self._dems[k]:
            t = topo.get(dem, self._wesn)
            demname = dem
            if t is not None:
                break

        if not t:
            raise NoTopo()

        return t, demname

    def _prep_topo(self, k):
        gmt = self._gmt
        t, demname = self._get_topo_tile(k)

        if demname not in self._prep_topo_have:

            grdfile = gmt.tempfilename()

            is_flat = num.all(t.data[0] == t.data)

            gmtpy.savegrd(
                t.x(), t.y(), t.data, filename=grdfile, naming='lonlat')

            if self.illuminate and not is_flat:
                if k == 'ocean':
                    factor = self.illuminate_factor_ocean
                else:
                    factor = self.illuminate_factor_land

                ilumfn = gmt.tempfilename()
                gmt.grdgradient(
                    grdfile,
                    N='e%g' % factor,
                    A=-45,
                    G=ilumfn,
                    out_discard=True)

                ilumargs = ['-I%s' % ilumfn]
            else:
                ilumargs = []

            if self.replace_topo_color_only:
                t2 = self.replace_topo_color_only
                grdfile2 = gmt.tempfilename()

                gmtpy.savegrd(
                    t2.x(), t2.y(), t2.data, filename=grdfile2,
                    naming='lonlat')

                if gmt.is_gmt5():
                    gmt.grdsample(
                        grdfile2,
                        G=grdfile,
                        n='l',
                        I='%g/%g' % (t.dx, t.dy),  # noqa
                        R=grdfile,
                        out_discard=True)
                else:
                    gmt.grdsample(
                        grdfile2,
                        G=grdfile,
                        Q='l',
                        I='%g/%g' % (t.dx, t.dy),  # noqa
                        R=grdfile,
                        out_discard=True)

                gmt.grdmath(
                    grdfile, '0.0', 'AND', '=', grdfile2,
                    out_discard=True)

                grdfile = grdfile2

            self._prep_topo_have[demname] = grdfile, ilumargs

        return self._prep_topo_have[demname]

    def _draw_topo(self):
        widget = self._widget
        scaler = self._scaler
        gmt = self._gmt
        cres = self._coastline_resolution
        minarea = self._minarea

        JXY = widget.JXY()
        R = scaler.R()

        try:
            grdfile, ilumargs = self._prep_topo('ocean')
            gmt.pscoast(D=cres, S='c', A=minarea, *(JXY+R))
            gmt.grdimage(grdfile, C=topo.cpt(self.topo_cpt_wet),
                         *(ilumargs+JXY+R))
            gmt.pscoast(Q=True, *(JXY+R))
            self._have_topo_ocean = True
        except NoTopo:
            self._have_topo_ocean = False

        try:
            grdfile, ilumargs = self._prep_topo('land')
            gmt.pscoast(D=cres, G='c', A=minarea, *(JXY+R))
            gmt.grdimage(grdfile, C=topo.cpt(self.topo_cpt_dry),
                         *(ilumargs+JXY+R))
            gmt.pscoast(Q=True, *(JXY+R))
            self._have_topo_land = True
        except NoTopo:
            self._have_topo_land = False

    def _draw_topo_scale(self, label='Elevation [km]'):
        dry = read_cpt(topo.cpt(self.topo_cpt_dry))
        wet = read_cpt(topo.cpt(self.topo_cpt_wet))
        combi = cpt_merge_wet_dry(wet, dry)
        for level in combi.levels:
            level.vmin /= km
            level.vmax /= km

        topo_cpt = self.gmt.tempfilename() + '.cpt'
        write_cpt(combi, topo_cpt)

        (w, h), (xo, yo) = self.widget.get_size()
        self.gmt.psscale(
            D='%gp/%gp/%gp/%gph' % (xo + 0.5*w, yo - 2.0*gmtpy.cm, w,
                                    0.5*gmtpy.cm),
            C=topo_cpt,
            B='1:%s:' % label)

    def _draw_basefeatures(self):
        gmt = self._gmt
        cres = self._coastline_resolution
        rivers = self._rivers
        minarea = self._minarea

        color_wet = self.color_wet
        color_dry = self.color_dry

        if self.show_rivers and rivers:
            rivers = ['-Ir/0.25p,%s' % gmtpy.color(self.color_wet)]
        else:
            rivers = []

        fill = {}
        if not self._have_topo_land:
            fill['G'] = color_dry

        if not self._have_topo_ocean:
            fill['S'] = color_wet

        if self.show_boundaries:
            fill['N'] = '1/1p,%s,%s' % (
                gmtpy.color(self.color_boundaries), 'solid')

        gmt.pscoast(
            D=cres,
            W='thinnest,%s' % gmtpy.color(darken(gmtpy.color_tup(color_dry))),
            A=minarea,
            *(rivers+self._jxyr), **fill)

        if self.show_plates:
            self.draw_plates()

    def _draw_axes(self):
        gmt = self._gmt
        scaler = self._scaler
        widget = self._widget

        if self.axes_layout is None:
            if self.lat > 0.0:
                axes_layout = 'WSen'
            else:
                axes_layout = 'WseN'
        else:
            axes_layout = self.axes_layout

        scale_km = gmtpy.nice_value(self.radius/5.) / 1000.

        if self.show_center_mark:
            gmt.psxy(
                in_rows=[[self.lon, self.lat]],
                S='c20p', W='2p,black',
                *self._jxyr)

        if self.show_grid:
            btmpl = ('%(xinc)gg%(xinc)g:%(xlabel)s:/'
                     '%(yinc)gg%(yinc)g:%(ylabel)s:')
        else:
            btmpl = '%(xinc)g:%(xlabel)s:/%(yinc)g:%(ylabel)s:'

        if self.show_scale:
            scale = 'x%gp/%gp/%g/%g/%gk' % (
                    6./7*widget.width(),
                    widget.height()/7.,
                    self.lon,
                    self.lat,
                    scale_km)
        else:
            scale = False

        gmt.psbasemap(
            B=(btmpl % scaler.get_params())+axes_layout,
            L=scale,
            *self._jxyr)

        if self.comment:
            font_size = self.gmt.label_font_size()

            _, east, south, _ = self._wesn
            if gmt.is_gmt5():
                row = [
                    1, 0,
                    '%gp,%s,%s' % (font_size, 0, 'black'), 'BR',
                    self.comment]

                farg = ['-F+f+j']
            else:
                row = [1, 0, font_size, 0, 0, 'BR', self.comment]
                farg = []

            gmt.pstext(
                in_rows=[row],
                N=True,
                R=(0, 1, 0, 1),
                D='%gp/%gp' % (-font_size*0.2, font_size*0.3),
                *(widget.PXY() + farg))

    def draw_axes(self):
        if not self._have_drawn_axes:
            self._draw_axes()
            self._have_drawn_axes = True

    def _have_coastlines(self):
        gmt = self._gmt
        cres = self._coastline_resolution
        minarea = self._minarea

        checkfile = gmt.tempfilename()

        gmt.pscoast(
            M=True,
            D=cres,
            W='thinnest,black',
            A=minarea,
            out_filename=checkfile,
            *self._jxyr)

        points = []
        with open(checkfile, 'r') as f:
            for line in f:
                ls = line.strip()
                if ls.startswith('#') or ls.startswith('>') or ls == '':
                    continue
                plon, plat = [float(x) for x in ls.split()]
                points.append((plat, plon))

        points = num.array(points, dtype=num.float)
        return num.any(points_in_region(points, self._wesn))

    def have_coastlines(self):
        self.gmt
        return self._have_coastlines()

    def project(self, lats, lons, jr=None):
        onepoint = False
        if isinstance(lats, float) and isinstance(lons, float):
            lats = [lats]
            lons = [lons]
            onepoint = True

        if jr is not None:
            j, r = jr
            gmt = gmtpy.GMT(version=self._gmtversion)
        else:
            j, _, _, r = self.jxyr
            gmt = self.gmt

        f = BytesIO()
        gmt.mapproject(j, r, in_columns=(lons, lats), out_stream=f, D='p')
        f.seek(0)
        data = num.loadtxt(f, ndmin=2)
        xs, ys = data.T
        if onepoint:
            xs = xs[0]
            ys = ys[0]
        return xs, ys

    def _map_box(self, jr=None):
        ll_lon, ll_lat, ur_lon, ur_lat = self._corners

        xs_corner, ys_corner = self.project(
            (ll_lat, ur_lat), (ll_lon, ur_lon), jr=jr)

        w = xs_corner[1] - xs_corner[0]
        h = ys_corner[1] - ys_corner[0]

        return w, h

    def _map_aspect(self, jr=None):
        w, h = self._map_box(jr=jr)
        return h/w

    def _draw_labels(self):
        points_taken = []
        regions_taken = []

        def no_points_in_rect(xs, ys, xmin, ymin, xmax, ymax):
            xx = not num.any(la(la(xmin < xs, xs < xmax),
                                la(ymin < ys, ys < ymax)))
            return xx

        def roverlaps(a, b):
            return (a[0] < b[2] and b[0] < a[2] and
                    a[1] < b[3] and b[1] < a[3])

        w, h = self._map_box()

        label_font_size = self.gmt.label_font_size()

        if self._labels:

            n = len(self._labels)

            lons, lats, texts, sx, sy, colors, fonts, font_sizes, styles = \
                list(zip(*self._labels))

            font_sizes = [
                (font_size or label_font_size) for font_size in font_sizes]

            sx = num.array(sx, dtype=num.float)
            sy = num.array(sy, dtype=num.float)

            xs, ys = self.project(lats, lons)

            points_taken.append((xs, ys))

            dxs = num.zeros(n)
            dys = num.zeros(n)

            for i in range(n):
                dx, dy = gmtpy.text_box(
                    texts[i],
                    font=fonts[i],
                    font_size=font_sizes[i],
                    **styles[i])

                dxs[i] = dx
                dys[i] = dy

            la = num.logical_and
            anchors_ok = (
                la(xs + sx + dxs < w, ys + sy + dys < h),
                la(xs - sx - dxs > 0., ys - sy - dys > 0.),
                la(xs + sx + dxs < w, ys - sy - dys > 0.),
                la(xs - sx - dxs > 0., ys + sy + dys < h),
            )

            arects = [
                (xs, ys, xs + sx + dxs, ys + sy + dys),
                (xs - sx - dxs, ys - sy - dys, xs, ys),
                (xs, ys - sy - dys, xs + sx + dxs, ys),
                (xs - sx - dxs, ys, xs, ys + sy + dys)]

            for i in range(n):
                for ianch in range(4):
                    anchors_ok[ianch][i] &= no_points_in_rect(
                        xs, ys, *[xxx[i] for xxx in arects[ianch]])

            anchor_choices = []
            anchor_take = []
            for i in range(n):
                choices = [ianch for ianch in range(4)
                           if anchors_ok[ianch][i]]
                anchor_choices.append(choices)
                if choices:
                    anchor_take.append(choices[0])
                else:
                    anchor_take.append(None)

            def cost(anchor_take):
                noverlaps = 0
                for i in range(n):
                    for j in range(n):
                        if i != j:
                            i_take = anchor_take[i]
                            j_take = anchor_take[j]
                            if i_take is None or j_take is None:
                                continue
                            r_i = [xxx[i] for xxx in arects[i_take]]
                            r_j = [xxx[j] for xxx in arects[j_take]]
                            if roverlaps(r_i, r_j):
                                noverlaps += 1

                return noverlaps

            cur_cost = cost(anchor_take)
            imax = 30
            while cur_cost != 0 and imax > 0:
                for i in range(n):
                    for t in anchor_choices[i]:
                        anchor_take_new = list(anchor_take)
                        anchor_take_new[i] = t
                        new_cost = cost(anchor_take_new)
                        if new_cost < cur_cost:
                            anchor_take = anchor_take_new
                            cur_cost = new_cost

                imax -= 1

            while cur_cost != 0:
                for i in range(n):
                    anchor_take_new = list(anchor_take)
                    anchor_take_new[i] = None
                    new_cost = cost(anchor_take_new)
                    if new_cost < cur_cost:
                        anchor_take = anchor_take_new
                        cur_cost = new_cost
                        break

            anchor_strs = ['BL', 'TR', 'TL', 'BR']

            for i in range(n):
                ianchor = anchor_take[i]
                color = colors[i]
                if color is None:
                    color = 'black'

                if ianchor is not None:
                    regions_taken.append([xxx[i] for xxx in arects[ianchor]])

                    anchor = anchor_strs[ianchor]

                    yoff = [-sy[i], sy[i]][anchor[0] == 'B']
                    xoff = [-sx[i], sx[i]][anchor[1] == 'L']
                    if self.gmt.is_gmt5():
                        row = (
                            lons[i], lats[i],
                            '%i,%s,%s' % (font_sizes[i], fonts[i], color),
                            anchor,
                            texts[i])

                        farg = ['-F+f+j']
                    else:
                        row = (
                            lons[i], lats[i],
                            font_sizes[i], 0, fonts[i], anchor,
                            texts[i])
                        farg = ['-G%s' % color]

                    self.gmt.pstext(
                        in_rows=[row],
                        D='%gp/%gp' % (xoff, yoff),
                        *(self.jxyr + farg),
                        **styles[i])

        if self._area_labels:

            for lons, lats, text, color, font, font_size, style in \
                    self._area_labels:

                if font_size is None:
                    font_size = label_font_size

                if color is None:
                    color = 'black'

                if self.gmt.is_gmt5():
                    farg = ['-F+f+j']
                else:
                    farg = ['-G%s' % color]

                xs, ys = self.project(lats, lons)
                dx, dy = gmtpy.text_box(
                    text, font=font, font_size=font_size, **style)

                rects = [xs-0.5*dx, ys-0.5*dy, xs+0.5*dx, ys+0.5*dy]

                locs_ok = num.ones(xs.size, dtype=num.bool)

                for iloc in range(xs.size):
                    rcandi = [xxx[iloc] for xxx in rects]

                    locs_ok[iloc] = True
                    locs_ok[iloc] &= (
                        0 < rcandi[0] and rcandi[2] < w
                        and 0 < rcandi[1] and rcandi[3] < h)

                    overlap = False
                    for r in regions_taken:
                        if roverlaps(r, rcandi):
                            overlap = True
                            break

                    locs_ok[iloc] &= not overlap

                    for xs_taken, ys_taken in points_taken:
                        locs_ok[iloc] &= no_points_in_rect(
                            xs_taken, ys_taken, *rcandi)

                        if not locs_ok[iloc]:
                            break

                rows = []
                for iloc, (lon, lat) in enumerate(zip(lons, lats)):
                    if not locs_ok[iloc]:
                        continue

                    if self.gmt.is_gmt5():
                        row = (
                            lon, lat,
                            '%i,%s,%s' % (font_size, font, color),
                            'MC',
                            text)

                    else:
                        row = (
                            lon, lat,
                            font_size, 0, font, 'MC',
                            text)

                    rows.append(row)

                    regions_taken.append([xxx[iloc] for xxx in rects])
                    break

                self.gmt.pstext(
                    in_rows=rows,
                    *(self.jxyr + farg),
                    **style)

    def draw_labels(self):
        self.gmt
        if not self._have_drawn_labels:
            self._draw_labels()
            self._have_drawn_labels = True

    def add_label(
            self, lat, lon, text,
            offset_x=5., offset_y=5.,
            color=None,
            font='1',
            font_size=None,
            style={}):

        if 'G' in style:
            style = style.copy()
            color = style.pop('G')

        self._labels.append(
            (lon, lat, text, offset_x, offset_y, color, font, font_size,
             style))

    def add_area_label(
            self, lat, lon, text,
            color=None,
            font='3',
            font_size=None,
            style={}):

        self._area_labels.append(
            (lon, lat, text, color, font, font_size, style))

    def cities_in_region(self):
        from pyrocko.dataset import geonames
        cities = geonames.get_cities_region(region=self.wesn, minpop=0)
        cities.extend(self.custom_cities)
        cities.sort(key=lambda x: x.population)
        return cities

    def draw_cities(self,
                    exact=None,
                    include=[],
                    exclude=[],
                    nmax_soft=10,
                    psxy_style=dict(S='s5p', G='black')):

        cities = self.cities_in_region()

        if exact is not None:
            cities = [c for c in cities if c.name in exact]
            minpop = None
        else:
            cities = [c for c in cities if c.name not in exclude]
            minpop = 10**3
            for minpop_new in [1e3, 3e3, 1e4, 3e4, 1e5, 3e5, 1e6, 3e6, 1e7]:
                cities_new = [
                    c for c in cities
                    if c.population > minpop_new or c.name in include]

                if len(cities_new) == 0 or (
                        len(cities_new) < 3 and len(cities) < nmax_soft*2):
                    break

                cities = cities_new
                minpop = minpop_new
                if len(cities) <= nmax_soft:
                    break

        if cities:
            lats = [c.lat for c in cities]
            lons = [c.lon for c in cities]

            self.gmt.psxy(
                in_columns=(lons, lats),
                *self.jxyr, **psxy_style)

            for c in cities:
                try:
                    text = c.name.encode('iso-8859-1').decode('iso-8859-1')
                except UnicodeEncodeError:
                    text = c.asciiname

                self.add_label(c.lat, c.lon, text)

        self._cities_minpop = minpop

    def add_stations(self, stations, psxy_style=dict()):

        default_psxy_style = {
            'S': 't8p',
            'G': 'black'
        }
        default_psxy_style.update(psxy_style)

        lats, lons = zip(*[od.ne_to_latlon(
                                s.lat, s.lon, s.north_shift, s.east_shift)
                           for s in stations])

        self.gmt.psxy(
            in_columns=(lons, lats),
            *self.jxyr, **default_psxy_style)

        for station in stations:
            self.add_label(station.lat, station.lon, '.'.join(
                x for x in (station.network, station.station) if x))

    def add_kite_scene(self, scene):
        tile = FloatTile(
            scene.frame.llLon,
            scene.frame.llLat,
            scene.frame.dLon,
            scene.frame.dLat,
            scene.displacement)

        return tile

    def add_gnss_campaign(self, campaign, psxy_style=None, offset_scale=None,
                          labels=True, vertical=False, fontsize=10):

        stations = campaign.stations

        if offset_scale is None:
            offset_scale = num.zeros(campaign.nstations)
            for ista, sta in enumerate(stations):
                for comp in sta.components.values():
                    offset_scale[ista] += comp.shift
            offset_scale = num.sqrt(offset_scale**2).max()

        size = math.sqrt(self.height**2 + self.width**2)
        scale = (size/10.) / offset_scale
        logger.debug('GNSS: Using offset scale %f, map scale %f',
                     offset_scale, scale)

        lats, lons = zip(
            *[od.ne_to_latlon(s.lat, s.lon, s.north_shift, s.east_shift)
              for s in stations])

        if vertical:
            rows = [[lons[ista], lats[ista],
                    0., s.up.shift,
                    (s.east.sigma + s.north.sigma) if s.east.sigma else 0.,
                    s.up.sigma, 0.,
                    s.code if labels else None]
                    for ista, s in enumerate(stations)
                    if s.up is not None]

        else:
            rows = [[lons[ista], lats[ista],
                     s.east.shift, s.north.shift,
                     s.east.sigma, s.north.sigma, s.correlation_ne,
                     s.code if labels else None]
                    for ista, s in enumerate(stations)
                    if s.east is not None or s.north is not None]

        default_psxy_style = {
            'h': 0,
            'W': '1.5p,black',
            'G': 'black',
            'L': True,
            'S': 'e%dc/0.95/%d' % (scale, fontsize),
        }

        if not labels:
            for row in rows:
                row.pop(-1)

        if psxy_style is not None:
            default_psxy_style.update(psxy_style)

        self.gmt.psvelo(
            in_rows=rows,
            *self.jxyr,
            **default_psxy_style)

    def draw_plates(self):
        from pyrocko.dataset import tectonics

        neast = 20
        nnorth = max(1, int(round(num.round(self._hreg/self._wreg * neast))))
        norths = num.linspace(-self._hreg*0.5, self._hreg*0.5, nnorth)
        easts = num.linspace(-self._wreg*0.5, self._wreg*0.5, neast)
        norths2 = num.repeat(norths, neast)
        easts2 = num.tile(easts, nnorth)
        lats, lons = od.ne_to_latlon(
            self.lat, self.lon, norths2, easts2)

        bird = tectonics.PeterBird2003()
        plates = bird.get_plates()

        color_plates = gmtpy.color('aluminium5')
        color_velocities = gmtpy.color('skyblue1')
        color_velocities_lab = gmtpy.color(darken(gmtpy.color_tup('skyblue1')))

        points = num.vstack((lats, lons)).T
        used = []
        for plate in plates:
            mask = plate.contains_points(points)
            if num.any(mask):
                used.append((plate, mask))

        if len(used) > 1:

            candi_fixed = {}

            label_data = []
            for plate, mask in used:

                mean_north = num.mean(norths2[mask])
                mean_east = num.mean(easts2[mask])
                iorder = num.argsort(num.sqrt(
                        (norths2[mask] - mean_north)**2 +
                        (easts2[mask] - mean_east)**2))

                lat_candis = lats[mask][iorder]
                lon_candis = lons[mask][iorder]

                candi_fixed[plate.name] = lat_candis.size

                label_data.append((
                    lat_candis, lon_candis, plate, color_plates))

            boundaries = bird.get_boundaries()

            size = 2

            psxy_kwargs = []

            for boundary in boundaries:
                if num.any(points_in_region(boundary.points, self._wesn)):
                    for typ, part in boundary.split_types(
                            [['SUB'],
                             ['OSR', 'OTF', 'OCB', 'CTF', 'CCB', 'CRB']]):

                        lats, lons = part.T

                        kwargs = {}
                        if typ[0] == 'SUB':
                            if boundary.kind == '\\':
                                kwargs['S'] = 'f%g/%gp+t+r' % (
                                    0.45*size, 3.*size)
                            elif boundary.kind == '/':
                                kwargs['S'] = 'f%g/%gp+t+l' % (
                                    0.45*size, 3.*size)

                            kwargs['G'] = color_plates

                        kwargs['in_columns'] = (lons, lats)
                        kwargs['W'] = '%gp,%s' % (size, color_plates),

                        psxy_kwargs.append(kwargs)

                        if boundary.kind == '\\':
                            if boundary.name2 in candi_fixed:
                                candi_fixed[boundary.name2] += neast*nnorth

                        elif boundary.kind == '/':
                            if boundary.name1 in candi_fixed:
                                candi_fixed[boundary.name1] += neast*nnorth

            candi_fixed = [name for name in sorted(
                list(candi_fixed.keys()), key=lambda name: -candi_fixed[name])]

            candi_fixed.append(None)

            gsrm = tectonics.GSRM1()

            for name in candi_fixed:
                if name not in gsrm.plate_names() \
                        and name not in gsrm.plate_alt_names():

                    continue

                lats, lons, vnorth, veast, vnorth_err, veast_err, corr = \
                    gsrm.get_velocities(name, region=self._wesn)

                fixed_plate_name = name

                self.gmt.psvelo(
                    in_columns=(
                        lons, lats, veast, vnorth, veast_err, vnorth_err,
                        corr),
                    W='0.25p,%s' % color_velocities,
                    A='9p+e+g%s' % color_velocities,
                    S='e0.2p/0.95/10',
                    *self.jxyr)

                for _ in range(len(lons) // 50 + 1):
                    ii = random.randint(0, len(lons)-1)
                    v = math.sqrt(vnorth[ii]**2 + veast[ii]**2)
                    self.add_label(
                        lats[ii], lons[ii], '%.0f' % v,
                        font_size=0.7*self.gmt.label_font_size(),
                        style=dict(
                            G=color_velocities_lab))

                break

            for (lat_candis, lon_candis, plate, color) in label_data:
                full_name = bird.full_name(plate.name)
                if plate.name == fixed_plate_name:
                    full_name = '@_' + full_name + '@_'

                self.add_area_label(
                    lat_candis, lon_candis,
                    full_name,
                    color=color,
                    font='3')

            for kwargs in psxy_kwargs:
                self.gmt.psxy(*self.jxyr, **kwargs)
Esempio n. 28
0
class DataProvider(Object):
    use = List.T(String.T())
    timings = Dict.T(String.T(), Timings.T())

    def __init__(self, channels="SHZ", use=None, timings=None):
        self.use = use or []
        self.timings = timings or {}
        iris_arrays = {
            "YKA": ("CN", "YKA*", "", channels),
            #'ESK': [('IM', 'EKB?', '', channels),
            #        ('IM', 'EKR*', '', channels)],
            #'ESK1': ('IM', 'EKA?', '', channels),
            "ILAR": ("IM", "IL*", "", channels),
            "IMAR": ("IM", "IM0?", "", channels),
            #'NIA': ('IM', 'I56H?', '', channels),
            #'PFIA': [('IM', 'I57H?', '', channels),
            #         ('IM', 'I57L?', '', channels)],
            "BMA": ("IM", "BM0?", "", channels),
            "BCA": ("IM", "BC0?", "", channels),
            #'HIA': ('IM', 'I59H?', '', channels),
            "NVAR": ("IM", "NV*", "", channels),
            "PDAR": [("IM", "PD0*", "", channels), ("IM", "PD1*", "", channels)],
            "TXAR": ("IM", "TX*", "", channels),
            #'Pilbara': ('AU', 'PSA*', '', channels),
            "AliceSprings": ("AU", "AS*", "", channels),
            #'GERES': [('IM', 'GEA?', '', channels),
            #         ('IM', 'GEB?', '', channels),
            #         ('IM', 'GEC?', '', channels),
            #         ('IM', 'GED?', '', channels)],
            # Diego Garcia Hydroacoustic array noqa
            "DGHAland": ("IM", "I52H?", "", channels),
            "DGHAS": ("IM", "H08S?", "", channels),
            "DGHAN": ("IM", "H08N?", "", channels),
            # Tristan da Cunha. channels: BDF. noqa
            #'TDC': [('IM', 'H09N?', '', channels),
            #        ('IM', 'I49H?', '', channels)],
            #'NarroginIA': ('IM', 'I04H?', '', channels),
            #'CocosIslands': ('IM', 'I06H?', '', channels),
            "Warramunga": ("IM", "I07H?", "", channels),
            #'BermudaIA': ('IM', 'I51H?', '', channels),
            #'FairbanksIA': ('IM', 'I53H?', '', channels)
        }

        geofon_arrays = {
            "ROHRBACH": ("6A", "V*", "", channels),
            "AntaOffshore": ("GR", "I27L?", "*", channels),
            "AntaOnshore": ("AW", "VNA*", "*", channels),
            #'NORES': [('NO', 'NA*', '*', channels),
            # ('NO', 'NB*', '*', channels),
            # ('NO', 'NC*', '*', channels)]}
        }
        bgr_arrays = {
            "GERES": [
                ("GR", "GEA?", "*", channels),
                ("GR", "GEB?", "*", channels),
                ("GR", "GEC?", "*", channels),
                ("GR", "GED?", "*", channels),
            ],
        }

        self.providers = {
            "iris": iris_arrays,
            "geofon": geofon_arrays,
            "bgr": bgr_arrays,
        }

    def download(
        self,
        event,
        directory="array_data",
        timing=None,
        length=None,
        want="all",
        force=False,
        prefix=False,
        dump_config=False,
        get_responses=False,
    ):
        """:param want: either 'all' or ID as string or list of IDs as strings"""
        use = []
        # ts = {}
        unit = "M"
        if all([timing, length]) is None:
            raise Exception('Define one of "timing" and "length"')
        prefix = prefix or ""
        directory = pjoin(prefix, directory)
        if not os.path.isdir(directory):
            os.mkdir(directory)
        pzresponses = {}
        logger.info("download data: %s at %sN %sE" % (event.name, event.lat, event.lon))
        for site, array_data_provder in self.providers.items():
            logger.info("requesting data from site %s" % site)
            for array_id, codes in array_data_provder.items():
                if array_id not in want and want != ["all"]:
                    continue
                sub_directory = pjoin(directory, array_id)
                logger.info("%s" % array_id)
                codes = array_data_provder[array_id]
                if not isinstance(codes, list):
                    codes = [codes]
                selection = [
                    c + tuple((event.time, event.time + 1000.0)) for c in codes
                ]
                logger.debug("selection: %s" % selection)
                try:
                    #    if site=='bgr':
                    #        st = ws.station(url='http://eida.bgr.de/', selection=selection)
                    #    else:
                    #        st = ws.station(site=site, selection=selection)
                    st = ws.station(site=site, selection=selection)
                except ws.EmptyResult as e:
                    logging.error("No results: %s %s. skip" % (e, array_id))
                    continue
                except ValueError as e:
                    logger.error(e)
                    logger.error("...skipping...")
                    continue

                stations = st.get_pyrocko_stations()
                min_dist = min([ortho.distance_accurate50m(s, event) for s in stations])
                max_dist = max([ortho.distance_accurate50m(s, event) for s in stations])

                mod = cake.load_model(crust2_profile=(event.lat, event.lon))
                if length:
                    tstart = 0.0
                    tend = length
                elif timing:
                    tstart = timing[0].t(mod, (event.depth, min_dist))
                    tend = timing[1].t(mod, (event.depth, max_dist))
                selection = [
                    c + tuple((event.time + tstart, event.time + tend)) for c in codes
                ]
                try:
                    d = ws.dataselect(site=site, selection=selection)
                    store.remake_dir(sub_directory, force)
                    store.remake_dir(pjoin(sub_directory, "responses"), force)
                    fn = pjoin(sub_directory, "traces.mseed")
                    with open(fn, "wb") as f:
                        f.write(d.read())
                        f.close()
                    if get_responses:
                        trs = io.load(fn, getdata=False)
                        logger.info("Request responses from %s" % site)
                        if progressbar:
                            pb = progressbar.ProgressBar(maxval=len(trs)).start()
                        for i_tr, tr in enumerate(trs):
                            try:
                                st = ws.station(
                                    site=site, selection=selection, level="response"
                                )
                                pzresponse = st.get_pyrocko_response(
                                    nslc=tr.nslc_id,
                                    timespan=(tr.tmin, tr.tmax),
                                    fake_input_units=unit,
                                )
                                pzresponse.regularize()
                            except fdsnstation.NoResponseInformation as e:
                                logger.warn("no response information: %s" % e)
                                pzresponse = None
                                pass
                            except fdsnstation.MultipleResponseInformation as e:
                                logger.warn("MultipleResponseInformation: %s" % e)
                                pzresponse = None
                                pass
                            pzresponses[tr.nslc_id] = pzresponse
                            pzresponses[tr.nslc_id].dump(
                                filename=pjoin(
                                    sub_directory,
                                    "responses",
                                    "resp_%s.yaml" % ".".join(tr.nslc_id),
                                )
                            )
                            if progressbar:
                                pb.update(i_tr)
                        if progressbar:
                            pb.finish()
                    model.dump_stations(stations, pjoin(sub_directory, "stations.pf"))

                    if timing:
                        t = Timings(list(timing))
                        self.timings[array_id] = t
                    if array_id not in use and array_id not in self.use:
                        use.append(array_id)
                except ws.EmptyResult as e:
                    logging.error("%s on %s" % (e, array_id))

        self.use.extend(use)