2019-06-27 16:42:35 +03:00
|
|
|
|
/*! \file ewald.h
|
|
|
|
|
* \brief Lattice sums of spherical waves.
|
|
|
|
|
*
|
|
|
|
|
* Implementation of two-dimensional lattice sum in three dimensions
|
|
|
|
|
* according to:
|
|
|
|
|
* - [1] C.M. Linton, I. Thompson
|
|
|
|
|
* Journal of Computational Physics 228 (2009) 1815–1829
|
|
|
|
|
* - [2] C.M.Linton
|
|
|
|
|
* SIAM Review Vol 52, No. 4, pp. 630–674
|
|
|
|
|
*
|
|
|
|
|
* N.B.!!! currently, the long-range parts are calculated
|
|
|
|
|
* not according to [1,(4.5)], but rather
|
|
|
|
|
* according to the spherical-harmonic-normalisation-independent
|
|
|
|
|
* formulation in my notes notes/ewald.lyx.
|
|
|
|
|
* Both parts of lattice sums are then calculated with
|
|
|
|
|
* the \f$ P_n^{|m|} e^{im\phi} \f$
|
|
|
|
|
* (N.B. or \f$ P_n^{|m|} e^{imf} (-1)^m \f$ for negative m)
|
|
|
|
|
* substituted in place of \f$ Y_n^m \f$
|
|
|
|
|
* (this is quite a weird normalisation especially
|
|
|
|
|
* for negative \f$ |m| \f$, but it is consistent
|
|
|
|
|
* with the current implementation of the translation coefficients in
|
|
|
|
|
* @ref translations.c;
|
|
|
|
|
* in the long run, it might make more sense to replace it everywhere with normalised
|
|
|
|
|
* Legendre polynomials).
|
|
|
|
|
*/
|
|
|
|
|
|
2018-08-20 15:07:22 +03:00
|
|
|
|
#ifndef EWALD_H
|
|
|
|
|
#define EWALD_H
|
|
|
|
|
#include <gsl/gsl_sf_result.h>
|
2018-11-21 21:42:17 +02:00
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <gsl/gsl_sf_legendre.h>
|
2018-09-07 20:46:07 +03:00
|
|
|
|
#include <gsl/gsl_errno.h>
|
2018-08-21 18:13:42 +03:00
|
|
|
|
#include <math.h> // for inlined lilgamma
|
2018-08-20 15:07:22 +03:00
|
|
|
|
#include <complex.h>
|
2018-08-21 18:13:42 +03:00
|
|
|
|
#include "qpms_types.h"
|
2018-11-21 21:42:17 +02:00
|
|
|
|
#include "lattices.h"
|
2018-08-21 18:13:42 +03:00
|
|
|
|
|
2019-11-04 09:38:23 +02:00
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
QPMS_EWALD_LONG_RANGE = 1,
|
|
|
|
|
QPMS_EWALD_SHORT_RANGE = 2,
|
|
|
|
|
QPMS_EWALD_0TERM = 4,
|
|
|
|
|
QPMS_EWALD_FULL = QPMS_EWALD_LONG_RANGE | QPMS_EWALD_SHORT_RANGE | QPMS_EWALD_0TERM,
|
|
|
|
|
} qpms_ewald_part;
|
|
|
|
|
|
|
|
|
|
|
2019-08-17 13:31:38 +03:00
|
|
|
|
/// Use this handler to ignore underflows of incomplete gamma.
|
2018-09-07 20:46:07 +03:00
|
|
|
|
gsl_error_handler_t IgnoreUnderflowsGSLErrorHandler;
|
|
|
|
|
|
|
|
|
|
|
2019-08-17 13:31:38 +03:00
|
|
|
|
/// Object holding the Ewald sum constant factors.
|
|
|
|
|
/**
|
|
|
|
|
* Used internally by qpms_translation_calculator_t.
|
|
|
|
|
* Initialised by qpms_ewald3_constants_init() and freed by qpms_ewald3_constants_free().
|
|
|
|
|
*/
|
2019-10-02 22:07:26 +03:00
|
|
|
|
typedef struct qpms_ewald3_constants_t {
|
2018-08-21 18:13:42 +03:00
|
|
|
|
qpms_l_t lMax;
|
2018-09-05 15:39:02 +03:00
|
|
|
|
qpms_y_t nelem_sc;
|
2019-08-17 13:31:38 +03:00
|
|
|
|
/// The values of maximum \a j's in the long-range part summation, `[(l-|m|/2)]`.
|
2018-08-21 18:13:42 +03:00
|
|
|
|
qpms_l_t *s1_jMaxes;
|
2019-08-17 13:31:38 +03:00
|
|
|
|
/// The constant factors for the long range part of a 2D Ewald sum.
|
2018-08-21 18:13:42 +03:00
|
|
|
|
complex double **s1_constfacs; // indices [y][j] where j is same as in [1, (4.5)]
|
2018-11-24 14:51:57 +02:00
|
|
|
|
/* These are the actual numbers now: (in the EWALD32_CONSTANTS_AGNOSTIC version)
|
|
|
|
|
* for m + n EVEN:
|
|
|
|
|
*
|
|
|
|
|
* s1_constfacs[y(m,n)][j] =
|
|
|
|
|
*
|
|
|
|
|
* -2 * I**(n+1) * sqrt(π) * ((n-m)/2)! * ((n+m)/2)! * (-1)**j
|
|
|
|
|
* -----------------------------------------------------------
|
|
|
|
|
* j! * ((n-m)/2 - j)! * ((n+m)/2 + j)!
|
|
|
|
|
*
|
|
|
|
|
* for m + n ODD:
|
|
|
|
|
*
|
|
|
|
|
* s1_constfacs[y(m,n)][j] = 0
|
|
|
|
|
*/
|
2019-08-17 13:31:38 +03:00
|
|
|
|
complex double *s1_constfacs_base; ///< Internal pointer holding memory for the 2D Ewald sum constant factors.
|
2018-11-24 14:51:57 +02:00
|
|
|
|
// similarly for the 1D z-axis aligned case; now the indices are [n][j] (as m == 0)
|
2019-08-17 13:31:38 +03:00
|
|
|
|
/// The constant factors for the long range part of a 1D Ewald sum along the \a z axis.
|
|
|
|
|
/** If the summation points lie along a different direction, use the formula for
|
|
|
|
|
* 2D sum with additional factor of
|
|
|
|
|
* \f$ \sqrt{pi} \kappa \gamma(\abs{\vect{k}+\vect{K}}/\kappa) \f$.
|
|
|
|
|
*/
|
2020-05-29 15:55:52 +03:00
|
|
|
|
|
|
|
|
|
///=============== NEW GENERATION GENERAL 2D-IN-3D, including z != 0 =========================
|
|
|
|
|
|
|
|
|
|
// TODO indexing mechanisms
|
|
|
|
|
|
|
|
|
|
/// The constant factors for the long range part of a 2D Ewald sum.
|
|
|
|
|
complex double **S1_constfacs; // indices [y][j] where j is same as in [1, (4.5)]
|
|
|
|
|
/* These are the actual numbers now: (in the EWALD32_CONSTANTS_AGNOSTIC version)
|
|
|
|
|
* for m + n EVEN:
|
|
|
|
|
*
|
2020-05-30 22:39:20 +03:00
|
|
|
|
* S1_constfacs[y(m,n)][x(j,s)] =
|
2020-05-29 15:55:52 +03:00
|
|
|
|
*
|
|
|
|
|
* -2 * I**(n+1) * sqrt(π) * ((n-m)/2)! * ((n+m)/2)! * (-1)**j / j \
|
|
|
|
|
* ----------------------------------------------------------- | |
|
|
|
|
|
* j! * ((n - m - s)/2)! * ((n + m - s)/2)! \ 2j - s /
|
|
|
|
|
*
|
|
|
|
|
* for m + n ODD:
|
|
|
|
|
*
|
2020-05-30 22:39:20 +03:00
|
|
|
|
* S1_constfacs[y(m,n)][j] = 0
|
2020-05-29 15:55:52 +03:00
|
|
|
|
*/
|
|
|
|
|
complex double *S1_constfacs_base; ///< Internal pointer holding memory for the 2D Ewald sum constant factors.
|
|
|
|
|
/// The constant factors for the long range part of a 1D Ewald sum along the \a z axis.
|
|
|
|
|
/** If the summation points lie along a different direction, use the formula for
|
|
|
|
|
* 2D sum with additional factor of
|
|
|
|
|
* \f$ \sqrt{pi} \kappa \gamma(\abs{\vect{k}+\vect{K}}/\kappa) \f$.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2018-11-24 14:51:57 +02:00
|
|
|
|
complex double **s1_constfacs_1Dz;
|
|
|
|
|
/* These are the actual numbers now:
|
2019-08-17 13:31:38 +03:00
|
|
|
|
* s1_constfacs_1Dz[n][j] =
|
2018-11-24 14:51:57 +02:00
|
|
|
|
*
|
|
|
|
|
* -I**(n+1) (-1)**j * n!
|
|
|
|
|
* --------------------------
|
|
|
|
|
* j! * 2**(2*j) * (n - 2*j)!
|
|
|
|
|
*/
|
2019-08-17 13:31:38 +03:00
|
|
|
|
complex double *s1_constfacs_1Dz_base; ///<Internal pointer holding memory for the 1D Ewald sum constant factors.
|
2018-09-05 09:07:03 +03:00
|
|
|
|
|
|
|
|
|
double *legendre0; /* now with GSL_SF_LEGENDRE_NONE normalisation, because this is what is
|
|
|
|
|
* what the multipliers from translations.c count with.
|
|
|
|
|
*/
|
2018-11-14 08:37:59 +02:00
|
|
|
|
double *legendre_plus1; // needed? TODO; in any case, nonzero only for m=0
|
|
|
|
|
double *legendre_minus1; // needed? TODO; in any case, nonzero only for m=0
|
2018-11-21 21:42:17 +02:00
|
|
|
|
gsl_sf_legendre_t legendre_normconv;
|
|
|
|
|
int legendre_csphase; /* 1 or -1; csphase of the Legendre polynomials saved in legendre0 etc.
|
2018-09-05 09:07:03 +03:00
|
|
|
|
This is because I dont't actually consider this fixed in
|
|
|
|
|
translations.c */
|
|
|
|
|
|
2018-12-21 21:31:07 +02:00
|
|
|
|
} qpms_ewald3_constants_t;
|
2018-08-21 18:13:42 +03:00
|
|
|
|
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Constructor for qpms_ewald3_constants_t.
|
2018-12-21 21:31:07 +02:00
|
|
|
|
qpms_ewald3_constants_t *qpms_ewald3_constants_init(qpms_l_t lMax, int csphase);
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Destructor for qpms_ewald3_constants_t.
|
2018-12-21 21:31:07 +02:00
|
|
|
|
void qpms_ewald3_constants_free(qpms_ewald3_constants_t *);
|
2018-08-21 18:13:42 +03:00
|
|
|
|
|
2018-08-20 15:07:22 +03:00
|
|
|
|
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Structure for holding complex-valued result of computation and an error estimate.
|
|
|
|
|
/** Similar to gsl_sf_result, but with complex val. */
|
2019-08-20 12:46:28 +03:00
|
|
|
|
typedef struct qpms_csf_result {
|
2019-08-19 12:02:22 +03:00
|
|
|
|
complex double val; ///< Calculation result.
|
|
|
|
|
double err; ///< Error estimate.
|
2018-08-20 15:07:22 +03:00
|
|
|
|
} qpms_csf_result;
|
|
|
|
|
|
|
|
|
|
|
2018-08-21 18:13:42 +03:00
|
|
|
|
// [1, (A.9)]
|
2018-08-20 15:07:22 +03:00
|
|
|
|
static inline complex double lilgamma(double t) {
|
|
|
|
|
t = fabs(t);
|
|
|
|
|
if (t >= 1)
|
|
|
|
|
return sqrt(t*t - 1);
|
|
|
|
|
else
|
|
|
|
|
return -I * sqrt(1 - t*t);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-21 16:50:53 +02:00
|
|
|
|
// [1, (A.8)], complex version of lilgamma()
|
|
|
|
|
static inline complex double clilgamma(complex double z) {
|
|
|
|
|
complex double a1 = z - 1, a2 = z + 1;
|
|
|
|
|
// ensure -pi/2 < arg(z + 1) < 3*pi/2
|
|
|
|
|
if (creal(a2) < 0 && cimag(a2) <= 0)
|
|
|
|
|
a2 = -csqrt(a2);
|
|
|
|
|
else
|
|
|
|
|
a2 = csqrt(a2);
|
|
|
|
|
// ensure -3*pi/2 < arg(z - 1) < pi/2
|
|
|
|
|
if (creal(a1) < 0 && cimag(a1) >= 0)
|
|
|
|
|
a1 = -csqrt(a1);
|
|
|
|
|
else
|
|
|
|
|
a1 = csqrt(a1);
|
|
|
|
|
return a1 * a2;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Incomplete Gamma function as a series.
|
2019-10-09 13:20:20 +03:00
|
|
|
|
/** 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))`.
|
|
|
|
|
*/
|
2020-04-11 10:01:58 +03:00
|
|
|
|
int cx_gamma_inc_series_e(double a, complex double z, qpms_csf_result * result);
|
2018-08-20 15:07:22 +03:00
|
|
|
|
|
2019-08-20 12:46:28 +03:00
|
|
|
|
/// Incomplete Gamma function as continued fractions.
|
2019-10-09 13:20:20 +03:00
|
|
|
|
/**
|
|
|
|
|
* 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))`.
|
|
|
|
|
*/
|
2020-04-11 10:01:58 +03:00
|
|
|
|
int cx_gamma_inc_CF_e(double a, complex double z, qpms_csf_result * result);
|
2019-08-20 12:46:28 +03:00
|
|
|
|
|
2019-06-27 16:42:35 +03:00
|
|
|
|
/// Incomplete gamma for complex second argument.
|
2019-10-09 13:20:20 +03:00
|
|
|
|
/**
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2019-10-06 01:30:29 +03:00
|
|
|
|
int complex_gamma_inc_e(double a, complex double x,
|
|
|
|
|
/// Branch index.
|
2019-10-09 13:20:20 +03:00
|
|
|
|
/** If zero, the principal value is calculated.
|
2019-10-06 01:30:29 +03:00
|
|
|
|
* 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);
|
2018-08-20 15:07:22 +03:00
|
|
|
|
|
2019-06-27 16:42:35 +03:00
|
|
|
|
/// Exponential integral for complex second argument.
|
|
|
|
|
/** If x is (almost) positive real, it just uses gsl_sf_expint_En_e(). */
|
2018-11-24 14:51:57 +02:00
|
|
|
|
int complex_expint_n_e(int n, complex double x, qpms_csf_result *result);
|
|
|
|
|
|
2018-09-11 10:07:37 +03:00
|
|
|
|
|
2019-06-27 16:42:35 +03:00
|
|
|
|
/// Hypergeometric 2F2, used to calculate some errors.
|
2019-10-02 20:11:25 +03:00
|
|
|
|
int hyperg_2F2_series(double a, double b, double c, double d, double x,
|
|
|
|
|
gsl_sf_result *result);
|
2018-09-11 10:07:37 +03:00
|
|
|
|
|
2018-08-27 14:39:29 +03:00
|
|
|
|
#if 0
|
|
|
|
|
// The integral from (4.6); maybe should be static and not here.
|
|
|
|
|
int ewald32_sr_integral(double r, double k, double n, double eta, double *result, double *err, gsl_integration_workspace *workspace);
|
|
|
|
|
#endif
|
2018-08-27 07:50:00 +03:00
|
|
|
|
|
2020-05-19 16:00:08 +03:00
|
|
|
|
/// The Delta_n factor from [Kambe II], Appendix 3, used in 2D-in-3D long range sum.
|
|
|
|
|
/** \f[ \Delta_n = \int_n^\infty t^{-1/2 - n} \exp(-t + z^2/(4t))\ud t \f]
|
|
|
|
|
*
|
2020-05-27 15:52:13 +03:00
|
|
|
|
* \bug The current choice of method, based purely on the value of \a z, might be
|
|
|
|
|
* unsuitable especially for big values of \a maxn.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2020-05-28 13:13:08 +03:00
|
|
|
|
void ewald3_2_sigma_long_Delta(complex double *target, double *target_err, int maxn, complex double x,
|
|
|
|
|
int xbranch, complex double z);
|
2020-05-27 15:52:13 +03:00
|
|
|
|
|
|
|
|
|
/// The Delta_n factor from [Kambe II], Appendix 3, used in 2D-in-3D long range sum.
|
|
|
|
|
/** This function always uses Kambe's (corrected) recurrent formula.
|
|
|
|
|
* For production, use ewald3_2_sigma_long_Delta() instead.
|
|
|
|
|
*/
|
2020-05-28 13:13:08 +03:00
|
|
|
|
void ewald3_2_sigma_long_Delta_recurrent(complex double *target, double *target_err, int maxn, complex double x,
|
2020-07-20 23:24:06 +03:00
|
|
|
|
int xbranch, complex double z, _Bool bigimz);
|
2020-05-27 15:52:13 +03:00
|
|
|
|
|
|
|
|
|
/// The Delta_n factor from [Kambe II], Appendix 3, used in 2D-in-3D long range sum.
|
|
|
|
|
/** This function always uses Taylor expansion in \a z.
|
|
|
|
|
* For production, use ewald3_2_sigma_long_Delta() instead.
|
|
|
|
|
*
|
|
|
|
|
* \bug The error estimate seems to be wrong (too small) at least in some cases: try
|
|
|
|
|
* parameters maxn = 40, z = 0.5, x = -3. This might be related to the exponential growth
|
|
|
|
|
* of the error.
|
2020-05-19 16:00:08 +03:00
|
|
|
|
*/
|
2020-05-28 13:13:08 +03:00
|
|
|
|
void ewald3_2_sigma_long_Delta_series(complex double *target, double *target_err, int maxn, complex double x,
|
|
|
|
|
int xbranch, complex double z);
|
2018-08-27 07:50:00 +03:00
|
|
|
|
|
2018-11-14 18:36:15 +02:00
|
|
|
|
// General functions acc. to [2], sec. 4.6 – currently valid for 2D and 1D lattices in 3D space
|
2018-09-05 14:09:22 +03:00
|
|
|
|
|
2019-10-02 20:11:25 +03:00
|
|
|
|
/// The Ewald sum "self-interaction" term that appears in the lattice sums with zero (direct-space) Bravais lattice displacement.
|
|
|
|
|
int ewald3_sigma0(complex double *result, ///< Pointer to save the result (single complex double).
|
|
|
|
|
double *err, ///< Pointer to save the result error estimate (single double).
|
|
|
|
|
const qpms_ewald3_constants_t *c, ///< Constant factors structure initialised by qpms_ewald3_constants_init().
|
|
|
|
|
double eta, ///< Ewald parameter.
|
|
|
|
|
complex double wavenumber ///< Wavenumber of the background medium.
|
2018-11-14 18:36:15 +02:00
|
|
|
|
);
|
|
|
|
|
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Short-range part of outgoing scalar spherical wavefunctions' lattice sum \f$ \sigma_{l,m}^\mathrm{S}(\vect k,\vect s)\f$.
|
2018-11-21 19:49:07 +02:00
|
|
|
|
int ewald3_sigma_short(
|
2019-08-19 12:02:22 +03:00
|
|
|
|
complex double *target_sigmasr_y, ///< Target array for \f$ \sigma_{l,m}^\mathrm{S} \f$, must be `c->nelem_sc` long.
|
|
|
|
|
double *target_sigmasr_y_err, ///< Target array for error estimates, must be `c->nelem_sc` long or `NULL`.
|
|
|
|
|
const qpms_ewald3_constants_t *c, ///< Constant factors structure initialised by qpms_ewald3_constants_init().
|
2019-10-02 20:11:25 +03:00
|
|
|
|
double eta, ///< Ewald parameter.
|
|
|
|
|
complex double wavenumber, ///< Wavenumber of the background medium.
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Lattice dimensionality.
|
|
|
|
|
/** Ignored apart from asserts and possible optimisations, as the SR formula stays the same. */
|
2019-10-02 20:11:25 +03:00
|
|
|
|
LatticeDimensionality latdim,
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Lattice point generator for the direct Bravais lattice.
|
2019-10-01 11:26:07 +03:00
|
|
|
|
/** There is a possibility that the whole PGen is not consumed
|
|
|
|
|
* (this might happen if the summand start to be consistently smaller
|
|
|
|
|
* than the (partial) sums * DBL_EPSILON.
|
|
|
|
|
* In such case, it is the responsibility of the caller to deallocate
|
|
|
|
|
* the generator.
|
|
|
|
|
*/
|
2019-08-19 12:02:22 +03:00
|
|
|
|
PGen *pgen_R,
|
|
|
|
|
/// Indicates whether pgen_R already generates shifted points.
|
|
|
|
|
/** If false, the behaviour corresponds to the old ewald32_sigma_short_points_and_shift(),
|
2018-11-21 19:49:07 +02:00
|
|
|
|
* so the function assumes that the generated points correspond to the unshifted Bravais lattice,
|
|
|
|
|
* and adds particle_shift to the generated points before calculations.
|
|
|
|
|
* If true, it assumes that they are already shifted (if calculating interaction between
|
|
|
|
|
* different particles in the unit cell).
|
2019-08-19 12:02:22 +03:00
|
|
|
|
*/
|
2019-10-02 20:11:25 +03:00
|
|
|
|
bool pgen_generates_shifted_points,
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Wave vector \f$\vect k\f$.
|
2019-10-02 20:11:25 +03:00
|
|
|
|
cart3_t k,
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Lattice offset \f$\vect s\f$ wrt. the Bravais lattice.
|
2019-10-02 20:11:25 +03:00
|
|
|
|
cart3_t particle_shift
|
2018-11-21 19:49:07 +02:00
|
|
|
|
);
|
|
|
|
|
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Long-range part of outgoing scalar spherical wavefunctions' lattice sum \f$ \sigma_{l,m}^\mathrm{L}(\vect k,\vect s)\f$.
|
2018-11-21 19:49:07 +02:00
|
|
|
|
int ewald3_sigma_long( // calls ewald3_21_sigma_long or ewald3_3_sigma_long, depending on latdim
|
2019-08-19 12:02:22 +03:00
|
|
|
|
complex double *target_sigmalr_y, ///< Target array for \f$ \sigma_{l,m}^\mathrm{L} \f$, must be `c->nelem_sc` long.
|
|
|
|
|
double *target_sigmalr_y_err, ///< Target array for error estimates, must be `c->nelem_sc` long or `NULL`.
|
|
|
|
|
const qpms_ewald3_constants_t *c, ///< Constant factors structure initialised by qpms_ewald3_constants_init().
|
2019-10-02 20:11:25 +03:00
|
|
|
|
double eta, ///< Ewald parameter.
|
|
|
|
|
complex double wavenumber, ///< Wavenumber of the background medium.
|
|
|
|
|
double unitcell_volume, ///< Volume of the (direct lattice) unit cell (with dimension corresponding to the lattice dimensionality).
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Lattice dimensionality.
|
2019-10-02 20:11:25 +03:00
|
|
|
|
LatticeDimensionality latdim,
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Lattice point generator for the reciprocal lattice.
|
2019-10-01 11:26:07 +03:00
|
|
|
|
/** There is a possibility that the whole PGen is not consumed
|
|
|
|
|
* (this might happen if the summand start to be consistently smaller
|
|
|
|
|
* than the (partial) sums * DBL_EPSILON.
|
|
|
|
|
* In such case, it is the responsibility of the caller to deallocate
|
|
|
|
|
* the generator.
|
|
|
|
|
*/
|
2019-08-19 12:02:22 +03:00
|
|
|
|
PGen *pgen_K,
|
|
|
|
|
/// Indicates whether pgen_K already generates shifted points.
|
|
|
|
|
/** If false, the behaviour corresponds to the old ewald32_sigma_long_points_and_shift(),
|
2018-11-21 19:49:07 +02:00
|
|
|
|
* so the function assumes that the generated points correspond to the unshifted reciprocal Bravais lattice,
|
|
|
|
|
* and adds beta to the generated points before calculations.
|
|
|
|
|
* If true, it assumes that they are already shifted.
|
2019-08-19 12:02:22 +03:00
|
|
|
|
*/
|
2019-10-02 20:11:25 +03:00
|
|
|
|
bool pgen_generates_shifted_points,
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Wave vector \f$\vect k\f$.
|
2019-10-02 20:11:25 +03:00
|
|
|
|
cart3_t k,
|
2019-08-19 12:02:22 +03:00
|
|
|
|
/// Lattice offset \f$\vect s\f$ wrt. the Bravais lattice.
|
2019-10-02 20:11:25 +03:00
|
|
|
|
cart3_t particle_shift
|
2018-11-21 19:49:07 +02:00
|
|
|
|
);
|
|
|
|
|
|
2018-08-20 15:07:22 +03:00
|
|
|
|
#endif //EWALD_H
|