#include #include #include #include static char vcid[] = "$Id: read_atmos_data.c,v 5.5.2.1 2007/02/06 01:33:14 vicadmin Exp $"; void read_atmos_data(FILE *infile, global_param_struct global_param, int file_num, int forceskip, double **forcing_data) /********************************************************************** read_atmos_data This routine reads in atmospheric data values from a binary/ascii file. BINARY Binary data are always specified as unsigned or signed ints, and a multiplier is used to convert to float. atmos variable: type: model units: precipitation unsigned short mm per file_dt temperature signed short C wind signed short m/s swap bytes code from Kernighan, Brian W. and Rob Pike, "The practice of programming", Addison-Wesley, Reading, Massachusetts, 1999, 267 pp, page 206. ASCII ASCII data should have the same units as given in the table above. Supported Input Field Combinations, options in parenthesis optional: Daily met data and daily model timestep - prec, tmax, tmin, (wind) Daily met data and subdaily model timestep - prec, tmax, tmin, (wind) If the code is modified check; * for BINARY, the number of fields is correct * get_global flags are implemented Modifications: 01/10/00 Modified to read a generic Binary, or ASCII column data file and read the contents into the provided data arrays. KAC ??-???-?? Replaced NF with global_param.dt in condition checking whether forcing file contains enough records to cover the time range of the simulation. (documented by TJB) 2006-08-23 Changed order of fread/fwrite statements from ...1, sizeof... to ...sizeof, 1,... GCT 2006-Sep-23 Fixed RCS ID string. TJB 2007-Jan-15 Added PRT_HEADER option; now binary forcing files might have headers, and these need to be skipped. TJB **********************************************************************/ { extern option_struct options; extern param_set_struct param_set; int rec; int skip_recs; int i; int endian; int fields; int Nfields; int day=0; int *field_index; unsigned short ustmp; signed short stmp; char str[MAXSTRING+1]; char ErrStr[MAXSTRING+1]; unsigned short Identifier[4]; int Nbytes; Nfields = param_set.N_TYPES[file_num]; field_index = param_set.FORCE_INDEX[file_num]; /** locate starting record **/ /* if ascii then the following refers to the number of lines to skip, if binary the following needs multiplying by the number of input fields */ skip_recs = (int)((float)(global_param.dt * forceskip)) / (float)param_set.FORCE_DT[file_num]; if((((global_param.dt < 24 && (param_set.FORCE_DT[file_num] * forceskip) % global_param.dt) > 0)) || (global_param.dt == 24 && (global_param.dt % param_set.FORCE_DT[file_num] > 0))) nrerror("Currently unable to handle a model starting date that does not correspond to a line in the forcing file."); /** Error checking - Model can be run at any time step using daily forcing data, but if sub-daily data is used, the model must be run at the same time step as the data. That way aggregation and disaggragation techniques are left to the user. **/ if(param_set.FORCE_DT[file_num] < 24 && global_param.dt != param_set.FORCE_DT[file_num]) { sprintf(ErrStr,"When forcing the model with sub-daily data, the model must be run at the same time step as the forcing data. Currently the model time step is %i hours, while forcing file %i has a time step of %i hours.",global_param.dt,file_num,param_set.FORCE_DT[file_num]); nrerror(ErrStr); } if(infile==NULL)fprintf(stderr,"NULL file\n"); /*************************** Read BINARY Forcing Data ***************************/ if(param_set.FORCE_FORMAT[file_num] == BINARY){ /** test whether the machine is little-endian or big-endian **/ i = 1; if(*(char *)&i == 1) endian = LITTLE; else endian = BIG; // Check for presence of a header, & skip over it if appropriate. // A VIC header will start with 4 instances of the identifier, // followed by number of bytes in the header (Nbytes). // Nbytes is assumed to be the byte offset at which the data records start. fseek(infile,0,SEEK_SET); if (feof(infile)) nrerror("No data in the forcing file. Model stopping..."); for (i=0; i<4; i++) { fread(&ustmp,sizeof(unsigned short),1,infile); if (endian != param_set.FORCE_ENDIAN[file_num]) { ustmp = ((ustmp & 0xFF) << 8) | ((ustmp >> 8) & 0xFF); } Identifier[i] = ustmp; } if (Identifier[0] != 0xFFFF || Identifier[1] != 0xFFFF || Identifier[2] != 0xFFFF || Identifier[3] != 0xFFFF) { Nbytes = 0; } else { fread(&ustmp,sizeof(unsigned short),1,infile); if (endian != param_set.FORCE_ENDIAN[file_num]) { ustmp = ((ustmp & 0xFF) << 8) | ((ustmp >> 8) & 0xFF); } Nbytes = (int)ustmp; } fseek(infile,Nbytes,SEEK_SET); /** if forcing file starts before the model simulation, skip over its starting records **/ fseek(infile,skip_recs*Nfields*sizeof(short),SEEK_CUR); if (feof(infile)) nrerror("No data for the specified time period in the forcing file. Model stopping..."); /** Read BINARY forcing data **/ rec = 0; while ( !feof(infile) && (rec * param_set.FORCE_DT[file_num] < global_param.nrecs * global_param.dt) ) { for(i=0;i> 8) & 0xFF); } forcing_data[field_index[i]][rec] = (double)stmp / param_set.TYPE[field_index[i]].multiplier; } else { fread(&ustmp,sizeof(unsigned short int),1,infile); if (endian != param_set.FORCE_ENDIAN[file_num]) { ustmp = ((ustmp & 0xFF) << 8) | ((ustmp >> 8) & 0xFF); } forcing_data[field_index[i]][rec] = (double)ustmp / param_set.TYPE[field_index[i]].multiplier; } } rec++; } } /************************** Read ASCII Forcing Data **************************/ else{ // No need to skip over a header here, since ascii file headers are skipped // in open_file(). However, if we wanted to read information from the header, // we'd want to do it here, after rewinding to the beginning of the file (or // moving the code that deals with headers from open_file() to this function // and to any other functions that read the files, so that those functions could // also read the headers if necessary). /* skip to the beginning of the required met data */ for(i=0;i