[Ifeffit] Larix Pre-edge Statistics

Matt Newville newville at cars.uchicago.edu
Thu Dec 14 20:29:38 CST 2023


Hi Ryan,

Yeah, this could be a little richer.   For clarity, the "amplitude"
Parameters will be the area of each peak.   Well, it's the amplitude
factor for the unit-normalized lineshape (Gaussian, Lorentzian, Voigt,
etc), so it will be the area under that curve from -Inf to Inf.
Those Infinities probably have small effects, here anyway ;).

As you say, the centroid of multiple peaks is given, but not the total
area under the sum of non-background peaks.  That would not be too
hard to add.  But it might also fall into the category of "the sorts
of calculations we should allow the user to do after a fit" without
having to bake them all in.

That is, if you open a Larch buffer after a pre-edge peak fit, you
could get the most recent best-fit Parameters from lmfit with:

    pars = peakresult.result.params

But also, you can get "uvars" as
   uvars = peakresult.result.uvars

which is a dictionary of name:"ufloat" values for all Parameters
(variables and "constrained values"). These "ufloat" values come from
the `uncertainties` package and include uncertainties that know about
the correlations between the Parameters. You can use these for simple
calculations that will propagate the uncertainties (including
correlations).

As an example, if I do a pre-edge peak fit, with 2 Gaussian peaks
(plus Line+Lorentzian for the background), I might get a good fit and
a resulting report (from the larch buffer, do
`print(peakresult.result.fit_report()`) that looks like this:


[[Model]]
    (((Model(lorentzian, prefix='bpeak_') + Model(linear,
prefix='bpoly_')) + Model(gaussian, prefix='gauss1_')) +
Model(gaussian, prefix='gauss2_'))
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 355
    # data points      = 162
    # variables        = 11
    chi-square         = 4.5237e-04
    reduced chi-square = 2.9958e-06
    Akaike info crit   = -2049.75462
    Bayesian info crit = -2015.79106
    R-squared          = 0.99953048
[[Variables]]
    bpeak_amplitude:   1.82988250 +/- 0.04372160 (2.39%) (init = 2.462209)
    bpeak_center:      7118.44625 +/- 0.02812082 (0.00%) (init = 7120.091)
    bpeak_sigma:       1.36103880 +/- 0.01273292 (0.94%) (init = 2.121656)
    bpeak_fwhm:        2.72207761 +/- 0.02546583 (0.94%) ==
'2.0000000*bpeak_sigma'
    bpeak_height:      0.42795967 +/- 0.00701416 (1.64%) ==
'0.3183099*bpeak_amplitude/max(1e-15, bpeak_sigma)'
    bpoly_intercept:  -6.37404087 +/- 0.65831626 (10.33%) (init = 2.467005)
    bpoly_slope:       8.9825e-04 +/- 9.2664e-05 (10.32%) (init = -0.000347)
    gauss1_amplitude:  0.10390560 +/- 0.00363058 (3.49%) (init = 0.14991)
    gauss1_center:     7111.52424 +/- 0.02714092 (0.00%) (init = 7112.452)
    gauss1_sigma:      0.75932812 +/- 0.02151410 (2.83%) (init = 1.315216)
    gauss1_fwhm:       1.78808103 +/- 0.05066183 (2.83%) ==
'2.3548200*gauss1_sigma'
    gauss1_height:     0.05459081 +/- 7.8147e-04 (1.43%) ==
'0.3989423*gass1_amplitude/max(1e-15, gauss1_sigma)'
    gauss2_amplitude:  0.03945700 +/- 0.00329914 (8.36%) (init = 0.116005)
    gauss2_center:     7113.18957 +/- 0.04258439 (0.00%) (init = 7113.403)
    gauss2_sigma:      0.57985874 +/- 0.03338641 (5.76%) (init = 0.556759)
    gauss2_fwhm:       1.36546297 +/- 0.07861898 (5.76%) ==
'2.3548200*gauss2_sigma'
    gauss2_height:     0.02714638 +/- 0.00110204 (4.06%) ==
'0.3989423*gauss2_amplitude/max(1e-15, gauss2_sigma)'
    fit_centroid:      7111.98258 +/- 0.01448240 (0.00%) ==
'(gauss1_amplitude*gauss1_center +gauss2_amplitude*gauss2_center
)/(gauss1_amplitude+gauss2_amplitude)'
[[Correlations]] (unreported correlations are < 0.100)
    C(bpoly_intercept, bpoly_slope)       = -1.0000
    C(bpeak_amplitude, bpeak_center)      = +0.9722
    C(gauss1_amplitude, gauss1_sigma)     = +0.9186
    ....
    C(gauss1_amplitude, gauss2_amplitude) = -0.7900


So there are 2 "gaussN_amplitude" Parameters for the area under each
Gaussian, with a strong negative correlation.    If you do

 >>>  uvars = peakresult.result.uvars
 >>>  print(uvars['gauss1_amplitude'], uvars['gauss2_amplitude'])
 >>>  print(uvars['gauss1_amplitude'] + uvars['gauss2_amplitude'])

You'll get the area of the sum of the two Gaussians as

   0.104+/-0.004 0.0395+/-0.0033
   0.1434+/-0.0023

That is, one might expect the uncertainties in 'gauss1_amplitude' and
'gauss2_amplitude' should add in quadrature, but that would
overestimate the uncertainty in the sum by almost ~2x because the
parameters are highly (and negatively) correlated.   The uncertainty
in the reported peak heights and the centroid of the two peaks also
takes the correlations into account.

Such calculations are not too hard to do from the Larch buffer or
Python script, but we might think about how that could be exposed more
flexibly.

I can be persuaded to just add a Parameter "peaks_area" = the sum of
the amplitudes, which would then have this value and uncertainty.
Any suggestions for what should be exposed here?

Cheers,

--Matt


On Thu, Dec 14, 2023 at 10:47 AM Ryan Parmenter <rap35 at kent.ac.uk> wrote:
>
> Hello,
>
>
>
> I successfully fitted Gaussian curves to my pre-edge peaks using Larix (XAS Viewer), yielding the centroid energy for indicating Fe oxidation state. The expected trends are observed, however, in reviewing articles, I noticed they report the area and integrated intensities of Gaussian curves, often automated with Peakfit software. Can Larix generate these values in its statistical report? If not, how can I calculate the area and integrated intensity using Larix's provided values, considering the absence of standard deviation?
>
>
>
> Thanks,
>
> Ryan
>
>
>
> _______________________________________________
> Ifeffit mailing list
> Ifeffit at millenia.cars.aps.anl.gov
> http://millenia.cars.aps.anl.gov/mailman/listinfo/ifeffit
> Unsubscribe: http://millenia.cars.aps.anl.gov/mailman/options/ifeffit



More information about the Ifeffit mailing list