diff --git a/qpms/ewald.c b/qpms/ewald.c index 3fec709..17ec200 100644 --- a/qpms/ewald.c +++ b/qpms/ewald.c @@ -66,15 +66,15 @@ qpms_ewald32_constants_t *qpms_ewald32_constants_init(const qpms_l_t lMax /*, co qpms_ewald32_constants_t *c = malloc(sizeof(qpms_ewald32_constants_t)); //if (c == NULL) return NULL; // Do I really want to do this? c->lMax = lMax; - c->nelem = qpms_lMax2nelem(lMax); - c->s1_jMaxes = malloc(c->nelem * sizeof(qpms_l_t)); - c->s1_constfacs = malloc(c->nelem * sizeof(complex double *)); + c->nelem_sc = qpms_lMax2nelem_sc(lMax); + c->s1_jMaxes = malloc(c->nelem_sc * sizeof(qpms_l_t)); + c->s1_constfacs = malloc(c->nelem_sc * sizeof(complex double *)); //if (c->s1_jMaxes == NULL) return NULL; //determine sizes size_t s1_constfacs_sz = 0; - for (qpms_y_t y = 0; y < c->nelem; ++y) { - qpms_l_t n; qpms_m_t m; qpms_y2mn_p(y, &m, &n); + for (qpms_y_t y = 0; y < c->nelem_sc; ++y) { + qpms_l_t n; qpms_m_t m; qpms_y2mn_sc_p(y, &m, &n); if ((m + n) % 2 == 0) s1_constfacs_sz += 1 + (c->s1_jMaxes[y] = (n-abs(m))/2); else @@ -82,10 +82,10 @@ qpms_ewald32_constants_t *qpms_ewald32_constants_init(const qpms_l_t lMax /*, co } c->s1_constfacs[0]; //WTF??? - c->s1_constfacs_base = malloc(c->nelem * sizeof(complex double)); + c->s1_constfacs_base = malloc(c->nelem_sc * sizeof(complex double)); size_t s1_constfacs_sz_cumsum = 0; - for (qpms_y_t y = 0; y < c->nelem; ++y) { - qpms_l_t n; qpms_m_t m; qpms_y2mn_p(y, &m, &n); + for (qpms_y_t y = 0; y < c->nelem_sc; ++y) { + qpms_l_t n; qpms_m_t m; qpms_y2mn_sc_p(y, &m, &n); if ((m + n) % 2 == 0) { c->s1_constfacs[y] = c->s1_constfacs_base + s1_constfacs_sz_cumsum; // and here comes the actual calculation @@ -151,7 +151,7 @@ int ewald32_sigma0(complex double *result, double *err, int ewald32_sigma_long_shiftedpoints ( - complex double *target, // must be c->nelem long + complex double *target, // must be c->nelem_sc long double *err, const qpms_ewald32_constants_t *c, const double eta, const double k, const double unitcell_area, @@ -159,16 +159,16 @@ int ewald32_sigma_long_shiftedpoints ( const point2d particle_shift // target - src ) { - const qpms_y_t nelem = c->nelem; + const qpms_y_t nelem_sc = c->nelem_sc; const qpms_l_t lMax = c->lMax; // Manual init of the ewald summation targets - complex double *target_c = calloc(nelem, sizeof(complex double)); - memset(target, 0, nelem * sizeof(complex double)); + complex double *target_c = calloc(nelem_sc, sizeof(complex double)); + memset(target, 0, nelem_sc * sizeof(complex double)); double *err_c = NULL; if (err) { - err_c = calloc(nelem, sizeof(double)); - memset(err, 0, nelem * sizeof(double)); + err_c = calloc(nelem_sc, sizeof(double)); + memset(err, 0, nelem_sc * sizeof(double)); } const double commonfac = 1/(k*k*unitcell_area); // used in the very end (CFC) @@ -197,11 +197,11 @@ int ewald32_sigma_long_shiftedpoints ( // TODO optimisations: all the j-dependent powers can be done for each j only once, stored in array // and just fetched for each n, m pair - for(qpms_l_t n = 1; n <= lMax; ++n) + for(qpms_l_t n = 0; n <= lMax; ++n) for(qpms_m_t m = -n; m <= n; ++m) { if((m+n) % 2 != 0) // odd coefficients are zero. continue; - qpms_y_t y = qpms_mn2y(m, n); + qpms_y_t y = qpms_mn2y_sc(m, n); complex double e_imalpha_pq = cexp(I*m*arg_pq); complex double jsum, jsum_c; ckahaninit(&jsum, &jsum_c); double jsum_err, jsum_err_c; kahaninit(&jsum_err, &jsum_err_c); // TODO do I really need to kahan sum errors? @@ -225,10 +225,10 @@ int ewald32_sigma_long_shiftedpoints ( free(err_c); free(target_c); - for(qpms_y_t y = 0; y < nelem; ++y) // CFC common factor from above + for(qpms_y_t y = 0; y < nelem_sc; ++y) // CFC common factor from above target[y] *= commonfac; if(err) - for(qpms_y_t y = 0; y < nelem; ++y) + for(qpms_y_t y = 0; y < nelem_sc; ++y) err[y] *= commonfac; return 0; } @@ -270,7 +270,7 @@ static int ewald32_sr_integral(double r, double k, int n, double eta, } int ewald32_sigma_short_shiftedpoints( - complex double *target, // must be c->nelem long + complex double *target, // must be c->nelem_sc long double *err, const qpms_ewald32_constants_t *c, // N.B. not too useful here const double eta, const double k, @@ -279,18 +279,18 @@ int ewald32_sigma_short_shiftedpoints( const point2d particle_shift // used only in the very end to multiply it by the phase ) { - const qpms_y_t nelem = c->nelem; + const qpms_y_t nelem_sc = c->nelem_sc; const qpms_l_t lMax = c->lMax; gsl_integration_workspace *workspace = gsl_integration_workspace_alloc(INTEGRATION_WORKSPACE_LIMIT); // Manual init of the ewald summation targets - complex double *target_c = calloc(nelem, sizeof(complex double)); - memset(target, 0, nelem * sizeof(complex double)); + complex double *target_c = calloc(nelem_sc, sizeof(complex double)); + memset(target, 0, nelem_sc * sizeof(complex double)); double *err_c = NULL; if (err) { - err_c = calloc(nelem, sizeof(double)); - memset(err, 0, nelem * sizeof(double)); + err_c = calloc(nelem_sc, sizeof(double)); + memset(err, 0, nelem_sc * sizeof(double)); } @@ -304,7 +304,7 @@ int ewald32_sigma_short_shiftedpoints( double Rpq_shifted_arg = atan2(Rpq_shifted.x, Rpq_shifted.y); // POINT-DEPENDENT complex double e_beta_Rpq = cexp(I*cart2_dot(beta, Rpq_shifted)); // POINT-DEPENDENT - for(qpms_l_t n = 1; n <= lMax; ++n) { + for(qpms_l_t n = 0; n <= lMax; ++n) { double complex prefacn = - I * pow(2./k, n+1) * M_2_SQRTPI / 2; // TODO put outside the R-loop and multiply in the end double R_pq_pown = pow(r_pq_shifted, n); // TODO the integral here @@ -317,7 +317,7 @@ int ewald32_sigma_short_shiftedpoints( continue; // nothing needed, already done by memset complex double e_imf = cexp(I*m*Rpq_shifted_arg); double leg = c->legendre0[gsl_sf_legendre_array_index(n, m)]; - qpms_y_t y = qpms_mn2y(m,n); + qpms_y_t y = qpms_mn2y_sc(m,n); if(err) kahanadd(err + y, err_c + y, cabs(leg * (prefacn / I) * R_pq_pown * interr)); // TODO include also other errors @@ -339,7 +339,7 @@ int ewald32_sigma_short_shiftedpoints( int ewald32_sigma_long_points_and_shift ( - complex double *target_sigmalr_y, // must be c->nelem long + complex double *target_sigmalr_y, // must be c->nelem_sc long const qpms_ewald32_constants_t *c, double eta, double k, double unitcell_area, size_t npoints, const point2d *Kpoints, @@ -347,21 +347,21 @@ int ewald32_sigma_long_points_and_shift ( point2d particle_shift ); int ewald32_sigma_long_shiftedpoints_rordered( - complex double *target_sigmalr_y, // must be c->nelem long + complex double *target_sigmalr_y, // must be c->nelem_sc long const qpms_ewald32_constants_t *c, double eta, double k, double unitcell_area, const points2d_rordered_t *Kpoints_plus_beta_rordered, point2d particle_shift ); int ewald32_sigma_short_points_and_shift( - complex double *target_sigmasr_y, // must be c->nelem long + complex double *target_sigmasr_y, // must be c->nelem_sc long const qpms_ewald32_constants_t *c, // N.B. not too useful here double eta, double k, size_t npoints, const point2d *Rpoints, point2d particle_shift ); int ewald32_sigma_short_points_rordered( - complex double *target_sigmasr_y, // must be c->nelem long + complex double *target_sigmasr_y, // must be c->nelem_sc long const qpms_ewald32_constants_t *c, // N.B. not too useful here double eta, double k, const points2d_rordered_t *Rpoints_plus_particle_shift_rordered, diff --git a/qpms/ewald.h b/qpms/ewald.h index 2fb42af..d0ae271 100644 --- a/qpms/ewald.h +++ b/qpms/ewald.h @@ -27,7 +27,7 @@ /* Object holding the constant factors from [1, (4.5)] */ typedef struct { qpms_l_t lMax; - qpms_y_t nelem; + qpms_y_t nelem_sc; qpms_l_t *s1_jMaxes; complex double **s1_constfacs; // indices [y][j] where j is same as in [1, (4.5)] // TODO probably normalisation and equatorial legendre polynomials should be included, too @@ -88,8 +88,8 @@ int ewald32_sigma0(complex double *result, double *err, // are not included. int ewald32_sigma_long_shiftedpoints_e ( - complex double *target_sigmalr_y, // must be c->nelem long - double *target_sigmalr_y_err, // must be c->nelem long or NULL + complex double *target_sigmalr_y, // must be c->nelem_sc long + double *target_sigmalr_y_err, // must be c->nelem_sc long or NULL const qpms_ewald32_constants_t *c, double eta, double k, double unitcell_area, size_t npoints, const point2d *Kpoints_plus_beta, @@ -97,8 +97,8 @@ int ewald32_sigma_long_shiftedpoints_e ( point2d particle_shift ); int ewald32_sigma_long_points_and_shift (//NI - complex double *target_sigmalr_y, // must be c->nelem long - double *target_sigmalr_y_err, // must be c->nelem long or NULL + complex double *target_sigmalr_y, // must be c->nelem_sc long + double *target_sigmalr_y_err, // must be c->nelem_sc long or NULL const qpms_ewald32_constants_t *c, double eta, double k, double unitcell_area, size_t npoints, const point2d *Kpoints, @@ -106,8 +106,8 @@ int ewald32_sigma_long_points_and_shift (//NI point2d particle_shift ); int ewald32_sigma_long_shiftedpoints_rordered(//NI - complex double *target_sigmalr_y, // must be c->nelem long - double *target_sigmalr_y_err, // must be c->nelem long or NULL + complex double *target_sigmalr_y, // must be c->nelem_sc long + double *target_sigmalr_y_err, // must be c->nelem_sc long or NULL const qpms_ewald32_constants_t *c, double eta, double k, double unitcell_area, const points2d_rordered_t *Kpoints_plus_beta_rordered, @@ -115,8 +115,8 @@ int ewald32_sigma_long_shiftedpoints_rordered(//NI ); int ewald32_sigma_short_shiftedpoints( - complex double *target_sigmasr_y, // must be c->nelem long - double *target_sigmasr_y_err, // must be c->nelem long or NULL + complex double *target_sigmasr_y, // must be c->nelem_sc long + double *target_sigmasr_y_err, // must be c->nelem_sc long or NULL const qpms_ewald32_constants_t *c, // N.B. not too useful here double eta, double k, size_t npoints, const point2d *Rpoints_plus_particle_shift, @@ -124,16 +124,16 @@ int ewald32_sigma_short_shiftedpoints( point2d particle_shift // used only in the very end to multiply it by the phase ); int ewald32_sigma_short_points_and_shift(//NI - complex double *target_sigmasr_y, // must be c->nelem long - double *target_sigmasr_y_err, // must be c->nelem long or NULL + complex double *target_sigmasr_y, // must be c->nelem_sc long + double *target_sigmasr_y_err, // must be c->nelem_sc long or NULL const qpms_ewald32_constants_t *c, // N.B. not too useful here double eta, double k, size_t npoints, const point2d *Rpoints, point2d particle_shift ); int ewald32_sigma_short_points_rordered(//NI - complex double *target_sigmasr_y, // must be c->nelem long - double *target_sigmasr_y_err, // must be c->nelem long or NULL + complex double *target_sigmasr_y, // must be c->nelem_sc long + double *target_sigmasr_y_err, // must be c->nelem_sc long or NULL const qpms_ewald32_constants_t *c, // N.B. not too useful here double eta, double k, const points2d_rordered_t *Rpoints_plus_particle_shift_rordered, diff --git a/qpms/indexing.h b/qpms/indexing.h index 24324b6..82268c9 100644 --- a/qpms/indexing.h +++ b/qpms/indexing.h @@ -25,4 +25,28 @@ static inline qpms_y_t qpms_lMax2nelem(qpms_l_t lmax){ return lmax * ((qpms_y_t)lmax + 2); } +// Scalar versions: they have a place for the 0, 0 term in the beginning + +static inline qpms_y_t qpms_mn2y_sc(qpms_m_t m, qpms_l_t n) { + return n * (n + 1) + m; +} + +static inline qpms_lm_t qpms_y2n_sc(qpms_y_t y) { + //return (sqrt(5+y)-2)/2; // the cast will truncate the fractional part, which is what we want + return sqrt(y); +} + +static inline qpms_m_t qpms_yn2m_sc(qpms_y_t y, qpms_l_t n) { + return y-qpms_mn2y_sc(0,n); +} + +static inline void qpms_y2mn_sc_p(qpms_y_t y, qpms_m_t *m, qpms_l_t *n){ + *m=qpms_yn2m_sc(y,*n=qpms_y2n_sc(y)); +} + +static inline qpms_y_t qpms_lMax2nelem_sc(qpms_l_t lmax){ + return lmax * ((qpms_y_t)lmax + 2) + 1; +} + + #endif //QPMS_INDEXING_H diff --git a/tests/ewalds.c b/tests/ewalds.c new file mode 100644 index 0000000..818bdf2 --- /dev/null +++ b/tests/ewalds.c @@ -0,0 +1,21 @@ +// implementation of the [LT(4.16)] test + +#include + +typedef struct ewaldtest_hex_params { + qpms_l_t lMax; + poinnt2d beta; + double k; + double h; + double eta; +} ewaldtest_hex_params; + + +ewaldtest_hex_paraps paramslist = { + { 3, {1.1, 0.23}, 2.3, 0.97, 0.3}, +// end: + { 0, {0, 0}, 0, 0, 0} +} + + +