/****************************************************************************** * read_smt2_v2.c * * Reads NESDIS SIB SSM/T2 level 1b data. * * LAST UPDATE: 2 December 1997 * * AUTHOR: * Wesley Berg, CIRES/CDC (4/4/94 converted to c!) * Darren Jackson CIRES/ESRL May 2005 * * MODIFICATIONS: * 12/02/97 Added standard write_hdr and write_scan routines to output * data in standard CDC pixel format. * * 03/16/98 Added scan-error checks to detect slope/intercept errors * and discard every scan with any such errors * * 05/17/06 Repaired problem with processing F15 data by changing scale * factor for intercept. * * 05/17/06 Fixed problem with intercept value after September 18, 2001 * for all satellites. Now it computes intercept value using warm * and cold temperature targets and counts for data after this date. * * FUNCTIONS CALLED: * write_hdr Writes 1000-byte header * write_scan Writes 1 scanline into std_data beginning at byte "readloc" * * NOTES: * (1) Output data are scaled by dscale and offset by 0. * ******************************************************************************/ #include #include #include #define MASK_FILE "/satellite/home/climsat/src/read_smt2/global_mask.dat" #define MISVAL -9999 #define NCHAN 5 #define NFIELD 8 #define NPIXEL 28 char mask[720][1440]; typedef struct { unsigned char dsn_name[44]; short int nscans, ngaps; short int wlt1_counts[11]; short int wlt1_temp[11]; short int wlt2_counts[11]; short int wlt2_temp[11]; short int cold_path_temp_corr[NCHAN]; short int warm_path_temp_corr[NCHAN]; short int antenna_patt_corr[140]; short int qc_flags[7]; short int spare[121]; } headrec; typedef struct { int orbit_no; short int scan_no; short int scan_index_to_t1; int scan_time[3]; short int earth_loc[56]; short int raw_counts[NPIXEL][NCHAN+1]; short int warm_cal_counts[20]; short int cold_cal_counts[20]; short int gain[NCHAN]; short int therm_ref_volt; short int therm_counts[18]; short int warm_load_temp[2]; short int warm_load_temp_avg[NCHAN]; short int warm_load_count_avg[NCHAN]; short int cold_load_count_avg[NCHAN]; short int cold_load_temp[NCHAN]; short int slopes[NCHAN]; short int intercepts[NCHAN]; short int d_qc_flags[7]; short int d_spares[9]; } datarec ; struct describe_text { char text[40] ; /* Description of data field */ } ; main(argc, argv) int argc; char **argv; { headrec *header ; /* input data header record */ datarec *data ; /* input data scan record */ char datain[692] ; /* input data record */ float **outdata ; /* output data array */ float btemp[NPIXEL][NCHAN] ; /* array of brightness temperatures */ float xraw[NPIXEL][NCHAN] ; /* array of raw input counts */ float lat[NPIXEL] ; /* array of latitudes across scan */ float lon[NPIXEL] ; /* array of longitudes across scan */ float llat=0.0 ; /* last latitude */ short stype ; /* surface type flag */ short iascend ; /* ascend/descending scan flag */ short scan_index ; /* scan postion index */ int surf_type() ; /* function to determine surface type*/ int apply_mask=0 ; /* flag to apply land mask */ int header_flag=0 ; /* output header record flag */ int scan_pos=0 ; /* flag to output scan position */ int ascend=0 ; /* flag to output ascend/descend ind.*/ int mask_index ; /* band index for land mask */ int position_index ; /* band index for scan postion */ int ascend_index ; /* band index for ascend/descend ind.*/ int bad_pix=0; /* number of bad pixels */ long itime ; /* scan time (seconds from 1/1/70) */ long scid ; /* spacecraft ID number */ long bad_flag ; /* bad data flag */ long bad_scan ; /* bad scan flag */ long nbad=0 ; /* counter with number of bad pixels */ long nbscan=0 ; /* counter with number of bad scans */ float amin[NFIELD] ; /* output data minimum value (float) */ float amax[NFIELD] ; /* output data maximum value (float) */ short bmin[NFIELD] ; /* output data minimum value (int*2) */ short bmax[NFIELD] ; /* output data maximum value (int*2) */ double atof() ; /* character to float function */ char *ptr ; /* generic pointer */ char cnv2ascii() ; /* converts EBCDIC to ASCII */ char dsname[45] ; /* data set name (from input file) */ int iyr ; /* year (i.e. 97) */ int iday ; /* julian day (i.e. 255) */ int nday ; /* number of days (from 1/1/70) */ int nskip=0 ; /* # of pixels at end of scan to skip*/ int nscan=0 ; /* # of scans written out */ float xslope=0.0001 ; /* Slope value mulitplier */ float xoffset=0.01 ; /* Offset value mulitplier */ unsigned char c ; /* generic character */ static char *s="SMT2.S"; /* verification string for data hdr */ /*---------------------------*/ /* miscellaneous variables */ /*---------------------------*/ FILE *inf ; /* Input file pointer */ FILE *err ; /* Input file pointer */ FILE *opf ; /* Output file pointer */ FILE *minf ; /* Input data mask file pointer */ int i,j,k,l ; /* Various counters */ int nfile=0 ; /* Number of input files counter */ int nout=5 ; /* Number of output data fields */ int ieof=0 ; /* End of File flag */ int chkrgn=0 ; /* Flag to check domain bounds */ int region ; /* Flag to check if scan is in bounds*/ float minlat ; /* Minimum latitude */ float maxlat ; /* Maximum latitude */ float minlon ; /* Minimum longitude */ float maxlon ; /* Maximum longitude */ char infile[80] ; /* Name of input data file */ char outfile[80] ; /* Name of output data file */ char satellite[80] ; /* Satellite name */ short satid ; /* Satellite ID */ char sensor[80] ; /* Sensor ID description */ short lscale ; /* Scaling factor for lat/lon fields */ float *scale ; /* Scaling factor for each field */ float *offset ; /* Offset value for each field */ char **units ; /* Units for each field */ char **var_desc ; /* Description for each field */ short blast[NCHAN] ; /* Intercept value for last scan */ short mlast[NCHAN] ; /* Slope value for last scan */ short error_check=1 ; /* Error check flag (default = true) */ short error_stats=0 ; /* Error stats flag (default = false)*/ short bscan[5][NCHAN] ; /* Number of bad scans for 5 tests */ int hswap() ; /* Function to swap bytes for header */ int dswap() ; /* Function to swap bytes for data */ float slope[NCHAN]; /* slope values after 9/18/2001 */ float intercept[NCHAN]; /* intercept values after 9/18/2001 */ float slope2[NCHAN]; /* slope values written in error.stats */ float intercept2[NCHAN]; /* intercept values writtin in error.stats */ float btemp_orig[NPIXEL][NCHAN] ; /* array of brightness temperatures */ float btemp_computed[NPIXEL][NCHAN] ; /* array of brightness temperatures for error.stats */ float dtemp; /* warm - cold calibration temperature difference */ float dcnt; /* warm - cold calibration count difference */ /* Min valid slope value for each ch */ short MLOW[NCHAN]={900,900,900,900,900} ; /* Max valid slope value for each ch */ short MHIGH[NCHAN]={1300,1300,1300,1500,2000} ; /* Min valid intcp value for each ch */ short BLOW[NCHAN]={-20000,-20000,-20000,-20000,-32767} ; /* Max valid intcp value for each ch */ short BHIGH[NCHAN]={0,0,0,0,0} ; /* Max delta-slope for consec scans */ short DELTAM[NCHAN]={3,3,3,3,3} ; /* Max delta-intcp for consec scans */ short DELTAB[NCHAN]={50,50,50,50,200} ; /*-----------------------------------*/ /* allocate and initialize variables */ /*-----------------------------------*/ minlat = -90.0 ; maxlat = 90.0 ; minlon = 0.0 ; maxlon = 360.0 ; strcpy(infile,"stdin") ; strcpy(outfile,"stdout") ; scale = (float *) malloc ( ( NFIELD ) * sizeof (float) ) ; offset = (float *) malloc ( ( NFIELD ) * sizeof (float) ) ; for ( i=0; i 1) { i=0; if (argv[1][0] == '-' && argv[1][1] == 'h') { printf("usage: read_smt2 -i -e -p -m -f -b 3 -t1 -t2 -n1 -n2 -o \n\n"); printf("flag arguements default description\n"); printf("---- ---------- ------- -----------\n"); printf(" -h (none) false display help information\n"); printf(" -p (none) false output scan position index\n"); printf(" -m (none) false output surface type index\n"); printf(" -f (none) false output ascend/descend index\n"); printf(" -b 3 number of pixels to delete at end of scan\n"); printf(" -e (none) true Turn on/off error check code\n"); printf(" -t1 -90.0 minimum latitude value\n"); printf(" -t2 90.0 maximum latitude value\n"); printf(" -n1 0.0 minimum longitude value\n"); printf(" -n2 360.0 maximum longitude value\n"); printf(" -i stdin input file\n"); printf(" -o stdout output file\n"); exit(1); } while (++i < argc) { if (argv[i][0] != '-') { fprintf(stderr," Illegal command parameter, exciting program! "); exit(1); } switch (argv[i][1]) { case 'i': strcpy ( infile, argv[i+1] ); i++; break; case 'm': apply_mask = 1; scale[nout] = 1 ; offset[nout] = 0 ; var_desc[nout] = "Surface type (0=land, 1=coast, 5=ocean)"; units[nout] = "Index"; mask_index = nout; nout = nout + 1; break; case 'p': scan_pos = 1; scale[nout] = 1 ; offset[nout] = 0 ; var_desc[nout] = "Scan position index (1 - 28) "; units[nout] = "Index"; position_index = nout; nout = nout + 1; break; case 'f': ascend = 1; scale[nout] = 1 ; offset[nout] = 0 ; var_desc[nout] = "Scan direction (0=descend, 1=ascend) "; units[nout] = "Index"; ascend_index = nout; nout = nout + 1; break; case 'b': bad_pix = 1; nskip = atoi(argv[i+1]); i++; break; case 'e': error_check = 0; break; case 'o': strcpy(outfile,argv[i+1]); i++; break; case 't': if (argv[i][2] == '1') minlat = atof(argv[i+1]); else if (argv[i][2] == '2') maxlat = atof(argv[i+1]); else { fprintf(stderr," Illegal command parameter, exciting program! "); exit(1); } chkrgn = 1; i++; break; case 'n': if (argv[i][2] == '1') { minlon = atof(argv[i+1]); if (minlon < 0.0) minlon = minlon + 360.0; } else if (argv[i][2] == '2') { maxlon = atof(argv[i+1]); if (maxlon < 0.0) maxlon = maxlon + 360.0; } else { fprintf(stderr," Illegal command parameter, exciting program! "); exit(1); } chkrgn = 1; i++; break; default: fprintf(stderr," Illegal command parameter, exciting program! "); exit(1); } } } /*--------------------*/ /* Initialize values */ /*--------------------*/ for (i=0; idsn_name[j]); dsname[44]='\0'; ptr=strstr(dsname,s); while (ptr == NULL || header->nscans == 0) { if (fread(datain,1,692,inf) != 692) { ieof = 1; break; } hswap(datain,header); for (j=0; j<44; j++) dsname[j]=cnv2ascii(header->dsn_name[j]); dsname[44]='\0'; ptr=strstr(dsname,s); } if (ieof == 1) break; nfile = nfile + 1; scid=ptr[6]-'0'; satid = scid + 6; if (scid == 5) nskip=3; if (scid == 8) nskip=3; fprintf(stderr,"File %2d -> %s F%2d, %3d scans\n", nfile,dsname,scid+6,header->nscans); /*----------------------*/ /* now read some data */ /*----------------------*/ for (i=0; inscans; i++) { fread(datain,1,692,inf); dswap(datain,data); /* fprintf(stderr,"scan_time[0:3] %d %d %d\n", data->scan_time[0],data->scan_time[1],data->scan_time[2]); */ iyr = data->scan_time[0]/1000; iday = data->scan_time[0] - 1000*iyr; if(iyr < 69) nday = 366*((iyr+100-69)/4) + 365*(iyr+100-70-(iyr+100-69)/4) + iday - 1; else nday = 366*((iyr-69)/4) + 365*(iyr-70-(iyr-69)/4) + iday - 1; itime = 86400*nday + data->scan_time[1]; /* fprintf(stderr,"iyr,iday,nday,itime %d %d %d %d\n", iyr,iday,nday,itime); */ if (iday < 0 || iday > 366) { fprintf(stderr,"Error, illegal julian day!\n"); fprintf(stderr,"%4d %3d %3d %10d\n",iyr,iday,nday,itime); exit(1); } /* Adjust intercept scale factor based on time */ if (scid == 6 && itime > 918486000) xoffset = 0.05; else if (scid == 8 && itime > 918489600) xoffset = 0.05; else if (scid == 9) xoffset = 0.05; else xoffset = 0.01; for (j=0; j<5; j++) { if(itime > 1000824317) { /* Commute new slope and intercepts after Sep 18, 2001 */ /* Intercepts provided in data are in error after this time */ dtemp = (float)data->warm_load_temp_avg[j]/100. - (float)data->cold_load_temp[j]/100.; dcnt = (float)data->warm_load_count_avg[j]/4. - (float)data->cold_load_count_avg[j]/4.; if (dtemp <= 0 || dtemp > 500. || dcnt <= 0.) { slope[j] = 0.; intercept[j] = 0.; } else { slope[j] = dtemp/dcnt; intercept[j] = (float)data->warm_load_temp_avg[j]/100. - slope[j]*(float)data->warm_load_count_avg[j]/4.; } } else { /* Use slope and intercept data provided in data file */ slope[j] = data->slopes[j]*xslope; intercept[j] = data->intercepts[j]*xoffset; } } /*-----------------------------------------*/ /*........compute brightness temps.........*/ /*-----------------------------------------*/ if (chkrgn == 0) region=0; else region=1; bad_scan = 1; /* print slope and intercept values from data file and computed slope and intercept*/ if (error_stats == 1) { fprintf(err,"%10d\n",itime); for (j=0; j<5; j++) { fprintf(err,"%12.5f %12.5f\n",data->slopes[j]*xslope,data->intercepts[j]*xoffset); slope2[j] = ((float)data->warm_load_temp_avg[j]/100. - (float)data->cold_load_temp[j]/100.)/((float)data->warm_load_count_avg[j]/4. - (float)data->cold_load_count_avg[j]/4.); intercept2[j] = (float)data->warm_load_temp_avg[j]/100. - slope2[j]*(float)data->warm_load_count_avg[j]/4.; fprintf(err,"%12.5f %12.5f\n",slope2[j],intercept2[j]); fprintf(err,"%12.7f %12.7f\n",data->slopes[j]*xslope - slope2[j],data->intercepts[j]*xoffset-intercept2[j]); } } for (k=0; kearth_loc[k*2]/128.0; lon[k]=(float)data->earth_loc[k*2+1]/128.0; if (lon[k] < 0.0) lon[k] = lon[k] + 360.0; if (llat == 0.0 || lat[0] > llat) iascend = 1; else iascend = 0; bad_flag = 0; for (j=0; j<5; j++) { xraw[k][j]=(float)data->raw_counts[k][j+1]; btemp[k][j]=slope[j]*xraw[k][j]+intercept[j]; if(error_stats == 1) { btemp_orig[k][j]=data->slopes[j]*xslope*xraw[k][j]+data->intercepts[j]*xoffset; btemp_computed[k][j]=slope2[j]*xraw[k][j]+intercept2[j]; fprintf(err,"%14.7f ",btemp_computed[k][j]-btemp_orig[k][j]); } /* Error test 1 (183+\-1 within physical limits) */ if (btemp[k][j]<=100.0 || btemp[k][j] > 327.0 || k >= NPIXEL-nskip) { if (j != 4 || scid != 5 ) { bad_flag = 1; if (error_check && (btemp[k][1] < 150.0 || btemp[k][1] > 280.0)) { if ( bad_scan ) bscan[0][j] = bscan[0][j] + 1; bad_scan = 0; } } outdata[k][j] = ( float ) MISVAL; } else outdata[k][j] = btemp[k][j]; /*********************/ /* Scan error checks */ /*********************/ if ( error_check && (bad_scan == 1) && (j != 4 || scid != 5 ) ) { /* Error test 2 (Slope value within specified limits) */ if (data->slopes[j] < MLOW[j] || data->slopes[j] > MHIGH[j] ) { bad_scan = 0; bscan[1][j] = bscan[1][j] + 1; } /* Error test 3 (Intercept value within specified limits) */ else { if (data->intercepts[j] < BLOW[j] || data->intercepts[j] > BHIGH[j] ) { bad_scan = 0; bscan[2][j] = bscan[2][j] + 1; } /* Error test 4 (Slope value scan difference < threshold) */ else { if (abs(data->slopes[j]-mlast[j]) > DELTAM[j] ) { bad_scan = 0; bscan[3][j] = bscan[3][j] + 1; } /* Error test 5 (Intercept value scan difference < threshold) */ else { if (abs(data->intercepts[j]-blast[j]) > DELTAB[j] ) { bad_scan = 0; bscan[4][j] = bscan[4][j] + 1; } } } } } mlast[j] = data->slopes[j]; blast[j] = data->intercepts[j]; } if (error_stats == 1) fprintf(err,"\n"); if (apply_mask == 1) { stype = surf_type(lat[k],lon[k]); outdata[k][mask_index] = stype; } if (scan_pos == 1) outdata[k][position_index] = scan_index; if (ascend == 1) outdata[k][ascend_index] = iascend; if (bad_flag == 1) nbad = nbad + 1; if (chkrgn == 1) { if (lat[k] >= minlat && lat[k] <= maxlat && lon[k] >= minlon && lon[k] <= maxlon) region = 0; } } if (region == 0) { /* open output file and write the output data file header */ if (header_flag == 0) { sprintf(sensor,"SSM/T2"); sprintf(satellite,"DMSP F%2d",satid); if (strcmp(outfile,"stdout") == 0) { opf = stdout; write_hdr(opf, dsname, satellite, sensor, MISVAL, satid, nout, NPIXEL, 0, 0, scale, offset, units, var_desc); } else { if ((opf = fopen(outfile,"w")) == NULL) { fprintf(stderr, " Unable to open specified output file, exiting program!"); exit(1); } write_hdr(opf, outfile, satellite, sensor, MISVAL, satid, nout, NPIXEL, 0, 0, scale, offset, units, var_desc); } header_flag = 1; } /** Write the scanline data, incrementing nbscan for each bad scan **/ if ( bad_scan ) { if ( write_scan ( 0, opf, outdata, NULL, NULL, itime, nout, 0, 28, 0, lat, lon, NULL, NULL, scale, NULL, offset, (double) lscale, MISVAL, amin, amax, bmin, bmax ) < 0 ) exit (1) ; } else nbscan = nbscan + 1; nscan = nscan + 1; } llat = lat[0]; } } /** write EOF record and close files **/ fclose(inf); if (header_flag == 1) { if ( write_scan ( 0, opf, outdata, NULL, NULL, MISVAL, nout, 0, 28, 0, lat, lon, NULL, NULL, scale, NULL, offset, (double) lscale, MISVAL, amin, amax, bmin, bmax ) < 0 ) exit (1) ; fclose(opf); fprintf(stderr, "\n%8d Total scans, %8d Bad scans\n",nscan,nbscan); fprintf(stderr, "\nChan 1 Badscans: %3d+%3d+%3d+%3d+%3d = %5d", bscan[0][0],bscan[1][0],bscan[2][0],bscan[3][0],bscan[4][0], bscan[0][0]+bscan[1][0]+bscan[2][0]+bscan[3][0]+bscan[4][0]); fprintf(stderr, "\nChan 2 Badscans: %3d+%3d+%3d+%3d+%3d = %5d", bscan[0][1],bscan[1][1],bscan[2][1],bscan[3][1],bscan[4][1], bscan[0][1]+bscan[1][1]+bscan[2][1]+bscan[3][1]+bscan[4][1]); fprintf(stderr, "\nChan 3 Badscans: %3d+%3d+%3d+%3d+%3d = %5d", bscan[0][2],bscan[1][2],bscan[2][2],bscan[3][2],bscan[4][2], bscan[0][2]+bscan[1][2]+bscan[2][2]+bscan[3][2]+bscan[4][2]); fprintf(stderr, "\nChan 4 Badscans: %3d+%3d+%3d+%3d+%3d = %5d", bscan[0][3],bscan[1][3],bscan[2][3],bscan[3][3],bscan[4][3], bscan[0][3]+bscan[1][3]+bscan[2][3]+bscan[3][3]+bscan[4][3]); fprintf(stderr, "\nChan 5 Badscans: %3d+%3d+%3d+%3d+%3d = %5d\n\n", bscan[0][4],bscan[1][4],bscan[2][4],bscan[3][4],bscan[4][4], bscan[0][4]+bscan[1][4]+bscan[2][4]+bscan[3][4]+bscan[4][4]); for (i=0; i= 0.0) jndex = (int)(rlon*4.0); else jndex = (int)((rlon+360.0)*4.0); if (index < 0) index=0; if (index > 719) index=719; if (jndex < 0) jndex=0; if (jndex > 1439) jndex=1439; if (mask[index][jndex] == 0) stype=5; else if (mask[index][jndex] >= 100) stype=0; else stype=1; return(stype); } char cnv2ascii(c) unsigned char c; { char ebcdic_ascii[256] = { '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?', '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?', '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?', '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?', ' ','?','?','?','?','?','?','?','?','?','?','.','?','?','+','?', '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?', '-','?','?','?','?','?','?','?','?','?','?','?','?','_','?','?', '?','?','?','?','?','?','?','?','?','?',':','#','@','?','=','?', '?','a','b','c','d','e','f','g','h','i','?','?','?','?','?','?', '?','j','k','l','m','n','o','p','q','r','?','?','?','?','?','?', '?','?','s','t','u','v','w','x','y','z','?','?','?','?','?','?', '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?', '?','A','B','C','D','E','F','G','H','I','?','?','?','?','?','?', '?','J','K','L','M','N','O','P','Q','R','?','?','?','?','?','?', '?','?','S','T','U','V','W','X','Y','Z','?','?','?','?','?','?', '0','1','2','3','4','5','6','7','8','9','?','?','?','?','?','?' }; char cascii; cascii = ebcdic_ascii[c]; return(cascii); }