/// <summary> /// Computes the complex Faddeeva function. /// </summary> /// <param name="z">The complex argument.</param> /// <returns>The complex value of w(z).</returns> /// <remarks> /// <para>The Faddeeva function w(z) is related to the error function with a complex argument.</para> /// <img src="../images/FaddeevaErfcRelation.png" /> /// <para>It also has an integral representation.</para> /// <img src="../images/FaddeevaIntegral.png" /> /// <para>For purely imaginary values, it reduces to the complementary error function (<see cref="AdvancedMath.Erfc"/>). /// For purely real values, it reduces to Dawson's integral (<see cref="AdvancedMath.Dawson"/>).</para> /// <para>It appears in the computation of the Voigt line profile function V(x;σ,γ).</para> /// <img src="../images/Voigt.png" /> /// <para>Near the origin, w(z) ≈ 1. To accurately determine w(z) - 1 in this region, use the <see cref="Erf"/> /// function. Away from the origin near the large negative imaginary axis, the magnitude w(z) increases rapidly and /// may overflow.</para> /// <para>The image below shows the complex Faddeeva function near the origin, using domain coloring.</para> /// <img src="../images/ComplexFaddeevaPlot.png" /> /// </remarks> /// <seealso cref="AdvancedComplexMath.Erf"/> /// <seealso cref="AdvancedMath.Erf" /> /// <seealso cref="AdvancedMath.Erfc" /> /// <seealso cref="AdvancedMath.Dawson"/> /// <seealso href="http://en.wikipedia.org/wiki/Voigt_profile" /> public static Complex Faddeeva(Complex z) { // use reflection formulae to ensure that we are in the first quadrant if (z.Im < 0.0) { return(2.0 * ComplexMath.Exp(-z * z) - Faddeeva(-z)); } if (z.Re < 0.0) { return(Faddeeva(-z.Conjugate).Conjugate); } double r = ComplexMath.Abs(z); if (r < 2.0) { // use series for small z return(ComplexMath.Exp(-z * z) * (1.0 - Erf_Series(-ComplexMath.I * z))); //return (Faddeeva_Series(z)); } else if ((z.Im < 0.1) && (z.Re < 30.0)) { // this is a special, awkward region // along the real axis, Re{w(x)} ~ e^{-x^2}; the Weideman algorthm doesen't compute this small number // well and the Laplace continued fraction misses it entirely; therefore very close to the real axis // we will use an analytic result on the real axis and Taylor expand to where we need to go. // unfortunately the Taylor expansion converges poorly for large x, so we drop this work-arround near x~30, // when this real part becomes too small to represent as a double anyway double x = z.Re; double y = z.Im; return(Faddeeva_Taylor(new Complex(x, 0.0), Math.Exp(-x * x) + 2.0 * AdvancedMath.Dawson(x) / Global.SqrtPI * ComplexMath.I, new Complex(0.0, y))); } else if (r > 7.0) { // use Laplace continued fraction for large z return(Faddeeva_ContinuedFraction(z)); } else { // use Weideman algorithm for intermediate region return(Faddeeva_Weideman(z)); } }