ocssw  1.0
/disk01/web/ocssw/build/src/l2gen/l1_czcs_hdf.c (r8084/r5616)
Go to the documentation of this file.
00001 /*
00002  *  W. Robinson, SAIC, 10 Dec 2004  I/O routines for CZCS
00003  */
00004 #include "hdf.h"
00005 #include "mfhdf.h"
00006 #include "l12_proto.h"
00007 #include "l1_czcs_hdf.h"
00008 #include "hdf_utils.h"
00009 #include <math.h>
00010 
00011 #define   NREC_IN_BUF             1
00012 #define   NBND_CZCS               5
00013 #define   POS_ERR_THRESH          2000.  /* orbit position error tolerence */
00014 
00015 int     syear, sday;       /* data start date                  */
00016 int32   smsec;             /* data start time                  */
00017 int16   eyear, eday;       /* data end date                    */
00018 int32   emsec;             /* data end time                    */
00019 int32   nscan;             /* number of scans                  */
00020 int32   npix;              /* number pixels per scan           */
00021 int32   spix;              /* start pixel number (from 0)      */
00022 int32   dpix;              /* LAC pixel increment              */
00023 int32   epix;
00024 
00025 char            dtype[8];
00026 
00027 int32           nsta;
00028 int32           ninc;
00029 
00030 uint8 *counts, cz_band_present;
00031 int32   *msec;
00032 int lgain,status;
00033 int16 *gain;
00034 float32 *tilt, *att_ang, *slope, *intercept;
00035 float32 *ctl_pt_lat, *ctl_pt_lon, *pos, *pos_err;
00036 int32 nctl_pt, *ctl_pt_cols;
00037 float *ctl_pt_vx, *ctl_pt_vy, *ctl_pt_vz, *y2_vx, *y2_vy, *y2_vz, *ctl_pt_x;
00038 float *lt750;  /* internal 750 mn data source */
00039 char *ring_sat;  /* set to 1 if 443, 520 or 550 are saturated for ringing 
00040                     mask computation */
00041 
00042 int czcs_ring( int gain, float *lt750, char *ring_sat, l1str *l1rec  )
00043 /*******************************************************************
00044 
00045    czcs_ring
00046 
00047    purpose: use the Mueller ringing flagging algorithm to set the stray 
00048      light mask for CZCS
00049 
00050    Returns type: int - 0 if OK
00051 
00052    Parameters: (in calling order)
00053       Type              Name            I/O     Description
00054       ----              ----            ---     -----------
00055       int               gain             I      gain for the line of data
00056       float *           lt750            I      750 nm total rads
00057       char *            ring_sat         I      1 if bands 1,2,or 3 are 
00058                                                 saturated = use the 750 
00059                                                 excess rad in this case
00060       l1str *           l1rec           I/O     L1 struc including tot rads,
00061                                                 flags
00062 
00063    Modification history:
00064       Programmer        Date            Description of change
00065       ----------        ----            ---------------------
00066       W. Robinson       31 May 2005     Original development
00067       W. Robinson       31 Jul 2007     repaired problem that occurs in SGIs
00068                                         if bsum = 0, avoid log and set ring
00069                                         distance to 0
00070 
00071   Based on the algorithm of Mueller, J. L., Nimbus-7 CZCS: electronic
00072   overshoot due to cloud reflectance, Appl. Optics, Vol 27, No 3, 1 Feb, 
00073   1988, pp 438 - 440
00074   Modified to only include the excess radiance in 750 for pixels where 
00075   bands 1, 2, or 3 have saturated.  This is to reduce the masking from
00076   coastal areas where the vis is not as bright as for cloud
00077 
00078 *******************************************************************/
00079 {
00080   static float gtrans[4] = { 1.0, 1.25, 1.5, 2.1 };
00081   /* note that the values below have +- of 9.7 and 3.3 in paper */
00082 /*  standard values followed by low, high confidence values
00083   static float mueller_int = 3.9, mueller_slp = 30.8;
00084   static float mueller_int = -6.2, mueller_slp = 27.5;
00085   static float mueller_int = 13.6, mueller_slp = 34.1;
00086 */
00087   static float mueller_int = 3.9, mueller_slp = 30.8;
00088   
00089   static float l0_750 = 2.45;
00090 
00091   float gfac, lthresh, gfac_ln, excess_brit[1968], bsub, bsum;
00092   int i, ipx, btarg, last_btarg, igrp, iavg, pxloc, n_ring;
00093   extern int32 npix;
00094 
00095  /*
00096   * set up gfac - gain factor for line, lthresh, brightness threshold
00097   * and flags for current and last pixel above threshold radiance
00098   */
00099   gfac = gtrans[ gain - 1];
00100   lthresh = l0_750 / gfac;
00101   gfac_ln = log( gfac );
00102   btarg = 0;
00103   last_btarg = 0;
00104 
00105  /*
00106   * go through pixels and set the mask for pixels downstream of bright target
00107   */
00108   for( i = 0; i < npix; i++ )
00109     {
00110     if( *( lt750 + i ) > lthresh )
00111       {
00112       btarg = 1;
00113       excess_brit[i] = 
00114         ( *( ring_sat + i ) == 1 ) ? *( lt750 + i ) - lthresh : 0.;
00115       l1rec->stlight[i] = 1;
00116       }
00117     else
00118       excess_brit[i] = 0.;
00119 
00120     if( ( btarg == 0 ) && ( last_btarg == 1 ) )
00121       {
00122      /*
00123       *  sum up excess brightness in 5 groups of 10, weighted by f(dist)
00124       */
00125       bsum = 0.;
00126       for( igrp = 0; igrp < 5; igrp++ )
00127         {
00128         bsub = 0.;
00129         for( iavg = 0; iavg < 10; iavg++ )
00130           {
00131           pxloc = i - 1 - ( iavg + igrp * 10 );
00132           if( pxloc >= 0 )
00133             bsub += excess_brit[ pxloc ];
00134           }
00135         bsub = bsub / 10.;
00136         bsum += bsub * exp( -0.32 * ( igrp + 1 ) );
00137         }
00138      /*
00139       * compute # pixels to mask and mark the pixels in that range
00140       */
00141       bsum = ( bsum > 450.) ? 450. : bsum;
00142       if( bsum > 0. )
00143         {
00144         n_ring = mueller_int + mueller_slp * ( log( bsum ) + gfac_ln );
00145         n_ring = ( n_ring < 0 ) ? 0 : n_ring;
00146         }
00147       else 
00148         n_ring = 0;
00149 
00150       for( ipx = 0; ipx < n_ring; ipx++ )
00151         {
00152         pxloc = ipx + i;
00153         if( pxloc < npix )
00154           l1rec->stlight[pxloc] = 1;
00155         }
00156       }
00157    /*
00158     *  lastly, reset to go to next pixel
00159     */
00160     last_btarg = btarg;
00161     btarg = 0;
00162     }
00163   return 0;
00164 }
00165 
00166 #define NBND 4
00167 #define NGAIN 4
00168 #define NEPOCH 5
00169 
00170 int get_czcscal( char *file, int orbit, int16 year, int16 day, int32 msec, short l1acnt[], float slope750, float intercept750, int16 igain, float32 l1brads[] )
00171 /******************************************************************
00172 
00173    get_czcscal
00174    purpose: replicate the Evans & Gordon calibration
00175 
00176    Modification history:
00177       Programmer        Date            Description of change
00178       ----------        ----            ---------------------
00179       Sean Bailey       08 Feb 2006     Original development
00180 
00181   Based on the original czcscaleg.f
00182   Modified to use cal_czcs.hdf
00183 
00184 *******************************************************************/
00185 {
00186     static int firstCall = 1;
00187     int status;
00188     static float slope_coeff[NGAIN][NBND_CZCS];
00189     static float offsets[NGAIN][NBND_CZCS];
00190     static float rk[NGAIN][NBND_CZCS];
00191     static float tdecay[NEPOCH][NBND_CZCS];
00192     static int orbitepoch[NEPOCH];
00193     static float timeconst[2];
00194     static float time_dep[NBND_CZCS][NGAIN][3];
00195 
00196     int epochidx = 0;
00197     int i, j, iorbit;
00198     float rden, rnum, x1, x2; 
00199     float tcorr, slp, S;
00200     static int orbepoch670 = 6750;
00201     float g[NBND];
00202     float64 jsec = yds2unix(year,day,((double)(msec))/1000.0);
00203     float64 refjsec = yds2unix(1978,278,(double)0.0);
00204     float64 decayday = (jsec - refjsec)/86400.;
00205 
00206     igain -= 1;
00207 
00208     if (firstCall) {
00209     char  name   [H4_MAX_NC_NAME]  = "";
00210     char  sdsname[H4_MAX_NC_NAME]  = "";
00211     int32 sd_id;
00212     int32 sds_id;
00213     int32 rank;
00214     int32 nt;
00215     int32 dims[H4_MAX_VAR_DIMS];
00216     int32 nattrs;
00217     int32 start[3] = {0,0,0};
00218     int32 end  [3] = {1,1,1};
00219     int32 status;
00220     /* get the current calibration */
00221     if (file == NULL) {
00222         fprintf(stderr,
00223         "-E %s Line %d: No calibration file specified.\n",
00224         __FILE__,__LINE__);
00225         exit(1);
00226     }
00227 
00228     printf("Loading caltable: %s\n",file);
00229     /* Open the file */
00230     sd_id = SDstart(file, DFACC_RDONLY);
00231     if (sd_id == FAIL){
00232         fprintf(stderr,"-E- %s line %d: SDstart(%s, %d) failed.\n",
00233         __FILE__,__LINE__,file,DFACC_RDONLY);
00234         exit(1);
00235     }
00236     
00237     strcpy(sdsname,"slope_coeff");
00238     sds_id = SDselect(sd_id, SDnametoindex(sd_id,sdsname));
00239     status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
00240     status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) slope_coeff);
00241     if (status != 0) {
00242         printf("-E- %s Line %d:  Error reading SDS %s from %s.\n",
00243         __FILE__,__LINE__,sdsname,file);
00244         exit(1);
00245     } else {
00246         status = SDendaccess(sds_id);
00247     }
00248     
00249     strcpy(sdsname,"offsets");
00250     sds_id = SDselect(sd_id, SDnametoindex(sd_id,sdsname));
00251     status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
00252     status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) offsets);
00253     if (status != 0) {
00254         printf("-E- %s Line %d:  Error reading SDS %s from %s.\n",
00255         __FILE__,__LINE__,sdsname,file);
00256         exit(1);
00257     } else {
00258         status = SDendaccess(sds_id);
00259     }
00260     
00261     strcpy(sdsname,"rk");
00262     sds_id = SDselect(sd_id, SDnametoindex(sd_id,sdsname));
00263     status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
00264     status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) rk);
00265     if (status != 0) {
00266         printf("-E- %s Line %d:  Error reading SDS %s from %s.\n",
00267         __FILE__,__LINE__,sdsname,file);
00268         exit(1);
00269     } else {
00270         status = SDendaccess(sds_id);
00271     }
00272     
00273     strcpy(sdsname,"dec");
00274     sds_id = SDselect(sd_id, SDnametoindex(sd_id,sdsname));
00275     status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
00276     status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) tdecay);
00277     if (status != 0) {
00278         printf("-E- %s Line %d:  Error reading SDS %s from %s.\n",
00279         __FILE__,__LINE__,sdsname,file);
00280         exit(1);
00281     } else {
00282         status = SDendaccess(sds_id);
00283     }
00284     
00285     strcpy(sdsname,"iorbdec");
00286     sds_id = SDselect(sd_id, SDnametoindex(sd_id,sdsname));
00287     status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
00288     status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) orbitepoch);
00289     if (status != 0) {
00290         printf("-E- %s Line %d:  Error reading SDS %s from %s.\n",
00291         __FILE__,__LINE__,sdsname,file);
00292         exit(1);
00293     } else {
00294         status = SDendaccess(sds_id);
00295     }
00296     
00297     strcpy(sdsname,"timeconst");
00298     sds_id = SDselect(sd_id, SDnametoindex(sd_id,sdsname));
00299     status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
00300     status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) timeconst);
00301     if (status != 0) {
00302         printf("-E- %s Line %d:  Error reading SDS %s from %s.\n",
00303         __FILE__,__LINE__,sdsname,file);
00304         exit(1);
00305     } else {
00306         status = SDendaccess(sds_id);
00307     }
00308     
00309     strcpy(sdsname,"time_dep");
00310     sds_id = SDselect(sd_id, SDnametoindex(sd_id,sdsname));
00311     status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
00312     status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) time_dep);
00313     if (status != 0) {
00314         printf("-E- %s Line %d:  Error reading SDS %s from %s.\n",
00315         __FILE__,__LINE__,sdsname,file);
00316         exit(1);
00317     } else {
00318         status = SDendaccess(sds_id);
00319     }
00320     /* terminate access to the SD interface and close the file */
00321     status = SDend(sd_id);
00322 
00323     firstCall = 0;
00324     }
00325 
00326     iorbit = MIN(orbit,39000);
00327     for (j=0; j< NEPOCH - 1; j++) {
00328     if ((iorbit >= orbitepoch[j]) && (iorbit <= orbitepoch[j+1]))
00329         epochidx = j;
00330     }
00331     
00332     x1 = (float) orbitepoch[epochidx];
00333     x2 = (float) orbitepoch[epochidx + 1];
00334     rden = (float) orbitepoch[epochidx + 1] - (float) orbitepoch[epochidx];
00335 
00336     for (i = 0; i < NBND; i++){
00337     /* Calculate time dependent correction... */
00338 /*  double exp  
00339     tcorr = time_dep[i][igain][0] - time_dep[i][igain][1] * (1.0 - exp(timeconst[0]*decayday)) - time_dep[i][igain][2] *(1.0 - exp(timeconst[1]*decayday));
00340 */
00341 /* single exp */
00342     tcorr = time_dep[i][igain][0] - time_dep[i][igain][1] * (1.0 - exp(-1*time_dep[i][igain][2] *decayday));
00343 
00344     rnum = tdecay[epochidx + 1][i] - tdecay[epochidx][i];
00345     slp = rnum/rden;
00346 
00347     /* Antione modification for 670nm */
00348     if (i == 3 && iorbit > orbepoch670) {
00349         rden = (float) orbitepoch[4] - (float) orbepoch670;
00350         rnum = tdecay[4][i] - tdecay[3][i];
00351         slp = rnum/rden;
00352         S = (float) iorbit - (float) orbepoch670;
00353         g[i] = 1.0 / (S * slp + tdecay[3][i]);
00354 
00355     } else {
00356         S = (float) iorbit - (float) orbitepoch[epochidx];
00357         g[i] = 1.0 / (S * slp + tdecay[epochidx][i]);
00358     }
00359     /*fprintf(stderr,"i: %d g: %8.6f tcorr: %8.6f\n",i,g[i],tcorr);*/
00360 
00361     l1brads[i] = (tcorr * g[i] * rk[igain][i] * slope_coeff[igain][i] * (float) l1acnt[i]) + offsets[igain][i];
00362 
00363     }
00364     
00365     l1brads[4] = slope750 * (float) l1acnt[4] + intercept750;
00366 
00367     return 0;
00368 }
00369 /*
00370    W. Robinson, SAIC, 6 Jan 2006  add code to read the position and 
00371    position error SDSes
00372 */
00373 
00374 int openl1_czcs(filehandle *file)
00375 {
00376 
00377     /*                                                                 */
00378     /* get_l1a_open interface                                          */
00379     /*                                                                 */
00380     int32 fileID;
00381     int32 status;
00382     int16 sy, sd;
00383     int i;
00384 
00385     /* open the file and get the file ID */
00386     fileID = SDstart(file->name, DFACC_RDONLY);
00387 
00388     if (fileID < 0) {
00389       fprintf(stderr,
00390           "-E %s Line %d: Error opening %s for reading.\n",
00391           __FILE__,__LINE__,file->name);
00392       return(1);
00393     }
00394     status = getHDFattr(fileID, "Start Year", "", (VOIDP) &sy );
00395     syear = (int32) sy;
00396     status = getHDFattr(fileID, "Start Day", "", (VOIDP) &sd );
00397     sday = (int32) sd;
00398     status = getHDFattr(fileID, "Start Millisec", "", (VOIDP) &smsec);
00399     status = getHDFattr(fileID, "End Year", "", (VOIDP) &eyear);
00400     status = getHDFattr(fileID, "End Day", "", (VOIDP) &eday);
00401     status = getHDFattr(fileID, "End Millisec", "", (VOIDP) &emsec);
00402     status = getHDFattr(fileID, "Number of Scan Lines", "", (VOIDP) &nscan);
00403     status = getHDFattr(fileID, "Data Type", "", (VOIDP) &dtype);
00404 
00405     status = getHDFattr(fileID, "Pixels per Scan Line", "", (VOIDP) &npix);
00406     status = getHDFattr(fileID, "LAC Pixel Start Number", "", (VOIDP) &nsta);
00407     status = getHDFattr(fileID, "LAC Pixel Subsampling", "", (VOIDP) &ninc);
00408 
00409     status = getHDFattr(fileID, "Orbit Number", "", (VOIDP)&file->orbit_number);
00410    /*  WDR not in czcs l1 file, so comment for now
00411     status = getHDFattr(fileID, "Orbit Node Longitude", "", 
00412         (VOIDP)&file->orbit_node_lon);
00413     status = getHDFattr(fileID, "Node Crossing Time", "", 
00414         (VOIDP)&file->node_crossing_time[0]);
00415     */
00416     status = getHDFattr( fileID, "Number of Pixel Control Points", "", 
00417        (VOIDP)&nctl_pt );
00418     status = getHDFattr( fileID, "Parameter Presence Code", "", 
00419        (VOIDP)&cz_band_present );
00420 
00421     /* call cdata.f to initialize global FORTRAN common block data  */
00422     cdata_();
00423 
00424 
00425     file->npix     = npix;
00426     file->nscan    = nscan;
00427     file->sensorID = CZCS;
00428     file->sd_id = fileID;
00429 
00430     msec = (int32 *) calloc(nscan, sizeof(int32));
00431     status = rdSDS(file->sd_id,"msec",0,0,0,0, (VOIDP) msec);
00432 
00433     att_ang = (float32 *) calloc( nscan * 3, sizeof( float32 ) );
00434     status = rdSDS( file->sd_id, "att_ang", 0, 0, 0, 0, (VOIDP) att_ang );
00435 
00436     ctl_pt_cols = (int32 *) calloc( nctl_pt, sizeof( int32 ) );
00437     status = rdSDS( file->sd_id, "cntl_pt_cols", 0, 0, 0, 0, 
00438        (VOIDP) ctl_pt_cols );
00439     ctl_pt_x = (float *) calloc( nctl_pt, sizeof( float ) );
00440     for( i = 0; i < nctl_pt; i++ )
00441       ctl_pt_x[i] = (float) ctl_pt_cols[i] - 1.;
00442 
00443     tilt = (float32 *) calloc(nscan, sizeof(float32));
00444     status = rdSDS(file->sd_id,"tilt",0,0,0,0, (VOIDP) tilt);
00445 
00446     slope = (float32 *) calloc(nscan * 6, sizeof(float32));
00447     status = rdSDS(file->sd_id,"slope",0,0,0,0, (VOIDP) slope );
00448     intercept = (float32 *) calloc(nscan * 6, sizeof(float32));
00449     status = rdSDS(file->sd_id,"intercept",0,0,0,0, (VOIDP) intercept );
00450    /* get nav orbit data  */
00451     pos = (float32 *) malloc( nscan * 3 * sizeof(float32) );
00452     status = rdSDS( file->sd_id, "orb_vec", 0, 0, 0, 0, (VOIDP) pos );
00453     pos_err = (float32 *) malloc( nscan * sizeof(float32) );
00454     status = rdSDS( file->sd_id, "pos_err", 0, 0, 0, 0, (VOIDP) pos_err );
00455 
00456     gain = (int16 *) malloc( nscan * sizeof( int16 ) );
00457     counts = (uint8 *) malloc( npix * NBND_CZCS* sizeof( uint8 ) );
00458     ctl_pt_lat = (float32 *) malloc( nctl_pt * sizeof( float32 ) );
00459     ctl_pt_lon = (float32 *) malloc( nctl_pt * sizeof( float32 ) );
00460     ctl_pt_vx = (float32 *) malloc( nctl_pt * sizeof( float32 ) );
00461     ctl_pt_vy = (float32 *) malloc( nctl_pt * sizeof( float32 ) );
00462     ctl_pt_vz = (float32 *) malloc( nctl_pt * sizeof( float32 ) );
00463     y2_vx = (float32 *) malloc( npix * sizeof( float32 ) );
00464     y2_vy = (float32 *) malloc( npix * sizeof( float32 ) );
00465     y2_vz = (float32 *) malloc( npix * sizeof( float32 ) );
00466     lt750 = (float *) malloc( npix * sizeof( float ) );
00467     ring_sat = (char *) malloc( npix * sizeof( char ) );
00468 
00469     spix = nsta - 1;
00470     dpix = ninc;
00471     epix = spix + npix * dpix;
00472 
00473     
00474     return (status);
00475 }
00476 
00477 /*
00478  W. Robinson       31 May 2005     add ringing masking call
00479  W. Robinson, SAIC, 6 Jan 2005     add code to compute sat angles with
00480                                    cz_posll_2_satang if pos_err is acceptable
00481  J. Gales          23 Sep 2005     add kludge for subsetted pixel range in
00482                                    satang
00483    (note that satang may not give proper values in pixel subsets with this 
00484     but it may be academic with...)
00485  W. Robinson, SAIC, 10 Sep 2010    use vectors instead of lat, lon when
00486                                    doing interpolation of ctl pt lat, lon to
00487                                    all samples
00488  */
00489 
00490 int readl1_czcs(filehandle *file, int32_t recnum, l1str *l1rec)
00491 {
00492   /*void czcscal_( int *, float[], float[], short *, int *, float * );*/
00493   void satang_( double *, double *, float *, float *, float *, float *, 
00494     float *, float *, float *, float * );
00495   void sunangs_( int *, int *, float *, float *, float *, float *, float * );
00496   int ll2vec( float *, float * );
00497   int vec2ll( float *, float * );
00498   short cnt_vec[NBND_CZCS];
00499   float lt_lcl[NBND_CZCS], yout1, yout2, yout3, llvec[2], vec[3], gmt;
00500   int ipx, ibnd, orbit, i, tpix;
00501   uint8 cal_sum[5], cal_scan[6];
00502   int32 status, navbad, ltsat;
00503   double pi, radeg;
00504   int32_t ib;
00505 
00506   int32_t  nwave = l1rec->nbands;
00507   int32_t *bindx = l1rec->bindx;
00508   char *cal_path = file->calfile;
00509   /* load scan times */
00510 /*  int year = *l1rec->year;
00511   int day = *l1rec->day;*/
00512 /*  int32 msec = l1rec->msec[recnum];*/
00513 
00514   float lonbuf[1968], latbuf[1968], senzbuf[1968], senabuf[1968];
00515 
00516  /*
00517   *  read in the line of counts, latitude, longitude
00518   */
00519   status = rdSDS( file->sd_id, "band1", recnum, 0, 1, npix, (VOIDP) counts );
00520   status = rdSDS( file->sd_id, "band2", recnum, 0, 1, npix, 
00521     (VOIDP) ( counts + npix ) );
00522   status = rdSDS( file->sd_id, "band3", recnum, 0, 1, npix, 
00523     (VOIDP) ( counts + 2 * npix ) );
00524   status = rdSDS( file->sd_id, "band4", recnum, 0, 1, npix,
00525     (VOIDP) ( counts + 3 * npix ) );
00526   status = rdSDS( file->sd_id, "band5", recnum, 0, 1, npix,
00527     (VOIDP) ( counts + 4 * npix ) );
00528 
00529   status = rdSDS( file->sd_id, "gain", recnum, 0, 1, 1, (VOIDP) gain);
00530   status = rdSDS( file->sd_id, "latitude", recnum, 0, 1, nctl_pt, 
00531     (VOIDP) ctl_pt_lat );
00532   status = rdSDS( file->sd_id, "longitude", recnum, 0, 1, nctl_pt,     
00533     (VOIDP) ctl_pt_lon );
00534 
00535   status = rdSDS( file->sd_id, "cal_sum", recnum, 0, 1, 5, (VOIDP) cal_sum );
00536   status = rdSDS( file->sd_id, "cal_scan", recnum, 0, 1, 6, (VOIDP) cal_scan );
00537  /*
00538   * flag setting for entire line: set navfail if cal_sum shows problems 
00539   * (suspect it is * bad ephemeris or atitude) and set hilt if bands 
00540   * missing
00541   */
00542   ltsat = 0;
00543   navbad = 0;
00544   if( ( cz_band_present & 0XF8 ) != 0XF8 )
00545     ltsat = 1;
00546   else
00547     {
00548     if( ( cal_sum[3] != 0 ) || ( cal_sum[4] != 0 ) )
00549       navbad = 1;
00550     if( ( cal_scan[0] != 0 ) || ( cal_scan[1] != 0 ) ||
00551         ( cal_scan[2] != 0 ) || ( cal_scan[3] != 0 ) ||
00552         ( cal_scan[4] != 0 ) )
00553       {
00554       ltsat = 1;
00555       navbad = 1;
00556       }
00557     }
00558  /*
00559   * calibrate the radiances and set flags for pixels
00560   */
00561   for( ipx = 0; ipx < npix; ipx++ )
00562     {
00563     for( ibnd = 0; ibnd < NBND_CZCS; ibnd++ )
00564       {
00565       cnt_vec[ibnd] = *( counts + ipx + ibnd * npix );
00566       if( ( cnt_vec[ibnd] == 255) || ( ltsat == 1 ) ) l1rec->hilt[ipx] = 1;
00567       }
00568     *( ring_sat + ipx ) = ( ( cnt_vec[0] == 255 ) || ( cnt_vec[1] == 255 ) 
00569                          || ( cnt_vec[2] == 255 ) ) ? 1 : 0;
00570    /*
00571     *  call the fortran calibration routine 
00572     */
00573     orbit = ( int ) file->orbit_number;
00574     /*czcscal_( &orbit, slope + recnum * 6, 
00575       intercept + recnum * 6, cnt_vec, &lgain, lt_lcl );*/
00576     status = get_czcscal( cal_path, orbit, syear, sday, msec[recnum],  
00577       cnt_vec, slope[4], intercept[4], gain[0], lt_lcl );
00578    /*
00579     *  assign the calibrated radiances
00580     */
00581     for( ibnd = 0; ibnd < nwave; ibnd++ )
00582       {
00583       ib = bindx[ ibnd ];
00584       l1rec->Lt[ ipx * NBANDS + ib ] = lt_lcl[ibnd];
00585       }
00586    /*
00587     *  save the 750 nm data here
00588     */
00589     *( lt750 + ipx ) = lt_lcl[4];
00590 
00591     if( navbad == 1 ) l1rec->navfail[ipx] = 1;
00592     }
00593  /*
00594   *  set the ringing mask
00595   */
00596   czcs_ring( gain[0], lt750, ring_sat, l1rec );
00597  /*
00598   *  get navigation at all points from control point lat and lon values
00599   *  use spline interpolation to fill in, do in vector space to avoid date 
00600   *  line discontinuity
00601   */
00602   for( i = 0; i < nctl_pt; i++ )
00603     {
00604     llvec[0] = ctl_pt_lat[i];
00605     llvec[1] = ctl_pt_lon[i];
00606     if( ll2vec( llvec, vec ) == 0 )
00607       {
00608       ctl_pt_vx[i] = *vec;
00609       ctl_pt_vy[i] = *( vec + 1 );
00610       ctl_pt_vz[i] = *( vec + 2 );
00611       }
00612     else
00613       {
00614       fprintf(stderr, "-E %s Line %d: ll2vec failure.\n",
00615         __FILE__,__LINE__);
00616       exit(1);
00617       }
00618     }
00619   spline( ctl_pt_x, ctl_pt_vx, nctl_pt, 1e30, 1e30, y2_vx );
00620   spline( ctl_pt_x, ctl_pt_vy, nctl_pt, 1e30, 1e30, y2_vy );
00621   spline( ctl_pt_x, ctl_pt_vz, nctl_pt, 1e30, 1e30, y2_vz );
00622   for( i = 0; i < npix; i++ )
00623     {
00624     tpix = i * ninc /*+ spix*/;
00625     splint( ctl_pt_x, ctl_pt_vx, y2_vx, nctl_pt, tpix, &yout1 );
00626     splint( ctl_pt_x, ctl_pt_vy, y2_vy, nctl_pt, tpix, &yout2 );
00627     splint( ctl_pt_x, ctl_pt_vz, y2_vz, nctl_pt, tpix, &yout3 );
00628 
00629     *vec = yout1; *( vec + 1 ) = yout2; *( vec + 2 ) = yout3;
00630     vec2ll( vec, llvec );
00631     
00632     l1rec->lon[i] = llvec[1];
00633     l1rec->lat[i] = llvec[0];
00634     }
00635  /*
00636   * calculate geometry.  For sensor angles, use the orbit info if the 
00637   * position error is available and within error threshold
00638   */
00639   if( ( *( pos_err + recnum ) >= 0. ) && 
00640       ( *( pos_err + recnum ) < POS_ERR_THRESH ) )
00641     {
00642     cz_posll_2_satang( ( pos + 3 * recnum ), npix, l1rec->lat, l1rec->lon,
00643       l1rec->senz, l1rec->sena );
00644     }
00645   else
00646     {
00647     pi = PI;  radeg = RADEG;
00648     for (i=0; i<1968; i++) {
00649       lonbuf[i] = 0.0;
00650       latbuf[i] = 0.0;
00651       senzbuf[i] = 0.0;
00652       senabuf[i] = 0.0;
00653     }
00654   
00655     for (i=0; i<npix; i++) {
00656       lonbuf[i] = l1rec->lon[i];
00657       latbuf[i] = l1rec->lat[i];
00658     }
00659   
00660     satang_( &pi, &radeg, tilt + recnum, att_ang + 3 * recnum + 1, 
00661       att_ang + 3 * recnum + 2, att_ang + 3 * recnum, lonbuf, 
00662       latbuf, senzbuf, senabuf );
00663   
00664     for (i=0; i<npix; i++) {
00665       l1rec->senz[i] = senzbuf[i];
00666       l1rec->sena[i] = senabuf[i];
00667     }
00668   }
00669 
00670 
00671   /*  for( i = spix; i < epix; i = i + ninc )*/
00672   for (i=0; i<npix; i++)
00673     {
00674     gmt = (float) msec[recnum] / ( 1000. * 3600 );
00675     sunangs_( &syear, &sday, &gmt, ( l1rec->lon ) + i, ( l1rec->lat ) + i, 
00676       ( l1rec->solz ) + i, ( l1rec->sola ) + i );
00677     }
00678  /*
00679   *  set scan time
00680   */
00681   if( recnum > 0 )
00682     {
00683     if( msec[recnum] < msec[recnum-1] )
00684       {
00685 printf("changing the day\n");
00686       sday += 1;
00687       if( *l1rec->day > ( 365 + ( *l1rec->year % 4 == 0 ) ) )
00688         {
00689         syear += 1;
00690         sday   = 1;
00691         }
00692       }
00693     }
00694   *l1rec->year = syear;
00695   *l1rec->day = sday;
00696   *l1rec->msec = msec[recnum];
00697 
00698   return(status);
00699 }
00700 
00701 /*  W. Robinson, SAIC, 6 Jan 2005   include the pos, pos_err arrays in free */
00702 
00703 int closel1_czcs(filehandle *file)
00704 {
00705   free(msec);
00706   free(tilt);
00707   free( att_ang );
00708   free( counts );
00709   free( ctl_pt_lat );
00710   free( ctl_pt_lon );
00711   free( ctl_pt_vx );
00712   free( ctl_pt_vy );
00713   free( ctl_pt_vz );
00714   free( y2_vx );
00715   free( y2_vy );
00716   free( y2_vz );
00717   free( ctl_pt_x );
00718   free( ctl_pt_cols );
00719   free( slope );
00720   free( intercept );
00721   free( lt750 );
00722   free( ring_sat );
00723   free( pos );
00724   free( pos_err );
00725 
00726   SDend(file->sd_id);
00727 
00728   return(0);
00729 }
00730 
00731 #define re 6378.137
00732 #define f 1. / 298.257
00733 #define omf2 ( 1 - f ) * ( 1 - f )
00734 
00735 int cz_posll_2_satang( float *pos, int npix, float *lat, float *lon,
00736   float *senz, float *sena )
00737 /*******************************************************************
00738 
00739    cz_posll_2_satang
00740 
00741    purpose: convert satellite position, lat, lon into satellite zenith 
00742      and azimuth for a line of czcs data
00743 
00744    Returns type: int - 0 if no problems
00745 
00746    Parameters: (in calling order)
00747       Type              Name            I/O     Description
00748       ----              ----            ---     -----------
00749       float *           pos              I      position (x, y, z) of 
00750                                                 satellite in meters
00751       int               npix             I      # pixels of lat, lon to find
00752                                                 sat angles for
00753       float *           lat              I      latitude array in degrees E
00754       float *           lon              I      longitude array in degrees E
00755       float *           senz             O      sensor zenith in degrees
00756       float *           sena             O      sensor azimuth in degrees
00757 
00758    Modification history:
00759       Programmer        Date            Description of change
00760       ----------        ----            ---------------------
00761       W. Robinson, SAIC  5-Jan-2006     Original development
00762 
00763 *******************************************************************/
00764   {
00765   double up[3], ea[3], no[3], radeg, upxy, xlmat[3][3], xlatg, gv[3];
00766   double r, rh[3], rl[3];
00767   int i, j;
00768 
00769   radeg = 90. / asin( 1. );
00770 
00771   for( i = 0; i < npix; i++ )
00772     {
00773    /*
00774     *  Compute the local vertical, East and North unit vectors
00775     */
00776     up[0] = cos( *( lat + i ) / radeg ) * cos( *( lon + i ) / radeg );
00777     up[1] = cos( *( lat + i ) / radeg ) * sin( *( lon + i ) / radeg );
00778     up[2] = sin( *( lat + i ) / radeg );
00779 
00780     upxy = sqrt( up[0] * up[0] + up[1] * up[1] );
00781 
00782     ea[0] = -up[1] / upxy;
00783     ea[1] = up[0] / upxy;
00784     ea[2] = 0.;
00785 
00786     cross_prod( up, ea, no );
00787 
00788    /*
00789     *  Store vectors in 3x3 array
00790     */
00791     for( j = 0; j < 3; j++ )
00792       {
00793       xlmat[0][j] = ea[j];
00794       xlmat[1][j] = no[j];
00795       xlmat[2][j] = up[j];
00796       }
00797    /*
00798     *  Compute geocentric position vector
00799     */
00800     xlatg = radeg * atan( tan( *( lat + i ) / radeg ) * omf2 );
00801     gv[0] = cos( xlatg / radeg ) * cos( *( lon + i ) / radeg );
00802     gv[1] = cos( xlatg / radeg ) * sin( *( lon + i ) / radeg );
00803     gv[2] = sin( xlatg / radeg );
00804 
00805     r = re * ( 1. - f ) / 
00806           sqrt( 1. - ( 2. - f ) * f * pow( cos( xlatg / radeg ), 2 ) );
00807 
00808    /* note that pos is in m but rest of constants are in km, hence the 
00809       1000 factor  */
00810     for( j = 0; j < 3; j++ )
00811       rh[j] = pos[j] / 1000. - r * gv[j];
00812    /*
00813     *  Transform the pixel-to-spacecraft vector into the local frame
00814     */
00815     matrix_mult( rh, xlmat, rl );
00816    /*
00817     *  Compute the sensor zenith and azimuth
00818     *  if zenith close to 0, set azimuth to 0 (and normalize azimuth)
00819     */
00820     *( senz + i ) = radeg * atan2( sqrt( rl[0] * rl[0] + rl[1] * rl[1] ), 
00821           rl[2] );
00822     if( *( senz + i ) > 0.05 )
00823       *( sena + i ) = radeg * atan2( rl[0], rl[1] );
00824     else
00825       *( sena + i ) = 0.;
00826 
00827     if( *( sena + i ) < 0. ) *( sena + i ) += 360.;
00828     }
00829  /*
00830   *  and end
00831   */ 
00832   return 0;
00833   }
00834 
00835 void matrix_mult( double vecin[3], double matrix[3][3], double vecout[3] )
00836 /*******************************************************************
00837 
00838    matrix_mult
00839 
00840    purpose: multiply a vector by a matrix and produce the output vector
00841 
00842    Returns type: void
00843 
00844    Parameters: (in calling order)
00845       Type              Name            I/O     Description
00846       ----              ----            ---     -----------
00847       double[3]         vecin            I      input vector
00848       double[3][3]      matrix           I      rotation matrix
00849       double[3]         vecout           O      rotated vector
00850 
00851    Modification history:
00852       Programmer        Date            Description of change
00853       ----------        ----            ---------------------
00854       W. Robinson, SAIC  2-Nov-2005     Original development
00855 
00856 *******************************************************************/
00857   {
00858   int i, j;
00859   for( i = 0; i < 3; i++ )
00860     {
00861     vecout[i] = 0.;
00862     for( j = 0; j < 3; j++ )
00863       {
00864       vecout[i] += matrix[i][j] * vecin[j];
00865       }
00866     }
00867   }
00868 
00869 void cross_prod( double *v1, double *v2, double *vout )
00870 /*******************************************************************
00871 
00872    cross_prod
00873 
00874    purpose: produce the cross product of 2 vectors
00875 
00876    Returns type: void
00877 
00878    Parameters: (in calling order)
00879       Type              Name            I/O     Description
00880       ----              ----            ---     -----------
00881       double *          v1               I      vector 1
00882       double *          v2               I      vector 1
00883       double *          vout             O      v1 X v2
00884 
00885    Modification history:
00886       Programmer        Date            Description of change
00887       ----------        ----            ---------------------
00888       W. Robinson, SAIC  4-Jan-2006     Original development
00889 
00890 *******************************************************************/
00891   {
00892   *vout = v1[1] * v2[2] - v1[2] * v2[1];
00893   *( vout + 1 ) = v1[2] * v2[0] - v1[0] * v2[2];
00894   *( vout + 2 ) = v1[0] * v2[1] - v1[1] * v2[0];
00895   }