Basic branch selection functionality for incomplete Γ.
No modifications with effects on Ewald sums done yet. Former-commit-id: e362341713ce306482386b9e6f2a48c336fad7a1
This commit is contained in:
parent
2dd9fe2f34
commit
e7f0e0131f
|
@ -181,7 +181,7 @@ 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)), &gam);
|
int retval = complex_gamma_inc_e(-0.5, -csq(k/(2*eta)), 0 /*TODO*/, &gam);
|
||||||
// FIXME DO THIS CORRECTLY gam.val = conj(gam.val); // We take the other branch, cf. [Linton, p. 642 in the middle]
|
// FIXME DO THIS CORRECTLY gam.val = conj(gam.val); // We take the other branch, cf. [Linton, p. 642 in the middle]
|
||||||
if (0 != retval)
|
if (0 != retval)
|
||||||
abort();
|
abort();
|
||||||
|
@ -301,7 +301,7 @@ int ewald3_21_xy_sigma_long (
|
||||||
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
|
// TODO COMPLEX FIXME check the branches in the old lilgamma case
|
||||||
int retval = complex_gamma_inc_e(0.5-j, z, Gamma_pq+j);
|
int retval = complex_gamma_inc_e(0.5-j, z, 0 /*TODO*/, Gamma_pq+j);
|
||||||
// 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 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
|
||||||
//if(creal(z) < 0)
|
//if(creal(z) < 0)
|
||||||
// Gamma_pq[j].val = conj(Gamma_pq[j].val); //FIXME as noted above
|
// Gamma_pq[j].val = conj(Gamma_pq[j].val); //FIXME as noted above
|
||||||
|
@ -443,7 +443,7 @@ 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, Gamma_pq+j);
|
int retval = complex_gamma_inc_e(0.5-j, z, 0 /*TODO*/, Gamma_pq+j);
|
||||||
// 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 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
|
||||||
//if(creal(z) < 0)
|
//if(creal(z) < 0)
|
||||||
// Gamma_pq[j].val = conj(Gamma_pq[j].val); //FIXME as noted above
|
// Gamma_pq[j].val = conj(Gamma_pq[j].val); //FIXME as noted above
|
||||||
|
|
18
qpms/ewald.h
18
qpms/ewald.h
|
@ -141,7 +141,23 @@ 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(). */
|
||||||
int complex_gamma_inc_e(double a, complex double x, qpms_csf_result *result);
|
int complex_gamma_inc_e(double a, complex double x,
|
||||||
|
/// Branch index.
|
||||||
|
/** If zero, the principal value is calculated; on the negative real axis
|
||||||
|
* 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.
|
||||||
|
* In such case, the returned value corresponds to \f[
|
||||||
|
* \Gamma(a,ze^{2\pi mi})=e^{2\pi mia} \Gamma(a,z)
|
||||||
|
* + (1-e^{2\pi mia}) \Gamma(a).
|
||||||
|
* \f]
|
||||||
|
*
|
||||||
|
* If \a a is non-positive integer, the limiting value should
|
||||||
|
* be used, but this is not yet implemented!
|
||||||
|
*/
|
||||||
|
int m,
|
||||||
|
qpms_csf_result *result);
|
||||||
|
|
||||||
/// Exponential integral for complex second argument.
|
/// Exponential integral for complex second argument.
|
||||||
/** If x is (almost) positive real, it just uses gsl_sf_expint_En_e(). */
|
/** If x is (almost) positive real, it just uses gsl_sf_expint_En_e(). */
|
||||||
|
|
|
@ -162,26 +162,44 @@ int cx_gamma_inc_CF_e(const double a, const complex double z, qpms_csf_result *r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Incomplete gamma function for complex second argument.
|
// Incomplete gamma function for complex second argument.
|
||||||
int complex_gamma_inc_e(double a, complex double x, qpms_csf_result *result) {
|
int complex_gamma_inc_e(double a, complex double x, int m, qpms_csf_result *result) {
|
||||||
|
int retval;
|
||||||
if (creal(x) >= 0 &&
|
if (creal(x) >= 0 &&
|
||||||
(0 == fabs(cimag(x)) || // x is real positive; just use the real fun
|
(0 == fabs(cimag(x)) || // x is real positive; just use the real fun
|
||||||
fabs(cimag(x)) < fabs(creal(x)) * COMPLEXPART_REL_ZERO_LIMIT)) {
|
fabs(cimag(x)) < fabs(creal(x)) * COMPLEXPART_REL_ZERO_LIMIT)) {
|
||||||
gsl_sf_result real_gamma_inc_result;
|
gsl_sf_result real_gamma_inc_result;
|
||||||
int retval = gsl_sf_gamma_inc_e(a, creal(x), &real_gamma_inc_result);
|
retval = gsl_sf_gamma_inc_e(a, creal(x), &real_gamma_inc_result);
|
||||||
result->val = real_gamma_inc_result.val;
|
result->val = real_gamma_inc_result.val;
|
||||||
result->err = real_gamma_inc_result.err;
|
result->err = real_gamma_inc_result.err;
|
||||||
return retval;
|
|
||||||
} else if (creal(x) >= 0 && cabs(x) > 0.5)
|
} else if (creal(x) >= 0 && cabs(x) > 0.5)
|
||||||
return cx_gamma_inc_CF_e(a, x, result);
|
retval = cx_gamma_inc_CF_e(a, x, result);
|
||||||
else if (QPMS_LIKELY(a > 0 || (a % 1.0)))
|
else if (QPMS_LIKELY(a > 0 || fmod(a, 1.0)))
|
||||||
return cx_gamma_inc_series_e(a, x, result);
|
retval = cx_gamma_inc_series_e(a, x, result);
|
||||||
else
|
else
|
||||||
/* FIXME cx_gamma_inc_series_e() probably fails for non-positive integer a.
|
/* FIXME cx_gamma_inc_series_e() probably fails for non-positive integer a.
|
||||||
* This does not matter for 2D lattices in 3D space,
|
* This does not matter for 2D lattices in 3D space,
|
||||||
* but it might cause problems in the other cases.
|
* but it might cause problems in the other cases.
|
||||||
*/
|
*/
|
||||||
QPMS_NOT_IMPLEMENTED("Incomplete Gamma function with non-positive integer a.");
|
QPMS_NOT_IMPLEMENTED("Incomplete Gamma function with non-positive integer a.");
|
||||||
|
if (m) { // Non-principal branch.
|
||||||
|
/* This might be sub-optimal, as Γ(a) has probably been already evaluated
|
||||||
|
* somewhere in the functions called above. */
|
||||||
|
gsl_sf_result fullgamma;
|
||||||
|
int retval_fg = gsl_sf_gamma_e(a, &fullgamma);
|
||||||
|
if (GSL_EUNDRFLW == retval_fg)
|
||||||
|
fullgamma.err += DBL_MIN;
|
||||||
|
else if (GSL_SUCCESS != retval_fg){
|
||||||
|
result->val = NAN + NAN*I; result->err = NAN;
|
||||||
|
return GSL_ERROR_SELECT_2(retval_fg, retval);
|
||||||
|
}
|
||||||
|
complex double f = cexp(2*m*M_PI*a*I);
|
||||||
|
result->val *= f;
|
||||||
|
f = 1 - f;
|
||||||
|
result->err += cabs(f) * fullgamma.err;
|
||||||
|
result->val += f * fullgamma.val;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exponential integral for complex argument; !UNTESTED! and probably not needed, as I expressed everything in terms of inc. gammas anyways.
|
// Exponential integral for complex argument; !UNTESTED! and probably not needed, as I expressed everything in terms of inc. gammas anyways.
|
||||||
|
@ -195,7 +213,7 @@ int complex_expint_n_e(int n, complex double x, qpms_csf_result *result) {
|
||||||
result->err = real_expint_result.err;
|
result->err = real_expint_result.err;
|
||||||
return retval;
|
return retval;
|
||||||
} else {
|
} else {
|
||||||
int retval = complex_gamma_inc_e(-n+1, x, result);
|
int retval = complex_gamma_inc_e(-n+1, x, 0, result);
|
||||||
complex double f = cpow(x, 2*n-2);
|
complex double f = cpow(x, 2*n-2);
|
||||||
result->val *= f;
|
result->val *= f;
|
||||||
result->err *= cabs(f);
|
result->err *= cabs(f);
|
||||||
|
|
|
@ -598,10 +598,10 @@ def linton_gamma(cdouble x):
|
||||||
def linton_gamma_real(double x):
|
def linton_gamma_real(double x):
|
||||||
return lilgamma(x)
|
return lilgamma(x)
|
||||||
|
|
||||||
def gamma_inc(double a, cdouble x):
|
def gamma_inc(double a, cdouble x, int m = 0):
|
||||||
cdef qpms_csf_result res
|
cdef qpms_csf_result res
|
||||||
with pgsl_ignore_error(15): #15 is underflow
|
with pgsl_ignore_error(15): #15 is underflow
|
||||||
complex_gamma_inc_e(a, x, &res)
|
complex_gamma_inc_e(a, x, m, &res)
|
||||||
return (res.val, res.err)
|
return (res.val, res.err)
|
||||||
|
|
||||||
def gamma_inc_series(double a, cdouble x):
|
def gamma_inc_series(double a, cdouble x):
|
||||||
|
|
|
@ -572,7 +572,7 @@ cdef extern from "ewald.h":
|
||||||
cdouble clilgamma(cdouble z)
|
cdouble clilgamma(cdouble z)
|
||||||
int cx_gamma_inc_series_e(double a, cdouble x, qpms_csf_result *result)
|
int cx_gamma_inc_series_e(double a, cdouble x, qpms_csf_result *result)
|
||||||
int cx_gamma_inc_CF_e(double a, cdouble x, qpms_csf_result *result)
|
int cx_gamma_inc_CF_e(double a, cdouble x, qpms_csf_result *result)
|
||||||
int complex_gamma_inc_e(double a, cdouble x, qpms_csf_result *result)
|
int complex_gamma_inc_e(double a, cdouble x, int m, qpms_csf_result *result)
|
||||||
|
|
||||||
int ewald3_sigma0(cdouble *target, double *err, const qpms_ewald3_constants_t *c, double eta, cdouble wavenumber)
|
int ewald3_sigma0(cdouble *target, double *err, const qpms_ewald3_constants_t *c, double eta, cdouble wavenumber)
|
||||||
int ewald3_sigma_long(cdouble *target_sigmalr_y, double *target_sigmalr_y_err, const qpms_ewald3_constants_t *c,
|
int ewald3_sigma_long(cdouble *target_sigmalr_y, double *target_sigmalr_y_err, const qpms_ewald3_constants_t *c,
|
||||||
|
|
Loading…
Reference in New Issue