\ voigt.4th \ \ Calculate the convolution of Gaussian and Lorentzian functions. \ \ The Voigt function, which arises frequently in spectroscopy, is \ related to the Faddeeva function, w(z), through the relation, \ \ K(x, y) = Re(w(z)) \ \ with z = x + i*y. \ \ x is the normalized detuning from line center, defined by \ \ x = sqrt(ln(2)) * Delta/gamma_G \ \ where Delta is the detuning from line center, and gamma_G is \ the half-width at half-maximum (HWHM) for the Gaussian profile. \ \ y is the ratio of the widths of the Lorentzian and Gaussian \ profiles, \ \ y = sqrt(ln(2)) * gamma_L/gamma_G \ \ where gamma_L is the width (HWHM) for the Lorentzian profile. \ \ \ Alternatively, the normalized Voigt probability density function \ is given by \ \ V(x; sigma, gamma_L) = (1/sqrt(2pi))* Re(w(z))/sigma \ \ with \ \ z = (x + i*gamma_L)/(sigma*sqrt(2)) \ \ where sigma is the standard deviation of the Gaussian distribution, and \ gamma_L is the HWHM width for the Lorentzian distribution. The relation \ between sigma and gamma_G is \ \ sigma = gamma_G/sqrt(2*ln(2)) \ \ Notes: \ \ 1. The widths of the constituent Gaussian and Lorentzian profiles MUST \ FIRST BE SET, prior to calling any of the Voigt function words. Two \ methods may be used: \ \ a) Specify the full-width at half maximum (FWHM) of the Gaussian and \ Lorentzian profiles, Gamma_G and Gamma_L. Use the word, \ \ set-fwhm-widths \ \ to specify the FWHM widths of the constituent profiles. \ \ b) Speciy the standard deviation (sigma) of the Gaussian, and the \ half-width at half-maximum (gamma_L) of the Lorentzian. Use \ \ set-sd-hwhm-widths \ \ 2. The approach used here computes the complex function, w(z), using the \ high-accuracy algorithm, zwofz. For lengthy spectral calculations, or \ for least-squares fitting of Voigt profiles to data, a faster approach \ may be needed. A fast, but less accurate method of computing the Voigt \ profile, with a relative error between 1e-2 and 1e-5, is given in ref. [2]. \ \ 3. Reference values to six significant digits are provided in ref. [4]. \ \ References: \ \ 1. W. Demtroeder, Laser Spectroscopy: Basic Concepts and Instrumentation, \ 3rd ed., 2003. \ \ 2. R.J. Wells, Rapid Approximation to the Voigt/Faddeeva Function and its \ Derivatives, Journal of Quantitative Spectroscopy and Radiative Transfer, \ v. 62, p. 29 (1999). \ \ 3. http://en.wikipedia.org/wiki/Voigt_profile \ \ 4. C. Young, Tables for calculating the Voigt profile, Technical Report, \ College of Engineering, University of Michigan, July 1965, available \ online at http://hdl.handle.net/2027.42/8438 \ \ \ Copyright (c) 2009--2022 Krishna Myneni, krishna.myneni@ccreweb.org \ Provided under the LGPL \ \ Revisions: \ 2009-08-21 km v1.0 \ 2022-05-10 km v1.1; fixed bug in SET-FWHM-WIDTHS with \ computing V_Y (imaginary part of z); \ modified test code accordingly. \ 2023-12-05 km v1.1b; replace FDUP F* with FSQUARE \ \ Requires fsl-util.4th zwofz.4th [UNDEFINED] zwofz [IF] include zwofz [THEN] CR .( VOIGT V1.1b 05 Dec 2023 ) BASE @ DECIMAL 2e fsqrt fconstant SQRT_2 2e PI f* fsqrt fconstant SQRT_2PI 2e fln fsqrt fconstant SQRT_LN2 2e fln 2e f* fsqrt fconstant SQRT_2LN2 \ Convert between width at half-max of Gaussian profile and its s.d. : fwhm>sigma ( F: Gamma -- sigma ) 2e f/ SQRT_2LN2 f/ ; : sigma>fwhm ( F: sigma -- Gamma ) 2e f* SQRT_2LN2 f* ; \ parameters which are functions of the Gaussian and Lorentzian widths fvariable v_y fvariable v_gamma fvariable v_sigma fvariable v_xscale fvariable v_vscale fvariable v_im_z \ Set Gaussian and Lorentzian widths, and associated parameters for the \ Voigt profile calculations. This must be done once, either with \ set-fwhm-widths, or with set-sd-hwhm-widths, prior to using the \ functions, K(x,y), L(x), G(x), or V(x). : set-voigt-params ( -- ) \ helper word v_sigma f@ fdup SQRT_2PI f* v_vscale f! \ scale factor for V(x) SQRT_2 f* fdup v_xscale f! \ scale factor for x>z v_gamma f@ fswap f/ v_im_z f! \ imaginary part of z ; : set-fwhm-widths ( F: Gamma_G Gamma_L -- ) f2dup fswap f/ SQRT_LN2 f* v_y f! \ value of y for K(x,y) 2e f/ v_gamma f! \ Lorentzian HWHM fwhm>sigma v_sigma f! \ Gaussian s.d. set-voigt-params ; : set-sd-hwhm-widths ( F: sigma gamma_L -- ) f2dup fswap SQRT_2 f* f/ v_y f! v_gamma f! v_sigma f! set-voigt-params ; \ Default width values 1e 1e set-fwhm-widths \ Lorentzian probability density function : L(x) ( F: x -- L[x] ) v_gamma f@ fswap fsquare fover fsquare f+ f/ pi f/ ; \ Gaussian probability density function : G(x) ( F: x -- G[x] ) v_sigma f@ fswap fsquare fover fsquare 2e f* f/ fnegate fexp fswap SQRT_2PI f* f/ ; \ standard form of the Voigt function used in spectroscopy : K(x,y) ( F: x -- K[x,y] ) v_y f@ zwofz drop fdrop ; : x>z ( F: x -- z ) v_xscale f@ f/ v_im_z f@ ; \ Voigt probability density function \ returns NaN if both v_sigma and v_gamma are zero. : Voigt ( F: x -- V[x] ) v_sigma f@ f0= IF L(x) ELSE v_gamma f@ f0= IF G(x) ELSE x>z zwofz drop fdrop \ F: Re(w(z)) v_vscale f@ f/ THEN THEN ; BASE ! test-code? [IF] [UNDEFINED] T{ [IF] include ttester [THEN] [UNDEFINED] )integral [IF] false to test-code? include fsl/adaptint [THEN] BASE @ DECIMAL CR TESTING G(x), L(x) 1e-15 rel-near f! 1e-256 abs-near f! set-near t{ 1e 0e set-sd-hwhm-widths v_sigma f@ v_gamma f@ -> 1e 0e rr}t t{ 0e G(x) -> 0.39894228040143269e r}t t{ 1e G(x) -> 0.24197072451914337e r}t t{ -1e G(x) -> 1e G(x) r}t t{ 0e 2e set-fwhm-widths v_sigma f@ v_gamma f@ -> 0e 1e rr}t t{ 0e L(x) -> 0.3183098861837907e r}t t{ 1e L(x) -> 0.15915494309189535e r}t t{ -1e L(x) -> 1e L(x) r}t \ Check normalization of G(x) and L(x) \ Note the difference in widths and integration limits for G(x) and L(x)! 1e-6 rel-near f! 1e 1e-3 set-sd-hwhm-widths t{ use( G(x) -10e 10e 1e-6 )integral -> 1e r}t t{ use( L(x) -1000e 1000e 1e-6 )integral -> 1e r}t \ Accuracy of our calculation is much better than indicated \ by rel-near, but the reference values from [4] only have 6 \ significant digits. 5e-6 rel-near f! 1e-256 abs-near f! set-near CR TESTING K(x,y) t{ SQRT_LN2 1e set-fwhm-widths v_y f@ -> 1e r}t \ y = 1 t{ 0.0e K(x,y) -> 0.427583e r}t t{ 0.1e K(x,y) -> 0.426043e r}t t{ 0.5e K(x,y) -> 0.391233e r}t t{ 1.0e K(x,y) -> 0.304744e r}t t{ 1.5e K(x,y) -> 0.211836e r}t t{ 2.0e K(x,y) -> 0.140239e r}t t{ 3.0e K(x,y) -> 0.653178e-1 r}t t{ 4.0e K(x,y) -> 0.362814e-1 r}t t{ 5.0e K(x,y) -> 0.230031e-1 r}t t{ 10.0e K(x,y) -> 0.566994e-2 r}t t{ 20.0e K(x,y) -> 0.141223e-2 r}t t{ 50.0e K(x,y) -> 0.225721e-3 r}t t{ 100.0e K(x,y) -> 0.564218e-4 r}t t{ 200.0e K(x,y) -> 0.141049e-4 r}t \ Check normalization of the Voigt probability density function SQRT_LN2 1e set-fwhm-widths v_sigma f@ v_gamma f@ f+ 5000e f* fdup fconstant +xlim fnegate fconstant -xlim CR TESTING VOIGT 1e-4 rel-near f! 1e-256 abs-near f! set-near t{ use( Voigt -xlim +xlim 1e-4 )integral -> 1e r}t BASE ! [THEN]