funkalicious 0.1

density_1d.c

Go to the documentation of this file.
00001  /*
00002  *1D density routines
00003 
00004     Copyright (C) 2010 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     *
00020     */
00021 
00022 #include <stdlib.h>
00023 #include <math.h>
00024 #include <gsl/gsl_errno.h>
00025 #include <gsl/gsl_interp.h>
00026 #include <gsl/gsl_spline.h>
00027 #include <gsl/gsl_integration.h>
00028 #include <libpostproc/density_1d.h>
00029 
00030 //#define DEBUG_DENSITY_1D_C
00031 
00032 #define DENSITY_1D_GERROR_DOMAIN 3328
00033 
00034 void init_density_1d(struct density_1d* d, double initial_value) {
00035   for(int i=0; i<d->N; i++) {
00036     d->storage[i] = initial_value;
00037   }
00038 }
00039 
00040 void density_1d_mul_by_const(struct density_1d* d, double c) {
00041   for(int i=0; i<d->N; i++) {
00042     d->storage[i] *= c;
00043   }
00044 }
00045 
00046 struct density_1d* new_density_1d(int N, double dx, double initial_value) {
00047   struct density_1d *d = (struct density_1d*)malloc(sizeof(struct density_1d));
00048   if(d == NULL) return NULL;
00049   d->N = N;
00050   d->dx = dx;
00051   d->storage = (double*)malloc(sizeof(double)*N);
00052   if(d->storage == NULL) {
00053     free(d);
00054     return NULL;
00055   }
00056   init_density_1d(d, initial_value);
00057   return d;
00058 }
00059 
00060 struct density_1d* new_density_1d_copy(const struct density_1d* orig) {
00061   struct density_1d *d = (struct density_1d*)malloc(sizeof(struct density_1d));
00062   if(d == NULL) return NULL;
00063   d->N = orig->N;
00064   d->dx = orig->dx;
00065   d->storage = (double*)malloc(sizeof(double)*orig->N);
00066   if(d->storage == NULL) {
00067     free(d);
00068     return NULL;
00069   }
00070   for(int i=0; i<orig->N; i++) d->storage[i] = orig->storage[i];
00071   return d;
00072 }
00073 
00074 void free_density_1d(struct density_1d* d) {
00075   free(d->storage);
00076   free(d);
00077 }
00078 
00079 int op_density_1d_to_density_1d(struct density_1d* to, enum density_op op, const struct density_1d* from) {
00080   if(to->N != from->N) return 1;
00081   #ifdef OPENMP
00082   #pragma omp parallel for
00083   #endif
00084   for(int i=0; i<to->N; i++) {
00085     switch(op) {
00086     case ASSIGN:
00087       to->storage[i]
00088   += from->storage[i]
00089   ;
00090     break;
00091     case ADD_EQUALS:
00092       to->storage[i]
00093   += from->storage[i]
00094   ;
00095       break;
00096     case MINUS_EQUALS:
00097       to->storage[i]
00098   -= from->storage[i]
00099   ;
00100       break;
00101     case MUL_EQUALS:
00102       to->storage[i]
00103   *= from->storage[i]
00104   ;
00105       break;
00106     case DIV_EQUALS:
00107       to->storage[i]
00108   /= from->storage[i]
00109   ;
00110       break;
00111     }
00112   }
00113   return 0;
00114 }
00115  
00116 int op_density_1d_to_density_1d_cb(struct density_1d *restrict to, const struct density_1d *restrict from, void(*callback)(int X, unsigned N, double dx, double *restrict to, double from, void *restrict privdat), void *restrict privdat) {
00117   if(to->N != from->N) return 1;
00118   #ifdef OPENMP
00119   #pragma omp parallel for
00120   #endif
00121   for(int i=0; i<to->N; i++) {
00122     callback(i, to->N, to->dx, &(to->storage[i]), from->storage[i], privdat);
00123   }
00124   return 0;
00125 }
00126 
00127 double density_1d_sum(const struct density_1d* d, enum density_1d_distribution_hint hint) {
00128   double total = 0;
00129   unsigned i;
00130   switch(hint) {
00131   case CONSTANT:
00132     for(i=0; i<d->N; i++) total += d->storage[i];
00133     break;
00134   case CENTERED:
00135     for(i=0; i<(d->N - (d->N%2))/2; i++) {
00136       total += d->storage[i] + d->storage[d->N-1-i];
00137     }
00138     if((d->N%2) != 0) total += d->storage[(d->N - (d->N%2))/2];
00139     break;
00140   case ANTICENTERED:
00141     if((d->N%2) != 0) total = d->storage[(d->N - (d->N%2))/2];
00142     /*The -1 is because (N-N%2)/2 is the *center* point (if odd; if even, it is the last point on the opposite side!)*/
00143     for(i=((d->N - (d->N%2))/2-1); i>=0; i--) {
00144       total += d->storage[i] + d->storage[d->N-1-i];
00145     }
00146     break;
00147   default:
00148     return nan("NaN");
00149   }
00150   return total;
00151 }
00152 
00153 struct density_1d_params {
00154   gsl_spline *d;
00155   gsl_interp_accel *d_acc;
00156 #ifdef DEBUG_DENSITY_1D_C
00157   FILE* file;
00158   long unsigned count;
00159 #endif
00160 };
00161 
00162 static double integrand(double x, void *params) {
00163   struct density_1d_params* p = (struct density_1d_params*)params;
00164   double val=gsl_spline_eval(p->d, x, p->d_acc);
00165   #ifdef DEBUG_DENSITY_1D_C
00166   fprintf(p->file, "%lu\t%g\t%g\n", p->count++, x, val);
00167   #endif
00168   return val;
00169 }
00170 
00171 double density_1d_integrate_density(const struct density_1d* d, double abserr, double relerr, double* ierr, GError **e, int filename_index) {
00172   gsl_interp_accel *density_acc = gsl_interp_accel_alloc();
00173   /*Akima, so that it can cope with dropoffs.*/
00174   double* x = (double*)malloc(d->N*sizeof(double));
00175   if(x == NULL) {
00176     *e = g_error_new(DENSITY_1D_GERROR_DOMAIN, 100, "funkalicious::libpostproc::density_1d.c::density_1d_integrate_density: Failed to allocate array of x values");
00177     return nan("NaN");
00178   }
00179   for(unsigned i=0; i<d->N; i++) x[i] = i*(d->dx);
00180   gsl_spline *density = gsl_spline_alloc(gsl_interp_akima, d->N);
00181   gsl_spline_init(density, x, d->storage, d->N);
00182   free(x);
00183   struct density_1d_params ig = {
00184     .d = density, 
00185     .d_acc = density_acc
00186     #ifdef DEBUG_DENSITY_1D_C
00187     ,
00188     .file = NULL,
00189     .count = 0
00190     #endif
00191   };
00192   gsl_function gsl_func = {
00193     .function = &integrand,
00194     .params = &ig
00195   };
00196   double total;
00197   int status=0;
00198   gsl_integration_workspace *w = gsl_integration_workspace_alloc(4*d->N);
00199   double start=0, end=d->N-1;
00200   for(unsigned i=0; i<(d->N+1); i++) {
00201     /*fprintf(stderr, "start: %u->%g\n", i, d->storage[i]);*/
00202     /*If we hit the end, there's no charge in the structure!*/
00203     if(i == d->N) return 0;
00204     if(d->storage[i] != 0) {
00205       if(i == 0) {
00206   start = 0;
00207       }else{
00208   start = (i-1)*d->dx;
00209       }
00210       break;
00211     }
00212   }
00213   for(unsigned i=0; i<(d->N+1); i++) {
00214     /*fprintf(stderr, "end: %u->%g\n", i, d->storage[i]);*/
00215     if(d->storage[d->N-1-i] != 0) {
00216       if(i==0) {
00217   end = (d->N-1)*d->dx;
00218       }else{  
00219   end = (d->N-i)*d->dx;
00220       }
00221       break;
00222     }
00223   }
00224   /*fprintf(stderr, "start=%g end=%g\n", start, end);*/
00225   #ifdef DEBUG_DENSITY_1D_C
00226   char fn[2048];
00227   sprintf(fn, "density_1d_integrand_log_%d.pdata", filename_index);
00228   ig.file = fopen(fn, "w");
00229   ig.count = 0;
00230   #endif
00231   gsl_integration_qag(&gsl_func, start, end, abserr, relerr, 4*d->N, GSL_INTEG_GAUSS61, w, &total, ierr);
00232   #ifdef DEBUG_DENSITY_1D_C
00233   fclose(ig.file);
00234   #endif
00235   if(status != 0) {
00236     *e = g_error_new(DENSITY_1D_GERROR_DOMAIN, status, "funkalicious::libpostproc::density_1d.c::density_1d_integrate_density: Got error (status=%d) while integrating density to find total density: %s", status, gsl_strerror(status));
00237   }
00238   gsl_integration_workspace_free(w);
00239   gsl_spline_free(density);
00240   gsl_interp_accel_free(density_acc);
00241   return total;
00242 }
00243 
00244 
00245 void density_1d_add_const(struct density_1d* d, double c) {
00246   #ifdef OPENMP
00247   #pragma omp parallel for
00248   #endif
00249   for(long unsigned i=0; i<d->N; i++) d->storage[i] += c;
00250 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines