Beispiel #1
0
def get_equivalent_circuit_model(modelname, logscale=False, diel=False):
    """Get LMFIT CompositeModel.

    Parameters
    ----------
    modelname: str
        String representation of the equivalent circuit.
    logscale: bool
        Convert to logscale.
    diel: bool
        Convert to complex permittivity and fit this instead of impedance.

    Returns
    -------
    :py:class:`lmfit.model.CompositeModel` or :class:`lmfit.model.Model`
        the final model of the entire circuit

    Notes
    -----

    The parser is based on Pyparsing.
    It is sensitive towards extra `(` or `)` or `+`.
    Thus, keep the circuit simple.
    """

    circuit = []
    assert isinstance(modelname, str), "Pass the model as a string"
    str2parse = modelname.replace("parallel", "")
    circuit_elements = pp.Word(pp.srange("[a-zA-Z_0-9]"))
    plusop = pp.Literal('+')
    commaop = pp.Literal(',')
    expr = pp.infixNotation(circuit_elements, [(plusop, 2, pp.opAssoc.LEFT),
                                               (commaop, 2, pp.opAssoc.LEFT)])
    try:
        circuitstr = expr.parseString(str2parse)
    except pp.ParseException:
        raise ("You must provide a correct string!")
    _check_circuit(circuitstr.asList()[0],
                   startpar=modelname.startswith("parallel"))
    circuit = _process_circuit(circuitstr.asList()[0])
    if logscale:
        circuit = CompositeModel(circuit, Model(dummy), log)
    elif diel:
        circuit = CompositeModel(circuit, Model(make_eps), eps)
    if logscale and diel:
        raise RuntimeError(
            "You must chose the representation of the impedance value")
    _check_models_suffix(circuit)
    logger.debug("Created composite model {}".format(circuit))
    return circuit
def fit_composit(seq, *params, report=False):
    x = np.arange(len(seq))
    y = seq
    amp, cen, wid = params
    cmodel = CompositeModel(Model(gaussian), Model(LognormalModel),
                            ExponentialGaussianModel)
    pars = cmodel.make_params(amplitude=amp, center=cen, sigma=wid, mid=cen)
    # 'mid' and 'center' should be completely correlated, and 'mid' is
    # used as an integer index, so a very poor fit variable:
    pars['mid'].vary = False
    # fit this model to data array y
    result = cmodel.fit(y, params=pars, x=x)
    # limit the amplitude to be in 0-256
    cmodel.set_param_hint('amp', min=0)
    cmodel.set_param_hint('amp', max=256)
    result = gmodel.fit(y, x=x, amp=amp, cen=cen, wid=wid)
    if result.redchi >= 1e3:
        #    if report:
        plt.figure()
        plt.plot(x, y, 'bo')
        #        plt.plot(x, result.init_fit, 'k--')
        plt.plot(x, np.ceil(result.best_fit), 'r-')
        plt.title('chi2: {0:.2e} - red_chi2: {0:.2e}'.format(
            result.chisqr, result.redchi))
        plt.show()
    return result
Beispiel #3
0
def fit_gaussian_peak_step_background_2(x, y):
    # create data from broadened step
    npts = 201
    x = np.linspace(0, 10, npts)
    y = step(x, amplitude=12.5, center=4.5, sigma=0.88, form='erf')
    y = y + np.random.normal(size=npts, scale=0.35)
    # create Composite Model using the custom convolution operator
    mod = CompositeModel(Model(jump), Model(gaussian), convolve)
    pars = mod.make_params(amplitude=1, center=3.5, sigma=1.5, mid=5.0)
    # 'mid' and 'center' should be completely correlated, and 'mid' is
    # used as an integer index, so a very poor fit variable:
    pars['mid'].vary = False

    # fit this model to data array y
    result = mod.fit(y, params=pars, x=x)

    print(result.fit_report())

    plot_components = True

    # plot results
    plt.plot(x, y, 'bo')
    if plot_components:
        # generate components
        comps = result.eval_components(x=x)
        plt.plot(x, 10 * comps['jump'], 'k--')
        plt.plot(x, 10 * comps['gaussian'], 'r-')
    else:
        plt.plot(x, result.init_fit, 'k--')
        plt.plot(x, result.best_fit, 'r-')
    plt.show()
    # #<end examples/model_doc3.py>

    return fit_fwhm, fit_center, fwhm_err
Beispiel #4
0
    def __init__(self, q, nLor=2, **kwargs):
        prefix = ""
        if "prefix" in kwargs.keys():
            prefix = kwargs.pop("prefix")

        left = delta(q, prefix="%sdelta_" % prefix, **kwargs)

        right = lorentzian(q, prefix="%sl0_" % prefix, **kwargs)
        for i in range(1, nLor):
            right = CompositeModel(
                right,
                lorentzian(q, prefix="%sl%i_" % (prefix, i), **kwargs),
                operator.add,
            )

        super().__init__(left, right, operator.add)
Beispiel #5
0
def _process_parallel(model):
    """Process parallel circuit.

    Parameters
    ----------
    model: list
        Contains the parallel circuit as a nested list.

    Returns
    -------
    :py:class:`lmfit.model.CompositeModel`
        The CompositeModel of the parallel circuit.
    """
    assert len(model) == 3, "The model must be [model1, ',' , model2]"
    first_model = model[0]
    second_model = model[2]
    first = _process_element(first_model)
    second = _process_element(second_model)
    return CompositeModel(first, second, parallel)
# code from https://lmfit.github.io/lmfit-py/model.html


def convolve(arr, kernel):
    # simple convolution of two arrays
    npts = min(len(arr), len(kernel))
    pad = np.ones(npts)
    tmp = np.concatenate((pad * arr[0], arr, pad * arr[-1]))

    out = np.convolve(tmp, kernel, mode='valid')
    noff = int((len(out) - npts) / 2)
    return out[noff:noff + npts]


# Create model for the fit
gmodel = CompositeModel(Model(irf_gate), Model(model_2lorentzians), convolve)

print('Names of parameters:', gmodel.param_names)
print('Independent variable(s):', gmodel.independent_vars)

# Load reference data - extract x and y values
two_lorentzians_iris = np.loadtxt(path_to_data + 'data_2lorentzians.dat')
xx = two_lorentzians_iris[:, 0]
yy = two_lorentzians_iris[:, 1]

# Fit
result = gmodel.fit(yy,
                    x=xx,
                    scale1=1.,
                    center1=0.,
                    hwhm1=0.25,
Beispiel #7
0
# Create convolution function
# code from https://lmfit.github.io/lmfit-py/model.html


def convolve(arr, kernel):
    # simple convolution of two arrays
    npts = min(len(arr), len(kernel))
    pad = np.ones(npts)
    tmp = np.concatenate((pad * arr[0], arr, pad * arr[-1]))

    out = np.convolve(tmp, kernel, mode='valid')
    noff = int((len(out) - npts) / 2)
    return out[noff:noff + npts]


model = CompositeModel(Model(irf_gate), Model(QENSmodels.sqwWaterTeixeira),
                       convolve)

print('Names of parameters:', model.param_names)
print('Independent variable(s):', model.independent_vars)

# Define boundaries for parameters to be refined
model.set_param_hint('scale', min=0, max=100)
model.set_param_hint('center', min=-0.1, max=0.1)
model.set_param_hint('D', min=0.05, max=0.25)
model.set_param_hint('resTime', min=0, max=1)
model.set_param_hint('radius', min=0.9, max=1.1)
model.set_param_hint('DR', min=0, max=1)

# Fix some of the parameters
model.set_param_hint('q', vary=False)
model.set_param_hint('spectrum_nb', vary=False)
Beispiel #8
0
    def _convolve(
        self, left, right, params=None, returnComponents=None, **kwargs
    ):
        r"""Perform a convolution between `left` and `right`.

        If the convolutions between function in `left` and the
        function in `right` is defined in `convolutions` attribute,
        then use this corresponding function for analytical
        convolution.
        Else, the behavior is determined by the `on_undefined_conv`
        parameter.

        Parameters
        ----------
        left : :class:`Model` or :class:`CompositeModel`
            Model or CompositeModel to be used for convolution.
        right : :class:`Model` or :class:`CompositeModel`
            Model or CompositeModel to be used for convolution.
        params : Parameters, optional
            Parameters to be given to the model functions.
        kwargs : dict
            Additional keyword arguments to pass to the model functions.

        Returns
        -------
        An array containing the result of the convolution.

        Notes
        -----
        This composition of models works differently than for other operators,
        as the operators is applied between each pair of components in left
        and right components.
        That is, for ``left = a1 + a2 - a3`` and ``right = b1 * b2``, where
        a's and b's are instances of :class:`Model` class:

        .. math::
            left \otimes right = (a_1 \otimes b_1 * a_1 \otimes b_2)
                                 + (a_2 \otimes b_1 * a_2 \otimes b_2)
                                 - (a_3 \otimes b_1 * a_3 \otimes b_2)

        """
        if returnComponents == "right":
            tmp = left
            left = right
            right = tmp

        lcomponents = left.components
        rcomponents = right.components

        lops, rops = self._operators()

        models = []
        compPrefix = []
        for lcomp in lcomponents:
            tmpRes = []
            for rcomp in rcomponents:
                if lcomp.func.__name__ in self.convMap.keys():
                    funcName = rcomp.func.__name__
                    leftConvMap = self.convMap[lcomp.func.__name__]
                    if funcName in leftConvMap.keys():
                        if params is None:
                            params = self.make_params()
                        convFunc = leftConvMap[funcName]
                        tmpRes.append(convFunc(lcomp, rcomp, params, **kwargs))
                    else:
                        if self._on_undefined_conv == "numeric":
                            convFunc = lambda l, r: fftconvolve(
                                l, r, mode="same", axes=-1
                            )
                            tmpRes.append(
                                CompositeModel(lcomp, rcomp, convFunc).eval(
                                    params, **kwargs
                                )
                            )
                        elif self._on_undefined_conv == "raise":
                            raise KeyError(
                                "Convolution function between %s and %s is "
                                "not defined."
                                % (lcomp.func.__name__, funcName)
                            )
                else:
                    if self._on_undefined_conv == "numeric":
                        convFunc = lambda l, r: fftconvolve(
                            l, r, mode="same", axes=-1
                        )
                        tmpRes.append(
                            CompositeModel(lcomp, rcomp, convFunc).eval(
                                params, **kwargs
                            )
                        )

            # apply operators from the right
            if len(tmpRes) > 1:
                for idx, rop in enumerate(rops):
                    tmpRes[0] = rop(tmpRes[idx], tmpRes[idx + 1])
            models.append(tmpRes[0])
            compPrefix.append(lcomp.prefix)

        if returnComponents is None:
            # finally apply operators from the left
            if len(models) > 1:
                for idx, lop in enumerate(lops):
                    models[0] = lop(models[idx], models[idx + 1])
            return models[0]
        else:
            out = OrderedDict()
            for val in zip(compPrefix, models):
                out[val[0]] = val[1]
            return out
    return o


def convolve(arr, kernel):
    # simple convolution of two arrays
    npts = min(len(arr), len(kernel))
    pad = np.ones(npts)
    tmp = np.concatenate((pad * arr[0], arr, pad * arr[-1]))
    out = np.convolve(tmp, kernel, mode='valid')
    noff = int((len(out) - npts) / 2)
    return out[noff:noff + npts]


#
# create Composite Model using the custom convolution operator
mod = CompositeModel(Model(jump), Model(gaussian), convolve)

pars = mod.make_params(amplitude=1, center=3.5, sigma=1.5, mid=5.0)

# 'mid' and 'center' should be completely correlated, and 'mid' is
# used as an integer index, so a very poor fit variable:
pars['mid'].vary = False

# fit this model to data array y
result = mod.fit(y, params=pars, x=x)

print(result.fit_report())

plot_components = False

# plot results