funkalicious 0.1

function_parser.c

Go to the documentation of this file.
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 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines