Skip to content

adding peak_voigt model#743

Open
marimperorclerc wants to merge 2 commits into
masterfrom
peak_voigt
Open

adding peak_voigt model#743
marimperorclerc wants to merge 2 commits into
masterfrom
peak_voigt

Conversation

@marimperorclerc

Copy link
Copy Markdown
Contributor

No description provided.

@marimperorclerc

Copy link
Copy Markdown
Contributor Author

Purpose of this PR is to add pseudo Voigt peak shape model.
It is a pure python model based on the one writen for the marketplace :
https://marketplace.sasview.org/uploads/619

If someone could help with the RUFF issue, I would be grateful !

@krzywon

krzywon commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@marimperorclerc - I've applied the ruff fixes. If you would like to not have this type of issue in the future, please follow the instructions at https://github.com/orgs/SasView/discussions/3171#discussioncomment-17148772 to get ruff and pre-commit set up.

sigma = hwhm / cste
intensity = (wf * (1 / (1 + ((q - q0)**2.0 / hwhm**2.0)))) + \
((1.0 - wf) * np.exp((-0.5 * (q - q0)**2.0) / (sigma**2.0)))
return intensity

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use Voigt rather than pseudo-Voigt:

def voigt(x, sigma, gamma):
    """
    Return the voigt function, which is the convolution of a Lorentz
    function with a Gaussian.

    :Parameters:
     gamma : real
      The half-width half-maximum of the Lorentzian
     sigma : real
      The 1-sigma width of the Gaussian, which is one standard deviation.

    Ref: W.I.F. David, J. Appl. Cryst. (1986). 19, 63-64

    Note: adjusted to use stddev and HWHM rather than FWHM parameters
    """
    # wofz function = w(z) = Fad[d][e][y]eva function = exp(-z**2)erfc(-iz)
    from scipy.special import wofz

    # TODO: if sigma == 0: return Lorentzian
    z = (x + 1j * gamma) / (sigma * np.sqrt(2))
    V = wofz(z) / (np.sqrt(2 * pi) * sigma)
    return V.real

For a 1000 point function on my mac this takes 47.5 μs vs 12.5 μs for the pseudo-Voigt function.

# cste = 1.17741
sigma = hwhm / cste
intensity = (wf * (1 / (1 + ((q - q0)**2.0 / hwhm**2.0)))) + \
((1.0 - wf) * np.exp((-0.5 * (q - q0)**2.0) / (sigma**2.0)))

@pkienzle pkienzle Jul 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than the "\" line extender use parentheses around the entire expression so it can break across multiple lines without the backslash.

Move the "+" operator to the beginning of the second line.

half-maximum) for the Lorentzian and sigma = HWHM / 1.17741 for the
Gaussian, where sigma is the standard deviation of the Gaussian. In
other words, the widths of the Lorentzian and the Gaussian have been
coupled for convenience of parameterisation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convenient for whom? The width of the Gaussian and Lorentzian are easier to interpret physically. I don't think the optimizer will care which pair it is fitting. The only advantage seems to be that it is easier to guess the initial value of HWHM from the graph.

This pseudo-Voigt peak function is a weighted linear summation of
Lorentzian (L) and Gaussian (G) peak shapes.
It is a popular function for modelling peak shape.
It can be tailored to any specific peak shape and it can also produce a peak shape with asymmetry.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both the gaussian and the lorentzian are symmetric about peak_pos, and so is the linear combination. It make look asymmetric due to log q scale, or because the resolution function Δq is increasing with q.

Mention that the voigt function is a convolution $(L_γ \star G_σ)(q)$. pseudo-Voigt approximates this with a linear combination of a lorentzian and a gaussian.

Add a note that the instrument resolution function contributes to the convolution. That is, if the resolution is a gaussian of approximately constant width Δq then $f(q) = (L_γ \star G_σ \star G_{Δq})(q) = (L_γ \star G_σ')(q)$ with σ'=√(σ² + Δq²) where σ is the width returned from the fit. The fitted σ is intrinsic to the sample. You will need to subtract the modified resolution width Δq/√(2 \ln 2) from the HWHM when guessing the peak_hwhm parameter value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants