예제 #1
0
파일: smtk.py 프로젝트: rizac/eGSIM
def _extract_params(params):
    '''Returns the basic parameters from a trellis `params` dict, converting
    them according to egsim needs. Returns the tuple:
    (gsim, imt, magnitudes, distances, trellisclass, stdev_trellisclass)
    where `trellis_class_for_stddev` can be None or the `trellis_class`
    counterpart for computing the standard deviations
    '''
    MAG = 'magnitude'  # pylint: disable=invalid-name
    DIST = 'distance'  # pylint: disable=invalid-name
    GSIM = 'gsim'  # pylint: disable=invalid-name
    IMT = 'imt'  # pylint: disable=invalid-name
    STDEV = 'stdev'  # pylint: disable=invalid-name
    PLOT_TYPE = 'plot_type'  # pylint: disable=invalid-name

    # NOTE: the `params` dict will be passed to smtk routines: we use 'pop'
    # whenever possible to avoid passing unwanted params:
    gsim = params.pop(GSIM)
    # imt might be None for "spectra" Trellis classes, thus provide None:
    imt = params.pop(IMT, None)
    magnitudes = np.asarray(vectorize(params.pop(MAG)))  # smtk wants np arrays
    distances = np.asarray(vectorize(params.pop(DIST)))  # smtk wants np arrays

    trellisclass = params.pop(PLOT_TYPE)
    # define stddev trellis class if the parameter stdev is true
    stdev_trellisclass = None  # do not compute stdev (default)
    if params.pop(STDEV, False):
        if trellisclass == DistanceIMTTrellis:
            stdev_trellisclass = DistanceSigmaIMTTrellis
        elif trellisclass == MagnitudeIMTTrellis:
            stdev_trellisclass = MagnitudeSigmaIMTTrellis
        elif trellisclass == MagnitudeDistanceSpectraTrellis:
            stdev_trellisclass = MagnitudeDistanceSpectraSigmaTrellis

    return gsim, imt, magnitudes, distances, trellisclass, stdev_trellisclass
예제 #2
0
def test_vectorize():
    '''tests the vectorize function'''
    for arg in (None, '', 'abc', 1, 1.4005, True):
        expected = [arg]
        assert vectorize(arg) == expected
        assert vectorize(expected) is expected
    args = ([1, 2, 3], range(5), (1 for _ in [1, 2, 3]))
    for arg in args:
        assert vectorize(arg) is arg
예제 #3
0
파일: forms.py 프로젝트: rizac/eGSIM
    def clean(self):
        cleaned_data = super(TrellisForm, self).clean()

        # calculate z1pt0 and z2pt5 if needed, raise in case of errors:
        vs30 = cleaned_data['vs30']  # surely a list with st least one element
        vs30scalar = isscalar(vs30)
        vs30s = np.array(vectorize(vs30), dtype=float)

        # check vs30-dependent values:
        for name, func in (['z1pt0', vs30_to_z1pt0_cy14],
                           ['z2pt5', vs30_to_z2pt5_cb14]):
            if name not in cleaned_data or cleaned_data[name] == []:
                values = func(vs30s)  # numpy-function
                cleaned_data[name] = \
                    float(values[0]) if vs30scalar else values.tolist()
            elif isscalar(cleaned_data[name]) != isscalar(vs30) or \
                    (not isscalar(vs30) and
                     len(vs30) != len(cleaned_data[name])):
                str_ = 'scalar' if isscalar(vs30) else \
                    '%d-elements vector' % len(vs30)
                # instead of raising ValidationError, which is keyed with
                # '__all__' we add the error keyed to the given field name
                # `name` via `self.add_error`:
                # https://docs.djangoproject.com/en/2.0/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
                error = ValidationError(_("value must be consistent with vs30 "
                                          "(%s)" % str_),
                                        code='invalid')
                self.add_error(name, error)

        return cleaned_data
예제 #4
0
파일: fields.py 프로젝트: rizac/eGSIM
    def to_python(self, value):
        '''Converts the given input value to a Python list of IMT strings
        Remember that this method is called from within `self.clean` which in
        turns calls first `self.to_python` and then `self.validate`. The latter
        calls `self.valid_value` on each element of the input IMT list
        '''
        # convert strings with wildcards to matching elements
        # (see MultipleChoiceWildcardField):
        imts = ImtclassField.to_python(self, value)
        # combine with separate SA periods, if provided
        periods_str = self.sa_periods_str
        if periods_str:
            try:
                saindex = imts.index(self.SA)
            except ValueError:
                saindex = len(imts)

            try:
                periods = \
                    vectorize(NArrayField(required=False).clean(periods_str))
                ret = [_ for _ in imts if _ != self.SA]
                sa_str = '{}(%s)'.format(self.SA)
                sa_periods = [sa_str % _ for _ in periods]
                imts = ret[:saindex] + sa_periods + ret[saindex:]
            except Exception as _exc:
                raise ValidationError(
                    self.error_messages['invalid_sa_period'],
                    code='invalid_sa_period',
                    params={'value': periods_str},
                )

        return imts
예제 #5
0
    def to_python(self, value):
        # three scenarios: iterable: take iterable
        # non iterable: parse [value]
        # string: split value into iterable
        values = []
        is_vector = not isscalar(value)

        if value is not None:
            if not is_vector and isinstance(value, str):
                value = value.strip()
                is_vector = value[:1] == '['
                if is_vector != (value[-1:] == ']'):
                    raise ValidationError('unbalanced brackets')
                try:
                    value = json.loads(value if is_vector else "[%s]" % value)
                except Exception:  # pylint: disable=broad-except
                    try:
                        value = shlex.split(
                            value[1:-1].strip() if is_vector else value)
                    except Exception:
                        raise ValidationError('Input syntax error')

            for val in vectorize(value):
                try:
                    vls = self.parse(val)
                except ValidationError:
                    raise
                except Exception as exc:
                    raise ValidationError("%s: %s" % (str(val), str(exc)))

                if isscalar(vls):
                    values.append(vls)
                else:
                    # force the return value to be list even if we have 1 elm:
                    is_vector = True
                    values.extend(vls)

            # check lengths:
            try:
                self.checkrange(len(values), self.min_count, self.max_count)
            except ValidationError as verr:
                # just re-format exception stringand raise:
                # msg should be in the form '% not in ...', remove first '%s'
                msg = verr.message[verr.message.find(' '):]
                raise ValidationError('number of elements (%d) %s' %
                                      (len(values), msg))

            # check bounds:
            minval, maxval = self.min_value, self.max_value
            minval = [minval] * len(values) if isscalar(minval) else minval
            maxval = [maxval] * len(values) if isscalar(maxval) else maxval
            for numval, mnval, mxval in zip(values,
                                            chain(minval, repeat(None)),
                                            chain(maxval, repeat(None))):
                self.checkrange(numval, mnval, mxval)

        return values[0] if (len(values) == 1 and not is_vector) else values
예제 #6
0
    def to_python(self, value):
        imts = ImtclassField.to_python(self, value)
        # combine with separate SA periods, if provided
        periods_str = self.sa_periods_str
        if periods_str:
            try:
                saindex = imts.index(self.SA)
            except ValueError:
                saindex = len(imts)

            try:
                periods = \
                    vectorize(NArrayField(required=False).clean(periods_str))
                ret = [_ for _ in imts if _ != self.SA]
                sa_str = '{}(%s)'.format(self.SA)
                sa_periods = [sa_str % _ for _ in periods]
                imts = ret[:saindex] + sa_periods + ret[saindex:]
            except Exception as _:
                raise ValidationError(
                    self.error_messages['invalid_sa_periods'],
                    code='invalid_sa_periods')

        return imts
예제 #7
0
def get_trellis(params):
    # param names:
    MAG = 'magnitude'  # pylint: disable=invalid-name
    DIST = 'distance'  # pylint: disable=invalid-name
    VS30 = 'vs30'  # pylint: disable=invalid-name
    Z1PT0 = 'z1pt0'  # pylint: disable=invalid-name
    Z2PT5 = 'z2pt5'  # pylint: disable=invalid-name
    GSIM = 'gsim'  # pylint: disable=invalid-name
    IMT = 'imt'  # pylint: disable=invalid-name

    # dip, aspect will be used below, we oparse them here because they are
    # mandatory (FIXME: are they?)
    magnitude, distance, vs30, z1pt0, z2pt5, gsim = \
        params.pop(MAG), params.pop(DIST), params.pop(VS30), \
        params.pop(Z1PT0), params.pop(Z2PT5), params.pop(GSIM)
    magnitudes = np.asarray(vectorize(magnitude))  # smtk wants numpy arrays
    distances = np.asarray(vectorize(distance))  # smtk wants numpy arrays

    vs30s = vectorize(vs30)
    z1pt0s = vectorize(z1pt0)
    z2pt5s = vectorize(z2pt5)

    trellisclass = params.pop('plot_type')
    isdist = trellisclass in (DistanceIMTTrellis, DistanceSigmaIMTTrellis)
    ismag = trellisclass in (MagnitudeIMTTrellis, MagnitudeSigmaIMTTrellis)
    isspectra = not isdist and not ismag
    if isspectra:  # magnitudedistancetrellis:
        # imt is actually a vector of periods for the SA. This is misleading in
        # smtk, might be better implemented (maybe future PR?)
        imt = _default_periods_for_spectra()
        params.pop(IMT, None)  # remove IMT and do not raise if not defined
        imt_names = ['SA']
    else:
        imt = imt_names = params.pop(IMT)  # this raises if IMT is not in dict

    def jsonserialize(value):
        '''serializes a numpy scalr into python scalar, no-op if value is not
        a numpy number'''
        try:
            return value.item()
        except AttributeError:
            return value

    ret = None
    figures = defaultdict(list)
    col_key, row_key = 'column', 'row'
    for vs30, z1pt0, z2pt5 in zip(vs30s, z1pt0s, z2pt5s):
        params[VS30] = vs30
        params[Z1PT0] = z1pt0
        params[Z2PT5] = z2pt5
        # Depending on `trellisclass` we might need to iterate over
        # `magnitudes`, or use `magnitudes` once (the same holds for
        # `distances`). In order to make code cleaner we define a magnitude
        # iterator which yields a two element tuple (m1, m2) where m1 is the
        # scalar value to be saved as json, and m2 is the value
        # (scalar or array) to be passed to the Trellis class:
        magiter = zip(magnitudes, magnitudes) if isdist else \
            zip([None], [magnitudes])
        for mag, mags in magiter:
            # same as magnitudes (see above):
            distiter = zip(distances, distances) if ismag else \
                zip([None], [distances])
            for dist, dists in distiter:
                trellis_obj = trellisclass.from_rupture_properties(
                    params, mags, dists, gsim, imt)

                data = trellis_obj.to_dict()
                #
                # data = {
                #    xlabel: string
                #    xvalues: list of floats
                #    figures: [
                #        ylabel:
                #        magnitude:
                #        distance:
                #        row:
                #        column:
                #        yvalues:
                #    ]
                # }
                if ret is None:
                    ret = {
                        'xlabel': _relabel_sa(data['xlabel']),
                        'xvalues': data['xvalues']
                    }
                # get the imt. Unfortunately, the imt is "hidden"
                # within each data.figures.ylabel, thus we have to
                # re-evaluate them using trellis_obj._get_ylabel,
                # which is what smtk uses
                if not isspectra:
                    ylabel2imt = {trellis_obj._get_ylabel(_): _ for _ in imt}

                src_figures = data['figures']
                for fig in src_figures:
                    fig.pop(col_key, None)
                    fig.pop(row_key, None)
                    fig[VS30] = jsonserialize(vs30)
                    fig[MAG] = jsonserialize(fig.get(MAG, mag))
                    fig[DIST] = jsonserialize(fig.get(DIST, dist))
                    imt_name = \
                        'SA' if isspectra else ylabel2imt[fig['ylabel']]
                    figures[imt_name].append(fig)
                    # change labels SA(1.0000) into SA(1.0) but at the end
                    # because the ylabel might have been used
                    # as key (see line above)
                    fig['ylabel'] = _relabel_sa(fig['ylabel'])

    # re-arrange labels FIXME: implement it in smtk?
    return {**ret, **{'imts': imt_names}, **figures}
예제 #8
0
파일: smtk.py 프로젝트: rizac/eGSIM
def get_trellis(params):
    '''Core method to compute trellis plots data

    :param params: dict with the request parameters

    :return: json serializable dict to be passed into a Response object
    '''
    # param names:
    MAG = 'magnitude'  # pylint: disable=invalid-name
    DIST = 'distance'  # pylint: disable=invalid-name
    VS30 = 'vs30'  # pylint: disable=invalid-name
    Z1PT0 = 'z1pt0'  # pylint: disable=invalid-name
    Z2PT5 = 'z2pt5'  # pylint: disable=invalid-name

    gsim, imt, magnitudes, distances, trellisclass, stdev_trellisclass = \
        _extract_params(params)

    xdata = None
    figures = defaultdict(list)  # imt name -> list of dicts (1 dict=1 plot)
    for vs30, z1pt0, z2pt5 in zip(vectorize(params.pop(VS30)),
                                  vectorize(params.pop(Z1PT0)),
                                  vectorize(params.pop(Z2PT5))):
        params[VS30] = vs30
        params[Z1PT0] = z1pt0
        params[Z2PT5] = z2pt5
        # Depending on `trellisclass` we might need to iterate over
        # `magnitudes`, or use `magnitudes` once (the same holds for
        # `distances`). In order to make code cleaner we define a magnitude
        # iterator which yields a two element tuple (m1, m2) where m1 is the
        # scalar value to be saved as json, and m2 is the value
        # (scalar or array) to be passed to the Trellis class:
        for mag, mags in zip(magnitudes, magnitudes) \
                if _isdist(trellisclass) else zip([None], [magnitudes]):
            # same as magnitudes (see above):
            for dist, dists in zip(distances, distances) \
                    if _ismag(trellisclass) else zip([None], [distances]):

                data = _get_trellis_dict(trellisclass, params, mags, dists,
                                         gsim, imt)

                if xdata is None:
                    xdata = {
                        'xlabel': _relabel_sa(data['xlabel']),
                        'xvalues': data['xvalues']
                    }

                _add_stdev(
                    data,
                    None if stdev_trellisclass is None else _get_trellis_dict(
                        stdev_trellisclass, params, mags, dists, gsim, imt))

                for fig in data['figures']:
                    # Now we will modify 'fig' and eventually add it to
                    # 'figures'.
                    # 'fig' is a dict of this type:
                    # (see method `_get_trellis_dict` and `_add_stdev` above):
                    #    {
                    #        ylabel: str
                    #        stdvalues: {} or dict gsimname -> list of numbers
                    #        stdlabel: str (might be empty str)
                    #        imt: str (the imt)
                    #        yvalues: dict (gsim name -> list of numbers)
                    #    }
                    # 1) Add some keys to 'fig':
                    fig[VS30] = _jsonserialize(vs30)
                    fig[MAG] = _jsonserialize(fig.get(MAG, mag))
                    fig[DIST] = _jsonserialize(fig.get(DIST, dist))
                    # 4: Remove the imt of 'fig', and use it as key of
                    # 'figures'
                    figures[fig.pop('imt')].append(fig)
                    # 'figures' is a dict of imt names mapped to a list of
                    # dict. Each dict is one of the 'fig' just processed,
                    # their count depends on the product of the chosen vs30,
                    # mad and dist

    return {
        **xdata, 'imts':
        imt if (_ismag(trellisclass) or _isdist(trellisclass)) else ['SA'],
        **figures
    }