funkalicious 0.1

lp_wavefunction.c

Go to the documentation of this file.
00001 /*
00002 ** wavefunction.c
00003 ** 
00004 
00005 Copyright (C) 2009 Joseph Pingenot
00006 
00007 This program is free software: you can redistribute it and/or modify
00008 it under the terms of the GNU Affero General Public License as published by
00009 the Free Software Foundation, either version 3 of the License, or
00010 (at your option) any later version.
00011 
00012 This program is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU Affero General Public License for more details.
00016 
00017 You should have received a copy of the GNU Affero General Public License
00018 along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 
00020 ** Made by (Johnny Q. Hacker)
00021 ** Login   <solarion@nathan>
00022 ** 
00023 ** Started on  Tue Nov 17 22:28:22 2009 Johnny Q. Hacker
00024 ** Last update Sun May 12 01:17:25 2002 Speed Blue
00025 */
00026 
00027 #include <gsl/gsl_errno.h>
00028 #include <gsl/gsl_interp.h>
00029 #include <gsl/gsl_spline.h>
00030 #include <gsl/gsl_integration.h>
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033 #include <glib-2.0/glib.h>
00034 #include <gio/gio.h>
00035 #include <math.h>
00036 #include <libpostproc/lp_wavefunction.h>
00037 #include <libdotcode/binary_data_common.h>
00038 #include <libpostproc/unit_conversion.h>
00039 #include "gcc_hints.h"
00040 
00041 #ifdef OPENMP
00042 #include <omp.h>
00043 #endif
00044 
00045 #define NUM_STEPS 12
00046 #define THRESHOLD 0.5
00047 
00048 #define WAVEFUNC_GERROR_DOMAIN 4096
00049 
00050 #define MAX_PIXEL_VAL 255
00051 
00052 #define MAX_GSL_INTEGRATION_INTERVALS 4096
00053 
00054 /**
00055  *Gets the index into the storage member for a wavefunction, or for a density
00056  *\param x x index component
00057  *\param y y index component
00058  *\param z z index component
00059  *\param b band index component
00060  *\param im 1 if imaginary component is wanted; 0 else.
00061  *\param Nx Number of x sites
00062  *\param Ny Number of y sites
00063  *\param Nb Number of bands
00064  *\returns long unsigned int, which is the address in the storage
00065  *array.
00066  *\note there is no error checking, for speed purposes. E.g. if im is
00067  *3, it'll just be blindly used as a 3 and you'll be addressing the
00068  *imaginary component of the next index.
00069  *\note Nz is not needed.
00070  */
00071 hotfunc ___const ___always_inline long unsigned int get_wavefunction_storage_index(unsigned int x, unsigned int y, unsigned int z, unsigned int im, unsigned int b, unsigned int Nx, unsigned int Ny, int Nb) {
00072   return im + 2*(b + Nb*(x + Nx*(y + Ny*(z))));
00073              }
00074 
00075 hotfunc ___const ___always_inline long unsigned int get_density_storage_index(unsigned int x, unsigned int y, unsigned int z, unsigned int Nx, unsigned int Ny) {
00076   return x + Nx*(y + Ny*(z));
00077 }
00078 hotfunc ___const ___always_inline long unsigned int get_density_slice_storage_index(enum coord c, unsigned int x, unsigned int y, unsigned int z, unsigned int Nx, unsigned int Ny) {
00079   switch(c) {
00080   case X:
00081     x=0;
00082     Nx=1;
00083     break;
00084   case Y:
00085     y=0;
00086     Ny=1;
00087     break;
00088   case Z:
00089     z=0;
00090     break;
00091   }
00092   return x + Nx*(y + Ny*(z));
00093 }
00094 
00095 long unsigned int get_density_storage_index_(unsigned int x, unsigned int y, unsigned int z, unsigned int Nx, unsigned int Ny) {
00096   return get_density_storage_index(x, y, z, Nx, Ny);
00097 }
00098 
00099 hotfunc ___always_inline double* get_density_storage_at(unsigned x, unsigned y, unsigned z, struct density* d) {
00100   return &(d->storage[get_density_storage_index(x, y, z, d->N[0], d->N[1])]);
00101 }
00102 
00103 double* get_density_storage_at_(unsigned x, unsigned y, unsigned z, struct density* d) {
00104   return get_density_storage_at(x, y, z, d);
00105 }
00106 
00107 hotfunc ___always_inline const double* get_density_storage_at_c(unsigned x, unsigned y, unsigned z, const struct density* d) {
00108   return &(d->storage[get_density_storage_index(x, y, z, d->N[0], d->N[1])]);
00109 }
00110 
00111 const double* get_density_storage_at_c_(unsigned x, unsigned y, unsigned z, const struct density* d) {
00112   return get_density_storage_at_c(x, y, z, d);
00113 }
00114 
00115 
00116 
00117 void init_density(struct density* d, double value) {
00118   int i, j, k;
00119 #ifdef DEBUG2
00120   fprintf(stderr, "wavefunc::init_density: d->N={%d,%d,%d} d->dx={%g,%g,%g}\n", d->N[0], d->N[1], d->N[2], d->dx[0], d->dx[1], d->dx[2]);
00121 #endif
00122   for(k=0; k<d->N[2]; k++) {
00123     for(j=0; j<d->N[1]; j++) {
00124       for(i=0; i<d->N[0]; i++) {
00125   d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])] = value;
00126       }
00127     }
00128   }
00129 }
00130 
00131 /*This is where the complex wavefunction becomes real (and
00132   pre-normalized like LAPACK) density.*/
00133 void internal_add_to_density(struct density* d, struct wavefunction* wf) {
00134   register int i, j, k, b;
00135   double re, im;
00136   for(k=0; k<d->N[2]; k++) {
00137     for(j=0; j<d->N[1]; j++) {
00138       for(i=0; i<d->N[0]; i++) {
00139   for(b=0; b<wf->bands; b++){
00140     re = wf->storage[get_wavefunction_storage_index(i, j, k, b, 0, wf->N[0], wf->N[1], wf->bands)];
00141     im = wf->storage[get_wavefunction_storage_index(i, j, k, b, 0, wf->N[0], wf->N[1], wf->bands)];
00142     d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])] += (re*re + im*im)*wf->charge;
00143   }
00144       }
00145     }
00146   }
00147 }
00148 void add_to_density(struct density* d, struct wavefunction* wf) {
00149   internal_add_to_density(d, wf);
00150 }
00151 
00152 struct density* get_density_for_list_of_wavefunctions(GList *list, GError** err) {
00153   if(list==NULL) {
00154     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 1, "lp_wavefunction.c::get_density_for_list_of_wavefunctions: ERROR: list was empty!\n");
00155     return NULL;
00156   }
00157   struct density *d;
00158   struct wavefunction *wf = (struct wavefunction*)(list->data);
00159   if((d = (struct density*)malloc(sizeof(struct density))) == NULL) {
00160     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 2, "lp_wavefunction.c::get_density_for_list_of_wavefunctions: ERROR: failed to allocate memory for total density structure.");
00161     return NULL;
00162   }
00163   if((d->storage = (double*)malloc(sizeof(double)*(wf->N[0])*(wf->N[1])*(wf->N[2]))) == NULL) {
00164     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 2, "lp_wavefunction.c::get_density_for_list_of_wavefunctions: ERROR: failed to allocate memory for total density's storage.");
00165     free(d);
00166     return NULL;
00167   }
00168   for(int i=0; i<3; i++) d->N[i] = wf->N[i];
00169   for(int i=0; i<3; i++) d->dx[i] = wf->dx[i];
00170   init_density(d, 0);
00171   GList *l;
00172   for(l=list; l != NULL; l=l->next) {
00173     wf = (struct wavefunction*)l->data;
00174     for(int i=0; i<3; i++) {
00175       if((wf->N[i] != d->N[i]) || (wf->dx[i] != d->dx[i])) {
00176   *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 2, "lp_wavefunction.c::get_density_for_list_of_wavefunctions: ERROR: wavefunction (%s) has an inconsistent size N=(%d, %d, %d) expected (%d, %d, %d); dx=(%g, %g, %g) expected (%g %g %g)", g_file_get_uri(wf->file), wf->N[0], wf->N[1], wf->N[2], d->N[0], d->N[1], d->N[2], wf->dx[0], wf->dx[1], wf->dx[2], d->dx[0], d->dx[1], d->dx[2]);
00177   free(d->storage);
00178   free(d);
00179   return NULL;
00180       }
00181       internal_add_to_density(d, wf);
00182     }
00183   }
00184   return d;
00185 }
00186 
00187 void load_wavefunctions(GList* wf_list, GError** err) {
00188   GList *l;
00189   struct wavefunction* wf;
00190   int ie;
00191   GError *e = NULL;
00192   for(l=wf_list; l!=NULL; l=l->next) {
00193     wf = (struct wavefunction *)(l->data);
00194     e=NULL;
00195     ie = read_wavefunction_gfile(wf->file, &(wf->header), &(wf->storage), &e);
00196     if((ie != 0) || (e != NULL)) {
00197       if(e == NULL) {
00198   *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, ie, "wavefunction::load_wavefunctions: Got a non-zero return value from function_parser::read_wavefunction_gfile: %d\n", ie);
00199       }else{
00200   *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, ie, "wavefunction::load_wavefunctions: Got following GError from function_parser::read_wavefunction_gfile: %d/%s\n", e->code, e->message);
00201       }
00202       return;
00203     }
00204     wf->N[0] = wf->header.Nx;
00205     wf->N[1] = wf->header.Ny;
00206     wf->N[2] = wf->header.Nz;
00207     wf->bands = wf->header.Nc;
00208     wf->dx[0] = wf->header.dx;
00209     wf->dx[1] = wf->header.dy;
00210     wf->dx[2] = wf->header.dz;
00211   }
00212 }
00213 
00214 void put_density_into_metadensity(struct density* md, const struct density* d, const int *Nn, int x, int y, int z, gboolean invert_x, gboolean invert_y, gboolean invert_z, const unsigned* offsets){
00215   if(d == NULL) return;
00216   if(d->storage == NULL) return;
00217   int xoffset = x*(d->N[0]+offsets[0]);
00218   int yoffset = y*(d->N[1]+offsets[1]);
00219   int zoffset = z*(d->N[2]+offsets[2]);
00220   int source_x, source_y, source_z;
00221   int k, j, i;
00222   #ifdef OPENMP
00223   #pragma omp parallel for private(k, j, i, source_z, source_y, source_x)
00224   #endif
00225   for(k=0; k<d->N[2]; k++) {
00226     /*The -1 is to ensure that we start at the last *valid* location
00227      *in the source (and end at the beginning of the source)
00228      */
00229     source_z = invert_z?(d->N[2]-k-1):k;
00230     for(j=0; j<d->N[1]; j++) {
00231       source_y = invert_y?(d->N[1]-j-1):j;
00232       for(i=0; i<d->N[0]; i++) {
00233   source_x = invert_x?(d->N[0]-i-1):i;
00234   md->storage[get_density_storage_index(i+xoffset, j+yoffset, k+zoffset, md->N[0], md->N[1])]
00235     = d->storage[get_density_storage_index(source_x, source_y, source_z, d->N[0], d->N[1])];
00236       }
00237     }
00238   }
00239 }
00240 
00241 /**Gets a block of the meta_density back out.
00242  *\param md the meta denstiy
00243  *\param d an initialized density the sizeo f one block
00244  *\param buffzone the buffer zone size around the meta_density
00245  *\param Mn the number of neighbors in each direction
00246  *\param x the x-coordinate of the block
00247  *\param y the y-coordinate of the block
00248  *\param z the z-coordinate of the block
00249  *\param offsets offset between neighbors in each dimension
00250  */
00251 void get_density_from_metadensity(const struct density* md, struct density* d, const int* buffzone, const int *Nn, int x, int y, int z, const unsigned* offsets){
00252   if(d == NULL) return;
00253   if(d->storage == NULL) return;
00254   int xoffset = x*(d->N[0]+offsets[0]);
00255   int yoffset = y*(d->N[1]+offsets[1]);
00256   int zoffset = z*(d->N[2]+offsets[2]);
00257   if(buffzone != NULL) {
00258     xoffset += buffzone[0];
00259     yoffset += buffzone[1];
00260     zoffset += buffzone[2];
00261   }
00262   int k, j, i;
00263   #ifdef OPENMP
00264   #pragma omp parallel for private(k, j, i)
00265   #endif
00266   for(k=0; k<d->N[2]; k++) {
00267     for(j=0; j<d->N[1]; j++) {
00268       for(i=0; i<d->N[0]; i++) {
00269   d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])]
00270     = md->storage[get_density_storage_index(i+xoffset, j+yoffset, k+zoffset, md->N[0], md->N[1])];
00271       }
00272     }
00273   }
00274 }
00275 
00276 void density_mul_by_const(struct density* d, double c) {
00277   int i, j, k;
00278   #ifdef OPENMP
00279   #pragma omp parallel for private(i, j, k)
00280   #endif
00281   for(k=0; k<d->N[2]; k++) {
00282     for(j=0; j<d->N[1]; j++) {
00283       for(i=0; i<d->N[0]; i++) {
00284   d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])] *= c;
00285       }
00286     }
00287   }
00288 }
00289 
00290 /**
00291  *The wavefunction itself is normalized such that adding all the values
00292  *togetheer yields 1. We need the density at each point; hence must divide
00293  * by dx*dy*dz
00294  */
00295 void density_un_normalize(struct density* d) {
00296   double volume = 1.0/((d->dx[0])*(d->dx[1])*(d->dx[2]));
00297   density_mul_by_const(d, volume);
00298 }
00299 
00300 
00301 void write_density_slice(enum coord c, const int* index, const struct density* d, char** filename, GError **err, GFile* location, char sepchar, const char* coord_units, const char* density_units) {
00302   /*If we're iterating on an index, go to the next loop unless the index is right*/
00303   GError *e = NULL;
00304   GFile* f;
00305   GString *s = g_string_new("slice_");
00306   if(index != NULL) {
00307     switch(c) {
00308     case X:
00309       g_string_append_printf(s, "X=%d.pdata", *index);
00310       break;
00311     case Y:
00312       g_string_append_printf(s, "Y=%d.pdata", *index);
00313       break;
00314     case Z:
00315       g_string_append_printf(s, "Z=%d.pdata", *index);
00316       break;
00317     }
00318     if(location == NULL) {
00319       f = g_file_new_for_path(s->str);
00320     }else{
00321       f = g_file_resolve_relative_path(location, s->str);
00322     }
00323   }else{
00324     f = location;
00325   }
00326   *filename = g_file_get_uri(f);
00327   //GFileIOStream *gfos = g_file_create_readwrite(f, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &e);
00328   GFileOutputStream *fos = g_file_replace(f, NULL, FALSE, 0, NULL, &e);
00329   if(e != NULL) {
00330     *err = e;
00331     return;
00332   }
00333   //GOutputStream *os =
00334   //g_io_stream_get_output_stream((GIOStream*)gfos);
00335   GDataOutputStream *dos = g_data_output_stream_new((GOutputStream*)fos);
00336   if(index != NULL) {
00337     switch(c) {
00338     case X:
00339       g_string_printf(s, "#Y(%s)%cZ(%s)%c(%s)\n", coord_units, sepchar, coord_units, sepchar, density_units);
00340       break;
00341     case Y:
00342       g_string_printf(s, "#X(%s)%cZ(%s)%c(%s)\n", coord_units, sepchar, coord_units, sepchar, density_units);
00343       break;
00344     case Z:
00345       g_string_printf(s, "#X(%s)%cY(%s)%c(%s)\n", coord_units, sepchar, coord_units, sepchar, density_units);
00346       break;
00347     }
00348   }else{
00349     g_string_printf(s, "#X(%s)%cY(%s)%cZ(%s)%c(%s)\n", coord_units, sepchar, coord_units, sepchar, coord_units, sepchar, density_units);
00350   }
00351   e=NULL;
00352   char *str;
00353   g_data_output_stream_put_string(dos, s->str, NULL, &e);
00354   if(e != NULL) {
00355     *err = e;
00356     g_string_free(s, TRUE);
00357     e=NULL;
00358     //g_io_stream_close((GIOStream*)gfos, NULL, &e);
00359     g_output_stream_close((GOutputStream*)fos, NULL, &e);
00360     if(e != NULL) {
00361       fprintf(stderr, "wavefunction::write_density_slice: had an error (%s) while writing string (%s), but had another error (%s) while closing the file (%s)!\n", (*err)->message, s->str, e->message, str=g_file_get_uri(f));
00362       g_free(str);
00363     }
00364     return;
00365   }
00366   for(int k=0; k<d->N[2]; k++) {
00367     if((index != NULL) && (c == Z) && (k != *index)) continue;
00368     for(int j=0; j<d->N[1]; j++) {
00369       if((index != NULL) && (c == Y) && (j != *index)) continue;
00370       for(int i=0; i<d->N[0]; i++) {
00371   if((index != NULL) && (c == X) && (i != *index)) continue;
00372   e=NULL;
00373   if(index != NULL) {
00374     switch(c) {
00375     case X:
00376       g_string_printf(s, "%g%c%g%c%g\n", j*(d->dx[1]), sepchar, k*(d->dx[2]), sepchar, d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])]);
00377       break;
00378     case Y:
00379       g_string_printf(s, "%g%c%g%c%g\n", i*(d->dx[0]), sepchar, k*(d->dx[2]), sepchar, d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])]);
00380       break;
00381     case Z:
00382       g_string_printf(s, "%g%c%g%c%g\n", i*(d->dx[0]), sepchar, j*(d->dx[1]), sepchar, d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])]);
00383       break;
00384     }
00385   }else{
00386     g_string_printf(s, "%g%c%g%c%g%c%g\n", i*(d->dx[0]), sepchar, j*(d->dx[1]), sepchar, k*(d->dx[2]), sepchar, d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])]);
00387   }
00388   g_data_output_stream_put_string(dos, s->str, NULL, &e);
00389   if(e != NULL) {
00390     *err = e;
00391     g_string_free(s, TRUE);
00392     e=NULL;
00393     //g_io_stream_close(os, NULL, &e);
00394     g_output_stream_close((GOutputStream*)fos, NULL, &e);
00395     if(e != NULL) {
00396       fprintf(stderr, "wavefunction::write_density_slice: had an error (%s) while writing string (%s), but had another error (%s) while closing the file (%s)!\n", (*err)->message, s->str, e->message, str=g_file_get_uri(f));
00397       g_free(str);
00398     }
00399     return;
00400   }
00401       }
00402     }
00403   }
00404   //g_io_stream_close((GIOStream*)gfos, NULL, &e);
00405   g_output_stream_close((GOutputStream*)fos, NULL, &e);
00406   if(e != NULL) {
00407     *err = e;
00408   }
00409   g_string_free(s, TRUE);
00410 }
00411 
00412 void write_density_sweep_slice(enum coord c, const int* index, const struct density* d, char** filename, GError **err, GFile *location, double maxval, int pixel_strategy) {
00413   /*If we're iterating on an index, go to the next loop unless the index is right*/
00414   GError *e;
00415   GString *s = g_string_new("");
00416   switch(c) {
00417   case X:
00418     g_string_append_printf(s, "X=%d.pbm", *index);
00419     break;
00420   case Y:
00421     g_string_append_printf(s, "Y=%d.pbm", *index);
00422     break;
00423   case Z:
00424     g_string_append_printf(s, "Z=%d.pbm", *index);
00425     break;
00426   }
00427   GFile* f;
00428   if(location == NULL) {
00429     f = g_file_new_for_path(s->str);
00430   }else{
00431     f = g_file_resolve_relative_path(location, s->str);
00432   }
00433   *filename = g_file_get_uri(f);
00434   e = NULL;
00435   //GFileIOStream *gfos = g_file_create_readwrite(f, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &e);
00436   GFileOutputStream *fos = g_file_replace(f, NULL, FALSE, 0, NULL, &e);
00437   if(e != NULL) {
00438     *err = e;
00439     return;
00440   }
00441   //GOutputStream *os = g_io_stream_get_output_stream((GIOStream*)gfos);
00442   char *str;
00443   /*Calculate the width and height of the resulting image*/
00444   s = g_string_new("P6\n");
00445   /*Height and width of the image. Format is width, whitespace, height*/
00446   int invert_coord = Z;
00447   switch(c) {
00448   case X:
00449     /*In x sweep, width is y height is z*/
00450     g_string_append_printf(s, "%d\t%d\n", d->N[1], d->N[2]);
00451     invert_coord=Z;
00452     break;
00453   case Y:
00454     /*In y sweep, width is x height is z*/
00455     g_string_append_printf(s, "%d\t%d\n", d->N[0], d->N[2]);
00456     invert_coord=Z;
00457     break;
00458   case Z:
00459     /*In z sweep, width is x height is y*/
00460     g_string_append_printf(s, "%d\t%d\n", d->N[0], d->N[1]);
00461     invert_coord=Y;
00462     break;
00463   }
00464   /*Notes from the above:
00465   ** x is always a width (Y, Z sweeps)
00466   ** z is always a height (X, Y sweeps)
00467   ** y is a width if Z sweep, height if X
00468   ** The below loop should be right: rows are x, then y if not x
00469   */
00470   g_string_append_printf(s, "%d\n", MAX_PIXEL_VAL);
00471 #ifdef DEBUG3
00472   fprintf(stderr, "wavefunc::write_density_sweep_slice: write header %s\n", s->str);
00473 #endif
00474   e=NULL;
00475   g_output_stream_write((GOutputStream*)fos, s->str, s->len, NULL, &e);
00476   if(e != NULL) {
00477     *err = e;
00478     g_string_free(s, TRUE);
00479     e=NULL;
00480     g_io_stream_close((GIOStream*)fos, NULL, &e);
00481     if(e != NULL) {
00482       fprintf(stderr, "wavefunction::write_density_slice: had an error (%s) while writing string (%s), but had another error (%s) while closing the file (%s)!\n", (*err)->message, s->str, e->message, str=g_file_get_uri(f));
00483       g_free(str);
00484     }
00485     return;
00486   }
00487   double val;
00488   double v;
00489   double oo_maxval = 1.0/maxval;
00490   char set[3];
00491   /**\note that the indices in the dotcode go from bottom to top, while the columns in the ppm file go from top to bottom; we need to go backwards here in order for the image to correspond to what the user is expecting to see*/
00492   for(int k=0; k<(d->N[2]); k++) {
00493     if((c == Z) && (k != *index)) continue;
00494     for(int j=0; j<(d->N[1]); j++) {
00495       if((c == Y) && (j != *index)) continue;
00496       for(int i=0; i<(d->N[0]); i++) {
00497   if((c == X) && (i != *index)) continue;
00498   e=NULL;
00499   v = (d->storage[get_density_storage_index((invert_coord==X)?(d->N[0]-i-1):i, (invert_coord==Y)?(d->N[1]-j-1):j, (invert_coord==Z)?(d->N[2]-k-1):k, d->N[0], d->N[1])]);
00500   /*oo_maxval is already absolute value*/
00501   if(pixel_strategy == 1) {
00502     val = log(oo_maxval*fabs(v)+1)/log(2);
00503   }else if(pixel_strategy == 2) {
00504     val = (1.0-exp(oo_maxval*fabs(v)))/(1.0-M_E);
00505   }else{
00506     val = fabs(oo_maxval*v);
00507   }
00508   /*use the following color scheme: blue is positive, red is neg.*/
00509   if(v>0) {
00510     set[0]=set[1]=0;
00511     set[2] = (char)(MAX_PIXEL_VAL*val);
00512   }else{
00513     set[2]=set[1]=0;
00514     set[0] = (char)(MAX_PIXEL_VAL*val);
00515   }
00516 #ifdef DEBUG3
00517   fprintf(stderr, "wavefunc::write_density_sweep_slice: i=%d j=%d k=%d val=%g->%d \n", i, j, k, val, set[0]);
00518 #endif
00519   g_output_stream_write((GOutputStream*)fos, set, 3, NULL, &e);
00520   if(e != NULL) {
00521     *err = e;
00522     g_string_free(s, TRUE);
00523     e=NULL;
00524     //g_io_stream_close((GIOStream*)gfos, NULL, &e);
00525     g_output_stream_close((GOutputStream*)fos, NULL, &e);
00526     if(e != NULL) {
00527       fprintf(stderr, "wavefunction::write_density_slice: had an error (%s) while writing (%d,%d,%d->%g->%d), but had another error (%s) while closing the file (%s)!\n", (*err)->message, i, j, k, val, set[0], e->message, str=g_file_get_uri(f));
00528       g_free(str);
00529     }
00530     return;
00531   }
00532       }
00533     }
00534   }
00535   //g_io_stream_close((GIOStream*)gfos, NULL, &e);
00536   g_output_stream_close((GOutputStream*)fos, NULL, &e);
00537   if(e != NULL) {
00538     *err = e;
00539   }
00540   g_string_free(s, TRUE);
00541 }
00542 
00543 /*Gets the *magnitude* of the largest value.*/
00544 double get_max_density_value(const struct density*d) {
00545   /*Find the max value.*/
00546   double maxval = -1;
00547   double v;
00548   for(int k=0; k<d->N[2]; k++) {
00549     for(int j=0; j<d->N[1]; j++) {
00550       for(int i=0; i<d->N[0]; i++) {
00551   v = d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])];
00552   if(fabs(v) > maxval) {
00553     maxval = fabs(v);
00554   }
00555       }
00556     }
00557   }
00558   return maxval;
00559 }
00560 
00561 void write_density_sweep(enum coord c, const struct density* d, char** filename, GError **err, GFile* location, int pixel_strategy) {
00562   /*If we're iterating on an index, go to the next loop unless the index is right*/
00563   GError *e;
00564   GString *s = g_string_new("sweep_");
00565   switch(c) {
00566   case X:
00567     g_string_append_printf(s, "x");
00568     break;
00569   case Y:
00570     g_string_append_printf(s, "y");
00571     break;
00572   case Z:
00573     g_string_append_printf(s, "z");
00574     break;
00575   }
00576   GFile* f;
00577   if(location == NULL) {
00578     f = g_file_new_for_path(s->str);
00579   }else{
00580     f = g_file_resolve_relative_path(location, s->str);
00581   }
00582   e=NULL;
00583   g_file_make_directory_with_parents(f, NULL, &e);
00584   if((e != NULL) && (e->code != G_IO_ERROR_EXISTS)) {
00585     char* fn = g_file_get_uri(f);
00586     fprintf(stderr, "E1\n");
00587     if(e == NULL) {
00588       *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 32, "wavefunction::write_density_sweep: unable to make directory for writing density sweep (%s)", fn);
00589     }else{
00590       g_propagate_prefixed_error(err, e, "wavefunction::write_density_sweep: unable to make directory for writing density sweep (%s): %s", fn, e->message);
00591     }
00592     free(fn);
00593     g_string_free(s, TRUE);
00594     return;
00595   }
00596   double maxval = get_max_density_value(d);
00597   /*Iterate over the sweep var*/
00598   char *fn;
00599   for(int i=0; i<(d->N[c]); i++) {
00600     e = NULL;
00601     write_density_sweep_slice(c, &i, d, &fn, &e, f, maxval, pixel_strategy);
00602     if(e != NULL) {
00603       *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 32, "Error writing slice into %s: %s", fn, e->message);
00604       g_error_free(e);
00605       free(fn);
00606       return;
00607     }
00608     free(fn);
00609   }
00610   *filename = s->str;
00611   /*We don't want to return false, since we're not getting the filename.*/
00612   g_string_free(s, FALSE);
00613 }
00614 
00615 
00616 struct density* new_density(const int* N, const double* dx, double initial_value) {
00617   struct density* d = (struct density*)malloc(sizeof(struct density));
00618   if(d == NULL) {
00619     return NULL;
00620   }
00621   for(int i=0; i<3; i++) {
00622     d->N[i] = N[i];
00623     d->dx[i] = dx[i];
00624   }
00625   d->storage = (double*)malloc(N[0]*N[1]*N[2]*sizeof(double));
00626   if(d->storage == NULL) {
00627     free(d);
00628     return NULL;
00629   }
00630   int k, j, i;
00631   #ifdef OPENMP
00632   #pragma omp parallel for private(k, j, i)
00633   #endif
00634   for(k=0; k<d->N[2]; k++) {
00635     for(j=0; j<d->N[1]; j++) {
00636       for(i=0; i<d->N[0]; i++) {
00637   d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])] 
00638     = initial_value;
00639       }
00640     }
00641   }
00642   return d;
00643 }
00644 struct density* new_density_copy(const struct density* orig) {
00645   struct density* d = (struct density*)malloc(sizeof(struct density));
00646   if(d == NULL) {
00647     return NULL;
00648   }
00649   for(int i=0; i<3; i++) {
00650     d->N[i] = orig->N[i];
00651     d->dx[i] = orig->dx[i];
00652   }
00653   d->storage = (double*)malloc((d->N[0])*(d->N[1])*(d->N[2])*sizeof(double));
00654   if(d->storage == NULL) {
00655     free(d);
00656     return NULL;
00657   }
00658   int k, j, i;
00659   #ifdef OPENMP
00660   #pragma omp parallel for private(k, j, i)
00661   #endif
00662   for(k=0; k<d->N[2]; k++) {
00663     for(j=0; j<d->N[1]; j++) {
00664       for(i=0; i<d->N[0]; i++) {
00665   d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])] 
00666     = orig->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])];
00667       }
00668     }
00669   }
00670   return d;
00671 }
00672 
00673 int op_density_to_density(struct density* to, enum density_op op, const struct density* from) {
00674   for(int i=0; i<3; i++) {
00675     if((to->N[i] != from->N[i]) || (to->dx[i] != from->dx[i])) {
00676       return 1;
00677     }
00678   }
00679   /*The switch can probably be lifted out of the loops by the compiler.*/
00680   int k, j, i;
00681   #ifdef OPENMP
00682   #pragma omp parallel for private(k, j, i)
00683   #endif
00684   for(k=0; k<to->N[2]; k++) {
00685     for(j=0; j<to->N[1]; j++) {
00686       for(i=0; i<to->N[0]; i++) {
00687   switch(op) {
00688   case ASSIGN:
00689     *get_density_storage_at(i, j, k, to) = *get_density_storage_at_c(i, j, k, from);
00690   case ADD_EQUALS:
00691     to->storage[get_density_storage_index(i, j, k, to->N[0], to->N[1])] 
00692       += from->storage[get_density_storage_index(i, j, k, from->N[0], from->N[1])]
00693       ;
00694     break;
00695   case MINUS_EQUALS:
00696     to->storage[get_density_storage_index(i, j, k, to->N[0], to->N[1])] 
00697       -= from->storage[get_density_storage_index(i, j, k, from->N[0], from->N[1])]
00698       ;
00699     break;
00700   case MUL_EQUALS:
00701     to->storage[get_density_storage_index(i, j, k, to->N[0], to->N[1])] 
00702       *= from->storage[get_density_storage_index(i, j, k, from->N[0], from->N[1])]
00703       ;
00704     break;
00705   case DIV_EQUALS:
00706     to->storage[get_density_storage_index(i, j, k, to->N[0], to->N[1])] 
00707       /= from->storage[get_density_storage_index(i, j, k, from->N[0], from->N[1])]
00708       ;
00709     break;
00710   }
00711       }
00712     }
00713   }
00714   return 0;
00715 }
00716 
00717 void free_density(struct density* d) {
00718   if(d == NULL) return;
00719   if(d->storage != NULL) free(d->storage);
00720   free(d);
00721 }
00722 
00723 struct dotcode_grid* dotcode_grid_from_density(const struct density *d, GError **err) {
00724   struct dotcode_grid* g = (struct dotcode_grid*)malloc(sizeof(struct dotcode_grid));
00725   if(unlikely(g == NULL)) {
00726     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 100, "wavefunction::dotcode_grid_from_density: Error allocating memory for new dotcode_grid.");
00727     return NULL;
00728   }
00729   g->data = (struct dotcode_tensor*)malloc(sizeof(struct dotcode_tensor));
00730   if(unlikely(g->data == NULL)) {
00731     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 101, "wavefunction::dotcode_grid_from_density: Error allocating memory for tensor for the new grid.");
00732     free(g);
00733     return NULL;
00734   }
00735   g->data->Nd = 3;
00736   g->data->metadata = g_strdup("2.0");
00737   g->data->indices = (int*)malloc(2*(g->data->Nd)*sizeof(int));
00738   if(unlikely(g->data->indices == NULL)) {
00739     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 102, "wavefunction::dotcode_grid_from_density: Error allocating memory for indicies in the tensor for the new grid.");
00740     free(g->data);
00741     free(g);
00742     return NULL;
00743   }
00744   for(int i=0; i<3; i++) {
00745     (g->gridsites)[i] = (struct dotcode_array*)malloc(sizeof(struct dotcode_array));
00746     if(unlikely((g->gridsites)[i] == NULL)) {
00747       *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 103, "wavefunction::dotcode_grid_from_density: Error allocating memory for the %d-th array for the new grid.", i);
00748       GError *e = NULL;
00749       for(int j=i-1; j>=0; j++) {
00750   dotcode_free_type(DOTCODE_ARRAY, (g->gridsites)[j], 1, &e, TRUE);
00751   if(e != NULL) g_error_free(e);
00752       }
00753       free(g->data->indices);
00754       free(g->data);
00755       free(g);
00756       return NULL;
00757     }
00758     (g->gridsites)[i]->t = DOTCODE_FLOAT8;
00759     (g->gridsites)[i]->imin = g->data->indices[2*i] = 0;
00760     (g->gridsites)[i]->imax = g->data->indices[2*i + 1] = d->N[i]-1;
00761     (g->gridsites)[i]->storage = (double*)malloc((d->N[i])*sizeof(double));
00762     if(unlikely((g->gridsites)[i]->storage == NULL)) {
00763       *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 104, "wavefunction::dotcode_grid_from_density: Error allocating memory for storage in the %d-th array for the new grid.", i);
00764       GError *e = NULL;
00765       for(int j=i-1; j>=0; j++) {
00766   dotcode_free_type(DOTCODE_ARRAY, (g->gridsites)[j], 1, &e, TRUE);
00767   if(e != NULL) g_error_free(e);
00768       }
00769       free(g->data->indices);
00770       free((g->gridsites)[i]);
00771       free(g->data);
00772       free(g);
00773       return NULL;
00774     }
00775     for(int j=0; j<d->N[i]; j++) ((double*)((g->gridsites)[i]->storage))[j] = j*(d->dx[i]);
00776     /*Put 0 in the center*/
00777     //g->Ng[i] = d->N[i]-1;
00778     g->Ng[i] = 0;
00779   }
00780   g->data->t = DOTCODE_FLOAT8;
00781   g->data->metadata = g_strdup("2.0");
00782   g->data->data = (double*)malloc((d->N[0])*(d->N[1])*(d->N[2])*sizeof(double));
00783   if(unlikely(g->data->data == NULL)) {
00784     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 105, "wavefunction::dotcode_grid_from_density: Error allocating memory for storage in the tensor for the new grid.");
00785     GError *e = NULL;
00786     for(int j=2; j>=0; j++) {
00787       dotcode_free_type(DOTCODE_ARRAY, (g->gridsites)[j], 1, &e, TRUE);
00788       if(e != NULL) g_error_free(e);
00789     }
00790     free(g->data->indices);
00791     free(g->data);
00792     free(g);
00793     return NULL;
00794   }
00795   /*i is z
00796    *j is y
00797    *k is x
00798    */
00799   int i, j, k;
00800   #ifdef OPENMP
00801   #pragma omp parallel for private(i, j, k)
00802   #endif
00803   for(i=0; i<d->N[2]; i++) {
00804     for(j=0; j<d->N[1]; j++) {
00805       for(k=0; k<d->N[0]; k++) {
00806   ((double*)(g->data->data))[k + (d->N[0])*(j + (d->N[1])*i)] = ev_to_hartree((d->storage)[get_density_storage_index(k, j, i, d->N[0], d->N[1])]);
00807       }
00808     }
00809   }
00810   
00811   return g;
00812 }
00813 
00814 struct density* expand_density_box_with_value(const struct density* od, const int* I, double value, GError **err) {
00815   struct density* d = (struct density*)malloc(sizeof(struct density));
00816   if(d == NULL) {
00817     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 106, "libpostproc::wavefunction::expand_density_box_with_material: failed to allocate the new density structure.");
00818     return NULL;
00819   }
00820   for(int i=0; i<3; i++) {
00821     d->dx[i] = od->dx[i];
00822     d->N[i] = od->N[i]+2*I[i];
00823     fprintf(stderr, "dx[%d](%g)->%g d->N[%d](%d)->%d (%d+2*%d)\n", i, od->dx[i], d->dx[i], i, od->N[i], d->N[i], od->N[i], I[i]);
00824   }
00825   d->storage = (double*)malloc(sizeof(double)*(d->N[0])*(d->N[1])*(d->N[2]));
00826   if(d->storage == NULL) {
00827     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 106, "libpostproc::wavefunction::expand_density_box_with_material: failed to allocate value storage for the new density (size is %dx%dx%d=%ld", d->N[0], d->N[1], d->N[2], ((long int)d->N[0])*((long int)d->N[1])*((long int)d->N[2]));
00828     free(d);
00829     return NULL;
00830   }
00831   /*Explicitly breaking out the regions saves 1 *branch* per loop*/
00832   /*First, the top of the box*/
00833   int i, j, k;
00834   #ifdef OPENMP
00835   #pragma omp parallel for private(i, j, k)
00836   #endif
00837   for(k=0; k<I[2]; k++) {
00838     for(j=0; j<d->N[1]; j++) {
00839       for(i=0; i<d->N[0]; i++) {
00840   (d->storage)[get_density_storage_index(i, j, k, d->N[0], d->N[1])] = value;
00841       }
00842     }
00843   }
00844   /*Now the z-interior of the box*/
00845   int yoffset, zoffset;
00846   #ifdef OPENMP
00847   #pragma omp parallel for private(i, j, k, yoffset, zoffset)
00848   #endif
00849   for(k=0; k<od->N[2]; k++) {
00850     zoffset = I[2];
00851 
00852     /*The lower-y outer region*/
00853     for(j=0; j<I[1]; j++) {
00854       for(i=0; i<d->N[0]; i++) {
00855   (d->storage)[get_density_storage_index(i, j, k+zoffset, d->N[0], d->N[1])] = value;
00856       }
00857     }
00858 
00859     /*Interior of the box in y (and z)*/
00860     for(j=0; j<od->N[1]; j++) {
00861       yoffset = I[1];
00862 
00863       for(i=0; i<I[0]; i++) {
00864   (d->storage)[get_density_storage_index(i, j+yoffset, k+zoffset, d->N[0], d->N[1])] = value;
00865       }
00866 
00867       /*We're in the middle region. Copy over from the source.*/
00868       for(i=0; i<od->N[0]; i++) {
00869   (d->storage)[get_density_storage_index(i+I[0], j+yoffset, k+zoffset, d->N[0], d->N[1])] = (od->storage)[get_density_storage_index(i, j, k, od->N[0], od->N[1])];
00870       }
00871 
00872       /*we're out the back region.*/
00873       for(i=0; i<I[0]; i++) {
00874   (d->storage)[get_density_storage_index(i+(od->N[0])+I[0], j+yoffset, k+zoffset, d->N[0], d->N[1])] = value;
00875       }
00876 
00877     }
00878 
00879     /*The upper-y outer region*/
00880     for(j=0; j<I[1]; j++) {
00881       yoffset = I[1] + od->N[1];
00882       for(i=0; i<d->N[0]; i++) {
00883   (d->storage)[get_density_storage_index(i, j+yoffset, k+zoffset, d->N[0], d->N[1])] = value;
00884       }
00885     }
00886 
00887   }
00888   /*Finally, the bottom of the box*/
00889   #ifdef OPENMP
00890   #pragma omp parallel for private(i, j, k, zoffset)
00891   #endif
00892   for(k=0; k<I[2]; k++) {
00893     zoffset = I[2] + od->N[2];
00894     for(j=0; j<d->N[2]; j++) {
00895       for(i=0; i<d->N[0]; i++) {
00896   (d->storage)[get_density_storage_index(i, j, k+zoffset, d->N[0], d->N[1])] = value;
00897       }
00898     }
00899   }
00900   return d;
00901 }
00902 
00903 struct density* expand_density_box(const struct density* od, const int* I, GError **err) {
00904   double val = od->storage[0];
00905   for(int i=0; i<od->N[2]; i++) {
00906     if((i != 0) && (i != (od->N[2]-1))) continue;
00907     for(int j=0; j<od->N[1]; j++) {
00908       if((j != 0) && (j != (od->N[1]-1))) continue;
00909       for(int k=0; k<od->N[0]; k++) {
00910   if((k != 0) && (k != (od->N[0]-1))) continue;
00911   if((od->storage)[get_density_storage_index(k, j, i, od->N[0], od->N[1])] != val) {
00912     *err = g_error_new(WAVEFUNC_GERROR_DOMAIN, 106, "libpostproc::wavefunction::expand_density_box: value is not identical across the entire outside of the box! (was, %g is %g at %d/%d/%d)", val, (od->storage)[get_density_storage_index(k, j, i, od->N[0], od->N[1])], k, j, i);
00913     return NULL;
00914   }
00915       }
00916     }
00917   }
00918   return expand_density_box_with_value(od, I, val, err);
00919 }
00920 
00921 void write_density_povray(const struct density* d, GFile *towrite, int pixel_strategy, GError **err) {
00922   GError *e = NULL;
00923   GFileOutputStream *fos = g_file_replace(towrite, NULL, FALSE, 0, NULL, &e);
00924   if(e != NULL) {
00925     g_propagate_prefixed_error(err, e, "libpostproc::lp_wavefunction.c::write_density_povray: Error opening output file.");
00926     return;
00927   }
00928 
00929   double oo_maxval = 1.0/get_max_density_value(d);
00930 
00931   /*First, write out the initial chunks.*/
00932   GString* s = g_string_new("//Density vidualziation generated by libpostproc\n");
00933   s = g_string_append(s, "//\n//Important switches for the end-user are located here.\n");
00934   s = g_string_append(s, "//Below the ====BLOCKS==== label are the individual data blocks.\n\n");
00935   s = g_string_append(s, "#include \"colors.inc\"\n");
00936   s = g_string_append(s, "global_settings { ambient_light rgb<1, 1, 1> }\n");
00937   s = g_string_append(s, "//background {rgb<1,1,1>}\n\n");
00938   s = g_string_append(s, "#declare pos_block_color = rgb<0, 0, 1>;\n\n");
00939   s = g_string_append(s, "#declare neg_block_color = rgb<1, 0, 0>;\n\n");
00940   g_string_append_printf(s, "camera {\nlocation <%g, %g, %g>\nlook_at <%g, %g, %g>\n}\n\n",
00941    d->N[0]*d->dx[0]*1.5, d->N[1]*d->dx[1]*1.5, -d->N[2]*d->dx[2]*1.5,
00942    d->N[0]*d->dx[0]*0.5, d->N[1]*d->dx[1]*0.5, -d->N[2]*d->dx[2]*0.5);
00943   g_string_append_printf(s, "light_source {<%g, %g, %g> color rgb<1, 1, 1> shadowless}\n",
00944        d->N[0]*d->dx[0]*1.5, d->N[1]*d->dx[1]*1.5, -d->N[2]*d->dx[2]*1.5);
00945   s = g_string_append(s, "//====BLOCKS=====\n");
00946   s = g_string_append(s, "merge {\n");
00947   g_output_stream_write((GOutputStream*)fos, s->str, s->len, NULL, &e);
00948   if(e != NULL) {
00949     g_propagate_prefixed_error(err, e, "libpostproc::wavefunction::write_density_povray: Error while writing header to output stream: %s", e->message);
00950     g_output_stream_close((GOutputStream*)fos, NULL, &e);
00951     return;
00952   }
00953 
00954   double v, val;
00955   for(int k=0; k<d->N[2]; k++) {
00956     for(int j=0; j<d->N[1]; j++) {
00957       for(int i=0; i<d->N[0]; i++) {
00958   v = d->storage[get_density_storage_index_(i, j, k, d->N[0], d->N[1])];
00959   /*oo_maxval is already absolute value*/
00960   if(pixel_strategy == 1) {
00961     val = log(oo_maxval*fabs(v)+1)/log(2);
00962   }else if(pixel_strategy == 2) {
00963     val = (1.0-exp(oo_maxval*fabs(v)))/(1.0-M_E);
00964   }else{
00965     val = fabs(oo_maxval*v);
00966   }
00967 
00968   if(val < THRESHOLD) continue;
00969   /*Break the floating-point chunk into pieces. 1 is max, 0 is min, and we have N steps*/
00970   val *= NUM_STEPS;
00971   val = floor(val);
00972   /*Don't waste the processing time if it's totally clear!*/
00973   if(val == 0) continue;
00974   val /= NUM_STEPS;
00975 
00976 
00977   g_string_printf(s, "box {\n\t<%g, %g, %g>\n\t<%g, %g, %g>\n\ttexture {\n", i*d->dx[0], j*d->dx[1], -k*d->dx[2], (i+1)*d->dx[0], (j+1)*d->dx[1], -(k+1)*d->dx[2]);
00978   g_string_append_printf(s, "\t\tpigment{\n\t\t\tcolor %s_block_color\n\t\t\ttransmit %g\n\t\t}\n",  (v>=0)?"pos":"neg", 1.0-val);
00979   s = g_string_append(s, "\t}\n}\n\n");
00980   g_output_stream_write((GOutputStream*)fos, s->str, s->len, NULL, &e);
00981   if(e != NULL) {
00982     g_propagate_prefixed_error(err, e, "libpostproc::wavefunction::write_density_povray: Error while writing block <%d,%d,%d> to output stream: %s", i, j, k, e->message);
00983     g_output_stream_close((GOutputStream*)fos, NULL, &e);
00984     return;
00985   }
00986       }
00987     }
00988   }
00989 
00990   /*File footer*/
00991   g_string_printf(s, "}\n");
00992   g_output_stream_write((GOutputStream*)fos, s->str, s->len, NULL, &e);
00993   if(e != NULL) {
00994     g_propagate_prefixed_error(err, e, "libpostproc::wavefunction::write_density_povray: Error while writing file footer: %s\n", e->message);
00995     g_output_stream_close((GOutputStream*)fos, NULL, &e);
00996     return;
00997   }
00998 
00999   g_output_stream_close((GOutputStream*)fos, NULL, &e);
01000   if(e != NULL) {
01001     *err = e;
01002   }
01003 }
01004 
01005 
01006 struct density* get_double_resolution_density(const struct density* original, int auto_scale) {
01007   int N_new[3];
01008   double dx[3];
01009   for(int i=0; i<3; i++) {
01010     N_new[i] = (original->N[i])*2-1;
01011     dx[i] = original->dx[i]/2.0;
01012   }
01013   struct density* nd = new_density(N_new, dx, 0);
01014   if(nd == NULL) return NULL;
01015   /*Now do the interpolation.  We loop over the old points, setting the new ones in the inner loop (avoids branch prediction misses if we iterated over the new grid.*/
01016   long x, y, z;
01017   double a, b, c, d, e, f, g, h;
01018   #ifdef OPENMP
01019   #pragma omp parallel for private(y, x, a, b, c, d, e, f, g, h)
01020   #endif
01021   for(z=0; z<original->N[2]-1; z++) {
01022     for(y=0; y<original->N[1]-1; y++) {
01023       for(x=0; x<original->N[0]-1; x++) {
01024   /*For notational simplicity, we'll define the corners of the cube here.
01025    *\note Starting from the top (x=0 y=0 z=0) and going clockwise (y=1 x=0 z=0), and then the same for the upper 4 points*/
01026   a=original->storage[get_density_storage_index(x, y, z, original->N[0], original->N[1])];
01027   b=original->storage[get_density_storage_index(x, y+1, z, original->N[0], original->N[1])];
01028   c=original->storage[get_density_storage_index(x+1, y+1, z, original->N[0], original->N[1])];
01029   d=original->storage[get_density_storage_index(x+1, y, z, original->N[0], original->N[1])];
01030   e=original->storage[get_density_storage_index(x, y, z+1, original->N[0], original->N[1])];
01031   f=original->storage[get_density_storage_index(x, y+1, z+1, original->N[0], original->N[1])];
01032   g=original->storage[get_density_storage_index(x+1, y+1, z+1, original->N[0], original->N[1])];
01033   h=original->storage[get_density_storage_index(x+1, y, z+1, original->N[0], original->N[1])];
01034   /*Set the original 4 sites (the other sites in the new cell will be set by later iterations*/
01035   nd->storage[get_density_storage_index(2*x, 2*y, 2*z, N_new[0], N_new[1])] = a;
01036   nd->storage[get_density_storage_index(2*(x+1), 2*y, 2*z, N_new[0], N_new[1])] = d;
01037   nd->storage[get_density_storage_index(2*x, 2*(y+1), 2*z, N_new[0], N_new[1])] = b;
01038   nd->storage[get_density_storage_index(2*x, 2*y, 2*(z+1), N_new[0], N_new[1])] = e;
01039   /*Set the axial sites*/
01040   nd->storage[get_density_storage_index(2*x+1, 2*y, 2*z, N_new[0], N_new[1])] = (a+d)/2.0;
01041   nd->storage[get_density_storage_index(2*x, 2*y+1, 2*z, N_new[0], N_new[1])] = (a+b)/2.0;
01042   nd->storage[get_density_storage_index(2*x, 2*y, 2*z+1, N_new[0], N_new[1])] = (a+e)/2.0;
01043   /*Set the face sites*/
01044   nd->storage[get_density_storage_index(2*x+1, 2*y+1, 2*z, N_new[0], N_new[1])] = (a+b+c+d)/4.0;
01045   nd->storage[get_density_storage_index(2*x+1, 2*y, 2*z+1, N_new[0], N_new[1])] = (a+d+e+h)/4.0;
01046   nd->storage[get_density_storage_index(2*x, 2*y+1, 2*z+1, N_new[0], N_new[1])] = (a+b+e+f)/4.0;
01047   /*Set the interior point*/
01048   nd->storage[get_density_storage_index(2*x+1, 2*y+1, 2*z+1, N_new[0], N_new[1])] = (a+b+c+d+e+f+g+h)/8.0;
01049   #ifdef DEBUG3
01050   fprintf(stderr, "density doubling %ld %ld %ld: a=%g b=%g c=%g d=%g e=%g f=%g g=%g h=%g\n", x, y, z, a, b, c, d, e, f, g, h);
01051   fprintf(stderr, "\toriginal: %ld %ld %ld = %g, %ld %ld %ld = %g, %ld %ld %ld = %g, %ld %ld %ld = %g\n", 
01052     2*x, 2*y, 2*z, *get_density_storage_at_c_(2*x, 2*y, 2*z, nd),
01053     2*(x+1), 2*y, 2*z, *get_density_storage_at_c_(2*(x+1), 2*y, 2*z, nd),
01054     2*x, 2*(y+1), 2*z, *get_density_storage_at_c_(2*x, 2*(y+1), 2*z, nd),
01055     2*x, 2*y, 2*(z+1), *get_density_storage_at_c_(2*x, 2*y, 2*(z+1), nd)
01056     );
01057   fprintf(stderr, "\taxial: %ld %ld %ld = %g, %ld %ld %ld = %g, %ld %ld %ld = %g\n",
01058     2*x+1, 2*y, 2*z, *get_density_storage_at_c_(2*x+1, 2*y, 2*z, nd),
01059     2*x, 2*y+1, 2*z, *get_density_storage_at_c_(2*x, 2*y+1, 2*z, nd),
01060     2*x, 2*y, 2*z+1, *get_density_storage_at_c_(2*x, 2*y, 2*z+1, nd)
01061     );
01062   fprintf(stderr, "\tface: %ld %ld %ld = %g, %ld %ld %ld = %g, %ld %ld %ld = %g\n",
01063     2*x+1, 2*y+1, 2*z, *get_density_storage_at_c_(2*x+1, 2*y+1, 2*z, nd),
01064     2*x+1, 2*y, 2*z+1, *get_density_storage_at_c_(2*x+1, 2*y, 2*z+1, nd),
01065     2*x, 2*y+1, 2*z+1, *get_density_storage_at_c_(2*x, 2*y+1, 2*z+1, nd)
01066     );
01067   fprintf(stderr, "\tinterior: %ld %ld %ld = %g\n",
01068     2*x+1, 2*y+1, 2*z+1, *get_density_storage_at_c_(2*x+1, 2*y+1, 2*z+1, nd)
01069     );
01070   #endif
01071       }
01072     }
01073   }
01074   /*All of the points but the final x y and z planes have been set.  There are still axial and facial sites to be set on these.*/
01075   /*x face*/
01076   x=original->N[0]-1;
01077   #ifdef OPENMP
01078   #pragma omp parallel for private(y, a, b, e, f)
01079   #endif
01080   for(z=0; z<original->N[2]-1; ++z) {
01081     for(y=0; y<original->N[1]-1; ++y) {
01082   a=original->storage[get_density_storage_index(x, y, z, original->N[0], original->N[1])];
01083   b=original->storage[get_density_storage_index(x, y+1, z, original->N[0], original->N[1])];
01084   e=original->storage[get_density_storage_index(x, y, z+1, original->N[0], original->N[1])];
01085   f=original->storage[get_density_storage_index(x, y+1, z+1, original->N[0], original->N[1])];
01086   /*Set the original sites (the other sites in the new cell will be set by later iterations*/
01087   nd->storage[get_density_storage_index(2*x, 2*y, 2*z, N_new[0], N_new[1])] = a;
01088   nd->storage[get_density_storage_index(2*x, 2*(y+1), 2*z, N_new[0], N_new[1])] = b;
01089   nd->storage[get_density_storage_index(2*x, 2*y, 2*(z+1), N_new[0], N_new[1])] = e;
01090   /*Set the axial sites*/
01091   nd->storage[get_density_storage_index(2*x, 2*y+1, 2*z, N_new[0], N_new[1])] = (a+b)/2.0;
01092   nd->storage[get_density_storage_index(2*x, 2*y, 2*z+1, N_new[0], N_new[1])] = (a+e)/2.0;
01093   /*Set the face sites*/
01094   nd->storage[get_density_storage_index(2*x, 2*y+1, 2*z+1, N_new[0], N_new[1])] = (a+b+e+f)/4.0;
01095     }
01096   }
01097   /*y face*/
01098   y=original->N[1]-1;
01099   #ifdef OPENMP
01100   #pragma omp parallel for private(x, a, d, e, h)
01101   #endif
01102   for(z=0; z<original->N[2]-1; ++z) {
01103     for(x=0; x<original->N[0]-1; ++x) {
01104   a=original->storage[get_density_storage_index(x, y, z, original->N[0], original->N[1])];
01105   d=original->storage[get_density_storage_index(x+1, y, z, original->N[0], original->N[1])];
01106   e=original->storage[get_density_storage_index(x, y, z+1, original->N[0], original->N[1])];
01107   h=original->storage[get_density_storage_index(x+1, y, z+1, original->N[0], original->N[1])];
01108   /*Set the original sites (the other sites in the new cell will be set by later iterations*/
01109   nd->storage[get_density_storage_index(2*x, 2*y, 2*z, N_new[0], N_new[1])] = a;
01110   nd->storage[get_density_storage_index(2*(x+1), 2*y, 2*z, N_new[0], N_new[1])] = d;
01111   nd->storage[get_density_storage_index(2*x, 2*y, 2*(z+1), N_new[0], N_new[1])] = e;
01112   /*Set the axial sites*/
01113   nd->storage[get_density_storage_index(2*x+1, 2*y, 2*z, N_new[0], N_new[1])] = (a+d)/2.0;
01114   nd->storage[get_density_storage_index(2*x, 2*y, 2*z+1, N_new[0], N_new[1])] = (a+e)/2.0;
01115   /*Set the face sites*/
01116   nd->storage[get_density_storage_index(2*x+1, 2*y, 2*z+1, N_new[0], N_new[1])] = (a+d+e+h)/4.0;
01117     }
01118   }
01119   z=original->N[2]-1;
01120   #ifdef OPENMP
01121   #pragma omp parallel for private(x, a, b, c, d)
01122   #endif
01123   for(y=0; y<original->N[1]-1; ++y) {
01124     for(x=0; x<original->N[0]-1; ++x) {
01125       /*we only get the one set of z sites since the next z site is not extant*/
01126       a=original->storage[get_density_storage_index(x, y, z, original->N[0], original->N[1])];
01127       b=original->storage[get_density_storage_index(x, y+1, z, original->N[0], original->N[1])];
01128       c=original->storage[get_density_storage_index(x+1, y+1, z, original->N[0], original->N[1])];
01129       d=original->storage[get_density_storage_index(x+1, y, z, original->N[0], original->N[1])];
01130       /*Set the original sites (the other sites in the new cell will be set by later iterations*/
01131       nd->storage[get_density_storage_index(2*x, 2*y, 2*z, N_new[0], N_new[1])] = a;
01132       nd->storage[get_density_storage_index(2*(x+1), 2*y, 2*z, N_new[0], N_new[1])] = d;
01133       nd->storage[get_density_storage_index(2*x, 2*(y+1), 2*z, N_new[0], N_new[1])] = b;
01134       /*Set the axial sites*/
01135       nd->storage[get_density_storage_index(2*x+1, 2*y, 2*z, N_new[0], N_new[1])] = (a+d)/2.0;
01136       nd->storage[get_density_storage_index(2*x, 2*y+1, 2*z, N_new[0], N_new[1])] = (a+b)/2.0;
01137       /*Set the face sites*/
01138       nd->storage[get_density_storage_index(2*x+1, 2*y+1, 2*z, N_new[0], N_new[1])] = (a+b+c+d)/4.0;
01139     }
01140   }
01141   /*Finally, we have some axial sites that still haven't been set along the very edges:*/
01142   /*x axis*/
01143   y=original->N[1]-1;
01144   z=original->N[2]-1;
01145   #ifdef OPENMP
01146   #pragma omp parallel for private(a, d)
01147   #endif
01148   for(x=0; x<original->N[0]-1; ++x) {
01149     a=original->storage[get_density_storage_index(x, y, z, original->N[0], original->N[1])];
01150     d=original->storage[get_density_storage_index(x+1, y, z, original->N[0], original->N[1])];
01151     /*Set the original sites (the other sites in the new cell will be set by later iterations*/
01152     nd->storage[get_density_storage_index(2*x, 2*y, 2*z, N_new[0], N_new[1])] = a;
01153     nd->storage[get_density_storage_index(2*(x+1), 2*y, 2*z, N_new[0], N_new[1])] = d;
01154     /*Set the axial sites*/
01155     nd->storage[get_density_storage_index(2*x+1, 2*y, 2*z, N_new[0], N_new[1])] = (a+d)/2.0;
01156   }
01157   /*y axis*/
01158   x=original->N[0]-1;
01159   z=original->N[2]-1;
01160   #ifdef OPENMP
01161   #pragma omp parallel for private(a, b)
01162   #endif
01163   for(y=0; y<original->N[1]-1; ++y) {
01164     a=original->storage[get_density_storage_index(x, y, z, original->N[0], original->N[1])];
01165     b=original->storage[get_density_storage_index(x, y+1, z, original->N[0], original->N[1])];
01166     /*Set the original sites (the other sites in the new cell will be set by later iterations*/
01167     nd->storage[get_density_storage_index(2*x, 2*y, 2*z, N_new[0], N_new[1])] = a;
01168     nd->storage[get_density_storage_index(2*x, 2*(y+1), 2*z, N_new[0], N_new[1])] = b;
01169     /*Set the axial sites*/
01170     nd->storage[get_density_storage_index(2*x, 2*y+1, 2*z, N_new[0], N_new[1])] = (a+b)/2.0;
01171   }
01172   /*z axis*/
01173   x=original->N[0]-1;
01174   y=original->N[1]-1;
01175   #ifdef OPENMP
01176   #pragma omp parallel for private(a, e)
01177   #endif
01178   for(z=0; z<original->N[2]-1; ++z) {
01179     a=original->storage[get_density_storage_index(x, y, z, original->N[0], original->N[1])];
01180     e=original->storage[get_density_storage_index(x, y, z+1, original->N[0], original->N[1])];
01181     /*Set the original sites (the other sites in the new cell will be set by later iterations*/
01182     nd->storage[get_density_storage_index(2*x, 2*y, 2*z, N_new[0], N_new[1])] = a;
01183     nd->storage[get_density_storage_index(2*x, 2*y, 2*(z+1), N_new[0], N_new[1])] = e;
01184     /*Set the axial sites*/
01185     nd->storage[get_density_storage_index(2*x, 2*y, 2*z+1, N_new[0], N_new[1])] = (a+e)/2.0;
01186   }
01187   /*Set the original very corner site*/
01188   nd->storage[get_density_storage_index(2*(original->N[0]-1), 2*(original->N[1]-1), 2*(original->N[2]-1), N_new[0], N_new[1])] = original->storage[get_density_storage_index(original->N[0]-1, original->N[1]-1, original->N[2]-1, original->N[0], original->N[1])];
01189   if(auto_scale != 0) {
01190     double scaling=1;
01191     int invert=0;
01192     if(auto_scale < 0) {
01193       /*Units are grid size, not inverse grid size, so invert*/
01194       invert=1;
01195       /*Set it so we get the bits back out*/
01196       auto_scale=-auto_scale;
01197     }
01198     /**since units are f/(dx*dy*dz) -> f/(dx/2*dy/2*dz/2) we need to *divide* f by 2*2*2 to maintain the proper density (f/(dx*dy*dz)->(f/(2*2*2*dx/2*dy/2*dz/2))*/
01199     if(auto_scale & 1) {
01200       scaling /= 2;
01201     }
01202     if(auto_scale & 2) {
01203       scaling /= 2;
01204     }
01205     if(auto_scale & 4) {
01206       scaling /= 2;
01207     }
01208     if(invert) scaling = 1.0/scaling;
01209     fprintf(stderr, "DOUBLE-RES SCALING BY %g\n", scaling);
01210     density_mul_by_const(nd, scaling);
01211   }
01212   return nd;
01213 }
01214 
01215 
01216 /**Gets a new density with a half-resolution grid, using an average for assignment
01217  *\param original original density
01218  *\return pointer to a density, or NULL if memory allocation failed.
01219  *\note the new grid doesn't add an outside row of new sites; it only places a new grid site between two existing ones
01220  */
01221 struct density* get_half_resolution_density(const struct density* original, GError **e, int auto_scale) {
01222   int N_new[3];
01223   double dx[3];
01224   for(int i=0; i<3; i++) {
01225     if(original->N[i]%2 != 1) {
01226       *e = g_error_new(WAVEFUNC_GERROR_DOMAIN, 1, "lp_wavefunction.c::get_half_resolution_density: ERROR: %d-th coordinate is not odd, so there's no clean half-resolution grid!  (This feature is possible and may be added at some point in the future; at the moment, this function is solely for bringining the density back to the original resolution after doubling", i);
01227       return NULL;
01228     }
01229     N_new[i] = (original->N[i]+1)/2;
01230     dx[i] = original->dx[i]*2.0;
01231   }
01232   struct density* nd = new_density(N_new, dx, 0);
01233   if(nd == NULL) {
01234     *e = g_error_new(WAVEFUNC_GERROR_DOMAIN, 1, "lp_wavefunction.c::get_half_resolution_density: ERROR: failed to allocate space for half-resolution density.");
01235     return NULL;
01236   }
01237   for(long z=0; z<N_new[2]; ++z) {
01238     for(long y=0; y<N_new[1]; ++y) {
01239       for(long x=0; x<N_new[0]; ++x) {
01240   /*Simple version: just grab the point and neglect the double-res points*/
01241   nd->storage[get_density_storage_index(x, y, z, N_new[0], N_new[1])] = original->storage[get_density_storage_index(2*x, 2*y, 2*z, original->N[0], original->N[1])];
01242       }
01243     }
01244   }
01245   if(auto_scale != 0) {
01246     double scaling=1;
01247     int invert=1;
01248     if(auto_scale < 0) {
01249       /*Units are grid size, not inverse grid size, so don't (this is inverse operation of doubling the resolution)*/
01250       invert=0;
01251       /*Set it so we get the bits back out*/
01252       auto_scale=-auto_scale;
01253     }
01254     if(auto_scale & 1) {
01255       scaling /= 2;
01256     }
01257     if(auto_scale & 2) {
01258       scaling /= 2;
01259     }
01260     if(auto_scale & 4) {
01261       scaling /= 2;
01262     }
01263     if(invert) scaling = 1.0/scaling;
01264     fprintf(stderr, "HALF-RES SCALING BY %g\n", scaling);
01265     density_mul_by_const(nd, scaling);
01266   }
01267   return nd;
01268 }
01269 
01270 void density_execute_callback(const struct density* d, void (*callback)(int x, int y, int z, const struct density*d, void* privdat), void* privdat) {
01271   for(int z=0; z<d->N[2]; ++z) {
01272     for(int y=0; y<d->N[1]; ++y) {
01273       for(int x=0; x<d->N[0]; ++x) {
01274   callback(x, y, z, d, privdat);
01275       }
01276     }
01277   }
01278 }
01279 
01280 void density_2_execute_callback(const struct density* d1, const struct density* d2, void (*callback)(int x, int y, int z, const struct density* d1, const struct density* d2, void* privdat), void* privdat) {
01281   for(int z=0; z<d1->N[2]; ++z) {
01282     for(int y=0; y<d1->N[1]; ++y) {
01283       for(int x=0; x<d1->N[0]; ++x) {
01284   callback(x, y, z, d1, d2, privdat);
01285       }
01286     }
01287   }
01288 }
01289 
01290 void density_execute_callback_parallel(const struct density* d, void (*callback)(int x, int y, int z, const struct density*d, void* privdat), void** privdat, int* x_report) {
01291   int x, y, z;
01292   #ifdef OPENMP
01293   #pragma omp parallel for private(x, y, z)
01294   #endif
01295   for(z=0; z<d->N[2]; ++z) {
01296     x_report[
01297              #ifdef OPENMP
01298        omp_get_thread_num()
01299              #else
01300        0
01301              #endif
01302        ] = 1;
01303     for(y=0; y<d->N[1]; ++y) {
01304       for(x=0; x<d->N[0]; ++x) {
01305   callback(x, y, z, d, 
01306      #ifdef OPENMP
01307      privdat[omp_get_thread_num()]
01308      #else
01309      privdat[0]
01310      #endif
01311      );
01312       }
01313     }
01314   }
01315 }
01316 
01317 void density_2_execute_callback_parallel(const struct density* d1, const struct density* d2, void (*callback)(int x, int y, int z, const struct density* d1, const struct density* d2, void* privdat), void** privdat, int* x_report) {
01318   int x, y, z;
01319   #ifdef OPENMP
01320   #pragma omp parallel for private(x, y, z)
01321   #endif
01322   for(z=0; z<d1->N[2]; ++z) {
01323     x_report[
01324              #ifdef OPENMP
01325        omp_get_thread_num()
01326              #else
01327        0
01328              #endif
01329        ] = 1;
01330     for(y=0; y<d1->N[1]; ++y) {
01331       for(x=0; x<d1->N[0]; ++x) {
01332   callback(x, y, z, d1, d2, 
01333      #ifdef OPENMP
01334      privdat[omp_get_thread_num()]
01335      #else
01336      privdat[0]
01337      #endif
01338      );
01339       }
01340     }
01341   }
01342 }
01343 
01344 
01345 struct diff_data {
01346   double* minmax;
01347   /*Value to scale by, ready to *multiply* (i.e. should be inverse of e.g. the global maximum*/
01348   double scaling;
01349 };
01350 static void get_max_diff_scaled(int x, int y, int z, const struct density* d1, const struct density* d2, void* privdat) {
01351   struct diff_data* dd = (struct diff_data*)privdat;
01352   double diff = fabs((d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])] - d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])])*dd->scaling);  
01353   /**\note that this comparison will fail if diff is a NaN */
01354   if(!(diff <= (*dd->minmax))) (*dd->minmax) = diff;
01355 }
01356 static void get_min_diff_scaled(int x, int y, int z, const struct density* d1, const struct density* d2, void* privdat) {
01357   struct diff_data* dd = (struct diff_data*)privdat;
01358   double diff = fabs((d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])] - d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])])*dd->scaling);  
01359   if(!(diff >= (*dd->minmax))) (*dd->minmax) = diff;
01360 }
01361 
01362 static void get_max_diff_d1(int x, int y, int z, const struct density* d1, const struct density* d2, void* privdat) {
01363   double diff = fabs((d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])] - d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])])/d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])]);  
01364   //fprintf(stderr, "MAX: %d %d %d: %g - %g = %g\n", x, y, z, d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])], d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])], diff);
01365   /**\note that this comparison will fail if diff is a NaN */
01366   if(!(diff <= *(double*)privdat)) *(double*)privdat = diff;
01367 }
01368 static void get_min_diff_d1(int x, int y, int z, const struct density* d1, const struct density* d2, void* privdat) {
01369   double diff = fabs((d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])] - d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])])/d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])]);  
01370   //fprintf(stderr, "MIN: %d %d %d: %g - %g = %g\n", x, y, z, d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])], d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])], diff);
01371   if(!(diff >= *(double*)privdat)) *(double*)privdat = diff;
01372 }
01373 static void get_max_diff_d2(int x, int y, int z, const struct density* d1, const struct density* d2, void* privdat) {
01374   double diff = fabs((d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])] - d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])])/d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])]);  
01375   //fprintf(stderr, "MAX: %d %d %d: %g - %g = %g\n", x, y, z, d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])], d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])], diff);
01376   /**\note that this comparison will fail if diff is a NaN */
01377   if(!(diff <= *(double*)privdat)) *(double*)privdat = diff;
01378 }
01379 static void get_min_diff_d2(int x, int y, int z, const struct density* d1, const struct density* d2, void* privdat) {
01380   double diff = fabs((d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])] - d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])])/d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])]);  
01381   //fprintf(stderr, "MIN: %d %d %d: %g - %g = %g\n", x, y, z, d1->storage[get_density_storage_index(x, y, z, d1->N[0], d1->N[1])], d2->storage[get_density_storage_index(x, y, z, d2->N[0], d2->N[1])], diff);
01382   if(!(diff >= *(double*)privdat)) *(double*)privdat = diff;
01383 }
01384 
01385 double density_get_max_abs_delta_pct(const struct density* d1, const struct density* d2, int scaleby, double scaling) {
01386   double max = nan("NaN");
01387   for(int i=0; i<3; i++) if(d1->N[i] != d2->N[i]) return max;
01388   #ifdef OPENMP
01389   int N_threads = omp_get_max_threads();
01390   fprintf(stderr, "Got %d threads.\n", N_threads);
01391   struct diff_data dd_[N_threads];
01392   double max_[N_threads];
01393   void* maxset[N_threads];
01394   void* ddset[N_threads];
01395   int x_report[N_threads];
01396   int i;
01397   for(i=0; i<N_threads; ++i) {
01398     max_[i] = max;
01399     maxset[i] = (void*)&(max_[i]);
01400     dd_[i].minmax = &(max_[i]);
01401     ddset[i] = (void*)&(dd_[i]);
01402     x_report[i] = 0;
01403   }
01404   switch(scaleby) {
01405   case -1:
01406     density_2_execute_callback_parallel(d1, d2, get_max_diff_d2, maxset, x_report);
01407     break;
01408   case 0:
01409     density_2_execute_callback_parallel(d1, d2, get_max_diff_d1, maxset, x_report);
01410     break;
01411   case 1:
01412     for(i=0; i<N_threads; ++i) {
01413       dd_[i].scaling = 1.0/density_get_max(d1, 1);
01414     }
01415     density_2_execute_callback_parallel(d1, d2, get_max_diff_scaled, ddset, x_report);
01416     break;
01417   case 2:
01418     for(i=0; i<N_threads; ++i) {
01419       dd_[i].scaling = 1.0/density_get_max(d2, 1);
01420     }
01421     density_2_execute_callback_parallel(d1, d2, get_max_diff_scaled, ddset, x_report);
01422     break;
01423   case 3:
01424     for(i=0; i<N_threads; ++i) {
01425       dd_[i].scaling = scaling;
01426     }
01427     density_2_execute_callback_parallel(d1, d2, get_max_diff_scaled, ddset, x_report);
01428     break;
01429   default:
01430     return max;
01431   }
01432   max = max_[0];
01433   for(int i=1; i<N_threads; ++i) {
01434     /**\note that max[i] is already one or zero.*/
01435     fprintf(stderr, "\tmax_[%d]=%g max=%g\n", i, max_[i], max);
01436     if(x_report[i] && (!(max_[i] <= max))) max = max_[i];
01437   }
01438   #else
01439   struct diff_data dd;
01440   dd.minmax = &max;
01441   switch(scaleby) {
01442   case -1:
01443     density_2_execute_callback(d1, d2, get_max_diff_d2, &max);
01444     break;
01445   case 0:
01446     density_2_execute_callback(d1, d2, get_max_diff_d1, &max);
01447     break;
01448   case 1:
01449     dd.scaling = 1.0/density_get_max(d1, 1);
01450     density_2_execute_callback(d1, d2, get_max_diff_scaled, &dd);
01451     break;
01452   case 2:
01453     dd.scaling = 1.0/density_get_max(d2, 1);
01454     density_2_execute_callback(d1, d2, get_max_diff_scaled, &dd);
01455     break;
01456   case 3:
01457     dd.scaling = scaling;
01458     density_2_execute_callback(d1, d2, get_max_diff_scaled, &dd);
01459     break;
01460   default:
01461     return max;
01462   }
01463   #endif
01464   return max;
01465 }
01466 
01467 double density_get_min_abs_delta_pct(const struct density* d1, const struct density* d2, int scaleby, double scaling) {
01468   double min = nan("NaN");
01469   for(int i=0; i<3; i++) if(d1->N[i] != d2->N[i]) return min;
01470   #ifdef OPENMP
01471   int N_threads = omp_get_max_threads();
01472   fprintf(stderr, "Got %d threads.\n", N_threads);
01473   struct diff_data dd_[N_threads];
01474   double min_[N_threads];
01475   void* minset[N_threads];
01476   void* ddset[N_threads];
01477   int x_report[N_threads];
01478   int i;
01479   for(i=0; i<N_threads; ++i) {
01480     min_[i] = min;
01481     minset[i] = &(min_[i]);
01482     dd_[i].minmax = &(min_[i]);
01483     ddset[i] = &(dd_[i]);
01484     x_report[i] = 0;
01485   }
01486   switch(scaleby) {
01487   case -1:
01488     density_2_execute_callback_parallel(d1, d2, get_min_diff_d2, minset, x_report);
01489     break;
01490   case 0:
01491     density_2_execute_callback_parallel(d1, d2, get_min_diff_d1, minset, x_report);
01492     break;
01493   case 1:
01494     for(i=0; i<N_threads; ++i) {
01495       dd_[i].scaling = 1.0/density_get_min(d1, 1);
01496     }
01497     density_2_execute_callback_parallel(d1, d2, get_min_diff_scaled, ddset, x_report);
01498     break;
01499   case 2:
01500     for(i=0; i<N_threads; ++i) {
01501       dd_[i].scaling = 1.0/density_get_min(d2, 1);
01502     }
01503     density_2_execute_callback_parallel(d1, d2, get_min_diff_scaled, ddset, x_report);
01504     break;
01505   case 3:
01506     for(i=0; i<N_threads; ++i) {
01507       dd_[i].scaling = scaling;
01508     }
01509     density_2_execute_callback_parallel(d1, d2, get_min_diff_scaled, ddset, x_report);
01510     break;
01511   default:
01512     return min;
01513   }
01514   min = min_[0];
01515   for(int i=1; i<N_threads; ++i) {
01516     /**\note that min[i] is already one or zero.*/
01517     fprintf(stderr, "\tmin_[%d]=%g min=%g\n", i, min_[i], min);
01518     if((x_report[i]) && (!(min_[i] >= min))) min = min_[i];
01519   }
01520   #else
01521   struct diff_data dd;
01522   dd.minmax = &min;
01523   switch(scaleby) {
01524   case -1:
01525     density_2_execute_callback(d1, d2, get_min_diff_d2, &min);
01526     break;
01527   case 0:
01528     density_2_execute_callback(d1, d2, get_min_diff_d1, &min);
01529     break;
01530   case 1:
01531     dd.scaling = 1.0/density_get_min(d1, 1);
01532     density_2_execute_callback(d1, d2, get_min_diff_scaled, &dd);
01533     break;
01534   case 2:
01535     dd.scaling = 1.0/density_get_min(d2, 1);
01536     density_2_execute_callback(d1, d2, get_min_diff_scaled, &dd);
01537     break;
01538   case 3:
01539     dd.scaling = scaling;
01540     density_2_execute_callback(d1, d2, get_min_diff_scaled, &dd);
01541     break;
01542   default:
01543     return min;
01544   }
01545   #endif
01546   return min;
01547 }
01548 
01549 struct minmax_dat {
01550   double minmax;
01551   int location[3];
01552 };
01553 
01554 static void get_max(int x, int y, int z, const struct density* d, void* privdat) {
01555   struct minmax_dat* mmd = (struct minmax_dat*)privdat;
01556   if(!(mmd->minmax >= *get_density_storage_at_c(x, y, z, d))) {
01557     mmd->minmax = *get_density_storage_at_c(x, y, z, d);
01558     mmd->location[0]=x;
01559     mmd->location[1]=y;
01560     mmd->location[2]=z;
01561   }
01562 }
01563 static void get_min(int x, int y, int z, const struct density* d, void* privdat) {
01564   struct minmax_dat* mmd = (struct minmax_dat*)privdat;
01565   if(!(mmd->minmax <= *get_density_storage_at_c(x, y, z, d))) {
01566     mmd->minmax = *get_density_storage_at_c(x, y, z, d);
01567     mmd->location[0]=x;
01568     mmd->location[1]=y;
01569     mmd->location[2]=z;
01570   }
01571 }
01572 
01573 static void get_max_abs(int x, int y, int z, const struct density* d, void* privdat) {
01574   struct minmax_dat* mmd = (struct minmax_dat*)privdat;
01575   if(!(fabs(mmd->minmax) >= fabs(*get_density_storage_at_c(x, y, z, d)))) {
01576     mmd->minmax = fabs(*get_density_storage_at_c(x, y, z, d));
01577     mmd->location[0]=x;
01578     mmd->location[1]=y;
01579     mmd->location[2]=z;
01580   }
01581 }
01582 static void get_min_abs(int x, int y, int z, const struct density* d, void* privdat) {
01583   struct minmax_dat* mmd = (struct minmax_dat*)privdat;
01584   if(!(fabs(mmd->minmax) <= fabs(*get_density_storage_at_c(x, y, z, d)))) {
01585     mmd->minmax = fabs(*get_density_storage_at_c(x, y, z, d));
01586     mmd->location[0]=x;
01587     mmd->location[1]=y;
01588     mmd->location[2]=z;
01589   }
01590 }
01591 
01592 double density_get_max(const struct density* d, int abs) {
01593   int location[3];
01594   return density_get_max_and_loc(d, abs, location);
01595 }
01596 double density_get_max_and_loc(const struct density* d, int abs, int* location) {
01597   double max = nan("NaN");
01598   int N_threads = 0;
01599   #ifdef OPENMP
01600   N_threads = omp_get_max_threads();
01601   #endif
01602   struct minmax_dat max_[N_threads];
01603   /*maxset is the array of private data pointers*/
01604   void* maxset[N_threads];
01605   int x_report[N_threads];
01606   for(int i=0; i<N_threads; ++i) {
01607     max_[i].minmax = nan("NaN");
01608     maxset[i] = &max_[i];
01609     x_report[i] = 0;
01610   }
01611   if(abs) {
01612     density_execute_callback_parallel(d, get_max_abs, maxset, x_report);
01613   }else{
01614     density_execute_callback_parallel(d, get_max, maxset, x_report);
01615   }
01616   max = max_[0].minmax;
01617   for(int j=0; j<3; ++j) location[j] = max_[0].location[j];
01618   for(int i=1; i<N_threads; ++i) {
01619     /**\note that max[i] is already one or zero.*/
01620     if(x_report[i] && (!(max_[i].minmax <= max))) {
01621       max = max_[i].minmax;
01622       for(int j=0; j<3; ++j) location[j] = max_[0].location[j];
01623     }
01624   }
01625   return max;
01626 }
01627 double density_get_min(const struct density* d, int abs) {
01628   int location[3];
01629   return density_get_min_and_loc(d, abs, location);
01630 }
01631 double density_get_min_and_loc(const struct density* d, int abs, int* location) {
01632   double min = nan("NaN");
01633   int N_threads = 0;
01634   #ifdef OPENMP
01635   N_threads = omp_get_max_threads();
01636   #endif
01637   struct minmax_dat min_[N_threads];
01638   /*minset is the array of private data pointers*/
01639   void* minset[N_threads];
01640   int x_report[N_threads];
01641   for(int i=0; i<N_threads; ++i) {
01642     min_[i].minmax = nan("NaN");
01643     minset[i] = &min_[i];
01644     x_report[i] = 0;
01645   }
01646   if(abs) {
01647     density_execute_callback_parallel(d, get_min_abs, minset, x_report);
01648   }else{
01649     density_execute_callback_parallel(d, get_min, minset, x_report);
01650   }
01651   min = min_[0].minmax;
01652   for(int j=0; j<3; ++j) location[j] = min_[0].location[j];
01653   for(int i=1; i<N_threads; ++i) {
01654     /**\note that min[i] is already one or zero.*/
01655     if(x_report[i] && (!(min_[i].minmax <= min))) {
01656       min = min_[i].minmax;
01657       for(int j=0; j<3; ++j) location[j] = min_[0].location[j];
01658     }
01659   }
01660   return min;
01661 }
01662 
01663 
01664  struct gsl_integrand_x {
01665    gsl_interp_accel* accel;
01666    gsl_spline* spline;
01667    double(*f)(double x, double y, double z, void* privdat);
01668    void* privdat;
01669    double y;
01670    double z;
01671    FILE* outfile;
01672    int iter;
01673  };
01674 
01675  hotfunc double gsl_integrand_x_func(double x, void* privdat) {
01676    struct gsl_integrand_x* gix = (struct gsl_integrand_x*)privdat;
01677    double val = gix->f(x, gix->y, gix->z, gix->privdat);
01678    double splineval = gsl_spline_eval(gix->spline, x, gix->accel);
01679    fprintf(gix->outfile, "%d\t%g\t%g\t%g\t%g\t%g\t%g\n", ++gix->iter, x, gix->y, gix->z, val, splineval, val*splineval);
01680    return val*splineval;
01681  }
01682 
01683  hotfunc double gsl_integrand_x_nofunc(double x, void* privdat) {
01684    struct gsl_integrand_x* gix = (struct gsl_integrand_x*)privdat;
01685    double splineval = gsl_spline_eval(gix->spline, x, gix->accel);
01686    fprintf(gix->outfile, "%d\t%g\t%g\t%g\t%g\n", ++gix->iter, x, gix->y, gix->z, splineval);
01687    return splineval;
01688  }
01689  
01690  hotfunc double gsl_integrand_yz(double coord, void* privdat) {
01691    struct gsl_integrand_x* gix = (struct gsl_integrand_x*)privdat;
01692    double splineval = gsl_spline_eval(gix->spline, coord, gix->accel);
01693    fprintf(gix->outfile, "%d\t%g\t%g\n", ++gix->iter, coord, splineval);
01694    return splineval;
01695  }
01696 
01697 /**Note to self: this will be much cleaner for a templated version.  What would happen is this:
01698  1) Allocate array of doubles
01699  2) Integrate each point in this dimension (e.g. if we're in 3D, do a 2D integral at each z point)
01700  3) Integrate the array of integrals
01701  4) We're done!
01702  
01703  What's more, one could set an extra argument (of dimension D-1, if template is for dimension D) which specifies the index to integrate at each step, e.g.
01704  int integrate_first[] = {2, 1};
01705  would specify that first the Z coordinate is to be integrated over (3D) then in the 2D integral, integrate over Y.  When we're at 1D, we have no further coordinate to specify.
01706 
01707  Of course, 0 has to be a specialized template.
01708 
01709  if this isnt' a class member, remember that we must fully specialize the template to provide the termination condition.
01710 
01711  Of course, this would obscure the fact that the strid is critically important to performance.  
01712  And we'd have to fetch out full on classes of the D-1 dim.
01713 */
01714 double density_integrate_spline(double* z_error_estimate, double* y_error_estimate, double* x_error_estimate, double relerr, double abserr, const struct density* d, double (*f)(double x, double y, double z, void* privdat), void* privdat) {
01715    /**Integrating x results in a yz plane of values
01716     *\note that the y coords are contiguous in memory
01717     */
01718    double* yzvals = (double*)malloc(sizeof(double)*d->N[1]*d->N[2]);
01719    /*This array has the coordinate we're integrating over*/
01720    double* coords = (double*)malloc(sizeof(double)*d->N[0]);
01721    if((yzvals == NULL) || (coords == NULL)) {
01722      if(yzvals != NULL) free(yzvals);
01723      if(coords != NULL) free(coords);
01724      return nan("NaN");
01725    }
01726    for(int x=0; x<d->N[0]; ++x) coords[x] = (x - d->N[0]/2)*d->dx[0];
01727    fprintf(stderr, "coords[0]=%g\tcoords[%d]=%g\n", coords[0], d->N[0]-1, coords[d->N[0]-1]);
01728    int index, z, y, status;
01729    gsl_interp_accel* accel = gsl_interp_accel_alloc();
01730    gsl_spline* spline =  gsl_spline_alloc(gsl_interp_cspline, d->N[0]);
01731    gsl_integration_workspace *w = gsl_integration_workspace_alloc(MAX_GSL_INTEGRATION_INTERVALS);
01732    struct gsl_integrand_x gix = {.accel=accel, .spline=spline, .f=f, .privdat=privdat, 0, 0};
01733    gsl_function gsl_func = {.function = gsl_integrand_x_nofunc, .params=&gix};
01734    if(f != NULL) gsl_func.function = gsl_integrand_x_func;
01735    double err_estimate;
01736    GString* filename = g_string_new("");
01737    status = 0;
01738    for(z=0; z<d->N[0]; ++z) {
01739      gix.z = (z - d->N[2]/2)*d->dx[2];
01740      for(y=0; y<d->N[1]; ++y) {
01741        gix.y = (y - d->N[1]/2)*d->dx[1];
01742        index = z*d->N[1] + y;
01743        g_string_printf(filename, "x_integration_y_%d_z_%d.pdata", y, z);
01744        gix.outfile = fopen(filename->str, "w+");
01745        gix.iter = -1;
01746        /*\note The x coordinates are contiguous; if we get the address for x=0, just move to the next double to get x=1 and so on.  That's why this next line works*/
01747        gsl_spline_init(spline, coords, get_density_storage_at_c(0, y, z, d), d->N[0]);
01748        status |= gsl_integration_qag(&gsl_func, coords[0], coords[d->N[0]-1], abserr, relerr, MAX_GSL_INTEGRATION_INTERVALS, GSL_INTEG_GAUSS61, w, &(yzvals[index]), (x_error_estimate==NULL)?(&err_estimate):(&x_error_estimate[index]));
01749        fclose(gix.outfile);
01750      }
01751    }
01752    free(coords);
01753    gsl_spline_free(spline);
01754    if(status != 0) {
01755      free(yzvals);
01756      gsl_interp_accel_free(accel);
01757      gsl_spline_free(spline);
01758      free(coords);
01759      return nan("NaN");
01760    }
01761 
01762    /*Now do the y integration; we end up with a z array of values.*/
01763    coords = (double*)malloc(sizeof(double)*d->N[1]);
01764    double* zvals = (double*)malloc(sizeof(double)*d->N[1]);
01765    for(int y=0; y<d->N[1]; ++y) coords[y] = (y - d->N[1]/2)*d->dx[1];
01766    fprintf(stderr, "coords[0]=%g\tcoords[%d]=%g\n", coords[0], d->N[1]-1, coords[d->N[1]-1]);
01767    if((zvals == NULL) || (coords == NULL)){
01768      free(yzvals);
01769      gsl_interp_accel_free(accel);
01770      gsl_spline_free(spline);
01771      if(coords != NULL) free(coords);
01772      if(zvals != NULL) free(zvals);
01773      return nan("NaN");
01774    }
01775    spline =  gsl_spline_alloc(gsl_interp_cspline, d->N[1]);
01776    gsl_func.function = gsl_integrand_yz;
01777    for(int z=0; z<d->N[0]; ++z) {
01778      g_string_printf(filename, "y_integration_z_%d.pdata", z);
01779      gix.outfile = fopen(filename->str, "w+");
01780      gix.iter = -1;
01781      gsl_spline_init(spline, coords, &yzvals[z*d->N[1]], d->N[1]);
01782      status |= gsl_integration_qag(&gsl_func, coords[0], coords[d->N[0]-1], abserr, relerr, MAX_GSL_INTEGRATION_INTERVALS, GSL_INTEG_GAUSS61, w, zvals, (y_error_estimate==NULL)?(&err_estimate):(&y_error_estimate[z]));
01783      fclose(gix.outfile);
01784    }
01785    free(coords);
01786    free(yzvals);
01787    gsl_spline_free(spline);
01788    if(status != 0) {
01789      gsl_interp_accel_free(accel);
01790      gsl_spline_free(spline);
01791      free(coords);
01792      free(zvals);
01793      return nan("NaN");
01794    }
01795 
01796    /*Finally, do the z integration.*/
01797    coords = (double*)malloc(sizeof(double)*d->N[2]);
01798    for(int z=0; z<d->N[2]; ++z) coords[z] = (z - d->N[2]/2)*d->dx[2];
01799    fprintf(stderr, "coords[0]=%g\tcoords[%d]=%g\n", coords[0], d->N[2]-1, coords[d->N[2]-1]);
01800    if(coords == NULL){
01801      gsl_interp_accel_free(accel);
01802      gsl_spline_free(spline);
01803      free(zvals);
01804      if(coords != NULL) free(coords);
01805      return nan("NaN");
01806    }
01807    spline =  gsl_spline_alloc(gsl_interp_cspline, d->N[2]);
01808    gsl_spline_init(spline, coords, zvals, d->N[2]);
01809    double final_value = nan("NaN");
01810    g_string_printf(filename, "y_integration_z_%d.pdata", z);
01811    gix.outfile = fopen(filename->str, "w+");
01812    gix.iter = -1;
01813    status = gsl_integration_qag(&gsl_func, coords[0], coords[d->N[0]-1], abserr, relerr, MAX_GSL_INTEGRATION_INTERVALS, GSL_INTEG_GAUSS61, w, &final_value, (z_error_estimate==NULL)?(&err_estimate):(z_error_estimate));
01814    fclose(gix.outfile);
01815 
01816    gsl_interp_accel_free(accel);
01817    gsl_spline_free(spline);
01818    free(coords);
01819    free(zvals);
01820 
01821    if(status != 0) return nan("NaN");
01822    return final_value;
01823  }
01824 
01825 double density_integrate_sum(const struct density* d, double (*f)(double x, double y, double z, void* privdat), void* privdat) {
01826   double val;
01827   int x, y, z;
01828   double sum = 0;
01829   for(z=0; z<d->N[2]; ++z) {
01830     for(y=0; y<d->N[1]; ++y) {
01831       for(x=0; x<d->N[0]; ++x) {
01832   val = *get_density_storage_at_c_(x, y, z, d);
01833   if(f != NULL) {
01834     val *= f((x-d->N[0])*d->dx[0], (y-d->N[1])*d->dx[0], (z-d->N[2])*d->dx[0], privdat);
01835   }
01836   sum += val;
01837       }
01838     }
01839   }
01840   return sum;
01841 }
01842 
01843 double density_integrate_sum_parallel(const struct density* d, double (*f)(double x, double y, double z, void* privdat), void** privdat) {
01844   double val;
01845   int x, y, z;
01846   double sum = 0;
01847   #ifdef OPENMP
01848   #pragma omp parallel for private(x, y, z, val) reduction(+:sum)
01849   #endif
01850   for(z=0; z<d->N[2]; ++z) {
01851     for(y=0; y<d->N[1]; ++y) {
01852       for(x=0; x<d->N[0]; ++x) {
01853   val = *get_density_storage_at_c_(x, y, z, d);
01854   if(f != NULL) {
01855     if(privdat != NULL) {
01856       val *= f((x-d->N[0])*d->dx[0], (y-d->N[1])*d->dx[0], (z-d->N[2])*d->dx[0], privdat[
01857                              #ifdef OPENMP
01858                              omp_get_thread_num()
01859                              #else
01860                              0
01861                              #endif
01862 ]);
01863 
01864     }else{
01865       val *= f((x-d->N[0])*d->dx[0], (y-d->N[1])*d->dx[0], (z-d->N[2])*d->dx[0], NULL);
01866     }
01867   }
01868   sum += val;
01869       }
01870     }
01871   }
01872   return sum;
01873 }
01874 
01875 void write_density_line(enum coord axis, const int* gridsite, const struct density* d, char** filename, GError **err, GFile* location, char sepchar, const char* coord_units, const char* density_units) {
01876   /*If we're iterating on an index, go to the next loop unless the index is right*/
01877   GError *e = NULL;
01878   GFile* f;
01879   GString *s = g_string_new("line_");
01880   switch(axis) {
01881   case X:
01882     g_string_append_printf(s, "Y=%d_Z=%d.pdata", gridsite[1], gridsite[2]);
01883     break;
01884   case Y:
01885     g_string_append_printf(s, "X=%d_Z=%d.pdata", gridsite[0], gridsite[2]);
01886     break;
01887   case Z:
01888     g_string_append_printf(s, "X=%d_Y=%d.pdata", gridsite[0], gridsite[1]);
01889     break;
01890   }
01891   if(location == NULL) {
01892     f = g_file_new_for_path(s->str);
01893   }else{
01894     f = g_file_resolve_relative_path(location, s->str);
01895   }
01896   *filename = g_file_get_uri(f);
01897   //GFileIOStream *gfos = g_file_create_readwrite(f, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &e);
01898   GFileOutputStream *fos = g_file_replace(f, NULL, FALSE, 0, NULL, &e);
01899   if(e != NULL) {
01900     *err = e;
01901     return;
01902   }
01903   //GOutputStream *os =
01904   //g_io_stream_get_output_stream((GIOStream*)gfos);
01905   GDataOutputStream *dos = g_data_output_stream_new((GOutputStream*)fos);
01906   switch(axis) {
01907   case X:
01908     g_string_printf(s, "#X(%s)%c(%s)\n", coord_units, sepchar, density_units);
01909     break;
01910   case Y:
01911     g_string_printf(s, "#Y(%s)%c(%s)\n", coord_units, sepchar, density_units);
01912     break;
01913   case Z:
01914     g_string_printf(s, "#Z(%s)%c(%s)\n", coord_units, sepchar, density_units);
01915     break;
01916   }
01917   e=NULL;
01918   char *str;
01919   g_data_output_stream_put_string(dos, s->str, NULL, &e);
01920   if(e != NULL) {
01921     *err = e;
01922     g_string_free(s, TRUE);
01923     e=NULL;
01924     //g_io_stream_close((GIOStream*)gfos, NULL, &e);
01925     g_output_stream_close((GOutputStream*)fos, NULL, &e);
01926     if(e != NULL) {
01927       fprintf(stderr, "wavefunction::write_density_line: had an error (%s) while writing string (%s), but had another error (%s) while closing the file (%s)!\n", (*err)->message, s->str, e->message, str=g_file_get_uri(f));
01928       g_free(str);
01929     }
01930     return;
01931   }
01932   for(int k=0; k<d->N[2]; k++) {
01933     if(((axis == X) || (axis == Y)) && (k != gridsite[2])) continue;
01934     for(int j=0; j<d->N[1]; j++) {
01935       if(((axis == X) || (axis == Z)) && (j != gridsite[1])) continue;
01936       for(int i=0; i<d->N[0]; i++) {
01937   if(((axis == Z) || (axis == Y)) && (i != gridsite[0])) continue;
01938   e=NULL;
01939   switch(axis) {
01940   case X:
01941     g_string_printf(s, "%g%c%g\n", i*(d->dx[0]), sepchar, d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])]);
01942     break;
01943   case Y:
01944     g_string_printf(s, "%g%c%g\n", j*(d->dx[1]), sepchar, d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])]);
01945     break;
01946   case Z:
01947     g_string_printf(s, "%g%c%g\n", k*(d->dx[2]), sepchar, d->storage[get_density_storage_index(i, j, k, d->N[0], d->N[1])]);
01948     break;
01949   }
01950   g_data_output_stream_put_string(dos, s->str, NULL, &e);
01951   if(e != NULL) {
01952     *err = e;
01953     g_string_free(s, TRUE);
01954     e=NULL;
01955     //g_io_stream_close(os, NULL, &e);
01956     g_output_stream_close((GOutputStream*)fos, NULL, &e);
01957     if(e != NULL) {
01958       fprintf(stderr, "wavefunction::write_density_line: had an error (%s) while writing string (%s), but had another error (%s) while closing the file (%s)!\n", (*err)->message, s->str, e->message, str=g_file_get_uri(f));
01959       g_free(str);
01960     }
01961     return;
01962   }
01963       }
01964     }
01965   }
01966   //g_io_stream_close((GIOStream*)gfos, NULL, &e);
01967   g_output_stream_close((GOutputStream*)fos, NULL, &e);
01968   if(e != NULL) {
01969     *err = e;
01970   }
01971   g_string_free(s, TRUE);
01972 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines