
Custom peak function in MPF2 - what happened to the fit wave?

josh.liptonduffin
DS(a, G, A, x0) = A*( cos( Pi*a/2 + (1-a)*arctan((x-x0)/G) ) / (G^2 + (x-x0)^2)^(1/2-a/2)
Here A is the amplitude, G is the width, x0 is the centroid, and a is the asymmetry parameter. With a=0 the function simplifies to a Lorentzian, and with a between 0 and 1 it is asymmetric towards lower values of x. Typical fit values of a should be 0.1-0.3.
I believe I have successfully programmed this as an MPF2 fit function, and I can get the peaks to show up in the subcomponent axis. The fit appears to complete correctly, giving me reasonable-looking peaks. However, the fitted curve is not present on the graph - the original data is there, and the residuals look as if no fit is present (direct copy of the data, so it's subtracting zero from the data), see the attached image.
If I switch the peak type to Gaussian, it works correctly. The fit function reappears, and the residuals are calculated properly as well...
Have I messed up the peak definition? Why is it drawing the individual peaks, but not the fit function? Is it the arctangent function screwing me up?

January 25, 2012 at 09:36 am - Permalink
The DS peak shape should be generally no problem for MPF2 as even non-analytic peaks are possible. Have you actually thought about peak broadening of your experiment (?) via Gaussian convolution or is this not relevant? Also, you want to be extra careful of what to give back as fit results, since especially the area in this case is useless.
Anyway, it would make things easier if you could provide your code or an example experiment (attached to you entry).
Maybe it would also be a good idea to work together to create a generalized DS peak snippet for the community to use as it is a relatively common peak shape.
January 26, 2012 at 02:23 am - Permalink
I embarked upon this because I have a bunch of synchrotron XPS to fit. In the past I actually had a nice XOP compiled by a group where I did a postdoc, and this XOP included a gaussian convolution. Unfortunately that ran under windows only, and I am loath to switch operating systems back and forth just for running this one particular fitting. I wanted to see how fast (or slow) it would run without an XOP (I don't have the code, nor the XOP toolkit so I can't replicate this).
Here's the definitions for MPF2 - see if you get the same disappearing fit wave that I do?
January 26, 2012 at 06:48 am - Permalink
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
January 26, 2012 at 09:26 am - Permalink
January 26, 2012 at 11:09 am - Permalink
But when I returned the result I used 'x' instead of 'xw'!
Works a champ now, but no broadening yet.
January 26, 2012 at 12:54 pm - Permalink
For the record here, the function MPFDS() needs to have "x" replaced with "xw" so that X values come from the input xw wave. One of those easy-to-make, hard-to-see mistakes.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
January 26, 2012 at 12:55 pm - Permalink
I used basically the approach described in ‘All-At-Once Fitting Functions’ in the manual with some modifications. That is, generating to waves with the peak and the Gaussian, convolving them, and then let the fit function pick the results.
There is now an additional GaussWidth parameter which determines the Gaussian broadening (set to zero for no broadening). Inside the fit function itself the approach is now to generate a wave which is more extended and fine-grained than the incoming peak-wave (controlled by a resolution factor inside the function). The DS-peak is written into this wave which can then be used for convolution. Looks like this:
There, your first version of the equation with the x (instead of xw) comes into play again. ;) The wave has to be more extended to avoid funny effects of the convolution at the edge in the final product. The waves created here might be overkill for most cases, but I don’t have any performance problems even with 5 of these peaks. Suggestions for optimizations are always welcome.
With the convolution in effect the calculated values for height, FWHM, and so on are rather meaningless. I use a function to calculate all these values numerically. I don’t have a clue how to get fit errors for these values, so I leave them blank. Maybe someone has a good idea for this.
I have also modified the guess function a bit to work better with automatic guesses. Don’t know if there are cases which let the guess fail this way (enormous asymmetry for example). Finally, the fit starts to look funny if the DS width gets close to zero, so one needs to look out for this case.
I have attached the full peak procedure. Please report any issues you run into.
January 27, 2012 at 10:36 am - Permalink
This works quite well for me! A little slower than non-convolved lineshapes, but quite useable.
I'm beginning to realize that what would be most useful would be 'global' asymmetry and gaussian width values - for example, I don't the gausswidth or asymmetry to be different when decomposing spectral data from a single peak (or doublet). I wonder if there is some hackery to be done by applying a constraint wave post hoc to fix these to be identically valued for all DS peaks, even though they are nominally being varied?
I was also thinking we could add a "DS_doublet" lineshape that produces two DS lineshapes with a preset energy splitting and intensity ratio - this would make fitting of closely spaced (say, Si 2p) XPS peaks easier than having a separate DS for each SO-split component and trying to fix the known energy splitting values. I'm sure this can be trivially implemented with chozo's code, I just don't have the time to do it myself right now - perhaps next week, but if anyone is feeling enthusiastic about working on this...
February 2, 2012 at 12:21 pm - Permalink
As mentioned, this thing is not so optimized. I opted for a relatively high resolution (ten times the original points) to represent even extremely thin peaks and lots of space (double the initial size) to fit in the convolution. I’m having a hard time spying on the doings of MPF2 with the debugger, but usually there is a lot of unused space in the waves while going through the various steps. I can’t estimate the edge cases very well this way. I sure there are ways to adjust these things to the actual requirements of the particular fit. Also there are still some quirks of MPF2 which increase the difficulty here; like that the individual peak waves of the fit are not representing the correct size of the peaks (i.e. may be much too wide or too narrow).
As for the doublet peak, global asymmetry and so on, this would be possible with linked parameters (like global fit has for multiple sets). Maybe with some magic this can be implemented into MPF2 in the future. I still have it at the end of my crazy feature suggestion list. For now you could look out manually for the correct parameters while pushing the peaks around in the fit. Another lazy hack could be to synchronize parameters via a global variable or the Kx ones at runtime. Don’t know what this would break.
February 3, 2012 at 07:08 am - Permalink
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
February 3, 2012 at 09:02 am - Permalink