How to speed up Voigt profile fits?Compiling the VoigtDistribution PDFGetting lengths of sublists that sum to more than oneHow to Output Chi-Squared Statistics when using NonLinearModelFitModule in numerical model for NonlinearModelFit is slow and leaks memoryOptimizing code containing an infinite sumP-Values are inconsistent when using DistributionFitTest repeatedlyStill more problems with Fitting, please helpNon-linear curve fit problemCurve fitting using an asymmetrical sigmoid functionFitting a Voigt distribution - never finishesFitting data to an empirical distribution, finding best fit

Time travel from stationary position?

When do we add a hyphen (-) to a complex adjective word?

How to speed up Voigt profile fits?

AG's and indictments

Equilateral triangle on a concentric circle

If I can solve Sudoku can I solve Travelling Salesman Problem(TSP)? If yes, how?

How do I hide Chekhov's Gun?

Min function accepting varying number of arguments in C++17

What should tie a collection of short-stories together?

What are substitutions for coconut in curry?

The difference between「N分で」and「後N分で」

Is it possible to upcast ritual spells?

What do Xenomorphs eat in the Alien series?

Why did it take so long to abandon sail after steamships were demonstrated?

Declaring defaulted assignment operator as constexpr: which compiler is right?

Most cost effective thermostat setting: consistent temperature vs. lowest temperature possible

How can I track script which gives me "command not found" right after the login?

How to prevent Firefox and Chrome from opening ports in the firewall?

What is this large pipe coming out of my roof?

Property of summation

Why do Australian milk farmers need to protest supermarkets' milk price?

If curse and magic is two sides of the same coin, why the former is forbidden?

Welcoming 2019 Pi day: How to draw the letter π?

Are all passive ability checks floors for active ability checks?



How to speed up Voigt profile fits?


Compiling the VoigtDistribution PDFGetting lengths of sublists that sum to more than oneHow to Output Chi-Squared Statistics when using NonLinearModelFitModule in numerical model for NonlinearModelFit is slow and leaks memoryOptimizing code containing an infinite sumP-Values are inconsistent when using DistributionFitTest repeatedlyStill more problems with Fitting, please helpNon-linear curve fit problemCurve fitting using an asymmetrical sigmoid functionFitting a Voigt distribution - never finishesFitting data to an empirical distribution, finding best fit













6












$begingroup$


Voigt profile fits in Mathematica seem terribly slow. For an example data set with 81 points a corresponding fitting procedures for Voigt fits is >1000 times slower than for Gaussian or Lorentzian profile. How can Voigt profile fits be speed up?



Here is what I do. First we define the Voigt and Gaussian profile. As Mathematica often complains about δ and σ being <0, I use Abs instead of constraining the model as this proved faster. In addition I use the compile command to make the function even faster.



voigtprofile = Compile[δ, _Real, 0, σ, _Real, 0, A, _Real,0, ν0,_Real, 0, ν, _Real, 0, A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]];
gaussian[σ_, A_, ν0_, ν_] := Return[A PDF[NormalDistribution[ν0, σ], ν]];


Then I create noisy example data sets with a bit of noise:



noisyDataV = #, 
voigtprofile[0.15, 0.1, 1, 0, #] + RandomReal[-0.1, 0.1] & /@ Range[-2, 2, 0.05];
noisyDataG = #, gaussian[0.1, 1, 0, #] + RandomReal[-0.1, 0.1] & /@
Range[-2, 2, 0.05];


And we use NonlinearModelFit to fit the data with excellent start parameters:



tv = AbsoluteTiming[vfit = NonlinearModelFit[noisyDataV, 
voigtprofile[δ, σ,
A, ν0, ν], δ, 0.15, σ, 0.1, A,
1, ν0, 0, ν];]
tg = AbsoluteTiming[gfit = NonlinearModelFit[noisyDataG,
gaussian[σ,
A, ν0, ν], σ, 0.1, A, 1, ν0,
0, ν];]


And if we compare the required time for fit:



tv[[1]]/tg[[1]]


I get values between 1000 and 6000, which is terrible. In addition, selecting a fit Method e.g. NMinimize or other does at best yield the same result.



As this minimal example is just a very simple example, times scale up to unbearable long times for more realistic scenarios with real data.
I'm glad for any hint on how to speed this simple example up.










share|improve this question









New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$







  • 4




    $begingroup$
    Have you seen this?
    $endgroup$
    – J. M. is slightly pensive
    6 hours ago















6












$begingroup$


Voigt profile fits in Mathematica seem terribly slow. For an example data set with 81 points a corresponding fitting procedures for Voigt fits is >1000 times slower than for Gaussian or Lorentzian profile. How can Voigt profile fits be speed up?



Here is what I do. First we define the Voigt and Gaussian profile. As Mathematica often complains about δ and σ being <0, I use Abs instead of constraining the model as this proved faster. In addition I use the compile command to make the function even faster.



voigtprofile = Compile[δ, _Real, 0, σ, _Real, 0, A, _Real,0, ν0,_Real, 0, ν, _Real, 0, A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]];
gaussian[σ_, A_, ν0_, ν_] := Return[A PDF[NormalDistribution[ν0, σ], ν]];


Then I create noisy example data sets with a bit of noise:



noisyDataV = #, 
voigtprofile[0.15, 0.1, 1, 0, #] + RandomReal[-0.1, 0.1] & /@ Range[-2, 2, 0.05];
noisyDataG = #, gaussian[0.1, 1, 0, #] + RandomReal[-0.1, 0.1] & /@
Range[-2, 2, 0.05];


And we use NonlinearModelFit to fit the data with excellent start parameters:



tv = AbsoluteTiming[vfit = NonlinearModelFit[noisyDataV, 
voigtprofile[δ, σ,
A, ν0, ν], δ, 0.15, σ, 0.1, A,
1, ν0, 0, ν];]
tg = AbsoluteTiming[gfit = NonlinearModelFit[noisyDataG,
gaussian[σ,
A, ν0, ν], σ, 0.1, A, 1, ν0,
0, ν];]


And if we compare the required time for fit:



tv[[1]]/tg[[1]]


I get values between 1000 and 6000, which is terrible. In addition, selecting a fit Method e.g. NMinimize or other does at best yield the same result.



As this minimal example is just a very simple example, times scale up to unbearable long times for more realistic scenarios with real data.
I'm glad for any hint on how to speed this simple example up.










share|improve this question









New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$







  • 4




    $begingroup$
    Have you seen this?
    $endgroup$
    – J. M. is slightly pensive
    6 hours ago













6












6








6


1



$begingroup$


Voigt profile fits in Mathematica seem terribly slow. For an example data set with 81 points a corresponding fitting procedures for Voigt fits is >1000 times slower than for Gaussian or Lorentzian profile. How can Voigt profile fits be speed up?



Here is what I do. First we define the Voigt and Gaussian profile. As Mathematica often complains about δ and σ being <0, I use Abs instead of constraining the model as this proved faster. In addition I use the compile command to make the function even faster.



voigtprofile = Compile[δ, _Real, 0, σ, _Real, 0, A, _Real,0, ν0,_Real, 0, ν, _Real, 0, A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]];
gaussian[σ_, A_, ν0_, ν_] := Return[A PDF[NormalDistribution[ν0, σ], ν]];


Then I create noisy example data sets with a bit of noise:



noisyDataV = #, 
voigtprofile[0.15, 0.1, 1, 0, #] + RandomReal[-0.1, 0.1] & /@ Range[-2, 2, 0.05];
noisyDataG = #, gaussian[0.1, 1, 0, #] + RandomReal[-0.1, 0.1] & /@
Range[-2, 2, 0.05];


And we use NonlinearModelFit to fit the data with excellent start parameters:



tv = AbsoluteTiming[vfit = NonlinearModelFit[noisyDataV, 
voigtprofile[δ, σ,
A, ν0, ν], δ, 0.15, σ, 0.1, A,
1, ν0, 0, ν];]
tg = AbsoluteTiming[gfit = NonlinearModelFit[noisyDataG,
gaussian[σ,
A, ν0, ν], σ, 0.1, A, 1, ν0,
0, ν];]


And if we compare the required time for fit:



tv[[1]]/tg[[1]]


I get values between 1000 and 6000, which is terrible. In addition, selecting a fit Method e.g. NMinimize or other does at best yield the same result.



As this minimal example is just a very simple example, times scale up to unbearable long times for more realistic scenarios with real data.
I'm glad for any hint on how to speed this simple example up.










share|improve this question









New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$




Voigt profile fits in Mathematica seem terribly slow. For an example data set with 81 points a corresponding fitting procedures for Voigt fits is >1000 times slower than for Gaussian or Lorentzian profile. How can Voigt profile fits be speed up?



Here is what I do. First we define the Voigt and Gaussian profile. As Mathematica often complains about δ and σ being <0, I use Abs instead of constraining the model as this proved faster. In addition I use the compile command to make the function even faster.



voigtprofile = Compile[δ, _Real, 0, σ, _Real, 0, A, _Real,0, ν0,_Real, 0, ν, _Real, 0, A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]];
gaussian[σ_, A_, ν0_, ν_] := Return[A PDF[NormalDistribution[ν0, σ], ν]];


Then I create noisy example data sets with a bit of noise:



noisyDataV = #, 
voigtprofile[0.15, 0.1, 1, 0, #] + RandomReal[-0.1, 0.1] & /@ Range[-2, 2, 0.05];
noisyDataG = #, gaussian[0.1, 1, 0, #] + RandomReal[-0.1, 0.1] & /@
Range[-2, 2, 0.05];


And we use NonlinearModelFit to fit the data with excellent start parameters:



tv = AbsoluteTiming[vfit = NonlinearModelFit[noisyDataV, 
voigtprofile[δ, σ,
A, ν0, ν], δ, 0.15, σ, 0.1, A,
1, ν0, 0, ν];]
tg = AbsoluteTiming[gfit = NonlinearModelFit[noisyDataG,
gaussian[σ,
A, ν0, ν], σ, 0.1, A, 1, ν0,
0, ν];]


And if we compare the required time for fit:



tv[[1]]/tg[[1]]


I get values between 1000 and 6000, which is terrible. In addition, selecting a fit Method e.g. NMinimize or other does at best yield the same result.



As this minimal example is just a very simple example, times scale up to unbearable long times for more realistic scenarios with real data.
I'm glad for any hint on how to speed this simple example up.







performance-tuning fitting nonlinear






share|improve this question









New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 6 hours ago









Johu

3,7031037




3,7031037






New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 6 hours ago









Adrian BeckertAdrian Beckert

613




613




New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







  • 4




    $begingroup$
    Have you seen this?
    $endgroup$
    – J. M. is slightly pensive
    6 hours ago












  • 4




    $begingroup$
    Have you seen this?
    $endgroup$
    – J. M. is slightly pensive
    6 hours ago







4




4




$begingroup$
Have you seen this?
$endgroup$
– J. M. is slightly pensive
6 hours ago




$begingroup$
Have you seen this?
$endgroup$
– J. M. is slightly pensive
6 hours ago










2 Answers
2






active

oldest

votes


















3












$begingroup$

Thanks to J. M. for the suggestion. Instead of using the computationally intensive VoigtDistribution, we can use the Pseudo-Voigt numeric approximation from this post which exhibits very low errors compared to the analytical Voigt (see here or references in here) and speeds up the fitting procedure by approximately a factor of 100 or more.



pseudoVoigtProfile = With[n = 24, τ = 12, With[d = N[Range[n] π/τ],b = N[Exp[-(Range[n] π/τ)^2]], s = N[PadRight[, n, -1, 1]], sq = N[Sqrt[2]],sp = N[Sqrt[2 π]], 
Compile[δ, _Real, σ, _Real, x, _Real,
Module[z = (x + I δ)/(σ sq), e,
e = Exp[I τ z];
Re[(I (1 -e)/(τ z) + (2 I z/τ)b.((e s -1)/((d + z) (d - z))))]/(σ sp)],
RuntimeAttributes -> Listable]]];


and fit it to the noisy test data



tpv = AbsoluteTiming[pvfit = NonlinearModelFit[noisyDataV, 
pseudoVoigtProfile[δ, σ, ν - ν0], δ, 0.15, σ, 0.1, A, 1, ν0, 0, ν];]


which leads to a ratio tpv/tg ~ 10 on my computer.



Note: Although the Pseudo-Voigt profile is a numerical approximation it will do the job for most daily life applications where the noise on the e.g. optical spectrum is at least an order of magnitude larger than the numeric error of the approximation.






share|improve this answer










New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$












  • $begingroup$
    As Voigt is Gaussian convolved by Lorentzian another approach regularly used in spectrometry is to work in Fourier space: see sites.math.washington.edu/~morrow/papers/GVmathThesis2010.pdf for instance (sorry I do not have all the details in mind for a complete answer here)
    $endgroup$
    – Picaud Vincent
    4 hours ago






  • 1




    $begingroup$
    The compiled implementation you got from my answer is a genuine implementation of the Voigt profile, nothing "pseudo" about it.
    $endgroup$
    – J. M. is slightly pensive
    4 hours ago


















2












$begingroup$

You can use CompilePrint to check what Compile actually did:



Needs["CompiledFunctionTools`"];
voigtprofile1 =
Compile[δ, _Real, 0, σ, _Real, 0, A, _Real,
0, ν0, _Real, 0, ν, _Real, 0,
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
];
CompilePrint[voigtprofile1]

Out[26]= "5 arguments
7 Real registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes ->
R0 = A1
R1 = A2
R2 = A3
R3 = A4
R4 = A5
Result = R6
1 R5 = MainEvaluate[ Function[δ, σ, A, ν0, ν,
PDF[VoigtDistribution[Abs[δ], Abs[σ]], ν - ν0]][ R0, R1, R2, R3, R4]]
2 R6 = R2 * R5
3 Return"


As you can see, all the function really does is call MainEvaluate and then multiply two numbers together. Basically, you haven't compiled anything.



Instead, evaluate the PDF inside of the Compile to get a symbolic expression that is compilable:



voigtprofile2 = Compile[
δ, _Real, 0, σ, _Real, 0, A, _Real, 0, ν0, _Real, 0, ν, _Real, 0,
Evaluate[
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
],
CompilationOptions -> "ExpressionOptimization" -> True,
RuntimeAttributes -> Listable
];


This should be significantly faster.






share|improve this answer











$endgroup$








  • 1




    $begingroup$
    The problem with your voigtprofile2 is that Erfc[] only works for real arguments within a compiled function, so it gets wrapped in MainEvaluate. That was one reason why I wrote the routine in the thread I linked to in the comments.
    $endgroup$
    – J. M. is slightly pensive
    2 hours ago






  • 1




    $begingroup$
    Ok, that's handy to know. That's a specific problem of VoigtDistribution I didn't anticipate. I still wanted to point out the importance of using CompilePrint, though.
    $endgroup$
    – Sjoerd Smit
    2 hours ago










Your Answer





StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["$", "$"], ["\\(","\\)"]]);
);
);
, "mathjax-editing");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "387"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);






Adrian Beckert is a new contributor. Be nice, and check out our Code of Conduct.









draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f193317%2fhow-to-speed-up-voigt-profile-fits%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









3












$begingroup$

Thanks to J. M. for the suggestion. Instead of using the computationally intensive VoigtDistribution, we can use the Pseudo-Voigt numeric approximation from this post which exhibits very low errors compared to the analytical Voigt (see here or references in here) and speeds up the fitting procedure by approximately a factor of 100 or more.



pseudoVoigtProfile = With[n = 24, τ = 12, With[d = N[Range[n] π/τ],b = N[Exp[-(Range[n] π/τ)^2]], s = N[PadRight[, n, -1, 1]], sq = N[Sqrt[2]],sp = N[Sqrt[2 π]], 
Compile[δ, _Real, σ, _Real, x, _Real,
Module[z = (x + I δ)/(σ sq), e,
e = Exp[I τ z];
Re[(I (1 -e)/(τ z) + (2 I z/τ)b.((e s -1)/((d + z) (d - z))))]/(σ sp)],
RuntimeAttributes -> Listable]]];


and fit it to the noisy test data



tpv = AbsoluteTiming[pvfit = NonlinearModelFit[noisyDataV, 
pseudoVoigtProfile[δ, σ, ν - ν0], δ, 0.15, σ, 0.1, A, 1, ν0, 0, ν];]


which leads to a ratio tpv/tg ~ 10 on my computer.



Note: Although the Pseudo-Voigt profile is a numerical approximation it will do the job for most daily life applications where the noise on the e.g. optical spectrum is at least an order of magnitude larger than the numeric error of the approximation.






share|improve this answer










New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$












  • $begingroup$
    As Voigt is Gaussian convolved by Lorentzian another approach regularly used in spectrometry is to work in Fourier space: see sites.math.washington.edu/~morrow/papers/GVmathThesis2010.pdf for instance (sorry I do not have all the details in mind for a complete answer here)
    $endgroup$
    – Picaud Vincent
    4 hours ago






  • 1




    $begingroup$
    The compiled implementation you got from my answer is a genuine implementation of the Voigt profile, nothing "pseudo" about it.
    $endgroup$
    – J. M. is slightly pensive
    4 hours ago















3












$begingroup$

Thanks to J. M. for the suggestion. Instead of using the computationally intensive VoigtDistribution, we can use the Pseudo-Voigt numeric approximation from this post which exhibits very low errors compared to the analytical Voigt (see here or references in here) and speeds up the fitting procedure by approximately a factor of 100 or more.



pseudoVoigtProfile = With[n = 24, τ = 12, With[d = N[Range[n] π/τ],b = N[Exp[-(Range[n] π/τ)^2]], s = N[PadRight[, n, -1, 1]], sq = N[Sqrt[2]],sp = N[Sqrt[2 π]], 
Compile[δ, _Real, σ, _Real, x, _Real,
Module[z = (x + I δ)/(σ sq), e,
e = Exp[I τ z];
Re[(I (1 -e)/(τ z) + (2 I z/τ)b.((e s -1)/((d + z) (d - z))))]/(σ sp)],
RuntimeAttributes -> Listable]]];


and fit it to the noisy test data



tpv = AbsoluteTiming[pvfit = NonlinearModelFit[noisyDataV, 
pseudoVoigtProfile[δ, σ, ν - ν0], δ, 0.15, σ, 0.1, A, 1, ν0, 0, ν];]


which leads to a ratio tpv/tg ~ 10 on my computer.



Note: Although the Pseudo-Voigt profile is a numerical approximation it will do the job for most daily life applications where the noise on the e.g. optical spectrum is at least an order of magnitude larger than the numeric error of the approximation.






share|improve this answer










New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$












  • $begingroup$
    As Voigt is Gaussian convolved by Lorentzian another approach regularly used in spectrometry is to work in Fourier space: see sites.math.washington.edu/~morrow/papers/GVmathThesis2010.pdf for instance (sorry I do not have all the details in mind for a complete answer here)
    $endgroup$
    – Picaud Vincent
    4 hours ago






  • 1




    $begingroup$
    The compiled implementation you got from my answer is a genuine implementation of the Voigt profile, nothing "pseudo" about it.
    $endgroup$
    – J. M. is slightly pensive
    4 hours ago













3












3








3





$begingroup$

Thanks to J. M. for the suggestion. Instead of using the computationally intensive VoigtDistribution, we can use the Pseudo-Voigt numeric approximation from this post which exhibits very low errors compared to the analytical Voigt (see here or references in here) and speeds up the fitting procedure by approximately a factor of 100 or more.



pseudoVoigtProfile = With[n = 24, τ = 12, With[d = N[Range[n] π/τ],b = N[Exp[-(Range[n] π/τ)^2]], s = N[PadRight[, n, -1, 1]], sq = N[Sqrt[2]],sp = N[Sqrt[2 π]], 
Compile[δ, _Real, σ, _Real, x, _Real,
Module[z = (x + I δ)/(σ sq), e,
e = Exp[I τ z];
Re[(I (1 -e)/(τ z) + (2 I z/τ)b.((e s -1)/((d + z) (d - z))))]/(σ sp)],
RuntimeAttributes -> Listable]]];


and fit it to the noisy test data



tpv = AbsoluteTiming[pvfit = NonlinearModelFit[noisyDataV, 
pseudoVoigtProfile[δ, σ, ν - ν0], δ, 0.15, σ, 0.1, A, 1, ν0, 0, ν];]


which leads to a ratio tpv/tg ~ 10 on my computer.



Note: Although the Pseudo-Voigt profile is a numerical approximation it will do the job for most daily life applications where the noise on the e.g. optical spectrum is at least an order of magnitude larger than the numeric error of the approximation.






share|improve this answer










New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$



Thanks to J. M. for the suggestion. Instead of using the computationally intensive VoigtDistribution, we can use the Pseudo-Voigt numeric approximation from this post which exhibits very low errors compared to the analytical Voigt (see here or references in here) and speeds up the fitting procedure by approximately a factor of 100 or more.



pseudoVoigtProfile = With[n = 24, τ = 12, With[d = N[Range[n] π/τ],b = N[Exp[-(Range[n] π/τ)^2]], s = N[PadRight[, n, -1, 1]], sq = N[Sqrt[2]],sp = N[Sqrt[2 π]], 
Compile[δ, _Real, σ, _Real, x, _Real,
Module[z = (x + I δ)/(σ sq), e,
e = Exp[I τ z];
Re[(I (1 -e)/(τ z) + (2 I z/τ)b.((e s -1)/((d + z) (d - z))))]/(σ sp)],
RuntimeAttributes -> Listable]]];


and fit it to the noisy test data



tpv = AbsoluteTiming[pvfit = NonlinearModelFit[noisyDataV, 
pseudoVoigtProfile[δ, σ, ν - ν0], δ, 0.15, σ, 0.1, A, 1, ν0, 0, ν];]


which leads to a ratio tpv/tg ~ 10 on my computer.



Note: Although the Pseudo-Voigt profile is a numerical approximation it will do the job for most daily life applications where the noise on the e.g. optical spectrum is at least an order of magnitude larger than the numeric error of the approximation.







share|improve this answer










New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this answer



share|improve this answer








edited 1 hour ago









MarcoB

37.5k556113




37.5k556113






New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









answered 4 hours ago









Adrian BeckertAdrian Beckert

613




613




New contributor




Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Adrian Beckert is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











  • $begingroup$
    As Voigt is Gaussian convolved by Lorentzian another approach regularly used in spectrometry is to work in Fourier space: see sites.math.washington.edu/~morrow/papers/GVmathThesis2010.pdf for instance (sorry I do not have all the details in mind for a complete answer here)
    $endgroup$
    – Picaud Vincent
    4 hours ago






  • 1




    $begingroup$
    The compiled implementation you got from my answer is a genuine implementation of the Voigt profile, nothing "pseudo" about it.
    $endgroup$
    – J. M. is slightly pensive
    4 hours ago
















  • $begingroup$
    As Voigt is Gaussian convolved by Lorentzian another approach regularly used in spectrometry is to work in Fourier space: see sites.math.washington.edu/~morrow/papers/GVmathThesis2010.pdf for instance (sorry I do not have all the details in mind for a complete answer here)
    $endgroup$
    – Picaud Vincent
    4 hours ago






  • 1




    $begingroup$
    The compiled implementation you got from my answer is a genuine implementation of the Voigt profile, nothing "pseudo" about it.
    $endgroup$
    – J. M. is slightly pensive
    4 hours ago















$begingroup$
As Voigt is Gaussian convolved by Lorentzian another approach regularly used in spectrometry is to work in Fourier space: see sites.math.washington.edu/~morrow/papers/GVmathThesis2010.pdf for instance (sorry I do not have all the details in mind for a complete answer here)
$endgroup$
– Picaud Vincent
4 hours ago




$begingroup$
As Voigt is Gaussian convolved by Lorentzian another approach regularly used in spectrometry is to work in Fourier space: see sites.math.washington.edu/~morrow/papers/GVmathThesis2010.pdf for instance (sorry I do not have all the details in mind for a complete answer here)
$endgroup$
– Picaud Vincent
4 hours ago




1




1




$begingroup$
The compiled implementation you got from my answer is a genuine implementation of the Voigt profile, nothing "pseudo" about it.
$endgroup$
– J. M. is slightly pensive
4 hours ago




$begingroup$
The compiled implementation you got from my answer is a genuine implementation of the Voigt profile, nothing "pseudo" about it.
$endgroup$
– J. M. is slightly pensive
4 hours ago











2












$begingroup$

You can use CompilePrint to check what Compile actually did:



Needs["CompiledFunctionTools`"];
voigtprofile1 =
Compile[δ, _Real, 0, σ, _Real, 0, A, _Real,
0, ν0, _Real, 0, ν, _Real, 0,
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
];
CompilePrint[voigtprofile1]

Out[26]= "5 arguments
7 Real registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes ->
R0 = A1
R1 = A2
R2 = A3
R3 = A4
R4 = A5
Result = R6
1 R5 = MainEvaluate[ Function[δ, σ, A, ν0, ν,
PDF[VoigtDistribution[Abs[δ], Abs[σ]], ν - ν0]][ R0, R1, R2, R3, R4]]
2 R6 = R2 * R5
3 Return"


As you can see, all the function really does is call MainEvaluate and then multiply two numbers together. Basically, you haven't compiled anything.



Instead, evaluate the PDF inside of the Compile to get a symbolic expression that is compilable:



voigtprofile2 = Compile[
δ, _Real, 0, σ, _Real, 0, A, _Real, 0, ν0, _Real, 0, ν, _Real, 0,
Evaluate[
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
],
CompilationOptions -> "ExpressionOptimization" -> True,
RuntimeAttributes -> Listable
];


This should be significantly faster.






share|improve this answer











$endgroup$








  • 1




    $begingroup$
    The problem with your voigtprofile2 is that Erfc[] only works for real arguments within a compiled function, so it gets wrapped in MainEvaluate. That was one reason why I wrote the routine in the thread I linked to in the comments.
    $endgroup$
    – J. M. is slightly pensive
    2 hours ago






  • 1




    $begingroup$
    Ok, that's handy to know. That's a specific problem of VoigtDistribution I didn't anticipate. I still wanted to point out the importance of using CompilePrint, though.
    $endgroup$
    – Sjoerd Smit
    2 hours ago















2












$begingroup$

You can use CompilePrint to check what Compile actually did:



Needs["CompiledFunctionTools`"];
voigtprofile1 =
Compile[δ, _Real, 0, σ, _Real, 0, A, _Real,
0, ν0, _Real, 0, ν, _Real, 0,
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
];
CompilePrint[voigtprofile1]

Out[26]= "5 arguments
7 Real registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes ->
R0 = A1
R1 = A2
R2 = A3
R3 = A4
R4 = A5
Result = R6
1 R5 = MainEvaluate[ Function[δ, σ, A, ν0, ν,
PDF[VoigtDistribution[Abs[δ], Abs[σ]], ν - ν0]][ R0, R1, R2, R3, R4]]
2 R6 = R2 * R5
3 Return"


As you can see, all the function really does is call MainEvaluate and then multiply two numbers together. Basically, you haven't compiled anything.



Instead, evaluate the PDF inside of the Compile to get a symbolic expression that is compilable:



voigtprofile2 = Compile[
δ, _Real, 0, σ, _Real, 0, A, _Real, 0, ν0, _Real, 0, ν, _Real, 0,
Evaluate[
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
],
CompilationOptions -> "ExpressionOptimization" -> True,
RuntimeAttributes -> Listable
];


This should be significantly faster.






share|improve this answer











$endgroup$








  • 1




    $begingroup$
    The problem with your voigtprofile2 is that Erfc[] only works for real arguments within a compiled function, so it gets wrapped in MainEvaluate. That was one reason why I wrote the routine in the thread I linked to in the comments.
    $endgroup$
    – J. M. is slightly pensive
    2 hours ago






  • 1




    $begingroup$
    Ok, that's handy to know. That's a specific problem of VoigtDistribution I didn't anticipate. I still wanted to point out the importance of using CompilePrint, though.
    $endgroup$
    – Sjoerd Smit
    2 hours ago













2












2








2





$begingroup$

You can use CompilePrint to check what Compile actually did:



Needs["CompiledFunctionTools`"];
voigtprofile1 =
Compile[δ, _Real, 0, σ, _Real, 0, A, _Real,
0, ν0, _Real, 0, ν, _Real, 0,
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
];
CompilePrint[voigtprofile1]

Out[26]= "5 arguments
7 Real registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes ->
R0 = A1
R1 = A2
R2 = A3
R3 = A4
R4 = A5
Result = R6
1 R5 = MainEvaluate[ Function[δ, σ, A, ν0, ν,
PDF[VoigtDistribution[Abs[δ], Abs[σ]], ν - ν0]][ R0, R1, R2, R3, R4]]
2 R6 = R2 * R5
3 Return"


As you can see, all the function really does is call MainEvaluate and then multiply two numbers together. Basically, you haven't compiled anything.



Instead, evaluate the PDF inside of the Compile to get a symbolic expression that is compilable:



voigtprofile2 = Compile[
δ, _Real, 0, σ, _Real, 0, A, _Real, 0, ν0, _Real, 0, ν, _Real, 0,
Evaluate[
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
],
CompilationOptions -> "ExpressionOptimization" -> True,
RuntimeAttributes -> Listable
];


This should be significantly faster.






share|improve this answer











$endgroup$



You can use CompilePrint to check what Compile actually did:



Needs["CompiledFunctionTools`"];
voigtprofile1 =
Compile[δ, _Real, 0, σ, _Real, 0, A, _Real,
0, ν0, _Real, 0, ν, _Real, 0,
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
];
CompilePrint[voigtprofile1]

Out[26]= "5 arguments
7 Real registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes ->
R0 = A1
R1 = A2
R2 = A3
R3 = A4
R4 = A5
Result = R6
1 R5 = MainEvaluate[ Function[δ, σ, A, ν0, ν,
PDF[VoigtDistribution[Abs[δ], Abs[σ]], ν - ν0]][ R0, R1, R2, R3, R4]]
2 R6 = R2 * R5
3 Return"


As you can see, all the function really does is call MainEvaluate and then multiply two numbers together. Basically, you haven't compiled anything.



Instead, evaluate the PDF inside of the Compile to get a symbolic expression that is compilable:



voigtprofile2 = Compile[
δ, _Real, 0, σ, _Real, 0, A, _Real, 0, ν0, _Real, 0, ν, _Real, 0,
Evaluate[
A PDF[VoigtDistribution[Abs@δ, Abs@σ], ν - ν0]
],
CompilationOptions -> "ExpressionOptimization" -> True,
RuntimeAttributes -> Listable
];


This should be significantly faster.







share|improve this answer














share|improve this answer



share|improve this answer








edited 1 hour ago









MarcoB

37.5k556113




37.5k556113










answered 2 hours ago









Sjoerd SmitSjoerd Smit

4,030815




4,030815







  • 1




    $begingroup$
    The problem with your voigtprofile2 is that Erfc[] only works for real arguments within a compiled function, so it gets wrapped in MainEvaluate. That was one reason why I wrote the routine in the thread I linked to in the comments.
    $endgroup$
    – J. M. is slightly pensive
    2 hours ago






  • 1




    $begingroup$
    Ok, that's handy to know. That's a specific problem of VoigtDistribution I didn't anticipate. I still wanted to point out the importance of using CompilePrint, though.
    $endgroup$
    – Sjoerd Smit
    2 hours ago












  • 1




    $begingroup$
    The problem with your voigtprofile2 is that Erfc[] only works for real arguments within a compiled function, so it gets wrapped in MainEvaluate. That was one reason why I wrote the routine in the thread I linked to in the comments.
    $endgroup$
    – J. M. is slightly pensive
    2 hours ago






  • 1




    $begingroup$
    Ok, that's handy to know. That's a specific problem of VoigtDistribution I didn't anticipate. I still wanted to point out the importance of using CompilePrint, though.
    $endgroup$
    – Sjoerd Smit
    2 hours ago







1




1




$begingroup$
The problem with your voigtprofile2 is that Erfc[] only works for real arguments within a compiled function, so it gets wrapped in MainEvaluate. That was one reason why I wrote the routine in the thread I linked to in the comments.
$endgroup$
– J. M. is slightly pensive
2 hours ago




$begingroup$
The problem with your voigtprofile2 is that Erfc[] only works for real arguments within a compiled function, so it gets wrapped in MainEvaluate. That was one reason why I wrote the routine in the thread I linked to in the comments.
$endgroup$
– J. M. is slightly pensive
2 hours ago




1




1




$begingroup$
Ok, that's handy to know. That's a specific problem of VoigtDistribution I didn't anticipate. I still wanted to point out the importance of using CompilePrint, though.
$endgroup$
– Sjoerd Smit
2 hours ago




$begingroup$
Ok, that's handy to know. That's a specific problem of VoigtDistribution I didn't anticipate. I still wanted to point out the importance of using CompilePrint, though.
$endgroup$
– Sjoerd Smit
2 hours ago










Adrian Beckert is a new contributor. Be nice, and check out our Code of Conduct.









draft saved

draft discarded


















Adrian Beckert is a new contributor. Be nice, and check out our Code of Conduct.












Adrian Beckert is a new contributor. Be nice, and check out our Code of Conduct.











Adrian Beckert is a new contributor. Be nice, and check out our Code of Conduct.














Thanks for contributing an answer to Mathematica Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f193317%2fhow-to-speed-up-voigt-profile-fits%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown