Remove the branch cut at negative real axis in Ewald sum.

Move the cut to the negative imaginary axis instead.

Also update comments.


Former-commit-id: a70e6a4db0ac33836d672d9ee2356ea19a899a30
This commit is contained in:
Marek Nečada 2019-10-09 13:20:20 +03:00
parent acff55f396
commit 4dd3234b0a
3 changed files with 45 additions and 18 deletions

View File

@ -181,8 +181,10 @@ int ewald3_sigma0(complex double *result, double *err,
const double eta, const complex double k) const double eta, const complex double k)
{ {
qpms_csf_result gam; qpms_csf_result gam;
int retval = complex_gamma_inc_e(-0.5, -csq(k/(2*eta)), 0 /*TODO*/, &gam); complex double z = -csq(k/(2*eta));
// FIXME DO THIS CORRECTLY gam.val = conj(gam.val); // We take the other branch, cf. [Linton, p. 642 in the middle] int retval = complex_gamma_inc_e(-0.5, z,
// we take the branch which is principal for the Re z < 0, Im z < 0 quadrant, cf. [Linton, p. 642 in the middle]
QPMS_LIKELY(creal(z) < 0) && !signbit(cimag(z)) ? -1 : 0, &gam);
if (0 != retval) if (0 != retval)
abort(); abort();
*result = gam.val * c->legendre0[gsl_sf_legendre_array_index(0,0)] / 2 / M_SQRTPI; *result = gam.val * c->legendre0[gsl_sf_legendre_array_index(0,0)] / 2 / M_SQRTPI;
@ -300,11 +302,9 @@ int ewald3_21_xy_sigma_long (
gamma_pq = clilgamma(rbeta_pq/k); gamma_pq = clilgamma(rbeta_pq/k);
z = csq(gamma_pq*k/(2*eta)); z = csq(gamma_pq*k/(2*eta));
for(qpms_l_t j = 0; j <= lMax/2; ++j) { for(qpms_l_t j = 0; j <= lMax/2; ++j) {
// TODO COMPLEX FIXME check the branches in the old lilgamma case int retval = complex_gamma_inc_e(0.5-j, z,
int retval = complex_gamma_inc_e(0.5-j, z, 0 /*TODO*/, Gamma_pq+j); // we take the branch which is principal for the Re z < 0, Im z < 0 quadrant, cf. [Linton, p. 642 in the middle]
// we take the other branch, cf. [Linton, p. 642 in the middle]: FIXME instead use the C11 CMPLX macros and fill in -O*I part to z in the line above QPMS_LIKELY(creal(z) < 0) && !signbit(cimag(z)) ? -1 : 0, Gamma_pq+j);
//if(creal(z) < 0)
// Gamma_pq[j].val = conj(Gamma_pq[j].val); //FIXME as noted above
if(!(retval==0 || retval==GSL_EUNDRFLW)) abort(); if(!(retval==0 || retval==GSL_EUNDRFLW)) abort();
} }
if (latdim & LAT1D) if (latdim & LAT1D)
@ -443,10 +443,9 @@ int ewald3_1_z_sigma_long (
complex double gamma_pq = clilgamma(rbeta_mu/k); // For real beta and k this is real or pure imaginary ... complex double gamma_pq = clilgamma(rbeta_mu/k); // For real beta and k this is real or pure imaginary ...
const complex double z = csq(gamma_pq*k/(2*eta));// ... so the square (this) is in fact real. const complex double z = csq(gamma_pq*k/(2*eta));// ... so the square (this) is in fact real.
for(qpms_l_t j = 0; j <= lMax/2; ++j) { for(qpms_l_t j = 0; j <= lMax/2; ++j) {
int retval = complex_gamma_inc_e(0.5-j, z, 0 /*TODO*/, Gamma_pq+j); int retval = complex_gamma_inc_e(0.5-j, z,
// we take the other branch, cf. [Linton, p. 642 in the middle]: FIXME instead use the C11 CMPLX macros and fill in -O*I part to z in the line above // we take the branch which is principal for the Re z < 0, Im z < 0 quadrant, cf. [Linton, p. 642 in the middle]
//if(creal(z) < 0) QPMS_LIKELY(creal(z) < 0) && !signbit(cimag(z)) ? -1 : 0, Gamma_pq+j);
// Gamma_pq[j].val = conj(Gamma_pq[j].val); //FIXME as noted above
if(!(retval==0 || retval==GSL_EUNDRFLW)) abort(); if(!(retval==0 || retval==GSL_EUNDRFLW)) abort();
} }
// R-DEPENDENT END // R-DEPENDENT END

View File

@ -133,20 +133,48 @@ static inline complex double clilgamma(complex double z) {
} }
/// Incomplete Gamma function as a series. /// Incomplete Gamma function as a series.
/** DLMF 8.7.3 (latter expression) for complex second argument */ /** DLMF 8.7.3 (latter expression) for complex second argument.
*
* The principal value is calculated. On the negative real axis
* (where the function has branch cut), the sign of the imaginary
* part is what matters (even if it is zero). Therefore one
* can have
* `cx_gamma_inc_series_e(a, z1) != cx_gamma_inc_series_e(a, z2)`
* even if `z1 == z2`, because `-0 == 0` according to IEEE 754.
* The side of the branch cut can be determined using `signbit(creal(z))`.
*/
int cx_gamma_inc_series_e(double a, complex z, qpms_csf_result * result); int cx_gamma_inc_series_e(double a, complex z, qpms_csf_result * result);
/// Incomplete Gamma function as continued fractions. /// Incomplete Gamma function as continued fractions.
/**
* The principal value is calculated. On the negative real axis
* (where the function has branch cut), the sign of the imaginary
* part is what matters (even if it is zero). Therefore one
* can have
* `cx_gamma_inc_CF_e(a, z1) != cx_gamma_inc_CF_e(a, z2)`
* even if `z1 == z2`, because `-0 == 0` according to IEEE 754.
* The side of the branch cut can be determined using `signbit(creal(z))`.
*/
int cx_gamma_inc_CF_e(double a, complex z, qpms_csf_result * result); int cx_gamma_inc_CF_e(double a, complex z, qpms_csf_result * result);
/// Incomplete gamma for complex second argument. /// Incomplete gamma for complex second argument.
/** if x is (almost) real, it just uses gsl_sf_gamma_inc_e(). */ /**
* If x is (almost) real, it just uses gsl_sf_gamma_inc_e().
*
* On the negative real axis
* (where the function has branch cut), the sign of the imaginary
* part is what matters (even if it is zero). Therefore one
* can have
* `complex_gamma_inc_e(a, z1, m) != complex_gamma_inc_e(a, z2, m)`
* even if `z1 == z2`, because `-0 == 0` according to IEEE 754.
* The side of the branch cut can be determined using `signbit(creal(z))`.
*
* Another than principal branch can be selected using non-zero \a m
* argument.
*/
int complex_gamma_inc_e(double a, complex double x, int complex_gamma_inc_e(double a, complex double x,
/// Branch index. /// Branch index.
/** If zero, the principal value is calculated; on the negative real axis /** If zero, the principal value is calculated.
* we take the limit \f[
* \Gamma(a,z)=\lim_{\epsilon\to 0+}\Gamma(\mu,z-i\epsilon).
* \f]
* Other branches might be chosen using non-zero \a m. * Other branches might be chosen using non-zero \a m.
* In such case, the returned value corresponds to \f[ * In such case, the returned value corresponds to \f[
* \Gamma(a,ze^{2\pi mi})=e^{2\pi mia} \Gamma(a,z) * \Gamma(a,ze^{2\pi mi})=e^{2\pi mia} \Gamma(a,z)

View File

@ -195,7 +195,7 @@ int complex_gamma_inc_e(double a, complex double x, int m, qpms_csf_result *resu
} }
complex double f = cexp(2*m*M_PI*a*I); complex double f = cexp(2*m*M_PI*a*I);
result->val *= f; result->val *= f;
f = 1 - f; f = -f + 1;
result->err += cabs(f) * fullgamma.err; result->err += cabs(f) * fullgamma.err;
result->val += f * fullgamma.val; result->val += f * fullgamma.val;
} }