|
funkalicious 0.1
|
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