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