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

Last change on this file since 5482 was 5482, checked in by ole, 16 years ago

Comments

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   /*
273   for (i=0;i<nsta0*numSrc;i++){
274       printf("%d, fros %d\n",i,fros[i]);
275       printf("%d, lros %d\n",i,lros[i]);
276       }*/
277
278   if (permutation == Py_None){
279       // if no permutation is specified return the times series of all the gauges in the mux file
280       permuation_dimensions[0]=nsta0;
281       permutation_array=(PyArrayObject *) PyArray_FromDims(1, permuation_dimensions, PyArray_INT);
282       for (ista=0; ista<nsta0; ista++){
283           *(long *) (permutation_array -> data+ista*permutation_array->strides[0])=ista;
284       } 
285   }else{
286       // Specifies the gauge numbers that for which data is to be extracted
287       permutation_array=(PyArrayObject *) PyArray_ContiguousFromObject(permutation,PyArray_INT,1,1);
288       N = permutation_array->dimensions[0]; //FIXME: this is overwritten below
289       for (ista=0; ista<N; ista++){
290           if ((int)*(long *) (permutation_array -> data+ista*permutation_array->strides[0])>=nsta0){
291               printf("Maximum index = %d, you had %d\n",nsta0-1,(int)*(long *) (permutation_array -> data+ista*permutation_array->strides[0]));
292               PyErr_SetString(PyExc_RuntimeError,"The permutation specified is out of bounds");
293               return NULL;
294           }
295       }
296   }
297   if(permutation_array == NULL){
298     PyErr_SetString(PyExc_RuntimeError,"Memory for permutation_array array could not be allocated");
299     return NULL;
300   }
301
302   N = permutation_array->dimensions[0];
303   
304   params[0]=(double)N;
305   params[1]=(double)mytgs0[0].dt;
306   params[2]=(double)num_ts;
307 
308   
309   // Find min and max start times of all gauges
310   start_tstep=num_ts+1;
311   finish_tstep=-1;
312   for (i=0;i<N;i++){
313       ista = *(long *) (permutation_array -> data+i*permutation_array->strides[0]); 
314       if (fros[ista]< start_tstep){
315           start_tstep=fros[ista];
316       }
317       if (lros[0+nsta0*ista] > finish_tstep){
318           finish_tstep=lros[ista]; 
319       }
320   }
321   
322   if ((start_tstep>num_ts) | (finish_tstep < 0)){
323       printf("s=%d,f=%d,num_ts=%d\n",start_tstep,finish_tstep,num_ts);
324     PyErr_SetString(PyExc_RuntimeError,"Gauge data has incorrect start and finsh times");
325     return NULL;
326   }
327   
328   if (start_tstep>=finish_tstep){
329     PyErr_SetString(PyExc_RuntimeError,"Gauge data has non-postive_length");
330     return NULL;
331   }
332   
333   /* Make array(s) to hold the demuxed data */
334   len_sts_data=num_ts+POFFSET;
335   dimensions[0]=N;
336   dimensions[1]=len_sts_data;
337   sts_data = (PyArrayObject *) PyArray_FromDims(2, dimensions, PyArray_DOUBLE);
338   if(sts_data == NULL){
339    PyErr_SetString(PyExc_RuntimeError,"Memory for pydata array could not be allocated");
340    return NULL;
341   }
342   
343   /* Initialise sts data to zero */
344   for(i=0; i<N; i++){ 
345     ista = *(long *) (permutation_array -> data+i*permutation_array->strides[0]);
346     for (t=0;t<num_ts;t++){
347       *(double *) (sts_data -> data+i*sts_data->strides[0]+t*sts_data->strides[1])=0.0;
348     }
349     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts)*sts_data->strides[1])=(float)mytgs0[ista].geolat;
350     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts+1)*sts_data->strides[1])=(float)mytgs0[ista].geolon;
351     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts+2)*sts_data->strides[1])=(float)mytgs0[ista].z;
352     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts+3)*sts_data->strides[1])=(float)fros[ista];
353     *(double *) (sts_data -> data+i*sts_data->strides[0]+(num_ts+4)*sts_data->strides[1])=(float)lros[ista];
354   } 
355
356   temp_sts_data = (float *)calloc(len_sts_data, sizeof(float) );
357     
358   /* Loop over all sources */
359   //FIXME: remove istart and istop they are not used.
360   istart = -1;
361   istop = -1;
362   for (isrc=0;isrc<numSrc;isrc++){
363     /* Read in data block from mux2 file */
364     muxFileName = muxFileNameArray[isrc];
365     if((fp=fopen(muxFileName,"r"))==NULL)
366       {
367         fprintf(stderr, "Cannot open file %s\n", muxFileName);
368         PyErr_SetString(PyExc_RuntimeError,"");
369         return NULL;
370       }
371       
372     if (verbose){
373       printf("Reading mux file %s\n",muxFileName);
374     }
375
376     offset=sizeof(int)+nsta0*(sizeof(struct tgsrwg)+2*sizeof(int));
377     fseek(fp,offset,0);
378     
379     numData = getNumData(fros+isrc*nsta0, lros+isrc*nsta0, nsta0);
380     muxData = (float*) malloc(numData*sizeof(float));
381     fread(muxData, numData*sizeof(float),1,fp); 
382     fclose(fp);         
383
384     /* loop over stations */
385     for(j=0; j<N; j++){ 
386       ista = *(long *) (permutation_array -> data+j*permutation_array->strides[0]);
387       //printf("%d\n",(int)*(long *) (permutation_array -> data+j*permutation_array->strides[0]));
388       
389       /* fill the data0 array from the mux file, and weight it */
390       fillDataArray(ista, nsta0, num_ts, mytgs0[ista].ig, fros+isrc*nsta0, lros+isrc*nsta0, temp_sts_data, &istart, &istop, muxData);
391       
392       /* weight appropriately and add */
393       for(t=0; t<num_ts; t++){
394         if((isdata(*(double *) (sts_data -> data+j*sts_data->strides[0]+t*sts_data->strides[1]))) && isdata(temp_sts_data[t])){
395           *(double *) (sts_data -> data+j*sts_data->strides[0]+t*sts_data->strides[1]) += temp_sts_data[t] * weights[isrc];
396         }else{
397           *(double *) (sts_data -> data+j*sts_data->strides[0]+t*sts_data->strides[1]) = 0.0;
398         }
399       }
400     }
401   }   
402   free(muxData);
403   free(temp_sts_data);
404   free(fros);
405   free(lros);
406   return sts_data;
407}   
408
409
410/* thomas */
411void fillDataArray(int ista, int nsta, int nt, int ig, int *nst, int *nft, float *data, int *istart_p, int *istop_p, float *muxData)
412{
413   int it, last_it, jsta;
414   long int offset=0;
415
416
417   last_it=-1;
418   /* make arrays of starting and finishing time steps for the tide gauges */
419   /* and fill them from the file */
420     
421   /* update start and stop timesteps for this gauge */
422   if(nst[ista]!=-1){
423     if(*istart_p==-1){
424         *istart_p=nst[ista];
425     }else{
426         *istart_p=((nst[ista]<*istart_p)?nst[ista]:*istart_p);
427     }
428   }
429   if(nft[ista]!=-1){
430     if(*istop_p==-1){
431         *istop_p=nft[ista];
432     }else{
433         *istop_p=((nft[ista]<*istop_p)?nft[ista]:*istop_p);
434     }
435   }     
436   if(ig==-1 || nst[ista] == -1) /* currently ig==-1 => nst[ista]==-1 */
437   {
438      /* gauge never started recording, or was outside of all grids, fill array with 0 */
439      for(it=0; it<nt; it++)
440         data[it] = 0.0;
441   }   
442   else
443   {
444      for(it=0; it<nt; it++)
445      {
446         last_it = it;
447         /* skip t record of data block */
448         offset++;
449         /* skip records from earlier tide gauges */
450         for(jsta=0; jsta<ista; jsta++)
451            if(it+1>=nst[jsta]&&it+1<=nft[jsta])
452               offset++;
453               
454         /* deal with the tide gauge at hand */
455         if(it+1>=nst[ista]&&it+1<=nft[ista])
456         /* gauge is recording at this time */
457         {
458            memcpy(data+it,muxData+offset,sizeof(float));
459            offset++;
460         }
461         else if (it+1<nst[ista])
462         {
463            /* gauge has not yet started recording */
464            data[it] = 0.0;
465         }   
466         else
467         /* gauge has finished recording */                                           
468         {
469            data[it] = NODATA;
470            break;
471         }
472   
473         /* skip records from later tide gauges */
474         for(jsta=ista+1; jsta<nsta; jsta++)
475            if(it+1>=nst[jsta]&&it+1<=nft[jsta])
476               offset++;
477      }
478   
479      if(last_it < nt - 1)
480         /* the loop was exited early because the gauge had finished recording */
481         for(it=last_it+1; it < nt; it++)
482            data[it] = NODATA;
483   }
484} 
485
486 
487char isdata(float x)
488{
489  //char value;
490   if(x < NODATA + EPSILON && NODATA < x + EPSILON)
491      return 0;
492   else
493      return 1; 
494}
495
496long getNumData(int *fros, int *lros, int nsta)
497/* calculates the number of data in the data block of a mux file */
498/* based on the first and last recorded output steps for each gauge */ 
499{
500   int ista, last_output_step;
501   long numData = 0;
502
503   last_output_step = 0;   
504   for(ista=0; ista < nsta; ista++)
505      if(*(fros + ista) != -1)
506      {
507         numData += *(lros + ista) - *(fros + ista) + 1;
508         last_output_step = (last_output_step < *(lros+ista) ? *(lros+ista):last_output_step);
509      }   
510   numData += last_output_step*nsta; /* these are the t records */
511   return numData;
512}   
513
514
515
516//-------------------------------
517// Method table for python module
518//-------------------------------
519static struct PyMethodDef MethodTable[] = {
520  {"read_mux2", read_mux2, METH_VARARGS, "Print out"},
521  {NULL, NULL}
522};
523
524// Module initialisation
525void initurs_ext(void){
526  Py_InitModule("urs_ext", MethodTable);
527
528  import_array(); // Necessary for handling of NumPY structures
529}
Note: See TracBrowser for help on using the repository browser.