cantera/src/spectra/LineBroadener.cpp

173 lines
3.8 KiB
C++

#include "cantera/base/ct_defs.h"
#include <math.h>
#ifdef USE_BOOST_MATH
#include <boost/math/special_functions/erf.hpp>
using boost::math::erf;
#endif
#include "cantera/spectra/LineBroadener.h"
namespace Cantera
{
LorentzianProfile::LorentzianProfile(doublereal gamma)
{
m_hwhm = gamma;
m_hwhm2 = m_hwhm*m_hwhm;
}
/**
* The Lorentzian profile for collision-broadened lines.
*
*\f[
* \frac{1}{\pi} \frac{\gamma}{ (\Delta\nu)^2 + \gamma^2}
*\f]
* Units: 1/wavenumber (or cm).
*/
doublereal LorentzianProfile::profile(doublereal deltaFreq)
{
return (1.0/Cantera::Pi) *m_hwhm/(deltaFreq*deltaFreq + m_hwhm2);
}
/**
*
* The cumulative profile, given by
* \f[
* \frac{1}{\pi} \tan^{-1}\left(\frac{\Delta\nu}{gamma}\right) + 0.5
* \f]
*/
doublereal LorentzianProfile::cumulative(doublereal deltaFreq)
{
return (1.0/Pi) * atan(deltaFreq/m_hwhm) + 0.5;
}
doublereal LorentzianProfile::width()
{
return 2.0*m_hwhm;
}
GaussianProfile::GaussianProfile(doublereal sigma)
{
m_sigma = sigma;
m_sigma2 = m_sigma*m_sigma;
}
doublereal GaussianProfile::profile(doublereal deltaFreq)
{
//cout << "entered Gaussian::profile" << endl;
//cout << "deltaFreq = " << deltaFreq << endl;
//cout << "m_sigma = " << m_sigma << endl;
return 1.0/(m_sigma * Cantera::SqrtTwo *Cantera::SqrtPi) *
exp(-deltaFreq*deltaFreq/(2.0*m_sigma2));
}
doublereal GaussianProfile::cumulative(doublereal deltaFreq)
{
return 0.5*(1.0 + erf(deltaFreq/(m_sigma*SqrtTwo)));
}
doublereal GaussianProfile::width()
{
return 2.0*m_sigma*sqrt(log(4.0));
}
/**
* @param sigma The standard deviation of the Gaussian
* @param gamma The half-width of the Lorentzian.
*/
Voigt::Voigt(doublereal sigma, doublereal gamma)
{
m_sigma = sigma;
m_sigma2 = m_sigma*m_sigma;
m_gamma_lor = gamma;
m_sigsqrt2 = SqrtTwo*m_sigma;
m_gamma = gamma/m_sigsqrt2;
m_eps = 1.0e-20;
}
void Voigt::testv()
{
m_gamma = 1.0e1;
std::cout << F(1.0) << std::endl;
m_gamma = 0.5;
std::cout << F(1.0) << std::endl;
m_gamma = 0.0001;
std::cout << F(10.0) << std::endl;
}
/**
* This method evaluates the function
* \f[
* F(x, y) = \frac{y}{\pi}\int_{-\infty}^{+\infty} \frac{e^{-z^2}}
* {(x - z)^2 + y^2} dz
* \f]
* The algorithm used to cmpute this function is described in the
* reference below. @see F. G. Lether and P. R. Wenston, "The
* numerical computation of the %Voigt function by a corrected
* midpoint quadrature rule for \f$ (-\infty, \infty) \f$. Journal
* of Computational and Applied Mathematics}, 34 (1):75--92, 1991.
*/
doublereal Voigt::F(doublereal x)
{
if (x < 0.0) {
x = -x;
}
double y = m_gamma;
double c3 = log(Pi*m_eps/2.0);
double tau = sqrt(-log(y) - c3);
double b = (tau + x)/y;
double t = b*y;
double f1, f2, f3;
const double c0 = 2.0/(Pi*exp(0.0));
const double c1 = 1.0/SqrtTwo;
const double c2 = 2.0/SqrtPi;
if (y > c0/m_eps) {
return 0.0;
}
double f0, ef0;
while (1 > 0) {
f0 = Pi*Pi/(t*t);
ef0 = exp(-f0);
f1 = c2*y*ef0;
f2 = fabs(y*y - Pi*Pi/(t*t));
f3 = 1.0 - ef0*ef0;
t *= c1;
if (f1/(f2*f3) < 0.5*m_eps) {
break;
}
}
double h = t/y;
int N = int(0.5 + b/h);
double S = 0.0;
double u = h/2;
for (int i = 0; i < N; i++) {
S += (1.0 + exp(-4.0*x*y*u))*exp(-pow(y*u-x,2))/(u*u+1.0);
u += h;
}
double Q = h*S/Pi;
double C = 0.0;
if (y*y < Pi/h) {
C = 2.0*exp(y*y - x*x)*cos(2*x*y)/(1.0 + exp(2*Pi/h));
} else {
return 0.0;
}
return Q + C;
}
/**
* Voigt profile.
*
* Not sure that constant is right.
*/
doublereal Voigt::profile(doublereal deltaFreq)
{
const double ff = 1.0/(m_sigsqrt2*SqrtPi);
return ff*F(deltaFreq/m_sigsqrt2);
}
}