source: anuga_core/source/anuga/shallow_water/urs_ext.c @ 5477

Last change on this file since 5477 was 5477, checked in by jakeman, 14 years ago

cleaned up urs_ext.c. Currently failing to read fros and lros correctly in in boxing_day mux2 files

File size: 16.8 KB
Line 
1/*
2gcc -fPIC -c urs_ext.c -I/usr/include/python2.5 -o urs_ext.o -Wall -O
3gcc -shared urs_ext.o  -o urs_ext.so
4*/
5#include "Python.h"
6#include "Numeric/arrayobject.h"
7#include "math.h"
8#include <stdio.h>
9#include <float.h>
10#include <time.h>
11#include "structure.h"
12
13#define MAX_FILE_NAME_LENGTH 128
14#define NODATA 99.0
15#define EPSILON  0.00001
16
17#define DEBUG 0
18
19#define POFFSET 5 //Number of site_params
20
21void fillDataArray(int, int, int, int, int *, int *, float *, int *, int *, float *);
22long getNumData(int*, int*, int);
23char isdata(float);
24void wrttxt(char *, float, int, float *, float, float, float, float, float, int, int, int);
25PyArrayObject *_read_mux2(int, char **, float *, double *, PyObject *, int);
26
27PyObject *read_mux2(PyObject *self, PyObject *args){
28/*Read in mux 2 file
29   
30    Python call:
31    read_mux2(numSrc,filenames,weights,file_params,permutation,verbose)
32
33    NOTE:
34    A Python int is equivalent to a C long
35    A Python double corresponds to a C double
36*/
37  PyObject *filenames;
38  PyArrayObject *pyweights,*file_params;
39  PyArrayObject *sts_data;
40  PyObject *permutation;
41  PyObject *fname;
42
43  char **muxFileNameArray;
44  float *weights;
45  long numSrc;
46  long verbose;
47
48  int nsta0;
49  int nt;
50  double dt;
51  int i;
52 
53  // Convert Python arguments to C
54  if (!PyArg_ParseTuple(args, "iOOOOi",
55                        &numSrc,&filenames,&pyweights,&file_params,&permutation,&verbose)) {                   
56                       
57    PyErr_SetString(PyExc_RuntimeError, 
58                    "Input arguments to read_mux2 failed");
59    return NULL;
60  }
61
62  if(!PyList_Check(filenames)) {
63    PyErr_SetString(PyExc_TypeError, "get_first_elem expects a list");
64    return NULL;
65  }
66
67  if(PyList_Size(filenames) == 0){
68    PyErr_SetString(PyExc_ValueError, "empty lists not allowed");
69    return NULL;
70  }
71
72  if (pyweights->nd != 1 || pyweights->descr->type_num != PyArray_DOUBLE) {
73    PyErr_SetString(PyExc_ValueError,
74                    "pyweights must be one-dimensional and of type double");
75    return NULL; 
76  }
77
78  if(PyList_Size(filenames) != pyweights->dimensions[0]){
79      PyErr_SetString(PyExc_ValueError, "Must specify one weight for each filename");
80      return NULL;
81  }
82
83  muxFileNameArray = (char **) malloc((int)numSrc*sizeof(char *));
84  if (muxFileNameArray == NULL) {
85     PyErr_SetString(PyExc_RuntimeError,"Memory for muxFileNameArray could not be allocated");
86     return NULL;
87  }
88  for (i=0;i<PyList_Size(filenames);i++){
89    muxFileNameArray[i] = (char *) malloc((MAX_FILE_NAME_LENGTH+1)*sizeof(char));
90    if (muxFileNameArray[i] == NULL) {
91      PyErr_SetString(PyExc_RuntimeError,"Memory for muxFileNameArray could not be allocated");
92      return NULL;
93    }
94    fname=PyList_GetItem(filenames, i);
95    if (!PyString_Check(fname)) {
96      PyErr_SetString(PyExc_ValueError, "filename not a string");
97      return NULL;
98    }
99    muxFileNameArray[i]=PyString_AsString(fname);
100  }
101
102  if (file_params->nd != 1 || file_params->descr->type_num != PyArray_DOUBLE) {
103    PyErr_SetString(PyExc_ValueError,
104                    "file_params must be one-dimensional and of type double");
105    return NULL; 
106  }
107
108  // Create array for weights which are passed to read_mux2
109  weights = (float *) malloc((int)numSrc*sizeof(float));
110  for (i=0;i<(int)numSrc;i++){
111    weights[i]=(float)(*(double *)(pyweights->data+i*pyweights->strides[0]));
112  }
113
114  // Read in mux2 data from file
115  sts_data=_read_mux2((int)numSrc,muxFileNameArray,weights,(double*)file_params->data,permutation,(int)verbose);
116
117  // Allocate space for return vector
118  nsta0=(int)*(double *) (file_params -> data+0*file_params->strides[0]);
119  dt=*(double *) (file_params -> data+1*file_params->strides[0]);
120  nt=(int)*(double *) (file_params -> data+2*file_params->strides[0]);
121
122  free(weights);
123  free(muxFileNameArray);
124  return  PyArray_Return(sts_data);
125
126}
127
128PyArrayObject *_read_mux2(int numSrc, char **muxFileNameArray, float *weights, double *params, PyObject *permutation, int verbose)
129{
130   FILE *fp;
131   int nsta, nsta0, i, j, t, isrc, ista, N;
132   struct tgsrwg *mytgs, *mytgs0;
133   char *muxFileName;                                                                 
134   int istart, istop;
135   int *fros, *lros;
136   char susMuxFileName;
137   float *muxData;
138   long numData;
139
140   int start_tstep;
141   int finish_tstep;
142   int num_ts;
143   int dimensions[2];
144   int len_sts_data;
145   float *temp_sts_data;
146
147   PyArrayObject *sts_data;
148   
149   int permuation_dimensions[1];
150   PyArrayObject *permutation_array;
151   
152   long int offset;   
153   
154   /* Check that the input files have mux2 extension*/
155   susMuxFileName=0;
156   for(isrc=0;isrc<numSrc;isrc++)
157     { 
158       muxFileName=muxFileNameArray[isrc];
159       if(!susMuxFileName && strcmp(muxFileName+strlen(muxFileName)-4,"mux2")!=0){
160         susMuxFileName=1;
161       }
162     }
163   
164   if(susMuxFileName)
165   {
166      printf("\n**************************************************************************\n");
167      printf("   WARNING: This program operates only on multiplexed files in mux2 format\n"); 
168      printf("   At least one input file name does not end with mux2\n");
169      printf("   Check your results carefully!\n");
170      printf("**************************************************************************\n\n");
171   }   
172                     
173   if (verbose){
174     printf("Reading mux header information\n");
175   }
176   
177   /* Open the first muxfile */
178   if((fp=fopen(muxFileNameArray[0],"r"))==NULL){
179     fprintf(stderr,"Cannot open file %s\n", muxFileNameArray[0]);
180     PyErr_SetString(PyExc_RuntimeError,"");
181     return NULL; 
182   }
183 
184   /* Read in the header */
185   /* First read the number of stations*/   
186   fread(&nsta0,sizeof(int),1,fp);
187   
188   /*now allocate space for, and read in, the structures for each station*/
189   mytgs0 = (struct tgsrwg *) malloc(nsta0*sizeof(struct tgsrwg));
190   fread(&mytgs0[0], nsta0*sizeof(struct tgsrwg), 1, fp);
191
192   /*make an array to hold the start and stop steps for each station for each
193     source*/   
194   fros = (int *) malloc(nsta0*numSrc*sizeof(int));
195   lros = (int *) malloc(nsta0*numSrc*sizeof(int));
196   
197   /* read the start and stop steps for source 0 into the array */   
198   fread(fros,nsta0*sizeof(int),1,fp);
199   fread(lros,nsta0*sizeof(int),1,fp);
200
201   /* compute the size of the data block for source 0 */   
202   numData = getNumData(fros, lros, nsta0);
203   num_ts = mytgs0[0].nt;
204   
205   /* Burbidge: Added a sanity check here */
206   if (numData < 0) {
207     fprintf(stderr,"Size of data block appears to be negative!\n");
208     PyErr_SetString(PyExc_RuntimeError,"");
209     return NULL; 
210   }
211   fclose(fp); 
212
213   // Allocate header array for each remaining source file.
214   if(numSrc > 1){
215      /* allocate space for tgsrwg for the other sources */
216      mytgs = (struct tgsrwg *)malloc( nsta0*sizeof(struct tgsrwg) );
217   } else {
218     /* FIXME (JJ): What should happen in case the are no source files?*/
219     /* If we exit here, tests will break */       
220   }
221   
222   /* loop over remaining sources and read headers */
223   for(isrc=1; isrc<numSrc; isrc++){
224     muxFileName = muxFileNameArray[isrc];
225     
226     /* open the mux file */
227     if((fp=fopen(muxFileName,"r"))==NULL)
228       {
229         fprintf(stderr, "cannot open file %s\n", muxFileName);
230         PyErr_SetString(PyExc_RuntimeError,"");
231         return NULL; 
232       }
233     
234     /* check that the mux files are compatible */     
235     fread(&nsta,sizeof(int),1,fp);
236     if(nsta != nsta0){
237       fprintf(stderr,"%s has different number of stations to %s\n", muxFileName, muxFileNameArray[0]);
238       PyErr_SetString(PyExc_RuntimeError,"");
239       fclose(fp);
240       return NULL; 
241     }
242     fread(&mytgs[0], nsta*sizeof(struct tgsrwg), 1, fp);
243     for(ista=0; ista < nsta; ista++){
244       if(mytgs[ista].dt != mytgs0[ista].dt){
245         fprintf(stderr,"%s has different sampling rate to %s\n", muxFileName, muxFileNameArray[0]);
246         fclose(fp);
247         return NULL;               
248       }   
249       if(mytgs[ista].nt != num_ts){
250         fprintf(stderr,"%s has different series length to %s\n", muxFileName, muxFileNameArray[0]);
251         PyErr_SetString(PyExc_RuntimeError,"");
252         fclose(fp);
253         return NULL;             
254       }
255     }
256
257      /* read the start and stop times for this source */
258      fread(fros+isrc*nsta0,nsta0*sizeof(int),1,fp);
259      fread(lros+isrc*nsta0,nsta0*sizeof(int),1,fp);
260     
261      /* compute the size of the data block for this source */
262      numData = getNumData(fros+isrc*nsta0, lros+isrc*nsta0, nsta0);
263
264      if (numData < 0){
265          fprintf(stderr,"Size of data block appears to be negative!\n");
266          PyErr_SetString(PyExc_RuntimeError,"");
267          return NULL;
268      }
269      fclose(fp);             
270   }
271
272   for (i=0;i<nsta0*numSrc;i++){
273       printf("%d, fros %d\n",i,fros[i]);
274       printf("%d, lros %d\n",i,lros[i]);
275   }
276
277   if (permutation == Py_None){
278       // if no permutation is specified return the times series of all the gauges in the mux file
279       permuation_dimensions[0]=nsta0;
280       permutation_array=(PyArrayObject *) PyArray_FromDims(1, permuation_dimensions, PyArray_INT);
281       for (ista=0; ista<nsta0; ista++){
282           *(long *) (permutation_array -> data+ista*permutation_array->strides[0])=ista;
283       } 
284   }else{
285       // Specifies the gauge numbers that for which data is to be extracted
286       permutation_array=(PyArrayObject *) PyArray_ContiguousFromObject(permutation,PyArray_INT,1,1);
287       N = permutation_array->dimensions[0]; //FIXME: this is overwritten below
288       for (ista=0; ista<N; ista++){
289           if ((int)*(long *) (permutation_array -> data+ista*permutation_array->strides[0])>=nsta0){
290               printf("Maximum index = %d, you had %d\n",nsta0-1,(int)*(long *) (permutation_array -> data+ista*permutation_array->strides[0]));
291               PyErr_SetString(PyExc_RuntimeError,"The permutation specified is out of bounds");
292               return NULL;
293           }
294       }
295   }
296   if(permutation_array == NULL){
297     PyErr_SetString(PyExc_RuntimeError,"Memory for permutation_array array could not be allocated");
298     return NULL;
299   }
300
301   N = permutation_array->dimensions[0];
302   
303   params[0]=(double)N;
304   params[1]=(double)mytgs0[0].dt;
305   params[2]=(double)num_ts;
306 
307   
308   // Find min and max start times of all gauges
309   start_tstep=num_ts+1;
310   finish_tstep=-1;
311   for (i=0;i<N;i++){
312       ista = *(long *) (permutation_array -> data+i*permutation_array->strides[0]); 
313       if (fros[ista]< start_tstep){
314           start_tstep=fros[ista];
315       }
316       if (lros[0+nsta0*ista] > finish_tstep){
317           finish_tstep=lros[ista]; 
318       }
319   }
320   
321   if ((start_tstep>num_ts) | (finish_tstep < 0)){
322       printf("s=%d,f=%d,num_ts=%d\n",start_tstep,finish_tstep,num_ts);
323     PyErr_SetString(PyExc_RuntimeError,"Gauge data has incorrect start and finsh times");
324     return NULL;
325   }
326   
327   if (start_tstep>=finish_tstep){
328     PyErr_SetString(PyExc_RuntimeError,"Gauge data has non-postive_length");
329     return NULL;
330   }
331   
332   /* Make array(s) to hold the demuxed data */
333   len_sts_data=num_ts+POFFSET;
334   dimensions[0]=N;
335   dimensions[1]=len_sts_data;
336   sts_data = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
337   if(sts_data == NULL){
338    PyErr_SetString(PyExc_RuntimeError,"Memory for pydata array could not be allocated");
339    return NULL;
340   }
341   
342   /* Initialise sts data to zero */
343   for(i=0; i<N; i++){ 
344     ista = *(long *) (permutation_array -> data+i*permutation_array->strides[0]);
345     for (t=0;t<num_ts;t++){
346       *(double *) (sts_data -> data+i*sts_data->strides[0]+t*sts_data->strides[1])=0.0;
347     }
348     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts)*sts_data->strides[1])=(float)mytgs0[ista].geolat;
349     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts+1)*sts_data->strides[1])=(float)mytgs0[ista].geolon;
350     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts+2)*sts_data->strides[1])=(float)mytgs0[ista].z;
351     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts+3)*sts_data->strides[1])=(float)fros[ista];
352     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts+4)*sts_data->strides[1])=(float)lros[ista];
353   } 
354
355   temp_sts_data = (float *)calloc(len_sts_data, sizeof(float) );
356     
357   /* Loop over all sources */
358   //FIXME: remove istart and istop they are not used.
359   istart = -1;
360   istop = -1;
361   for (isrc=0;isrc<numSrc;isrc++){
362     /* Read in data block from mux2 file */
363     muxFileName = muxFileNameArray[isrc];
364     if((fp=fopen(muxFileName,"r"))==NULL)
365       {
366         fprintf(stderr, "Cannot open file %s\n", muxFileName);
367         PyErr_SetString(PyExc_RuntimeError,"");
368         return NULL;
369       }
370       
371     if (verbose){
372       printf("Reading mux file %s\n",muxFileName);
373     }
374
375     offset=sizeof(int)+nsta0*(sizeof(struct tgsrwg)+2*sizeof(int));
376     fseek(fp,offset,0);
377     
378     numData = getNumData(fros+isrc*nsta0, lros+isrc*nsta0, nsta0);
379     muxData = (float*) malloc(numData*sizeof(float));
380     fread(muxData, numData*sizeof(float),1,fp); 
381     fclose(fp);         
382
383     /* loop over stations */
384     for(j=0; j<N; j++){ 
385       ista = *(long *) (permutation_array -> data+j*permutation_array->strides[0]);
386       //printf("%d\n",(int)*(long *) (permutation_array -> data+j*permutation_array->strides[0]));
387       
388       /* fill the data0 array from the mux file, and weight it */
389       fillDataArray(ista, nsta0, num_ts, mytgs0[ista].ig, fros+isrc*nsta0, lros+isrc*nsta0, temp_sts_data, &istart, &istop, muxData);
390       
391       /* weight appropriately and add */
392       for(t=0; t<num_ts; t++){
393         if((isdata(*(double *) (sts_data -> data+j*sts_data->strides[0]+t*sts_data->strides[1]))) && isdata(temp_sts_data[t])){
394           *(double *) (sts_data -> data+j*sts_data->strides[0]+t*sts_data->strides[1]) += temp_sts_data[t] * weights[isrc];
395         }else{
396           *(double *) (sts_data -> data+j*sts_data->strides[0]+t*sts_data->strides[1]) = 0.0;
397         }
398       }
399     }
400   }   
401   free(muxData);
402   free(temp_sts_data);
403   free(fros);
404   free(lros);
405   return sts_data;
406}   
407
408
409/* thomas */
410void fillDataArray(int ista, int nsta, int nt, int ig, int *nst, int *nft, float *data, int *istart_p, int *istop_p, float *muxData)
411{
412   int it, last_it, jsta;
413   long int offset=0;
414
415
416   last_it=-1;
417   /* make arrays of starting and finishing time steps for the tide gauges */
418   /* and fill them from the file */
419     
420   /* update start and stop timesteps for this gauge */
421   if(nst[ista]!=-1){
422     if(*istart_p==-1){
423         *istart_p=nst[ista];
424     }else{
425         *istart_p=((nst[ista]<*istart_p)?nst[ista]:*istart_p);
426     }
427   }
428   if(nft[ista]!=-1){
429     if(*istop_p==-1){
430         *istop_p=nft[ista];
431     }else{
432         *istop_p=((nft[ista]<*istop_p)?nft[ista]:*istop_p);
433     }
434   }     
435   if(ig==-1 || nst[ista] == -1) /* currently ig==-1 => nst[ista]==-1 */
436   {
437      /* gauge never started recording, or was outside of all grids, fill array with 0 */
438      for(it=0; it<nt; it++)
439         data[it] = 0.0;
440   }   
441   else
442   {
443      for(it=0; it<nt; it++)
444      {
445         last_it = it;
446         /* skip t record of data block */
447         offset++;
448         /* skip records from earlier tide gauges */
449         for(jsta=0; jsta<ista; jsta++)
450            if(it+1>=nst[jsta]&&it+1<=nft[jsta])
451               offset++;
452               
453         /* deal with the tide gauge at hand */
454         if(it+1>=nst[ista]&&it+1<=nft[ista])
455         /* gauge is recording at this time */
456         {
457            memcpy(data+it,muxData+offset,sizeof(float));
458            offset++;
459         }
460         else if (it+1<nst[ista])
461         {
462            /* gauge has not yet started recording */
463            data[it] = 0.0;
464         }   
465         else
466         /* gauge has finished recording */                                           
467         {
468            data[it] = NODATA;
469            break;
470         }
471   
472         /* skip records from later tide gauges */
473         for(jsta=ista+1; jsta<nsta; jsta++)
474            if(it+1>=nst[jsta]&&it+1<=nft[jsta])
475               offset++;
476      }
477   
478      if(last_it < nt - 1)
479         /* the loop was exited early because the gauge had finished recording */
480         for(it=last_it+1; it < nt; it++)
481            data[it] = NODATA;
482   }
483} 
484
485 
486char isdata(float x)
487{
488  //char value;
489   if(x < NODATA + EPSILON && NODATA < x + EPSILON)
490      return 0;
491   else
492      return 1; 
493}
494
495long getNumData(int *fros, int *lros, int nsta)
496/* calculates the number of data in the data block of a mux file */
497/* based on the first and last recorded output steps for each gauge */ 
498{
499   int ista, last_output_step;
500   long numData = 0;
501
502   last_output_step = 0;   
503   for(ista=0; ista < nsta; ista++)
504      if(*(fros + ista) != -1)
505      {
506         numData += *(lros + ista) - *(fros + ista) + 1;
507         last_output_step = (last_output_step < *(lros+ista) ? *(lros+ista):last_output_step);
508      }   
509   numData += last_output_step*nsta; /* these are the t records */
510   return numData;
511}   
512
513
514
515//-------------------------------
516// Method table for python module
517//-------------------------------
518static struct PyMethodDef MethodTable[] = {
519  {"read_mux2", read_mux2, METH_VARARGS, "Print out"},
520  {NULL, NULL}
521};
522
523// Module initialisation
524void initurs_ext(void){
525  Py_InitModule("urs_ext", MethodTable);
526
527  import_array(); // Necessary for handling of NumPY structures
528}
Note: See TracBrowser for help on using the repository browser.