2018-09-11 13:10:25 +03:00
// c99 -ggdb -Wall -I ../ ewalds.c ../qpms/ewald.c ../qpms/ewaldsf.c ../qpms/lattices2d.c -lgsl -lm -lblas
2018-09-05 22:07:41 +03:00
2018-09-05 15:39:02 +03:00
// implementation of the [LT(4.16)] test
2018-09-05 21:50:02 +03:00
# include <math.h>
# define M_SQRTPI 1.7724538509055160272981674833411452
2018-09-05 15:39:02 +03:00
# include <qpms/ewald.h>
2018-09-05 21:50:02 +03:00
# include <qpms/tiny_inlines.h>
# include <qpms/indexing.h>
# include <stdlib.h>
# include <stdio.h>
# include <float.h>
# include <gsl/gsl_sf_legendre.h>
typedef struct ewaldtest_triang_params {
2018-09-05 15:39:02 +03:00
qpms_l_t lMax ;
2018-09-05 21:50:02 +03:00
point2d beta ;
2018-09-05 15:39:02 +03:00
double k ;
2018-09-05 21:50:02 +03:00
double a ;
2018-09-05 15:39:02 +03:00
double eta ;
2018-09-05 21:50:02 +03:00
double maxR ;
double maxK ;
double csphase ;
TriangularLatticeOrientation orientation ;
} ewaldtest_triang_params ;
typedef struct ewaldtest_triang_results {
ewaldtest_triang_params p ;
complex double * sigmas_short ,
* sigmas_long ,
sigma0 ,
* sigmas_total ;
double * err_sigmas_short ,
* err_sigmas_long ,
err_sigma0 ,
* err_sigmas_total ;
complex double * regsigmas_416 ;
} ewaldtest_triang_results ;
2018-09-05 15:39:02 +03:00
2018-09-05 21:50:02 +03:00
ewaldtest_triang_params paramslist [ ] = {
2018-09-12 20:12:49 +03:00
// lMax, beta, k, a, eta, maxR, maxK, csphase, orientation
#if 0
2018-09-05 22:07:41 +03:00
{ 3 , { 1.1 , 0.23 } , 2.3 , 0.97 , 0.5 , 20 , 20 , 1. , TRIANGULAR_VERTICAL } ,
2018-09-10 08:10:13 +03:00
{ 3 , { 1.1 , 0.23 } , 2.3 , 0.97 , 0.5 , 30 , 30 , - 1. , TRIANGULAR_VERTICAL } ,
2018-09-05 22:45:28 +03:00
{ 3 , { 1.1 , 0.23 } , 2.3 , 0.97 , 0.9 , 30 , 30 , 1. , TRIANGULAR_VERTICAL } ,
{ 3 , { 1.1 , 0.23 } , 2.3 , 0.97 , 1.3 , 30 , 30 , 1. , TRIANGULAR_VERTICAL } ,
2018-09-06 16:17:28 +03:00
{ 6 , { 1.1 , 0.23 } , 2.3 , 0.97 , 1.9 , 30 , 30 , 1. , TRIANGULAR_VERTICAL } ,
2018-09-11 13:10:25 +03:00
{ 6 , { 1.1 , 0.23 } , 2.3 , 0.97 , 2.5 , 30 , 30 , 1. , TRIANGULAR_VERTICAL } ,
{ 6 , { 1.1 , 0.23 } , 2.3 , 0.97 , 3.2 , 30 , 30 , 1. , TRIANGULAR_VERTICAL } ,
{ 6 , { 1.1 , 0.23 } , 2.3 , 0.97 , 3.8 , 30 , 30 , 1. , TRIANGULAR_VERTICAL } ,
{ 6 , { 1.1 , 0.23 } , 2.3 , 0.97 , 4.5 , 30 , 30 , 1. , TRIANGULAR_VERTICAL } ,
{ 6 , { 1.1 , 0.23 } , 2.3 , 0.97 , 4.5 , 40 , 40 , 1. , TRIANGULAR_VERTICAL } ,
{ 6 , { 1.1 , 0.23 } , 2.3 , 0.97 , 2.3 , 100 , 100 , 1. , TRIANGULAR_VERTICAL } ,
{ 6 , { 1.1 , 0.23 } , 2.3 , 0.97 , 2.9 , 100 , 100 , 1. , TRIANGULAR_VERTICAL } ,
2018-09-12 20:12:49 +03:00
# endif
{ 2 , { 1.1 , 0.23 } , 2.3 , 0.97 , 0.5 , 20 , 20 , 1. , TRIANGULAR_VERTICAL } ,
{ 2 , { - 1.1 , - 0.23 } , 2.3 , 0.97 , 0.5 , 20 , 20 , 1. , TRIANGULAR_VERTICAL } ,
{ 2 , { 0 , 1.1 } , 2.3 , 0.97 , 0.5 , 20 , 20 , 1. , TRIANGULAR_VERTICAL } ,
{ 2 , { 0 , - 1.1 } , 2.3 , 0.97 , 0.5 , 20 , 20 , 1. , TRIANGULAR_VERTICAL } ,
{ 2 , { - 1.1 , 0 } , 2.3 , 0.97 , 0.5 , 20 , 20 , 1. , TRIANGULAR_VERTICAL } ,
{ 2 , { 1.1 , 0 } , 2.3 , 0.97 , 0.5 , 20 , 20 , 1. , TRIANGULAR_VERTICAL } ,
{ 2 , { 1.1 , 0 } , 2.3 , 0.97 , 0.5 , 10 , 10 , 1. , TRIANGULAR_VERTICAL } ,
{ 2 , { 1.1 , 0 } , 2.3 , 0.97 , 0.5 , 5 , 5 , 1. , TRIANGULAR_VERTICAL } ,
{ 2 , { 1.1 , 0 } , 2.3 , 0.97 , 0.5 , 2 , 2 , 1. , TRIANGULAR_VERTICAL } ,
2018-09-12 21:08:16 +03:00
{ 2 , { 0.3 , 0 } , 2.3 , 0.97 , 0.5 , 2 , 2 , 1. , TRIANGULAR_VERTICAL } ,
{ 2 , { 2.7 , 0 } , 2.3 , 0.97 , 0.5 , 2 , 2 , 1. , TRIANGULAR_VERTICAL } ,
2018-09-12 20:12:49 +03:00
2018-09-05 15:39:02 +03:00
// end:
2018-09-05 22:07:41 +03:00
// { 0, {0, 0}, 0, 0, 0, 0, 0, 0, 0}
2018-09-05 21:50:02 +03:00
} ;
void ewaldtest_triang_results_free ( ewaldtest_triang_results * r ) {
free ( r - > sigmas_short ) ;
free ( r - > sigmas_long ) ;
free ( r - > sigmas_total ) ;
free ( r - > err_sigmas_long ) ;
free ( r - > err_sigmas_total ) ;
free ( r - > err_sigmas_short ) ;
free ( r - > regsigmas_416 ) ;
free ( r ) ;
2018-09-05 15:39:02 +03:00
}
2018-09-12 20:12:49 +03:00
void dump_points2d_rordered ( const points2d_rordered_t * ps , char * filename ) {
FILE * f = fopen ( filename , " w " ) ;
for ( size_t i = 0 ; i < ps - > nrs ; + + i ) {
fprintf ( f , " # r = %.16g \n " , ps - > rs [ i ] ) ;
for ( ptrdiff_t j = ps - > r_offsets [ i ] ; j < ps - > r_offsets [ i + 1 ] ; + + j )
fprintf ( f , " %.16g %.16g \n " , ps - > base [ j ] . x , ps - > base [ j ] . y ) ;
}
fclose ( f ) ;
}
2018-09-05 21:50:02 +03:00
ewaldtest_triang_results * ewaldtest_triang ( const ewaldtest_triang_params p ) ;
int main ( ) {
2018-09-07 20:46:07 +03:00
gsl_set_error_handler ( IgnoreUnderflowsGSLErrorHandler ) ;
2018-09-05 21:50:02 +03:00
for ( size_t i = 0 ; i < sizeof ( paramslist ) / sizeof ( ewaldtest_triang_params ) ; + + i ) {
ewaldtest_triang_params p = paramslist [ i ] ;
ewaldtest_triang_results * r = ewaldtest_triang ( p ) ;
// TODO print per-test header here
2018-09-05 22:07:41 +03:00
printf ( " =============================== \n " ) ;
2018-09-12 20:12:49 +03:00
printf ( " a = %g, K = %g, Kmax = %g, Rmax = %g, lMax = %d, eta = %g, k = %g, beta = (%g,%g), csphase = %g \n " ,
p . a , 4 * M_PI / sqrt ( 3 ) / p . a , p . maxK , p . maxR , p . lMax , p . eta , p . k , p . beta . x , p . beta . y , p . csphase ) ;
2018-09-06 15:00:38 +03:00
printf ( " sigma0: %.16g%+.16gj \n " , creal ( r - > sigma0 ) , cimag ( r - > sigma0 ) ) ;
2018-09-05 21:50:02 +03:00
for ( qpms_l_t n = 0 ; n < = p . lMax ; + + n ) {
for ( qpms_m_t m = - n ; m < = n ; + + m ) {
2018-09-12 21:08:16 +03:00
if ( ( m + n ) % 2 ) continue ;
2018-09-05 21:50:02 +03:00
qpms_y_t y = qpms_mn2y_sc ( m , n ) ;
qpms_y_t y_conj = qpms_mn2y_sc ( - m , n ) ;
// y n m sigma_total (err), regsigmas_416 regsigmas_415_recon
2018-09-10 08:10:13 +03:00
printf ( " %zd %d %d: T:%.16g%+.16gj(%.3g) L:%.16g%+.16gj(%.3g) S:%.16g%+.16gj(%.3g) \n | predict %.16g%+.16gj \n | actual %.16g%+.16gj \n " ,
2018-09-05 21:50:02 +03:00
y , n , m , creal ( r - > sigmas_total [ y ] ) , cimag ( r - > sigmas_total [ y ] ) ,
r - > err_sigmas_total [ y ] ,
2018-09-06 15:00:38 +03:00
creal ( r - > sigmas_long [ y ] ) , cimag ( r - > sigmas_long [ y ] ) ,
2018-09-05 22:45:28 +03:00
r - > err_sigmas_long [ y ] ,
creal ( r - > sigmas_short [ y ] ) , cimag ( r - > sigmas_short [ y ] ) ,
r - > err_sigmas_short [ y ] ,
2018-09-05 21:50:02 +03:00
creal ( r - > regsigmas_416 [ y ] ) , cimag ( r - > regsigmas_416 [ y ] ) ,
creal ( r - > sigmas_total [ y ] ) + creal ( r - > sigmas_total [ y_conj ] ) ,
cimag ( r - > sigmas_total [ y ] ) - cimag ( r - > sigmas_total [ y_conj ] )
) ;
}
}
ewaldtest_triang_results_free ( r ) ;
}
return 0 ;
}
2018-09-12 20:12:49 +03:00
int ewaldtest_counter = 0 ;
2018-09-05 21:50:02 +03:00
ewaldtest_triang_results * ewaldtest_triang ( const ewaldtest_triang_params p ) {
const double a = p . a ; //const double a = p.h * sqrt(3);
const double A = sqrt ( 3 ) * a * a / 2. ; // unit cell size
const double K_len = 4 * M_PI / a / sqrt ( 3 ) ; // reciprocal vector length
ewaldtest_triang_results * results = malloc ( sizeof ( ewaldtest_triang_results ) ) ;
results - > p = p ;
triangular_lattice_gen_t * Rlg = triangular_lattice_gen_init ( a , p . orientation , false , 0 ) ; // N.B. orig is not included (not directly usable for the honeycomb lattice)
triangular_lattice_gen_extend_to_r ( Rlg , p . maxR + a ) ;
triangular_lattice_gen_t * Klg = triangular_lattice_gen_init ( K_len , reverseTriangularLatticeOrientation ( p . orientation ) , true , 0 ) ;
triangular_lattice_gen_extend_to_r ( Klg , p . maxK + K_len ) ;
2018-09-05 15:39:02 +03:00
2018-09-10 08:10:13 +03:00
point2d * Rpoints = Rlg - > ps . base ; //point2d *Kpoints = Klg->ps.base;
2018-09-05 21:50:02 +03:00
size_t nR = Rlg - > ps . r_offsets [ Rlg - > ps . nrs ] ,
nK = Klg - > ps . r_offsets [ Klg - > ps . nrs ] ;
2018-09-05 15:39:02 +03:00
2018-09-05 21:50:02 +03:00
qpms_y_t nelem_sc = qpms_lMax2nelem_sc ( p . lMax ) ;
results - > sigmas_short = malloc ( sizeof ( complex double ) * nelem_sc ) ;
results - > sigmas_long = malloc ( sizeof ( complex double ) * nelem_sc ) ;
results - > sigmas_total = malloc ( sizeof ( complex double ) * nelem_sc ) ;
results - > err_sigmas_short = malloc ( sizeof ( double ) * nelem_sc ) ;
results - > err_sigmas_long = malloc ( sizeof ( double ) * nelem_sc ) ;
results - > err_sigmas_total = malloc ( sizeof ( double ) * nelem_sc ) ;
qpms_ewald32_constants_t * c = qpms_ewald32_constants_init ( p . lMax , p . csphase ) ;
points2d_rordered_t * Kpoints_plus_beta = points2d_rordered_shift ( & ( Klg - > ps ) , p . beta ,
8 * DBL_EPSILON , 8 * DBL_EPSILON ) ;
2018-09-12 20:12:49 +03:00
char filename [ BUFSIZ ] ;
sprintf ( filename , " betalattice_%d.out " , ewaldtest_counter ) ;
dump_points2d_rordered ( Kpoints_plus_beta , filename ) ;
2018-09-05 21:50:02 +03:00
point2d particle_shift = { 0 , 0 } ; // TODO make this a parameter
if ( 0 ! = ewald32_sigma_long_shiftedpoints ( results - > sigmas_long ,
results - > err_sigmas_long , c , p . eta , p . k , A ,
nK , Kpoints_plus_beta - > base ,
//p.beta,
particle_shift ) )
abort ( ) ;
if ( 0 ! = ewald32_sigma_short_shiftedpoints (
results - > sigmas_short , results - > err_sigmas_short , c ,
p . eta , p . k ,
nR , Rpoints , p . beta , particle_shift ) )
abort ( ) ;
if ( 0 ! = ewald32_sigma0 ( & ( results - > sigma0 ) , & ( results - > err_sigma0 ) , c , p . eta , p . k ) )
abort ( ) ;
for ( qpms_y_t y = 0 ; y < nelem_sc ; + + y ) {
results - > sigmas_total [ y ] = results - > sigmas_short [ y ] + results - > sigmas_long [ y ] ;
results - > err_sigmas_total [ y ] = results - > err_sigmas_short [ y ] + results - > err_sigmas_long [ y ] ;
}
results - > sigmas_total [ 0 ] + = results - > sigma0 ;
results - > err_sigmas_total [ 0 ] + = results - > err_sigma0 ;
// Now calculate the reference values [LT(4.16)]
results - > regsigmas_416 = calloc ( nelem_sc , sizeof ( complex double ) ) ;
results - > regsigmas_416 [ 0 ] = - 1 / M_SQRTPI ;
{
double legendres [ gsl_sf_legendre_array_n ( p . lMax ) ] ;
points2d_rordered_t sel =
points2d_rordered_annulus ( Kpoints_plus_beta , 0 , true , p . k , false ) ;
2018-09-12 21:08:16 +03:00
if ( 0 ! = sel . nrs )
{
point2d * beta_pq_lessthan_k = sel . base + sel . r_offsets [ 0 ] ;
size_t beta_pq_lessthan_k_count = sel . r_offsets [ sel . nrs ] - sel . r_offsets [ 0 ] ;
for ( size_t i = 0 ; i < beta_pq_lessthan_k_count ; + + i ) {
point2d beta_pq = beta_pq_lessthan_k [ i ] ;
double rbeta_pq = cart2norm ( beta_pq ) ;
double arg_pq = atan2 ( beta_pq . y , beta_pq . x ) ;
double denom = sqrt ( p . k * p . k - rbeta_pq * rbeta_pq ) ;
if ( gsl_sf_legendre_array_e ( GSL_SF_LEGENDRE_NONE ,
p . lMax , denom / p . k , p . csphase , legendres ) ! = 0 )
abort ( ) ;
for ( qpms_y_t y = 0 ; y < nelem_sc ; + + y ) {
qpms_l_t n ; qpms_m_t m ;
qpms_y2mn_sc_p ( y , & m , & n ) ;
if ( ( m + n ) % 2 ! = 0 )
continue ;
complex double eimf = cexp ( I * m * arg_pq ) ;
results - > regsigmas_416 [ y ] + =
4 * M_PI * ipow ( n ) / p . k / A
* eimf * legendres [ gsl_sf_legendre_array_index ( n , abs ( m ) ) ] * min1pow_m_neg ( m )
/ denom ;
}
2018-09-05 21:50:02 +03:00
}
}
}
points2d_rordered_free ( Kpoints_plus_beta ) ;
qpms_ewald32_constants_free ( c ) ;
triangular_lattice_gen_free ( Klg ) ;
triangular_lattice_gen_free ( Rlg ) ;
2018-09-12 20:12:49 +03:00
+ + ewaldtest_counter ;
2018-09-05 21:50:02 +03:00
return results ;
}