funkalicious 0.1

fftw_wavefunc.c

Go to the documentation of this file.
00001 /*
00002 ** fftw_wavefunc.c
00003 ** 
00004 Copyright (C) 2009 Joseph Pingenot
00005 
00006 This program is free software: you can redistribute it and/or modify
00007 it under the terms of the GNU Affero General Public License as published by
00008 the Free Software Foundation, either version 3 of the License, or
00009 (at your option) any later version.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU Affero General Public License for more details.
00015 
00016 You should have received a copy of the GNU Affero General Public License
00017 along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018 
00019 ** Made by (Johnny Q. Hacker)
00020 ** Login   <solarion@nathan>
00021 ** 
00022 ** Started on  Mon Nov 16 06:34:41 2009 Johnny Q. Hacker
00023 ** Last update Sun May 12 01:17:25 2002 Speed Blue
00024 */
00025 
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <fftw3.h>
00029 #include <math.h>
00030 #include <glib-2.0/glib.h>
00031 #ifdef OPENMP
00032 #include <omp.h>
00033 #endif
00034 #include <libpostproc/fftw_wavefunc.h>
00035 
00036 #define FFTW_WAVEFUNC_GERROR_DOMAIN 32
00037 
00038 #ifdef ACMLMATH
00039   #include <acml_mv.h>
00040   #define COS fastcos
00041 #else
00042   #define COS cos
00043 #endif
00044 
00045 
00046 void init_karray(fftw_complex* karray, int *ranges, double re, double im) {
00047   int i, j, k;
00048   #ifdef OPENMP
00049   #pragma omp parallel for private(i, j, k)
00050   #endif
00051   for(k=0; k<ranges[2]; k++) {
00052     for(j=0; j<ranges[1]; j++) {
00053       for(i=0; i<ranges[0]; i++) {
00054   karray[i + ranges[0]*(j + ranges[1]*k)][0] = re;
00055   karray[i + ranges[0]*(j + ranges[1]*k)][1] = im;
00056       }
00057     }
00058   }
00059 }
00060 
00061 void init_karray_1d(fftw_complex* karray, int range, double re, double im) {
00062   int i;
00063   #ifdef OPENMP
00064   #pragma omp parallel for private(i)
00065   #endif
00066   for(i=0; i<range; i++) {
00067     karray[i][0] = re;
00068     karray[i][1] = im;
00069   }
00070 }
00071 
00072 /*NOTES:
00073 **For index ordering, examine the figures at
00074 ****http://www.fftw.org/fftw3_doc/Multi_002dDimensional-DFTs-of-Real-Data.html#Multi_002dDimensional-DFTs-of-Real-Data
00075 */
00076 struct density* get_potential_for_density(const struct density* rho, const struct density* epsilon, struct density** rhoprime_out, const struct density* dielectric_term_k, const struct density* dielectric_term_r, GError **e) {
00077   for(int i=0; i<3; i++) {
00078     if(rho->N[i] != epsilon->N[i]) {
00079       *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 100, "fftw_wavefunc.c::get_potential_for_density: charge density and dielectric constant grid sizes for dimension %d are not the same! (%d and %d, respectively)\n", i, rho->N[i], epsilon->N[i]);
00080       return NULL;
00081     }
00082   }
00083   /*If instructed to, intialize the FFTW threading*/
00084   #ifdef OPENMP
00085   int errval = fftw_init_threads();
00086   if(errval == 0) {
00087     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 100, "fftw_wavefunc.c::get_potential_for_density: Failed to initialize FFTW threading: error %d", errval);
00088     return NULL;
00089   }
00090   int N_threads = omp_get_max_threads();
00091   fftw_plan_with_nthreads(N_threads);
00092   #endif
00093   
00094   fprintf(stderr, "In get_potential_for_density: \n");
00095   /*Construct rhoprime = rho/epsilon @ each lattice site*/
00096   struct density* rhoprime = new_density_copy(rho);
00097   if(rhoprime == NULL) {
00098     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 1, "fftw_wavefunc.c::get_potential_for_density: failed to allocate storage for rhoprime.");
00099     return NULL;
00100   }
00101   fprintf(stderr, "\t allocated rhoprime\n");
00102   if(op_density_to_density(rhoprime, DIV_EQUALS, epsilon)) {
00103     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 101, "fftw_wavefunc.c::get_potential_for_density: failed to divide rho by epsilon at each point");
00104     free_density(rhoprime);
00105     return NULL;
00106   }
00107   fprintf(stderr, "\tdivided by epsilon\n");
00108   /*Add in the realspace dielectric term if it's been specified.*/
00109   if(dielectric_term_r != NULL) {
00110     op_density_to_density(rhoprime, ADD_EQUALS, dielectric_term_r);
00111   }
00112   fprintf(stderr, "\tadded dielectric term\n");
00113   /*Save a copy for output, if requested.*/
00114   if(rhoprime_out != NULL) *rhoprime_out = rhoprime;
00115 
00116   /*Centralizes the size of k-space arrays*/
00117   int k_ranges[3] = {rhoprime->N[0]/2+1, rhoprime->N[1], rhoprime->N[2]};
00118   //if((rhoprime->N[0])%2 == 1) k_ranges[0]++;
00119 
00120   fftw_complex* rhoprime_k = (fftw_complex*)malloc(k_ranges[0]*k_ranges[1]*k_ranges[2]*sizeof(fftw_complex));
00121   if(rhoprime_k == NULL) {
00122     if(rhoprime_out == NULL) free_density(rhoprime);
00123     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 1, "fftw_wavefunc.c::get_potential_for_density: failed to allocate storage for k-space rhoprime.");
00124     return NULL;
00125   }
00126   //fprintf(stderr, "\tinitializing rhoprime_k array with 0\n");
00127   //init_karray(rhoprime_k, k_ranges, 0, 0);
00128   /*Note that indices are in opposite order from how we've been using
00129     them; is to make sure fftw gets the mapping into memory right.*/
00130   fftw_plan p_f = fftw_plan_dft_r2c_3d(rhoprime->N[2], rhoprime->N[1], rhoprime->N[0], rhoprime->storage, rhoprime_k, FFTW_ESTIMATE);
00131   fprintf(stderr, "\tExecuting FFT\n");
00132   fftw_execute(p_f);
00133   /*Free the plan now that we're done with it.*/
00134   fftw_destroy_plan(p_f);
00135 
00136   /*Calculate the potential in k-space*/
00137   /*The "cosine term" is
00138    *cos(2*pi*i/(N[0]/2))+cos(2*pi*j/N[1])+cos(2*pi*k/N[2])-4
00139    */
00140   fftw_complex* phi_k = (fftw_complex*)malloc(k_ranges[0]*k_ranges[1]*k_ranges[2]*sizeof(fftw_complex));
00141   if(phi_k == NULL ){
00142     if(rhoprime_out == NULL) free_density(rhoprime);
00143     free(rhoprime_k);
00144     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 1, "fftw_wavefunc.c::get_potential_for_density: failed to allocate storage for k-space potential.");
00145     return NULL;
00146   }
00147   //fprintf(stderr, "\tinitializing phi_k with 0\n");
00148   //init_karray(phi_k, k_ranges, 0, 0);
00149   /*Algo is from Numerical Recipes, 3rd ed., p 1055*/
00150   /*NOTE THAT DELTA^2 IS NO LONGER IN HERE; DIVIDE THE WAVEFUNCTION BY
00151     A *SINGLE* GRID SIDE LENGTH BEFORE CALLING HERE!*/
00152   int k, j, i;
00153   fprintf(stderr, "\t setting phi_k\n");
00154   #ifdef OPENMP
00155   #pragma omp parallel for private(k, j, i)
00156   #endif
00157   for(k=0; k<k_ranges[2]; k++) {
00158     for(j=0; j<k_ranges[1]; j++) {
00159       for(i=0; i<k_ranges[0]; i++) {
00160   phi_k[i + k_ranges[0]*(j + k_ranges[1]*k)][0] 
00161     /*TODO: fix this to not depend on dx->[0] only*/
00162     = rhoprime_k[i + k_ranges[0]*(j + k_ranges[1]*k)][0] 
00163     / (2.0*(COS(2.0*M_PI*((double)i)/((double)(rhoprime->N[0])))
00164       + COS(2.0*M_PI*((double)j)/((double)(rhoprime->N[1])))
00165       + COS(2.0*M_PI*((double)k)/((double)(rhoprime->N[2])))
00166       - 3.0));
00167   phi_k[i + k_ranges[0]*(j + k_ranges[1]*k)][1] 
00168     /*TODO: fix this to not depend on dx->[0] only*/
00169     =rhoprime_k[i + k_ranges[0]*(j + k_ranges[1]*k)][1] 
00170     / (2.0*(COS(2.0*M_PI*((double)i)/((double)(rhoprime->N[0])))
00171       + COS(2.0*M_PI*((double)j)/((double)(rhoprime->N[1])))
00172       + COS(2.0*M_PI*((double)k)/((double)(rhoprime->N[2])))
00173       - 3.0));
00174   if(dielectric_term_k != NULL)
00175     /**\note the dielectric term is real*/
00176     /**\note the d^2/dx^2 on the left-hand side introduces *dx^2, so we end up with one dx; the two dxes are implicitly cancelled in psi.*/
00177     phi_k[i + k_ranges[0]*(j + k_ranges[1]*k)][0] += *get_density_storage_at_c_(i, j, k, dielectric_term_k);
00178 #ifdef DEBUG3
00179   fprintf(stderr, "i=%d j=%d k=%d -> %g + i%g\n", i, j, k, phi_k[i + k_ranges[0]*(j + k_ranges[1]*k)][0], phi_k[i + k_ranges[0]*(j + k_ranges[1]*k)][1]);
00180 #endif
00181       }
00182     }
00183   }
00184   /*Set the 0th-component to 0; there's an inf and a nan otherwise;
00185     rho is disconnected from phi_k at this point.*/
00186   phi_k[0][0] = phi_k[0][1] = 0.0;
00187 
00188   /*reverse plan*/
00189   /*The final potential (density structure works as well for both)
00190     will be saved in phi.*/
00191   struct density* phi = new_density(rho->N, rho->dx, 0.0);
00192   if(phi == NULL) {
00193     if(rhoprime_out == NULL) free_density(rhoprime);
00194     free(rhoprime_k);
00195     free(phi_k);
00196     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 1, "fftw_wavefunc.c::get_potential_for_density: failed to allocate storage for realspace potential.");
00197     return NULL;
00198   }
00199   fftw_plan p_r = fftw_plan_dft_c2r_3d(phi->N[2], phi->N[1], phi->N[0], phi_k, phi->storage, FFTW_ESTIMATE);
00200   fprintf(stderr, "\treverse-transforming\n");
00201   fftw_execute(p_r);
00202   /*Free the plan now that we're done with it.*/
00203   fftw_destroy_plan(p_r);
00204   /*Free our structures*/
00205   if(rhoprime == NULL) free_density(rhoprime);
00206   free(rhoprime_k);
00207   free(phi_k);
00208   if(phi->storage == NULL) {
00209     fprintf(stderr, "After reverse FFT, phi was NULL!\n");
00210   }
00211   /*After reverse-transforming, we need to scale the data; the
00212     transforms are not normalized and must be scaled by 1/#real_elements
00213     see http://www.fftw.org/fftw3_doc/Multi_002dDimensional-DFTs-of-Real-Data.html#Multi_002dDimensional-DFTs-of-Real-Data
00214   */
00215   fprintf(stderr, "\tmultiplying by size of array\n");
00216   density_mul_by_const(phi, -1.0/((phi->N[0])*(phi->N[1])*(phi->N[2])));
00217   return phi;
00218 }
00219 
00220 struct density_1d* get_potential_for_density_1d(const struct density_1d* rho, const struct density_1d* epsilon, struct density_1d** rhoprime_out, GError **e) {
00221   if(rho->N != epsilon->N) {
00222     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 100, "fftw_wavefunc.c::get_potential_for_density_1d: charge density_1d and dielectric constant grid sizes for are not the same! (%d and %d, respectively)\n", rho->N, epsilon->N);
00223     return NULL;
00224   }
00225 
00226   /*Construct rhoprime = rho/epsilon @ each lattice site*/
00227   struct density_1d* rhoprime = new_density_1d_copy(rho);
00228   if(rhoprime == NULL) {
00229     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 1, "fftw_wavefunc.c::get_potential_for_density_1d: failed to allocate storage for rhoprime");
00230     return NULL;
00231   }
00232   if(op_density_1d_to_density_1d(rhoprime, DIV_EQUALS, epsilon)) {
00233     free_density_1d(rhoprime);
00234     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 101, "fftw_wavefunc.c::get_potential_for_density_1d: failed to divide rho by epsilon at each point");
00235     return NULL;
00236   }
00237   /*Save a copy for output, if requested.*/
00238   if(rhoprime_out != NULL) *rhoprime_out = rhoprime;
00239 
00240   /*Centralizes the size of k-space arrays*/
00241   int k_range = rhoprime->N/2 + 1;
00242   if((rhoprime->N)%2 == 1) k_range++;
00243 
00244   fftw_complex* rhoprime_k = (fftw_complex*)malloc(k_range*sizeof(fftw_complex));
00245   if(rhoprime_k == NULL) {
00246     if(rhoprime_out == NULL) free_density_1d(rhoprime);
00247     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 1, "fftw_wavefunc.c::get_potential_for_density_1d: failed to allocate storage for k-space rhoprime");
00248     return NULL;
00249   }
00250   init_karray_1d(rhoprime_k, k_range, 0, 0);
00251   /*Note that indices are in opposite order from how we've been using
00252     them; is to make sure fftw gets the mapping into memory right.*/
00253   fprintf(stderr, "rhoprime->N=%u krange=%d\n", rhoprime->N, k_range);
00254   fftw_plan p_f = fftw_plan_dft_r2c_1d(rhoprime->N, rhoprime->storage, rhoprime_k, FFTW_ESTIMATE);
00255   fftw_execute(p_f);
00256 
00257   /*Calculate the potential in k-space*/
00258   /*The "cosine term" is
00259    *cos(2*pi*i/(N[0]/2))+cos(2*pi*j/N[1])+cos(2*pi*k/N[2])-4
00260    */
00261   fftw_complex* phi_k = (fftw_complex*)malloc(k_range*sizeof(fftw_complex));
00262   if(phi_k == NULL ){
00263     if(rhoprime_out == NULL) free_density_1d(rhoprime);
00264     free(rhoprime_k);
00265     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 1, "fftw_wavefunc.c::get_potential_for_density_1d: failed to allocate storage for k-space potential");
00266     return NULL;
00267   }
00268   init_karray_1d(phi_k, k_range, 0, 0);
00269   /*Algo is from Numerical Recipes, 3rd ed., p 1055*/
00270   /*NOTE THAT DELTA^2 IS NO LONGER IN HERE; DIVIDE THE WAVEFUNCTION BY
00271     A *SINGLE* GRID SIDE LENGTH BEFORE CALLING HERE!*/
00272   for(int i=0; i<k_range; i++) {
00273     phi_k[i][0] 
00274       /*TODO: fix this to not depend on dx->[0] only*/
00275       = rhoprime_k[i][0] 
00276       / (2.0*(COS(2.0*M_PI*((double)i)/((double)(rhoprime->N)))
00277         - 1.0))*rhoprime->dx*rhoprime->dx;
00278     phi_k[i][1] 
00279       /*TODO: fix this to not depend on dx->[0] only*/
00280       = rhoprime_k[i][1] 
00281       / (2.0*(COS(2.0*M_PI*((double)i)/((double)(rhoprime->N)))
00282         - 1.0)) * rhoprime->dx*rhoprime->dx;
00283 #ifdef DEBUG3
00284     fprintf(stderr, "i=%d -> %g + i%g\n", i, phi_k[i][0], phi_k[i][1]);
00285 #endif
00286   }
00287   /*Set the 0th-component to 0; there's an inf and a nan otherwise;
00288     rho is disconnected from phi_k at this point.*/
00289   //phi_k[0][0] = phi_k[0][1] = 0.0;
00290 
00291   /*reverse plan*/
00292   /*The final potential (density_1d structure works as well for both)
00293     will be saved in phi.*/
00294   struct density_1d* phi = new_density_1d(rho->N, rho->dx, 0.0);
00295   if(phi == NULL) {
00296     if(rhoprime_out == NULL) free_density_1d(rhoprime);
00297     free(rhoprime_k);
00298     free(phi_k);
00299     *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 1, "fftw_wavefunc.c::get_potential_for_density_1d: failed to allocate storage for realspace potential");
00300     return NULL;
00301   }
00302   fftw_plan p_r = fftw_plan_dft_c2r_1d(phi->N, phi_k, phi->storage, FFTW_ESTIMATE);
00303   fftw_execute(p_r);
00304   /*Free our structures*/
00305   if(rhoprime == NULL) free_density_1d(rhoprime);
00306   free(rhoprime_k);
00307   free(phi_k);
00308   if(phi->storage == NULL) {
00309     fprintf(stderr, "After reverse FFT, phi was NULL!\n");
00310   }
00311   /*After reverse-transforming, we need to scale the data; the
00312     transforms are not normalized and must be scaled by 1/#real_elements
00313     see http://www.fftw.org/fftw3_doc/Multi_002dDimensional-DFTs-of-Real-Data.html#Multi_002dDimensional-DFTs-of-Real-Data
00314   */
00315   density_1d_mul_by_const(phi, -1.0/(phi->N));
00316   return phi;
00317 }
00318 
00319 /**sets the del_phi term
00320  *\param del_phi_term density struct to store the del_phi term; must be epsilon*N[i]*2-1 (i.e. doubled-grid size)
00321  *\param epsilon dielectric distribution; must be same dimensions as phi
00322  *\param phi electrostatic potential from the previous iteration
00323  *\return nothing
00324  */
00325 void set_del_phi_term(struct density *del_phi_term, const struct density *epsilon, const struct density* phi) {
00326   /*First, set everything but the final x, y, and z faces*/
00327   long x, y, z, ex, ox, ey, oy, ez, oz;
00328   double phi_a, phi_b, phi_c, phi_d, phi_e, phi_f, phi_g, phi_h, epsilon_a, epsilon_b, epsilon_c, epsilon_d, epsilon_e, epsilon_f, epsilon_g, epsilon_h, AB, CD, DA, BC, FE, HG, EH, GF, BF, EA, DH, GC;
00329   #ifdef OPENMP
00330 #pragma omp parallel for private(y, x, ex, ox, ey, oy, ez, oz, phi_a, phi_b, phi_c, phi_d, phi_e, phi_f, phi_g, phi_h, epsilon_a, epsilon_b, epsilon_c, epsilon_d, epsilon_e, epsilon_f, epsilon_g, epsilon_h, AB, CD, DA, BC, FE, HG, EH, GF, BF, EA, DH, GC)
00331   #endif
00332   for(z=0; z<(epsilon->N[2]-1); ++z) {
00333     ez=2*z;
00334     oz=ez+1;
00335     /**even-z loop*/
00336     for(y=0; y<(epsilon->N[1]-1); ++y){
00337       ey=2*y;
00338       oy=ey+1;
00339       /**even-y loop*/
00340       for(x=0; x<(epsilon->N[0]-1); ++x){
00341   /*Get phi and epsilon for the surrounding sites
00342 
00343     top level:      y+1   B    C
00344 
00345                             y   A    D   z
00346                                 x   x+1
00347 
00348 
00349 
00350     bottom level:   y+1   F    G
00351   
00352                             y   E    H   z+1
00353                 x   x+1
00354   */         
00355   phi_a=phi->storage[get_density_storage_index_(x, y, z, phi->N[0], phi->N[1])];
00356   phi_b=phi->storage[get_density_storage_index_(x, y+1, z, phi->N[0], phi->N[1])];
00357   phi_c=phi->storage[get_density_storage_index_(x+1, y+1, z, phi->N[0], phi->N[1])];
00358   phi_d=phi->storage[get_density_storage_index_(x+1, y, z, phi->N[0], phi->N[1])];
00359   phi_e=phi->storage[get_density_storage_index_(x, y, z+1, phi->N[0], phi->N[1])];
00360   phi_f=phi->storage[get_density_storage_index_(x, y+1, z+1, phi->N[0], phi->N[1])];
00361   phi_g=phi->storage[get_density_storage_index_(x+1, y+1, z+1, phi->N[0], phi->N[1])];
00362   phi_h=phi->storage[get_density_storage_index_(x+1, y, z+1, phi->N[0], phi->N[1])];
00363   epsilon_a=epsilon->storage[get_density_storage_index_(x, y, z, epsilon->N[0], epsilon->N[1])];
00364   epsilon_b=epsilon->storage[get_density_storage_index_(x, y+1, z, epsilon->N[0], epsilon->N[1])];
00365   epsilon_c=epsilon->storage[get_density_storage_index_(x+1, y+1, z, epsilon->N[0], epsilon->N[1])];
00366   epsilon_d=epsilon->storage[get_density_storage_index_(x+1, y, z, epsilon->N[0], epsilon->N[1])];
00367   epsilon_e=epsilon->storage[get_density_storage_index_(x, y, z+1, epsilon->N[0], epsilon->N[1])];
00368   epsilon_f=epsilon->storage[get_density_storage_index_(x, y+1, z+1, epsilon->N[0], epsilon->N[1])];
00369   epsilon_g=epsilon->storage[get_density_storage_index_(x+1, y+1, z+1, epsilon->N[0], epsilon->N[1])];
00370   epsilon_h=epsilon->storage[get_density_storage_index_(x+1, y, z+1, epsilon->N[0], epsilon->N[1])];
00371   /**The possible terms to average*/
00372   /*Top ones: clockwise*/
00373   AB = log(epsilon_b/epsilon_a)*(phi_b - phi_a)/epsilon->dx[1];
00374   CD = log(epsilon_d/epsilon_c)*(phi_d - phi_c)/epsilon->dx[1];
00375   DA = log(epsilon_a/epsilon_d)*(phi_a - phi_d)/epsilon->dx[0];
00376   BC = log(epsilon_c/epsilon_b)*(phi_c - phi_b)/epsilon->dx[0];
00377   /*Bottom ones: counter clockwise*/
00378   FE = log(epsilon_e/epsilon_f)*(phi_e - phi_f)/epsilon->dx[1];
00379   HG = log(epsilon_g/epsilon_h)*(phi_g - phi_h)/epsilon->dx[1];
00380   EH = log(epsilon_h/epsilon_e)*(phi_h - phi_e)/epsilon->dx[0];
00381   GF = log(epsilon_f/epsilon_g)*(phi_f - phi_g)/epsilon->dx[0];
00382   /*The z directions*/
00383   BF = log(epsilon_f/epsilon_b)*(phi_f - phi_b)/epsilon->dx[2];
00384   EA = log(epsilon_a/epsilon_e)*(phi_a - phi_e)/epsilon->dx[2];
00385   DH = log(epsilon_h/epsilon_d)*(phi_h - phi_d)/epsilon->dx[2];
00386   GC = log(epsilon_c/epsilon_g)*(phi_c - phi_g)/epsilon->dx[2];
00387   fprintf(stderr, "del_phi_term: %ld %ld %ld: AB=%g CD=%g DA=%g BC=%g FE=%g HG=%g EH=%g GF=%g BF=%g EA=%g DH=%g GC=%g\n", x, y, z, AB, CD, DA, BC, FE, HG, EH, GF, BF, EA, DH, GC);
00388   ex=2*x;
00389   ox=ex+1;
00390   /*We're setting the points from A*/
00391   /*use oz oy ox: central point*/
00392   del_phi_term->storage[get_density_storage_index_(ox, oy, oz, del_phi_term->N[0], del_phi_term->N[1])]
00393     = (AB+CD+DA+BC+FE+HG+EH+GF+BF+EA+DH+GC)/12.0;
00394   /*use oz oy ex: y-z facial*/
00395   del_phi_term->storage[get_density_storage_index_(ex, oy, oz, del_phi_term->N[0], del_phi_term->N[1])]
00396     = (AB + BF + FE + EA)/4.0;
00397   /*use oz ey ox: x-z facial*/
00398   del_phi_term->storage[get_density_storage_index_(ox, ey, oz, del_phi_term->N[0], del_phi_term->N[1])]
00399     = (DA + EA + EH + DH)/4.0;
00400   /*use oz ey ex: z axial */
00401   del_phi_term->storage[get_density_storage_index_(ex, ey, oz, del_phi_term->N[0], del_phi_term->N[1])]
00402     = EA;
00403   /*use ez oy ox: x-y facial*/
00404   del_phi_term->storage[get_density_storage_index_(ox, oy, ez, del_phi_term->N[0], del_phi_term->N[1])]
00405     = (AB + BC + CD + DA)/4.0;
00406   /*use ez oy ex: y axial*/
00407   del_phi_term->storage[get_density_storage_index_(ex, oy, ez, del_phi_term->N[0], del_phi_term->N[1])]
00408     = AB;
00409   /*use ez ey ox: x axial*/
00410   del_phi_term->storage[get_density_storage_index_(ex, ey, oz, del_phi_term->N[0], del_phi_term->N[1])]
00411       = DA;
00412   /*use ez ey ex: ignored*/
00413       }
00414     }
00415   }
00416 }
00417 
00418 /**Sets the effective potential for the simple method.
00419  *\param del_phi density to be asigned the del_phi term.
00420  *\param epsilon dielectric constant times epsilon_0
00421  *\param phi phi from the previous iteration
00422  *\param periodic true if this is to be periodic boundary conditions.
00423  */
00424 static void set_del_phi_term_simple(struct density* del_phi, const struct density* epsilon, const struct density* phi, int periodic) {
00425   /*Set the interior points with symmetric differencing*/
00426   int x, y, z;
00427   /**\note the dx terms cancel out (if all dx[0]==dx[1]==dx[2]) when multiplied by the dx^2 from the del^2 phi term, as is the case with rho!
00428   double inverse_4_delta2_x = 1.0/(4.0*del_phi->dx[0]*del_phi->dx[0]);
00429   double inverse_4_delta2_y = 1.0/(4.0*del_phi->dx[1]*del_phi->dx[1]);
00430   double inverse_4_delta2_z = 1.0/(4.0*del_phi->dx[2]*del_phi->dx[2]);
00431   */
00432   double inverse_4_delta2_x = 1.0/4.0;
00433   double inverse_4_delta2_y = 1.0/4.0;
00434   double inverse_4_delta2_z = 1.0/4.0;
00435   #ifdef OPENMP
00436   #pragma omp parallel for private(x, y, z)
00437   #endif
00438   for(z=1; z<del_phi->N[2]-1; z++) {
00439     for(y=1; y<del_phi->N[1]-1; y++) {
00440       for(x=1; x<del_phi->N[0]-1; x++) {
00441   *get_density_storage_at_(x, y, z, del_phi) = inverse_4_delta2_x*log((*get_density_storage_at_c_(x+1, y, z, epsilon))/(*get_density_storage_at_c_(x-1, y, z, epsilon)))*(*get_density_storage_at_c_(x+1, y, z, phi) - *get_density_storage_at_c_(x-1, y, z, phi));
00442   //fprintf(stderr, "%d %d %d: %g", x, y, z, *get_density_storage_at_c_(x, y, z, del_phi));
00443   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_y*log((*get_density_storage_at_c_(x, y+1, z, epsilon))/(*get_density_storage_at_c_(x, y-1, z, epsilon)))*(*get_density_storage_at_c_(x, y+1, z, phi) - *get_density_storage_at_c_(x, y-1, z, phi));
00444   //fprintf(stderr, " %g", *get_density_storage_at_c_(x, y, z, del_phi));
00445   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_z*log((*get_density_storage_at_c_(x, y, z+1, epsilon))/(*get_density_storage_at_c_(x, y, z-1, epsilon)))*(*get_density_storage_at_c_(x, y, z+1, phi) - *get_density_storage_at_c_(x, y, z-1, phi));
00446   //fprintf(stderr, " %g\n", *get_density_storage_at_c_(x, y, z, del_phi));
00447       }
00448     }
00449   }
00450   /*Set the z faces*/
00451   z=0;
00452   #ifdef OPENMP
00453   #pragma omp parallel for private(x, y)
00454   #endif
00455   for(y=1; y<del_phi->N[1]-1; y++) {
00456     for(x=1; x<del_phi->N[0]-1; x++) {
00457       *get_density_storage_at_(x, y, z, del_phi) = inverse_4_delta2_x*log((*get_density_storage_at_c_(x+1, y, z, epsilon))/(*get_density_storage_at_c_(x-1, y, z, epsilon)))*(*get_density_storage_at_c_(x+1, y, z, phi) - *get_density_storage_at_c_(x-1, y, z, phi));
00458       *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_y*log((*get_density_storage_at_c_(x, y+1, z, epsilon))/(*get_density_storage_at_c_(x, y-1, z, epsilon)))*(*get_density_storage_at_c_(x, y+1, z, phi) - *get_density_storage_at_c_(x, y-1, z, phi));
00459       if(periodic) {
00460   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_z*log((*get_density_storage_at_c_(x, y, z+1, epsilon))/(*get_density_storage_at_c_(x, y, del_phi->N[2]-1, epsilon)))*(*get_density_storage_at_c_(x, y, z+1, phi) - *get_density_storage_at_c_(x, y, del_phi->N[2]-1, phi));
00461       }else{
00462   *get_density_storage_at_(x, y, z, del_phi) += 4.0*inverse_4_delta2_z*log((*get_density_storage_at_c_(x, y, z+1, epsilon))/(*get_density_storage_at_c_(x, y, z, epsilon)))*(*get_density_storage_at_c_(x, y, z+1, phi) - *get_density_storage_at_c_(x, y, z, phi));
00463       }
00464     }
00465   }
00466   z=del_phi->N[2]-1;
00467   #ifdef OPENMP
00468   #pragma omp parallel for private(x, y)
00469   #endif
00470   for(y=1; y<del_phi->N[1]-1; y++) {
00471     for(x=1; x<del_phi->N[0]-1; x++) {
00472       *get_density_storage_at_(x, y, z, del_phi) = inverse_4_delta2_x*log((*get_density_storage_at_c_(x+1, y, z, epsilon))/(*get_density_storage_at_c_(x-1, y, z, epsilon)))*(*get_density_storage_at_c_(x+1, y, z, phi) - *get_density_storage_at_c_(x-1, y, z, phi));
00473       *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_y*log((*get_density_storage_at_c_(x, y+1, z, epsilon))/(*get_density_storage_at_c_(x, y-1, z, epsilon)))*(*get_density_storage_at_c_(x, y+1, z, phi) - *get_density_storage_at_c_(x, y-1, z, phi));
00474       if(periodic) {
00475   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_z*log((*get_density_storage_at_c_(x, y, 0, epsilon))/(*get_density_storage_at_c_(x, y, z-1, epsilon)))*(*get_density_storage_at_c_(x, y, 0, phi) - *get_density_storage_at_c_(x, y, z-1, phi));
00476       }else{
00477   *get_density_storage_at_(x, y, z, del_phi) += 4.0*inverse_4_delta2_z*log((*get_density_storage_at_c_(x, y, z, epsilon))/(*get_density_storage_at_c_(x, y, z-1, epsilon)))*(*get_density_storage_at_c_(x, y, z, phi) - *get_density_storage_at_c_(x, y, z-1, phi));
00478       }
00479     }
00480   }
00481   /*Set the y faces*/
00482   y=0;
00483   #ifdef OPENMP
00484   #pragma omp parallel for private(x, z)
00485   #endif
00486   for(z=1; z<del_phi->N[2]-1; z++) {
00487     for(x=1; x<del_phi->N[0]-1; x++) {
00488       *get_density_storage_at_(x, y, z, del_phi) = inverse_4_delta2_x*log((*get_density_storage_at_c_(x+1, y, z, epsilon))/(*get_density_storage_at_c_(x-1, y, z, epsilon)))*(*get_density_storage_at_c_(x+1, y, z, phi) - *get_density_storage_at_c_(x-1, y, z, phi));
00489       *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_z*log((*get_density_storage_at_c_(x, y, z+1, epsilon))/(*get_density_storage_at_c_(x, y, z-1, epsilon)))*(*get_density_storage_at_c_(x, y, z+1, phi) - *get_density_storage_at_c_(x, y, z-1, phi));
00490       if(periodic) {
00491   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_y*log((*get_density_storage_at_c_(x, y+1, z, epsilon))/(*get_density_storage_at_c_(x, del_phi->N[1]-1, z, epsilon)))*(*get_density_storage_at_c_(x, y+1, z, phi) - *get_density_storage_at_c_(x, del_phi->N[1]-1, z, phi));
00492       }else{
00493   *get_density_storage_at_(x, y, z, del_phi) += 4.0*inverse_4_delta2_y*log((*get_density_storage_at_c_(x, y+1, z, epsilon))/(*get_density_storage_at_c_(x, y, z, epsilon)))*(*get_density_storage_at_c_(x, y+1, z, phi) - *get_density_storage_at_c_(x, y, z, phi));
00494       }
00495     }
00496   }
00497   y=del_phi->N[1]-1;
00498   #ifdef OPENMP
00499   #pragma omp parallel for private(x, z)
00500   #endif
00501   for(z=1; z<del_phi->N[2]-1; z++) {
00502     for(x=1; x<del_phi->N[0]-1; x++) {
00503       *get_density_storage_at_(x, y, z, del_phi) = inverse_4_delta2_x*log((*get_density_storage_at_c_(x+1, y, z, epsilon))/(*get_density_storage_at_c_(x-1, y, z, epsilon)))*(*get_density_storage_at_c_(x+1, y, z, phi) - *get_density_storage_at_c_(x-1, y, z, phi));
00504       *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_z*log((*get_density_storage_at_c_(x, y, z+1, epsilon))/(*get_density_storage_at_c_(x, y, z-1, epsilon)))*(*get_density_storage_at_c_(x, y, z+1, phi) - *get_density_storage_at_c_(x, y, z-1, phi));
00505       if(periodic) {
00506   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_y*log((*get_density_storage_at_c_(x, 0, z, epsilon))/(*get_density_storage_at_c_(x, y-1, z, epsilon)))*(*get_density_storage_at_c_(x, 0, z, phi) - *get_density_storage_at_c_(x, y-1, z, phi));
00507       }else{
00508   *get_density_storage_at_(x, y, z, del_phi) += 4.0*inverse_4_delta2_y*log((*get_density_storage_at_c_(x, y, z, epsilon))/(*get_density_storage_at_c_(x, y-1, z, epsilon)))*(*get_density_storage_at_c_(x, y, z, phi) - *get_density_storage_at_c_(x, y-1, z, phi));
00509       }
00510     }
00511   }
00512   /*Finally, the x faces*/
00513   x=0;
00514   #ifdef OPENMP
00515   #pragma omp parallel for private(y, z)
00516   #endif
00517   for(z=1; z<del_phi->N[2]-1; z++) {
00518     for(y=1; y<del_phi->N[1]-1; y++) {
00519       *get_density_storage_at_(x, y, z, del_phi) = inverse_4_delta2_y*log((*get_density_storage_at_c_(x, y+1, z, epsilon))/(*get_density_storage_at_c_(x, y-1, z, epsilon)))*(*get_density_storage_at_c_(x, y+1, z, phi) - *get_density_storage_at_c_(x, y-1, z, phi));
00520       *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_z*log((*get_density_storage_at_c_(x, y, z+1, epsilon))/(*get_density_storage_at_c_(x, y, z-1, epsilon)))*(*get_density_storage_at_c_(x, y, z+1, phi) - *get_density_storage_at_c_(x, y, z-1, phi));
00521       if(periodic) {
00522   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_x*log((*get_density_storage_at_c_(x+1, y, z, epsilon))/(*get_density_storage_at_c_(del_phi->N[0]-1, y, z, epsilon)))*(*get_density_storage_at_c_(x+1, y, z, phi) - *get_density_storage_at_c_(del_phi->N[0]-1, y, z, phi));
00523       }else{
00524   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_x*log((*get_density_storage_at_c_(x+1, y, z, epsilon))/(*get_density_storage_at_c_(x, y, z, epsilon)))*(*get_density_storage_at_c_(x+1, y, z, phi) - *get_density_storage_at_c_(x, y, z, phi));
00525       }
00526     }
00527   }
00528   x=del_phi->N[0]-1;
00529   #ifdef OPENMP
00530   #pragma omp parallel for private(y, z)
00531   #endif
00532   for(z=1; z<del_phi->N[2]-1; z++) {
00533     for(y=1; y<del_phi->N[1]-1; y++) {
00534       *get_density_storage_at_(x, y, z, del_phi) = inverse_4_delta2_y*log((*get_density_storage_at_c_(x, y+1, z, epsilon))/(*get_density_storage_at_c_(x, y-1, z, epsilon)))*(*get_density_storage_at_c_(x, y+1, z, phi) - *get_density_storage_at_c_(x, y-1, z, phi));
00535       *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_z*log((*get_density_storage_at_c_(x, y, z+1, epsilon))/(*get_density_storage_at_c_(x, y, z-1, epsilon)))*(*get_density_storage_at_c_(x, y, z+1, phi) - *get_density_storage_at_c_(x, y, z-1, phi));
00536       if(periodic) {
00537   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_x*log((*get_density_storage_at_c_(0, y, z, epsilon))/(*get_density_storage_at_c_(x-1, y, z, epsilon)))*(*get_density_storage_at_c_(0, y, z, phi) - *get_density_storage_at_c_(x-1, y, z, phi));
00538       }else{
00539   *get_density_storage_at_(x, y, z, del_phi) += inverse_4_delta2_x*log((*get_density_storage_at_c_(x, y, z, epsilon))/(*get_density_storage_at_c_(x-1, y, z, epsilon)))*(*get_density_storage_at_c_(x, y, z, phi) - *get_density_storage_at_c_(x-1, y, z, phi));
00540       }
00541     }
00542   }
00543 }
00544 
00545 
00546 struct density* get_potential_for_density_inhomog_simple(const struct density* rho, const struct density* epsilon, double close_enough, int global, int save_iterations, GError **e) {
00547   fprintf(stderr, "get_potential_for_density_inhomog_simple: starting iteration.\n");
00548   /*Get our initial phi*/
00549   GError *err = NULL;
00550   struct density* previous_phi = get_potential_for_density(rho, epsilon, NULL, NULL, NULL, &err);
00551   if((previous_phi == NULL) || (err != NULL)) {
00552     if(err != NULL) {
00553       g_propagate_prefixed_error(e, err, "fftw_wavefunc.c::get_potential_for_density_inhomog_simple: error getting initial potential: ");
00554     }else{
00555       *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 102, "fftw_wavefunc.c::get_potential_for_density_inhomog_simple: error getting initial potential: no further data because error was NULL; this is definitely a bug in the code! ");
00556     }
00557     if(previous_phi != NULL) free_density(previous_phi);
00558     return NULL;
00559   } 
00560   /*Dump the output*/
00561   int level=0;
00562   GString *iter_dir = g_string_new("del_phi_iter=0");
00563   GFile* base_dir=g_file_new_for_path(iter_dir->str);
00564   g_string_free(iter_dir, TRUE);
00565   char* filename;
00566   if(save_iterations) {
00567     write_density_sweep(Z, previous_phi, &filename, &err, base_dir, FALSE);
00568     g_free(filename);
00569   }
00570   err = NULL;
00571   g_object_unref(base_dir);
00572   struct density* phi = NULL;
00573   struct density* del_phi = new_density(epsilon->N, epsilon->dx, 0);
00574   double diff;
00575   do {
00576     ++level;
00577     set_del_phi_term_simple(del_phi, epsilon, previous_phi, 1);
00578     phi = get_potential_for_density(rho, epsilon, NULL, NULL, del_phi, &err);
00579     if((phi == NULL) || (err != NULL)) {
00580       if(err != NULL) {
00581   g_propagate_prefixed_error(e, err, "fftw_wavefunc.c::get_potential_for_density_inhomog_simple: error getting potential for iteration %d: ", level);
00582       }else{
00583   *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 102, "fftw_wavefunc.c::get_potential_for_density_inhomog_simple: error getting initial potential for iteration %d: no further data because error was NULL; this is definitely a bug in the code! ", level);
00584       }
00585       if(phi != NULL) free_density(phi);
00586       free_density(del_phi);
00587       free_density(previous_phi);
00588       return NULL;
00589     } 
00590     iter_dir = g_string_new("del_phi_simple_iter=");
00591     g_string_append_printf(iter_dir, "%d/phi", level);
00592     base_dir=g_file_new_for_path(iter_dir->str);
00593     g_string_free(iter_dir, TRUE);
00594     err = NULL;
00595     if(save_iterations) {
00596       write_density_sweep(Z, phi, &filename, &err, base_dir, FALSE);
00597       g_free(filename);
00598     }
00599     err = NULL;
00600     g_object_unref(base_dir);
00601     iter_dir = g_string_new("del_phi_simple_iter=");
00602     g_string_append_printf(iter_dir, "%d/del_phi", level);
00603     base_dir=g_file_new_for_path(iter_dir->str);
00604     g_string_free(iter_dir, TRUE);
00605     err = NULL;
00606     if(save_iterations) {
00607       write_density_sweep(Z, del_phi, &filename, &err, base_dir, FALSE);
00608       g_free(filename);
00609     }
00610     err = NULL;
00611     GFile* dumpfile = g_file_get_child(base_dir, "del_phi.dump");
00612     if(save_iterations) write_density_slice(Z, NULL, del_phi, &filename, &err, dumpfile, ' ', "nm", "V");
00613     err = NULL;
00614     g_object_unref(base_dir);
00615     fprintf(stderr, "@%d:\n", level);
00616     if(global) {
00617       diff = density_get_max_abs_delta_pct(previous_phi, phi, 1, 0);
00618     }else{
00619       diff = density_get_max_abs_delta_pct(previous_phi, phi, 0, 0);
00620     }
00621     fprintf(stderr, "\tdiff=%g\n", diff);
00622     free_density(previous_phi);
00623     previous_phi=phi;
00624   } while(diff >= close_enough);
00625   free_density(del_phi);
00626   /**\note if we converged, then phi is contained in previous_phi from the end of the previous loop!!*/
00627   return previous_phi;
00628 }
00629 
00630 struct density* get_potential_for_density_inhomog_multigrid(const struct density* rho, const struct density* epsilon, double close_enough, GError **e) {
00631   /*Get the higher-res grid versions; note that the density is LAPACK-based so the grid spacing is implicitly included in the value of the density (f*dx*dy*dz).*/
00632   /*Get our initial phi*/
00633   GError *err = NULL;
00634   struct density* previous_phi = get_potential_for_density(rho, epsilon, NULL, NULL, NULL, &err);
00635   if((previous_phi == NULL) || (err != NULL)) {
00636     if(err != NULL) {
00637       g_propagate_prefixed_error(e, err, "fftw_wavefunc.c::get_potential_for_density_inhomog_multigrid: error getting initial potential: ");
00638     }else{
00639       *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 102, "fftw_wavefunc.c::get_potential_for_density_inhomog_multigrid: error getting initial potential: no further data because error was NULL; this is definitely a bug in the code! ");
00640     }
00641     if(previous_phi != NULL) free_density(previous_phi);
00642     return NULL;
00643   } 
00644   int level=0;
00645   /*Dump the output*/
00646   GString *iter_dir = g_string_new("del_phi_multigrid_iter=");
00647   g_string_append_printf(iter_dir, "%d", level);
00648   GFile* base_dir=g_file_new_for_path(iter_dir->str);
00649   g_string_free(iter_dir, TRUE);
00650   char* filename;
00651   write_density_sweep(Z, previous_phi, &filename, &err, base_dir, FALSE);
00652   err = NULL;
00653   g_free(filename);
00654   g_object_unref(base_dir);
00655   struct density* hires_rho = NULL;
00656   struct density* hires_epsilon = NULL;
00657   struct density* del_phi_term = NULL;
00658   struct density* phi = NULL;
00659   double final_max_pct_diff;
00660   do {
00661     ++level;
00662     if(phi != NULL) {
00663       /*To save space, start by removing the old del_phi term*/
00664       free_density(del_phi_term);
00665       /*Also, update previous_phi now*/
00666       free_density(previous_phi);
00667       previous_phi = phi;
00668       /*And also to save space, only do one density at a time*/
00669       struct density* hires_rho_ = get_double_resolution_density(rho, 3);
00670       free_density(hires_rho);
00671       hires_rho = hires_rho_;
00672       struct density* hires_epsilon_ = get_double_resolution_density(epsilon, 0);
00673       free_density(hires_epsilon);
00674       hires_epsilon = hires_epsilon_;
00675     }else{
00676       hires_rho = get_double_resolution_density(hires_rho, 3);
00677       hires_epsilon = get_double_resolution_density(hires_epsilon, 0);
00678     }
00679     /*Allocate and then set the del_phi term*/
00680     del_phi_term = new_density(hires_rho->N, hires_rho->dx, 0);
00681     set_del_phi_term(del_phi_term, epsilon, previous_phi);
00682     /*Get the updated phi*/
00683     struct density* phi = get_potential_for_density(hires_rho, hires_epsilon, NULL, del_phi_term, NULL, &err);
00684     if((phi == NULL) || (err != NULL)) {
00685       if(err != NULL) {
00686   g_propagate_prefixed_error(e, err, "fftw_wavefunc.c::get_potential_for_density_inhomog_multigrid: error getting potential for iteration %d: ", level);
00687       }else{
00688   *e = g_error_new(FFTW_WAVEFUNC_GERROR_DOMAIN, 102, "fftw_wavefunc.c::get_potential_for_density_inhomog_multigrid: error getting initial potential for iteration %d: no further data because error was NULL; this is definitely a bug in the code! ", level);
00689       }
00690       if(phi != NULL) free_density(phi);
00691       free_density(del_phi_term);
00692       free_density(hires_rho);
00693       free_density(hires_epsilon);
00694       free_density(previous_phi);
00695       return NULL;
00696     } 
00697     iter_dir = g_string_new("del_phi_multigrid_iter=");
00698     g_string_append_printf(iter_dir, "%d/phi", level);
00699     base_dir=g_file_new_for_path(iter_dir->str);
00700     g_string_free(iter_dir, TRUE);
00701     err = NULL;
00702     write_density_sweep(Z, phi, &filename, &err, base_dir, FALSE);
00703     err = NULL;
00704     g_free(filename);
00705     g_object_unref(base_dir);
00706     iter_dir = g_string_new("del_phi_multigrid_iter=");
00707     g_string_append_printf(iter_dir, "%d/del_phi", level);
00708     base_dir=g_file_new_for_path(iter_dir->str);
00709     g_string_free(iter_dir, TRUE);
00710     err = NULL;
00711     write_density_sweep(Z, del_phi_term, &filename, &err, base_dir, FALSE);
00712     err = NULL;
00713     g_free(filename);
00714     g_object_unref(base_dir);
00715     /*parallelized finding maximum deviation from previous phi*/
00716     int N_threads = 0;
00717     #ifdef OPENMP
00718     N_threads = omp_get_max_threads();
00719     #else
00720     N_threads = 1;
00721     #endif
00722     double max_pct_diff[N_threads];
00723     for(int i=0; i<N_threads; i++) max_pct_diff[i] = nan("NaN");
00724     long x, y, z;
00725     double diff;
00726     int thread;
00727     double max_previous_phi = density_get_max(previous_phi, 1);
00728     #ifdef OPENMP
00729     #pragma omp parallel for private(y, x, diff, thread)
00730     #endif
00731     for(z=0; z<previous_phi->N[2]; z++) {
00732       thread = 0;
00733       #ifdef OPENMP
00734       thread = omp_get_thread_num();
00735       #endif
00736       for(y=0; y<previous_phi->N[1]; y++) {
00737   for(x=0; x<previous_phi->N[0]; x++) {
00738     diff = abs(((*get_density_storage_at_c_(2*x, 2*y, 2*z, phi))-(*get_density_storage_at_c_(x, y, z, previous_phi)))/max_previous_phi);
00739     //we use !<= since NaN will evaluate to false on any comparison
00740     if(!(diff <= max_pct_diff[thread])) {
00741       max_pct_diff[thread] = diff;
00742     }
00743     //fprintf(stderr, "fastmax@%d %ld %ld %ld: (%g - %g)/%g = %g (/->%g)\n", level, x, y, z, *get_density_storage_at_c_(2*x, 2*y, 2*z, phi),  *get_density_storage_at_c_(x, y, z, previous_phi), max_previous_phi, diff, (*get_density_storage_at_c_(2*x, 2*y, 2*z, phi))/(*get_density_storage_at_c_(x, y, z, previous_phi)));
00744   }
00745       }
00746     }
00747     final_max_pct_diff = max_pct_diff[0];
00748     for(int i=1; i<N_threads; i++) {
00749       if(!(max_pct_diff[i] <= final_max_pct_diff)) final_max_pct_diff = max_pct_diff[i];
00750     }
00751     fprintf(stderr, "@%d: Max difference is %g:\n", level, final_max_pct_diff);
00752   } while(final_max_pct_diff >= close_enough);
00753   /*free the hires grids*/
00754   free_density(hires_rho);
00755   free_density(hires_epsilon);
00756   free_density(del_phi_term);
00757   /*Halve the grid resolution of phi until it's the original res*/
00758   err = NULL;
00759   for(int i=0; i<level; i++) {
00760     struct density* phi_ = get_half_resolution_density(phi, &err, 0);
00761     if(err != NULL) {
00762       free_density(phi);
00763       g_propagate_prefixed_error(e, err, "fftw_wavefunc::get_potential_for_density_inhomog@level %d: error occurred halving the resolution of a phi we got from a recursive call:\n\t", level);
00764       return NULL;
00765     }
00766     free_density(phi);
00767     phi = phi_;
00768   }
00769   return phi;
00770 }
00771 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines