|
funkalicious 0.1
|
00001 /* 00002 *function_parser 00003 *parses the wavefunctions from Craig Pryor's dotcode. 00004 n 00005 Copyright (C) 2006 Joseph Pingenot 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2 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 General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software 00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00020 00021 */ 00022 00023 #include <sys/stat.h> 00024 #include <stdlib.h> 00025 #include <fcntl.h> 00026 #include <unistd.h> 00027 #include <errno.h> 00028 #include <string.h> 00029 #include <stdio.h> 00030 #include "function_parser.h" 00031 #include "config.h" 00032 #include "common.h" 00033 00034 #define FUNCTION_PARSER_GERROR_DOMAIN 5031 00035 00036 /*If the "File" is a directory, we will tack this on to the end.*/ 00037 #define FILE_TO_APPEND ".psi.dat" 00038 00039 /*For efficiency, we read in some number of points at a time. 00040 *4 sets of 8 bands 00041 *NOTE: the buffer size MUST end up greater than or equal to the header size! 00042 */ 00043 #define BUFFERED_POINTS 32 00044 /*NOTE: this should have 8, but may in the future have more or less. 00045 * We use this number elsewhere, so it's size of a single band at a single 00046 * point. 00047 */ 00048 #define POINT_SIZE (sizeof(double)*2) 00049 #define HEADER_SIZE (12+1+3+4*sizeof(int)+4*sizeof(double)) 00050 /*Don't forget we have 2 doubles: real and im parts of wavefunc*/ 00051 /*Assume 8 points.*/ 00052 #define DATA_BUFFER_SIZE (BUFFERED_POINTS*POINT_SIZE*8) 00053 00054 /*Helper functions: update band, x, y, z if needed.*/ 00055 void increment_y(int *y, int *z, struct wavefunc_header *header) { 00056 (*y)++; 00057 if((*y) >= header->Ny) { 00058 (*y)=0; 00059 (*z)++; 00060 /*We might want to warn *at* Nz at some point in the future. 00061 *Right now, we increment before we hit solid EOF (0 bytes returned) 00062 * so we will end up getting to z = Nz. More than that, though, means 00063 * the file's broke. 00064 */ 00065 if((*z) > header->Nz) { 00066 fprintf(stderr, "WARNING: increment_y: incremented z to %d, but Nz is %d! This is a corrupted file!\n", *z, header->Nz); 00067 } 00068 }else{ 00069 } 00070 } 00071 void increment_x(int *x, int *y, int *z, struct wavefunc_header *header) { 00072 (*x)++; 00073 if((*x) >= header->Nx) { 00074 (*x) = 0; 00075 increment_y(y, z, header); 00076 }else{ 00077 } 00078 } 00079 void increment_band(int *band, int *x, int *y, int *z, struct wavefunc_header *header) { 00080 (*band)++; 00081 if((*band) >= header->Nc) { 00082 (*band) = 0; 00083 increment_x(x, y, z, header); 00084 }else{ 00085 } 00086 } 00087 00088 00089 /*Documented in function_parser.h*/ 00090 int read_wavefunction(char* filename, struct wavefunc_header *header, double **matrix, int *err) { 00091 fprintf(stderr, "Got filename %s\n", filename); 00092 GFile* f = g_file_new_for_commandline_arg(filename); 00093 GError *e = NULL; 00094 int arr; 00095 arr = read_wavefunction_gfile(f, header, matrix, &e); 00096 if(e != NULL) { 00097 *err = e->code; 00098 fprintf(stderr, "function_parser::read_wavefunction(char*)<legacy>: Got error %d; message=%s\n", e->code, e->message); 00099 free(e); 00100 } 00101 return arr; 00102 } 00103 00104 int read_wavefunction_gfile(GFile* f, struct wavefunc_header *header, double **matrix, GError **err) { 00105 GError *e=NULL; 00106 GFile *psifile = g_file_get_child(f, FILE_TO_APPEND); 00107 GFileInputStream *infile = g_file_read(psifile, NULL, &e); 00108 if(e!= NULL) {*err = e; return -3;} 00109 int count; 00110 GError *errn; 00111 char buffer[DATA_BUFFER_SIZE]; 00112 int n_pts; 00113 int band; 00114 /*We allocate the matrix locally, so that we don't stomp on anything 00115 *unnecessarily. Kinda overkill, but whatever.*/ 00116 double *mtrix; 00117 int pt; 00118 int ierr; 00119 char *bptr; 00120 int x, y, z; 00121 if((header == NULL) || (f == NULL)) { 00122 *err = g_error_new(FUNCTION_PARSER_GERROR_DOMAIN, 0, "function_parser::read_wavefunction_gfile: header and/or filename and/or matrix was NULL!"); 00123 if(header == NULL) return -1; 00124 if(f == NULL) return -2; 00125 if(matrix == NULL) return -5; 00126 } 00127 if((count = resilient_read(infile, buffer, HEADER_SIZE, &errn)) < HEADER_SIZE) { 00128 #ifdef DEBUG3 00129 fprintf(stderr, "INFO: read_wavefunction: read in only %d bytes, not %lu (when reading header)\n", count, (long unsigned int)HEADER_SIZE); 00130 #endif 00131 *err = errn; 00132 return -4; 00133 } 00134 if((ierr = parse_header(header, buffer)) < 0) { 00135 *err = g_error_new(FUNCTION_PARSER_GERROR_DOMAIN, ierr, "function_parser::read_wavefunction_gfile: Failed to parse header: %d", ierr); 00136 return -7; 00137 } 00138 00139 /*Allocate the matrix storage*/ 00140 if((mtrix = malloc(2*header->Nc*header->Nx*header->Ny*header->Nz*sizeof(double))) == NULL) { 00141 *err = g_error_new(FUNCTION_PARSER_GERROR_DOMAIN, 0, "function_parser::read_wavefunction_gfile: Failed to allocate storage for matrix"); 00142 return -8; 00143 } 00144 /*FROM HERE ON OUT, WE MUST FREE MATRIX STORAGE IF WE'RE FAILING!*/ 00145 band=x=y=z=0; 00146 while(((count = resilient_read(infile, buffer, DATA_BUFFER_SIZE, &errn)) != 0) && (count != -1)) { 00147 #ifdef DEBUG3 00148 fprintf(stderr, "read in %d bytes, err=%d (%s)\n", count, (errn!=NULL)?(errn->code):0, (errn!=NULL)?(errn->message):""); 00149 #endif 00150 /*We read in buffers!*/ 00151 if((count % (POINT_SIZE*header->Nc)) != 0) { 00152 fprintf(stderr, "WARNING: read_wavefunction: did not read in an full point for some reason! Ignoring extras\n"); 00153 } 00154 n_pts = (count - (count%(POINT_SIZE*header->Nc)))/(POINT_SIZE*header->Nc); 00155 #ifdef DEBUG3 00156 fprintf(stderr, "buffer holds %d bytes, n_pts=%d (n_pts*(POINT_SIZE=%lu)*(Nc=%d) = %lu)\n", count, n_pts, (long unsigned int)POINT_SIZE, header->Nc, (long unsigned int)n_pts*POINT_SIZE*header->Nc); 00157 #endif 00158 /*point bptr at the start of the buffer.*/ 00159 bptr = buffer; 00160 /*8 complex numbers per point (8 bands)*/ 00161 n_pts *= header->Nc; 00162 for(pt=0; pt<n_pts; ++pt) { 00163 /*Re*/ 00164 mtrix[band*2 + x*header->Nc*2 + y*header->Nx*header->Nc*2 + z*header->Ny*header->Nx*header->Nc*2] = get_binary_double(header->little_endian, bptr); 00165 /*update bptr.*/ 00166 bptr += sizeof(double); 00167 /*Im*/ 00168 mtrix[1+band*2 + x*header->Nc*2 + y*header->Nx*header->Nc*2 + z*header->Ny*header->Nx*header->Nc*2] = get_binary_double(header->little_endian, bptr); 00169 bptr += sizeof(double); 00170 #ifdef DEBUG3 00171 fprintf(stderr, "band=%d x=%d y=%d z=%d: Re=%g Im=%g\n", band, x, y, z, mtrix[band*2 + x*header->Nc*2 + y*header->Nx*header->Nc*2 + z*header->Ny*header->Nx*header->Nc*2], mtrix[1+band*2 + x*header->Nc*2 + y*header->Nx*header->Nc*2 + z*header->Ny*header->Nx*header->Nc*2]); 00172 #endif 00173 /*Update band, x, y, z 00174 *NOTE that increment_band increments x, y, and z if needed. 00175 */ 00176 increment_band(&band, &x, &y, &z, header); 00177 } 00178 } 00179 #ifdef DEBUG3 00180 fprintf(stderr, "read in %d bytes, err=%d (%s)\n", count, (errn!=NULL)?(errn->code):0, (errn!=NULL)?(errn->message):""); 00181 #endif 00182 /*Set matrix to the temporary matrix.*/ 00183 *matrix = mtrix; 00184 /*Return. Success!*/ 00185 *err = 0; 00186 return 0; 00187 } 00188 00189 /*Reads in all of the data, despite interruptions and junk. 00190 *ARGS: 00191 * if GFileInputStream* input file stream 00192 * buffer place to store final data read in 00193 * count number of chars to read 00194 * err pointer to pointer to GError, for permanent errors 00195 *RETURNS: 00196 * if successful, number of bytes read and err is set to 0. 00197 * if failed, -1 and err is set to errno. 00198 * if partially successful, number of bytes read and err is set to errno. 00199 *NOTES: 00200 * * "partially successful" means that some data was read before a fatal error 00201 * occurred. 00202 * * You almost certainly want to check errno if you care that a fatal error 00203 * occurred. 00204 * * Will set *err to NULL if we have success. 00205 */ 00206 int resilient_read(GFileInputStream *is, char *buffer, int count, GError **err) { 00207 int in; 00208 /*Start off at the start of the buffer.*/ 00209 char *buff=buffer; 00210 int to_read=count; 00211 GError *e = NULL; 00212 /*Read it right into buffer. We're just gonna copy it over anyway.*/ 00213 while((to_read > 0) && ((in = g_input_stream_read((GInputStream*)is, buff, to_read, NULL, &e)) < to_read)) { 00214 if(in > 0) { 00215 /*We read in data; just update where we are and how much we need to read.*/ 00216 buff += in; 00217 to_read -= in; 00218 continue; 00219 } 00220 if(e != NULL) { 00221 /*Permanent error.*/ 00222 *err=e; 00223 if((count - to_read) > 0) { 00224 /*We actaully read in data before error cropped up.*/ 00225 return count - to_read; 00226 }else{ 00227 /*No data, just error.*/ 00228 return -1; 00229 } 00230 } 00231 if(in == 0) { 00232 /*we hit EOF.*/ 00233 *err = NULL; 00234 /*If we started at EOF, to_read will be count, so we'll return 0. 00235 *Else, we will return the number of bytes read before EOF.*/ 00236 return count - to_read; 00237 } 00238 e = NULL; 00239 } 00240 /*If we made it here, we just read in all of the data in one go.*/ 00241 *err = NULL; 00242 return count; 00243 } 00244 00245 /*Fills in header struct from a buffer containing header info. 00246 *ARGS: 00247 * header pointer to header struct to fill in 00248 * buff buffer containing header data. 00249 *RETURNS: 00250 * 0 if successful 00251 * -1 if bad format string. 00252 * -2 if bad endian value (accepted is 'l' and 'b') 00253 * -3 if bad format string (i.e. doesn't start with 'v' and/or end 00254 * with '\n') 00255 * -4 if we don't understand this version. 00256 */ 00257 int parse_header(struct wavefunc_header *header, char *buff) { 00258 char *b=buff; 00259 /*First, we fill in the format and endianness info, since 00260 * we will need for converting the ints and things. 00261 */ 00262 memcpy(&(header->format[0]), b, 12); 00263 header->format[12]='\0'; 00264 b += 12; 00265 header->endian = b[0]; 00266 b++; 00267 header->version_string[0]=b[0]; 00268 header->version_string[1]=b[1]; 00269 header->version_string[2]=b[2]; 00270 header->version_string[3]='\0'; 00271 b += 3; 00272 /*Checks and fill in derive info (e.g. endianness int)*/ 00273 if(strcmp(header->format, "CompWaveFxnb") != 0) return -1; 00274 if(header->endian == 'b') { 00275 header->little_endian=0; 00276 }else if(header->endian == 'l') { 00277 header->little_endian=1; 00278 }else{ 00279 return -2; 00280 } 00281 if(header->version_string[0] != 'v') return -3; 00282 if(header->version_string[1] != '2') return -4; 00283 if(header->version_string[2] != '\n') return -3; 00284 else header->version = 2; 00285 00286 /*Now fetch doubles and ints.*/ 00287 header->Nc = get_binary_int(header->little_endian, b); 00288 b += FILE_SIZE_INT; 00289 header->Nx = get_binary_int(header->little_endian, b); 00290 b += FILE_SIZE_INT; 00291 header->Ny = get_binary_int(header->little_endian, b); 00292 b += FILE_SIZE_INT; 00293 header->Nz = get_binary_int(header->little_endian, b); 00294 b += FILE_SIZE_INT; 00295 00296 header->dx = get_binary_double(header->little_endian, b); 00297 b += FILE_SIZE_DOUBLE; 00298 header->dy = get_binary_double(header->little_endian, b); 00299 b += FILE_SIZE_DOUBLE; 00300 header->dz = get_binary_double(header->little_endian, b); 00301 b += FILE_SIZE_DOUBLE; 00302 header->energy = get_binary_double(header->little_endian, b); 00303 b += FILE_SIZE_DOUBLE; 00304 00305 return 0; 00306 } 00307 00308 /*Reads in a binary double from a buffer 00309 *ARGS: 00310 * le buffer is in little endian format. 00311 * buffer buffer containing the data to be read. 00312 *RETURNS: 00313 * the number stored in buffer 00314 *NOTES: 00315 * If you pass too few bytes, you're in trouble! 00316 */ 00317 double get_binary_double(int le, char *buffer) { 00318 double value; 00319 char *ptr = (char*)(&value); 00320 int i, j; 00321 #ifdef DEBUG2 00322 fprintf(stderr, "INFO: get_binary_double: le=%d, WORDS_BIGENDIAN=%d\n", le, 00323 #ifdef WORDS_BIGENDIAN 00324 1 00325 #else 00326 0 00327 #endif 00328 ); 00329 #endif 00330 #ifdef WORDS_BIGENDIAN 00331 if(!le) { 00332 #else 00333 if(le) { 00334 #endif 00335 /*Same endian-ness. No conversion needed.*/ 00336 #ifdef DEBUG2 00337 fprintf(stderr, "INFO: get_binary_double: no need to convert endianness.\n"); 00338 #endif 00339 memcpy(ptr, buffer, FILE_SIZE_DOUBLE); 00340 }else{ 00341 /*They're different. We must bit-flip.*/ 00342 #ifdef DEBUG2 00343 fprintf(stderr, "INFO: get_binary_double: MUST convert endianness.\n"); 00344 #endif 00345 for(i=0, j=(FILE_SIZE_DOUBLE-1); i<FILE_SIZE_DOUBLE; ++i, --j) { 00346 ptr[i]=buffer[j]; 00347 } 00348 } 00349 return value; 00350 } 00351 00352 /*Reads in a binary int from a buffer 00353 *ARGS: 00354 * le buffer is in little endian format. 00355 * buffer buffer containing the data to be read. 00356 *RETURNS: 00357 * the number stored in buffer 00358 *NOTES: 00359 * If you pass too few bytes, you're in trouble! 00360 */ 00361 int get_binary_int(int le, char *buffer) { 00362 int value; 00363 char *ptr = (char*)(&value); 00364 int i, j; 00365 #ifdef DEBUG2 00366 fprintf(stderr, "INFO: get_binary_int: le=%d, WORDS_BIGENDIAN=%d\n", le, 00367 #ifdef WORDS_BIGENDIAN 00368 1 00369 #else 00370 0 00371 #endif 00372 ); 00373 #endif 00374 #ifdef WORDS_BIGENDIAN 00375 if(!le) { 00376 #else 00377 if(le) { 00378 #endif 00379 /*Same endian-ness. No conversion needed.*/ 00380 #ifdef DEBUG2 00381 fprintf(stderr, "INFO: get_binary_int: no need to convert endianness.\n"); 00382 #endif 00383 memcpy(ptr, buffer, FILE_SIZE_INT); 00384 }else{ 00385 /*They're different. We must bit-flip.*/ 00386 #ifdef DEBUG2 00387 fprintf(stderr, "INFO: get_binary_int: MUST convert endianness.\n"); 00388 #endif 00389 for(i=0, j=(FILE_SIZE_INT-1); i<FILE_SIZE_INT; ++i, --j) { 00390 ptr[i]=buffer[j]; 00391 } 00392 } 00393 return value; 00394 }