/* * Copyright (c) 2010-2015 Centre National de la Recherche Scientifique. * written by Nathanael Schaeffer (CNRS, ISTerre, Grenoble, France). * * nathanael.schaeffer@ujf-grenoble.fr * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/or redistribute the software under the terms of the CeCILL * license as circulated by CEA, CNRS and INRIA at the following URL * "http://www.cecill.info". * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL license and that you accept its terms. * */ /// \file time_SHT.c This program performs some spherical harmonic transforms, and displays timings and accuracy. /// \c make \c time_SHT to compile, and then run. #include #include #include #include #include #include #include "fftw3/fftw3.h" // cycle counter from FFTW #include "fftw3/cycle.h" #include shtns_cfg shtns; complex double *Slm, *Slm0, *Tlm, *Tlm0, *Qlm; // spherical harmonics l,m space complex double *ShF, *ThF, *NLF; // Fourier space : theta,m double *Sh, *Th, *NL; // real space : theta,phi (alias of ShF) int LMAX,MMAX,MRES,NLM; int NLAT = 0; int NPHI = 0; // number of SH iterations int SHT_ITER = 50; // do 50 iterations by default #ifdef __MACH__ // Mac OSX : clock_gettime is not implemented #include #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC 0 #endif #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 0 #endif int clock_gettime(int ignored, struct timespec* t) { struct timeval now; int rv = gettimeofday(&now, NULL); if (rv) return rv; t->tv_sec = now.tv_sec; t->tv_nsec = now.tv_usec * 1000; return 0; } #endif void runerr(const char * error_text) { printf("%s\n",error_text); exit(1); } void write_vect(char *fn, double *vec, int N) { FILE *fp; int i; fp = fopen(fn,"w"); for (i=0;itv_sec - (long) start->tv_sec); ns += ((long) end->tv_nsec - (long) start->tv_nsec); return ns * (1.e-6/SHT_ITER); // time in ms. } // isNaN testing that works with -ffast-math double isNaN_0=0, isNaN_1=1; inline int isNaN(double x) { return ((x == isNaN_0)&&(x == isNaN_1)); } double scal_error(complex double *Slm, complex double *Slm0, int ltr) { long int jj,i, nlm_cplx; double tmax,t,n2; nlm_cplx = (MMAX*2 == NPHI) ? LiM(shtns, MRES*MMAX,MMAX) : NLM; // compute error : tmax = 0; n2 = 0; jj=0; for (i=0;ili[i]); if ((i <= LMAX)||(i >= nlm_cplx)) { // m=0, and 2*m=nphi is real if (shtns->li[i] <= ltr) Slm[i] = creal(Slm[i]-Slm0[i]); t = fabs(creal(Slm[i])); } else { if (shtns->li[i] <= ltr) Slm[i] -= Slm0[i]; t = cabs(Slm[i]); } n2 += t*t; if (t>tmax) { tmax = t; jj = i; } } printf(" => max error = %g (l=%d,lm=%ld) rms error = %g",tmax,shtns->li[jj],jj,sqrt(n2/NLM)); if (tmax > 1e-3) { if (NLM < 15) { printf("\n orig:"); for (i=0; i= nlm_cplx)) { // m=0, and 2*m=nphi is real printf(" %g",creal(Slm0[i])); } else { printf(" %g,%g",creal(Slm0[i]),cimag(Slm0[i])); } printf("\n diff:"); for (i=0; i= nlm_cplx)) { // m=0, and 2*m=nphi is real printf(" %g",creal(Slm[i])); } else { printf(" %g,%g",creal(Slm[i]),cimag(Slm[i])); } } printf(" **** ERROR ****\n"); } else printf("\n"); return(tmax); } double vect_error(complex double *Slm, complex double *Tlm, complex double *Slm0, complex double *Tlm0, int ltr) { long int jj,i; double tmax0, tmax,t,n2; // compute error : tmax = 0; n2 = 0; jj=0; for (i=0;i= LiM(shtns, MRES*(NPHI+1)/2,(NPHI+1)/2))) { if (shtns->li[i] <= ltr) Slm[i] = creal(Slm[i]-Slm0[i]); t = fabs(creal(Slm[i])); } else { if (shtns->li[i] <= ltr) Slm[i] -= Slm0[i]; t = cabs(Slm[i]); } n2 += t*t; if (t>tmax) { tmax = t; jj = i; } } printf(" Spheroidal => max error = %g (l=%d,lm=%ld) rms error = %g",tmax,shtns->li[jj],jj,sqrt(n2/NLM)); if (tmax > 1e-3) { printf(" **** ERROR ****\n"); } else printf("\n"); // write_vect("Slm",Slm,NLM*2); tmax0 = tmax; // compute error : tmax = 0; n2 = 0; jj=0; for (i=0;i= LiM(shtns, MRES*(NPHI+1)/2,(NPHI+1)/2))) { if (shtns->li[i] <= ltr) Tlm[i] = creal(Tlm[i]- Tlm0[i]); t = fabs(creal(Tlm[i])); } else { if (shtns->li[i] <= ltr) Tlm[i] -= Tlm0[i]; t = cabs(Tlm[i]); } n2 += t*t; if (t>tmax) { tmax = t; jj = i; } } printf(" Toroidal => max error = %g (l=%d,lm=%ld) rms error = %g",tmax,shtns->li[jj],jj,sqrt(n2/NLM)); if (tmax > 1e-3) { printf(" **** ERROR ****\n"); } else printf("\n"); // write_vect("Tlm",Tlm,NLM*2); return(tmax > tmax0 ? tmax : tmax0); } void test_SH_point() { long int jj,i; double ts2, ta2; struct timespec t1, t2; for (i=0;i : defines the maximum spherical harmonic order \n"); printf(" -nphi= : defines the number of azimutal (longitude) point\n"); printf(" -nlat= : defines the number of grid points in theta (latitude)\n"); printf(" -mres= : the azimutal periodicity (1 for no symmetry; 2 for two-fold symmetry, ...)\n"); printf(" -polaropt= : set the threshold for polar optimization. 0 for no polar optimization, 1.e-6 for agressive.\n"); printf(" -iter= : set the number of back-and-forth transforms to compute timings and errors.\n"); printf(" -gauss : force gauss grid\n"); printf(" -fly : force gauss grid with on-the-fly computations only\n"); printf(" -quickinit : force gauss grid and fast initialiation time (but suboptimal fourier transforms)\n"); printf(" -vector : time and test also vector transforms (2D and 3D)\n"); printf(" -reg : force regular grid\n"); printf(" -oop : force out-of-place transform\n"); printf(" -transpose : force transpose data (ie phi varies fastest)\n"); printf(" -nlorder : define non-linear order to be resolved.\n"); printf(" -schmidt : use schmidt semi-normalization.\n"); printf(" -4pi : use 4pi normalization.\n"); #ifdef _OPENMP printf(" -nth= : use n threads.\n"); #endif } int main(int argc, char *argv[]) { complex double t1, t2; double t,tmax,n2; int nthreads = 0; int i,im,m,l; clock_t tcpu; ticks tik0, tik1; double e0,e1; double polaropt = 1.e-8; // default for polar optimization. enum shtns_type shtmode = sht_auto; // default to "auto" (fastest) mode. enum shtns_norm shtnorm = sht_orthonormal; // default to "orthonormal" SH. int layout = SHT_NATIVE_LAYOUT; int nlorder = 0; int point = 0; int vector = 0; int loadsave = 0; char name[20]; FILE* fw; srand( time(NULL) ); // initialise les nombres. shtns_verbose(2); // output some diagnostics. printf("time_SHT performs some spherical harmonic transforms, and displays timings and accuracy.\n"); if (argc < 2) { usage(); exit(1); } // first argument is lmax, and is mandatory. sscanf(argv[1],"%lf",&t); LMAX=t; MMAX=-1; MRES=1; for (i=2; inlm; shtns_set_grid_auto(shtns, shtmode | layout, polaropt, nlorder, &NLAT, &NPHI); shtns_print_cfg(shtns); /* t1 = 1.0+2.0*I; t2 = 1.0-I; printf("test : %f, %f, %f, %f\n",creal(t1),cimag(t1), creal(t2),cimag(t2)); (double) t1 = 8.0 +I; (double) t2 = 8.1; printf("test : %f, %f, %f, %f\n",creal(t1),cimag(t1), creal(t2),cimag(t2)); */ // write_vect("cost",ct,NLAT); // write_vect("sint",st,NLAT); ShF = (complex double *) fftw_malloc( 2*(NPHI/2+1) * NLAT * sizeof(double)); Sh = (double *) ShF; if (ShF == NULL) runerr("memory allocation 1 failed"); if (vector) { ThF = (complex double *) fftw_malloc( 2*(NPHI/2+1) * NLAT * sizeof(double)); Th = (double *) ThF; NLF = (complex double *) fftw_malloc( 2*(NPHI/2+1) * NLAT * sizeof(double)); NL = (double *) NLF; if ((ThF == NULL)||(NLF == NULL)) runerr("memory allocation 2 failed"); } Slm0 = (complex double *) fftw_malloc(sizeof(complex double)* NLM); Slm = (complex double *) fftw_malloc(sizeof(complex double)* NLM); Tlm = (complex double *) fftw_malloc(sizeof(complex double)* NLM); if ((Slm0 == NULL)||(Slm == NULL)||(Tlm == NULL)) runerr("memory allocation 3 failed"); if (vector) { Tlm0 = (complex double *) fftw_malloc(sizeof(complex double)* NLM); Qlm = (complex double *) fftw_malloc(sizeof(complex double)* NLM); if ((Tlm0 == NULL)||(Qlm == NULL)) runerr("memory allocation 4 failed"); } // perform fft tests. // init_fft_tests(); // do_fft_tests(); // exit(0); if (NLM < 10000) { // SH_to_spat for (i=0;i 0)&&(MRES==1)) Slm[LiM(shtns, 1,1)] = sh11_st(shtns); // write_vect("ylm0",Slm, NLM*2); // SH_to_spat_ml(shtns, 0,Slm, Sh, LMAX); // spat_to_SH_ml(shtns, 0,Sh, Slm, LMAX); SH_to_spat(shtns, Slm,Sh); write_mx("spat",Sh,NPHI,NLAT); if (vector) { SHtor_to_spat(shtns, Slm,Sh,Th); write_mx("spatt",Sh,NPHI,NLAT); write_mx("spatp",Th,NPHI,NLAT); SHtor_to_spat_l(shtns, Slm,Sh,Th,LMAX/2); write_mx("spatt_l",Sh,NPHI,NLAT); write_mx("spatp_l",Th,NPHI,NLAT); } // SHqst_to_lat(Slm,Slm,Tlm,ct[0],Sh,Th,Th,NPHI/2,LMAX,MMAX); // write_vect("spat_lat", Sh, NPHI/2); /* for (i=0;i<(NLAT/2)*NPHI;i++) { Sh[i] = 0.0; } SHeo_to_spat(Slm, Sh, 0); write_mx("spate",Sh,NPHI,NLAT/2); for (i=0;i<(NLAT/2)*NPHI;i++) { Th[i] = 0.0; } SHeo_to_spat(Slm, Th, 1); write_mx("spato",Th,NPHI,NLAT/2); for (i=0;ict[i]; } } spat_to_SH(shtns, Sh,Slm); write_vect("ylm",(double *)Slm,NLM*2); } // test case... printf("generating random test case...\n"); t = 1.0 / (RAND_MAX/2); for (i=0;i