Example #1
0
// Input:
//   meta_parameters *meta_sar--  SAR geometry to subset the DEM
//   const char *demImg       --  DEM data filename
//   const char *demMeta      --  DEM metadata filename
//   int pad                  --  number of lines to add at the top/bottom/left/right
//   double tolerance         --  how accurate the approximation mapping needs to be,
//                                in units of pixels
//   const char *output_name  --  output filename (basename)
//   int test_mode            --  adds checks for the accuracy of the mapping, and
//                                does some unit testing
// Output:
//   no output parameters, the output is the output_name files (.img and .meta)
// Return Value:
//   return TRUE on success, FALSE on fail
//
int make_gr_dem_ext(meta_parameters *meta_sar, const char *demImg, const char *demMeta,
                    int pad, double tolerance, const char *output_name, int test_mode)
{
  if (test_mode)
    test_interp();
  
  asfPrintStatus("Reading DEM...\n");
  meta_parameters *meta_dem = meta_read(demMeta);
  float *demData = NULL;
  FloatImage *fi_dem = NULL;

  int dnl = meta_dem->general->line_count;
  int dns = meta_dem->general->sample_count;

  if (0)
    demData = read_dem(meta_dem, demImg);
  else
    fi_dem = float_image_new_from_metadata(meta_dem, demImg);

  if (demData)
    asfPrintStatus("Old method: reading entire DEM.\n");
  if (fi_dem)
    asfPrintStatus("New method: float image\n");
  if (demData && fi_dem)
    asfPrintError("Impossible.\n");

  char *outImg = appendExt(output_name, ".img");
  char *output_name_tmp, *outImgTmp;

  // do not do DEM smoothing if the DEM pixel size is better or close to the
  // SAR image's pixel size.
  int do_averaging = TRUE;
  if (meta_dem->general->y_pixel_size - 10 < meta_sar->general->y_pixel_size)
    do_averaging = FALSE;
  asfPrintStatus("Averaging: %s (DEM %f, SAR: %f)\n", do_averaging ? "YES" : "NO",
                 meta_dem->general->y_pixel_size,
                 meta_sar->general->y_pixel_size);
  if (do_averaging) {
    output_name_tmp = appendStr(output_name, "_unsmoothed");
    outImgTmp = appendExt(output_name_tmp, ".img");
  }
  else {
    output_name_tmp = STRDUP(output_name);
    outImgTmp = STRDUP(outImg);
  }

  // add the padding if requested
  meta_parameters *meta_out = meta_copy(meta_sar);
  meta_out->general->line_count += pad*2;
  meta_out->general->sample_count += pad*2;
  meta_out->general->start_line -= pad;
  meta_out->general->start_sample -= pad;

  // fixing up the output metadata.  Note that we must keep the SAR section
  // intact since that specifies our geometry which is the whole point of
  // this exercise.
  strcpy(meta_out->general->basename, meta_dem->general->basename);
  strcpy(meta_out->general->sensor, MAGIC_UNSET_STRING);
  strcpy(meta_out->general->processor, MAGIC_UNSET_STRING);
  strcpy(meta_out->general->mode, MAGIC_UNSET_STRING);
  strcpy(meta_out->general->sensor_name, MAGIC_UNSET_STRING);
  meta_out->general->image_data_type = DEM;
  meta_out->general->radiometry = MAGIC_UNSET_INT;
  strcpy(meta_out->general->acquisition_date, meta_dem->general->acquisition_date);
  meta_out->general->orbit = MAGIC_UNSET_INT;
  meta_out->general->orbit_direction = MAGIC_UNSET_CHAR;
  meta_out->general->frame = MAGIC_UNSET_INT;
  meta_out->general->band_count = 1;
  strcpy(meta_out->general->bands, "DEM");

  int nl = meta_out->general->line_count;
  int ns = meta_out->general->sample_count;

  // finding the right grid size
  int size = find_grid_size(meta_sar, meta_dem, 512, .1*tolerance);

  asfPrintStatus("Creating ground range image...\n");

  float *buf = MALLOC(sizeof(float)*ns*size);
  FILE *fpOut = FOPEN(outImgTmp, "wb");

  // these are for tracking the quality of the bilinear interp
  // not used if test_mode is false
  int num_out_of_tol = 0;
  int num_checked = 0;
  int num_bad = 0;
  double max_err = 0;
  double avg_err = 0;

  int ii, jj;
  for (ii=0; ii<nl; ii += size) {
    int line_lo = ii;
    int line_hi = ii + size;

    for (jj=0; jj<ns; jj += size) {
      double lines[4], samps[4];
      
      int samp_lo = jj;
      int samp_hi = jj + size;

      get_interp_params(meta_sar, meta_dem, line_lo, line_hi, samp_lo, samp_hi,
                        lines, samps);

      int iii, jjj;
      for (iii=0; iii<size; ++iii) {
        for (jjj=0; jjj<size && jj+jjj<ns; ++jjj) {
          int index = iii*ns + jj + jjj;
          assert(index < ns*size);

          double line_out, samp_out;
          xy_interp(ii+iii, jj+jjj, line_lo, line_hi, samp_lo, samp_hi, lines, samps,
                    &line_out, &samp_out);

          // random checking of the quality of our interpolations
          if (test_mode && iii%11==0 && jjj%13==0) {
            double real_line, real_samp; 
            sar_to_dem(meta_sar, meta_dem, ii+iii, jj+jjj, &real_line, &real_samp);

            double err = hypot(real_line - line_out, real_samp - samp_out);

            avg_err += err;
            if (err > max_err)
              max_err = err;

            if (err > tolerance) {
              asfPrintStatus("Out of tolerance at %d,%d: (%f,%f) vs (%f,%f) -> %f\n",
                             ii+iii, jj+jjj, line_out, samp_out, real_line, real_samp,
                             err);
              ++num_out_of_tol;
            }
            if (err > .5) {
              asfPrintStatus("Error is larger than 1 pixel!\n");
              ++num_bad;
            }
            ++num_checked;
          }
          if (demData)
            buf[index] = interp_demData(demData, dnl, dns, line_out, samp_out);
          else if (fi_dem)
            buf[index] = interp_dem(fi_dem, line_out, samp_out);
          else
            asfPrintError("Oops.\n");
        }
      }
    }

    put_float_lines(fpOut, meta_out, ii, size, buf);
    asfPrintStatus("Completed %.1f%%  \r", 100.*ii/(double)nl);
  }
  asfPrintStatus("Completed 100%%   \n");

  if (test_mode) {
    asfPrintStatus("Tolerance was %f\n", tolerance);
    asfPrintStatus("%d/%d checked pixels had error exceeding tolerance. (%.1f%%)\n",
                   num_out_of_tol, num_checked, 100.*num_out_of_tol/(double)num_checked);
    asfPrintStatus("%d/%d checked pixels had error larger than half a pixel. (%.1f%%)\n",
                   num_bad, num_checked, 100.*num_bad/(double)num_checked);
    asfPrintStatus("Maximum error: %f pixels\n", max_err);
    avg_err /= (double)num_checked;
    asfPrintStatus("Average error: %f pixels\n", avg_err);
  }

  FCLOSE(fpOut);
  meta_write(meta_out, outImgTmp);

  meta_free(meta_out);
  meta_free(meta_dem);

  FREE(buf);
  FREE(demData);
  if (fi_dem)
    float_image_free(fi_dem);

  // now apply 3x3 filter
  if (do_averaging) {
    asfPrintStatus("Smoothing with 3x3 kernel ...\n");
    smooth(outImgTmp, outImg, 3, EDGE_TRUNCATE);
  }

  FREE(outImg);
  FREE(outImgTmp);
  FREE(output_name_tmp);

  return FALSE;
}
Example #2
0
int main(int argc, char *argv[])
{
	char *MOD021KMfile, *MOD02HKMfile, *MOD02QKMfile;
	char *filename;	/* output file */

	FILE *fp;
	int outfile_exists;

	char *ancpath;
	SDS sds[Nitems], outsds[Nbands], dem, height;
	int32 MOD02QKMfile_id, MOD02HKMfile_id, MOD021KMfile_id;
	int32 sd_id, attr_index, count, num_type;

	int ib, j, iscan, Nscans, irow, jcol, idx, crsidx;
	int nbands;

	char *SDSlocatorQKM[Nitems] = {"EV_250_RefSB", "EV_250_RefSB",
		"EV_500_RefSB", "EV_500_RefSB", "EV_500_RefSB",
		"EV_500_RefSB", "EV_500_RefSB","EV_1KM_RefSB", "EV_1KM_RefSB",
		"EV_1KM_RefSB", "EV_1KM_RefSB", "EV_1KM_RefSB", "EV_1KM_RefSB",
		"EV_1KM_RefSB", "EV_1KM_RefSB", "EV_1KM_RefSB", "SolarZenith",
		"SensorZenith", "SolarAzimuth", "SensorAzimuth", "Longitude",
		"Latitude"};

	char *SDSlocatorHKM[Nitems] = {"EV_500_RefSB",
		"EV_500_RefSB", "EV_500_RefSB", "EV_500_RefSB",
		"EV_500_RefSB", "EV_500_RefSB", "EV_500_RefSB",
		"Reflectance_Img_I1","Reflectance_Img_I2","Reflectance_Img_I3",
		"EV_1KM_RefSB","EV_1KM_RefSB","EV_1KM_RefSB", "EV_1KM_RefSB",
		"EV_1KM_RefSB", "EV_1KM_RefSB","SolZenAng_Mod",
		"SenZenAng_Mod", "SolAziAng_Mod", "SenAziAng_Mod", "Longitude",
		"Latitude" };

	char *SDSlocator1KM[Nitems] = {"Reflectance_Mod_M5",
		"Reflectance_Mod_M7", "Reflectance_Mod_M3",
		"Reflectance_Mod_M4", "Reflectance_Mod_M8",
		"Reflectance_Mod_M10",  "Reflectance_Mod_M11",
		"EV_1KM_RefSB", "EV_1KM_RefSB", "EV_1KM_RefSB", "EV_1KM_RefSB",
		"EV_1KM_RefSB", "EV_1KM_RefSB",
		"EV_1KM_RefSB", "EV_1KM_RefSB", "EV_1KM_RefSB", "SolZenAng_Mod",
		"SenZenAng_Mod", "SolAziAng_Mod", "SenAziAng_Mod", "Longitude",
		"Latitude"};

	char indexlocator[Nitems] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 7,
		9, 10, 0, 0, 0, 0, 0, 0};

	char numtypelocator[Nitems] = {DFNT_UINT16, DFNT_UINT16, DFNT_UINT16,
		DFNT_UINT16, DFNT_UINT16, DFNT_UINT16, DFNT_UINT16,
		DFNT_UINT16, DFNT_UINT16, DFNT_UINT16, DFNT_UINT16,
		DFNT_UINT16, DFNT_UINT16, DFNT_UINT16, DFNT_UINT16,
		DFNT_UINT16,DFNT_FLOAT32 ,DFNT_FLOAT32 ,DFNT_FLOAT32 ,DFNT_FLOAT32 ,
		DFNT_FLOAT32, DFNT_FLOAT32};

	uint16 *l1bdata[Nbands];
	float32 *sola, *solz, *sena, *senz, *solzfill;
	float32 *lon, *lat, *lonfill, *latfill;
	char *attr_name;
	float64 scale_factor[Nitems], add_offset[Nitems];

	unsigned char process[Nbands];

	float refl, *mus, muv, phi;
	float *rhoray, *sphalb, *TtotraytH2O, *tOG;
	int aggfactor, crsrow1, crsrow2, crscol1, crscol2;
	int crsidx11, crsidx12, crsidx21, crsidx22;
	float mus0, mus11, mus12, mus21, mus22;
	float fractrow, fractcol, t, u;
	float rhoray0, rhoray11, rhoray12, rhoray21, rhoray22;
	float sphalb0, sphalb11, sphalb12, sphalb21, sphalb22;
	float reflmin=REFLMIN, reflmax=REFLMAX, maxsolz=MAXSOLZ;
	int bad;

	int write_mode = DFACC_CREATE;

	int st;

	size_t nbytes;

	int ftype;

	extern char *optarg;
	extern int optind, opterr;
	int option_index = 0;

	static int verbose, overwrite;
	static int gzip, append;

	static int output500m, output1km;
	static int sealevel, TOA, nearest;

	char dummy[H4_MAX_NC_NAME];

	enum{OPT_BANDS = 1, OPT_RANGE, OPT_OUTFILE, OPT_MAXSOLZ};

	static struct option long_options[] = {
		{"1km",		no_argument,		&output1km, 1},
		{"500m",	no_argument,		&output500m, 1},
		{"append",	no_argument,		&append, 1},
		{"bands",	required_argument,	(int *) NULL, OPT_BANDS},
		{"gzip",	no_argument,		&gzip,	1},
		{"maxsolz",	required_argument,	(int *) NULL, OPT_MAXSOLZ},
		{"nearest",	no_argument,		&nearest, 1},
		{"of",		required_argument,	(int *) NULL, OPT_OUTFILE},
		{"overwrite",	no_argument,		&overwrite, 1},
		{"range",	required_argument,	(int *) NULL, OPT_RANGE},
		{"sealevel",	no_argument,		&sealevel, 1},
		{"toa",		no_argument,		&TOA, 1},
		{"verbose",	no_argument,		&verbose, 1},
		{(char *) NULL, 0, (int *) NULL, 0}
		};

	int c;

	static char dem_filename_buff[MAXNAMELENGTH];


	MOD021KMfile = MOD02HKMfile = MOD02QKMfile = (char *) NULL;
	filename = (char *) NULL;

	for (ib = 0; ib < Nbands; ib++) process[ib] = FALSE;

	/* default settings */
	output500m = output1km = 0;
	append = gzip = nearest = sealevel = TOA = verbose = overwrite = 0;


	while ((c = getopt_long(argc, argv, "", long_options,
		&option_index)) >= 0) {

		switch (c) {
			case 0:
				/* do nothing for options which will have a
				flag set automatically by getopt_long() */
				break;

			case OPT_BANDS:
				if (parse_bands(optarg, process)) {
					fputs("Invalid band(s) specified.\n",
						stderr);
					exit(1);
					}
				break;

			case OPT_RANGE:
				if (sscanf(optarg, "%g,%g", &reflmin, &reflmax) != 2) {
					fputs("Error parsing reflectance range.\n", stderr);
					exit(1);
					}

				if ( range_check(reflmin, 0.0F, 1.0F) ||
					range_check(reflmax, 0.0F, 1.0F) ||
					(reflmin >= reflmax) ) {
					fputs("Invalid reflectance range.\n", stderr);
					exit(1);
					}

				printf("Output reflectance range [%.3f,%.3f] requested.\n",
					reflmin, reflmax);
				break;

			case OPT_MAXSOLZ:
				maxsolz = (float) atof(optarg);
				if (range_check(maxsolz, 0.0F, 90.0F)) {
					fputs("Invalid max. solar zenith angle.\n", stderr);
					exit(1);
					}
				break;

			case OPT_OUTFILE:
				filename = optarg;
				break;

			default:
				usage();
				exit(1);
			}
		}

	if (append) write_mode = DFACC_RDWR;

	/* at least one input file must follow */
	if (optind >= argc) {
		usage();
		exit(1);
		}


	/* check for conflicting options */
	if (overwrite && append) {
		fputs("Options --overwrite and --append are mutually exclusive.\n",
			stderr);
		exit(1);
		}
	if (sealevel && TOA) {
		fputs("Options --sealevel and --toa are mutually exclusive.\n",
			stderr);
		exit(1);
		}

#ifdef DEBUG
printf("append = %d\n", append);
if (filename) printf("output filename = %s\n", filename);
printf("output1km = %d\n", (int) output1km);
printf("output500m = %d\n", (int) output500m);
printf("gzip = %d\n", gzip);
printf("nearest = %d\n", nearest);
printf("sealevel = %d\n", sealevel);
printf("TOA = %d\n", TOA);
printf("Max. solar zenith angle: %g degrees\n", maxsolz);
if (filename) printf("Output file: %s.", filename);
#endif



	if (verbose) puts("Verbose mode requested.");
	if (overwrite) puts("Overwriting existing output file.");
	if (gzip) puts("Gzip compression requested.");
	if (sealevel) puts("Sea-level atmospheric correction requested. Terrain height ignored.");
	if (TOA) puts("Top-of-the-atmosphere reflectance requested. No atmospheric correction.");
	if (output1km) puts("1km-resolution output requested.");
	if (nearest) puts("Interpolation disabled.");



	/* parse input file names */
	for (j = optind; j < argc; j++) {
		ftype = input_file_type(argv[j]);

		switch (ftype) {
			case INPUT_1KM:
				MOD021KMfile = argv[j];
				break;

			case INPUT_500M:
				MOD02HKMfile = argv[j];
				break;

			case INPUT_250M:
				MOD02QKMfile = argv[j];
				break;

			default:
				fprintf(stderr,
					"Unrecognized input file \"%s\".\n",
					argv[j]);
					MOD021KMfile = argv[j];
/*				exit(1); I commented that*/
				break;
			}
		}



	if (verbose && MOD021KMfile)
		printf("Input geolocation file: %s\n", MOD021KMfile);


	/* output file name is mandatory */
	if (!filename) {
		fputs("Missing output file name.\n", stderr);
		exit(1);
		}

#ifdef DEBUG
if (MOD021KMfile) printf("MOD/MYD021KMfile = %s\n", MOD021KMfile);
if (MOD02HKMfile) printf("MOD/MYD02HKMfile = %s\n", MOD02HKMfile);
if (MOD02QKMfile) printf("MOD/MYD02QKMfile = %s\n", MOD02QKMfile);
#endif


	/*
	1KM file is mandatory for angles.
	HKM file is mandatory unless 1-km output is requested.
	QKM file is mandatory unless 500-m or 1-km output is requested.
	*/
/*	if ( (!MOD021KMfile) ||
		(!MOD02HKMfile && !output1km) ||
		(!MOD02QKMfile && !output500m && !output1km) ) {
		fputs("Invalid combination of input files.\n", stderr);
		exit(1);
		}
commented that too Eric*/

	/* count number of bands to process */
	for (ib = nbands = 0; ib < Nbands; ib++) if (process[ib]) nbands++;
	if (nbands < 1) {
		process[BAND1] = process[BAND3] = process[BAND4] = TRUE;
		if (verbose)
			puts("No band(s) specified.  Default is bands 1, 3, and 4.");
		}


	/* open input files */
  if ( MOD02QKMfile && (!output500m)  &&
       !output1km &&
       (MOD02QKMfile_id = SDstart(MOD02QKMfile, DFACC_READ)) == -1 ) {
    fprintf(stderr, "Cannot open input file %s.\n", MOD02QKMfile);
    exit(1);
  }
  if ( MOD02HKMfile && (!output1km) &&
       (MOD02HKMfile_id = SDstart(MOD02HKMfile, DFACC_READ)) == -1 ) {
    fprintf(stderr, "Cannot open input file %s.\n", MOD02HKMfile);
    exit(1);
  }
  if ( MOD021KMfile &&
       (MOD021KMfile_id = SDstart(MOD021KMfile, DFACC_READ)) == -1 ) {
    fprintf(stderr, "Cannot open input file %s.\n", MOD021KMfile);
    exit(1);
  }


	if (!sealevel && !TOA) {
		dem.filename = dem_filename_buff;

		if ((ancpath = getenv("ANCPATH")) == NULL)
			sprintf(dem.filename, "%s/%s", ANCPATH, DEMFILENAME);
		else
			sprintf(dem.filename, "%s/%s", ancpath, DEMFILENAME);

		if ( (dem.file_id = SDstart(dem.filename, DFACC_READ)) == -1 ) {
			fprintf(stderr, "Cannot open file %s.\n", dem.filename);
			exit(1);
			}
		}


	if ( (fp = fopen(filename, "r")) ) {
		(void) fclose(fp);
		outfile_exists = 1;
		}
	else
		outfile_exists = 0;

	if ((write_mode == DFACC_CREATE)  &&  !overwrite  && outfile_exists) {
		fprintf(stderr, "File \"%s\" already exits.\n", filename);
		exit(1);
		}

	if (output500m) {
		sds[BAND10].file_id =sds[BAND8].file_id = sds[BAND9].file_id = MOD02HKMfile_id;
		sds[BAND10].filename =sds[BAND8].filename = sds[BAND9].filename = MOD02HKMfile;
		}
	else {
		if (output1km) {
			sds[BAND1].file_id = sds[BAND2].file_id = MOD021KMfile_id;
			sds[BAND1].filename = sds[BAND2].filename = MOD021KMfile;
			}
		else {
			sds[BAND1].file_id = sds[BAND2].file_id = MOD02QKMfile_id;
			sds[BAND1].filename = sds[BAND2].filename = MOD02QKMfile;
			}
		}

	if (output1km) {
		sds[BAND3].file_id = sds[BAND4].file_id =
			sds[BAND5].file_id = sds[BAND6].file_id =
			sds[BAND7].file_id = MOD021KMfile_id;
		sds[BAND3].filename = sds[BAND4].filename =
			sds[BAND5].filename = sds[BAND6].filename =
			sds[BAND7].filename = MOD021KMfile;
		}
	else {
		sds[BAND3].file_id = sds[BAND4].file_id =
			sds[BAND5].file_id = sds[BAND6].file_id =
			sds[BAND7].file_id = MOD02HKMfile_id;
		sds[BAND3].filename = sds[BAND4].filename =
			sds[BAND5].filename = sds[BAND6].filename =
			sds[BAND7].filename = MOD02HKMfile;
		}

	 sds[SOLZ].file_id = sds[SOLA].file_id =
		sds[SENZ].file_id = sds[SENA].file_id = sds[LON].file_id =
		sds[LAT].file_id = MOD021KMfile_id;
	 sds[SOLZ].filename = sds[SOLA].filename =
		sds[SENZ].filename = sds[SENA].filename = sds[LON].filename =
		sds[LAT].filename = MOD021KMfile;

	 sds[BAND11].file_id =
		sds[BAND12].file_id = sds[BAND13].file_id =
		sds[BAND14].file_id = sds[BAND15].file_id =
		sds[BAND16].file_id = MOD021KMfile_id;
	  sds[BAND11].filename =
		sds[BAND12].filename = sds[BAND13].filename =
		sds[BAND14].filename = sds[BAND15].filename =
		sds[BAND16].filename = MOD021KMfile;

  for (ib=0; ib < Nitems; ib++) {
	/* initializing these fields will simplify releasing memory later */
	sds[ib].data = sds[ib].fillvalue = (void *) NULL;

    if ( ib < Nbands  &&
         ! process[ib] ) {
      sds[ib].id = -1;
      continue;
    }
    if (output500m)
      sds[ib].name = SDSlocatorHKM[ib];
    else if (output1km)
      sds[ib].name = SDSlocator1KM[ib];
    else
      sds[ib].name = SDSlocatorQKM[ib];

    if ( (sds[ib].index = SDnametoindex(sds[ib].file_id, sds[ib].name)) == -1 ) {
      fprintf(stderr, "Cannot find SDS %s in file %s.\n", sds[ib].name, sds[ib].filename);
      continue;
    }
    if ( (sds[ib].id = SDselect(sds[ib].file_id, sds[ib].index)) == -1 ) {
      fprintf(stderr, "Cannot select SDS no. %d\n", sds[ib].index);
      if (ib < Nbands)
        process[ib] = FALSE;
      continue;
    }

    /*
    Original code passed sds[ib].name as destination for SDS name in call to SDgetinfo().
    This was causing a core dump, apparently because SDgetinfo() writes some additional
    characters beyond the terminating null at the end of the SDS name, so I replaced
    the argument with a dummy character array.
    */
    if (SDgetinfo(sds[ib].id, dummy, &sds[ib].rank, sds[ib].dim_sizes, &sds[ib].num_type, &sds[ib].n_attr) == -1) {
      fprintf(stderr, "Can't get info from SDS \"%s\" in file %s.\n", sds[ib].name, sds[ib].filename);
      SDendaccess(sds[ib].id);
      sds[ib].id = -1;
      if (ib < Nbands)
        process[ib] = FALSE;
      continue;
    }


    sds[ib].factor = 1;
    if (ib < 5 ) sds[ib].factor = 2.441742e-05;
    attr_name = "scale_factor";
    printf("band %d \n",ib);
    if ( (attr_index = SDfindattr(sds[ib].id, attr_name)) != -1  &&
         SDattrinfo(sds[ib].id, attr_index, dummy, &num_type, &count) != -1  &&
         SDreadattr(sds[ib].id, attr_index, scale_factor) != -1 ) 
      sds[ib].factor = ((float32 *)scale_factor)[indexlocator[ib]];
    else {
	attr_name = "Scale";
	if ((attr_index = SDfindattr(sds[ib].id, attr_name)) != -1  &&
		SDattrinfo(sds[ib].id, attr_index, dummy, &num_type, &count) != -1  &&
		SDreadattr(sds[ib].id, attr_index, scale_factor) != -1 )
		sds[ib].factor = *scale_factor;
	}

    sds[ib].offset = 0;
    attr_name = "reflectance_offsets";
    if ( (attr_index = SDfindattr(sds[ib].id, attr_name)) != -1  &&
         SDattrinfo(sds[ib].id, attr_index, dummy, &num_type, &count) != -1  &&
         SDreadattr(sds[ib].id, attr_index, add_offset) != -1 )
      sds[ib].offset = ((float32 *)add_offset)[indexlocator[ib]];
    else {
	attr_name = "add_offset";
	if ( (attr_index = SDfindattr(sds[ib].id, attr_name)) != -1  &&
		SDattrinfo(sds[ib].id, attr_index, dummy, &num_type, &count) != -1  &&
		SDreadattr(sds[ib].id, attr_index, add_offset) != -1 )
		sds[ib].offset = *add_offset;
	}


    sds[ib].fillvalue = (void *) malloc(1 * DFKNTsize(sds[ib].num_type));
    if ( SDgetfillvalue(sds[ib].id, sds[ib].fillvalue) != 0 ) {
      fprintf(stderr, "Cannot read fill value of SDS \"%s\".\n", sds[ib].name);
/*      exit(1); commmented that*/
    }

    switch (sds[ib].rank) {
      case 2:
        sds[ib].Nl = sds[ib].dim_sizes[0];
        sds[ib].Np = sds[ib].dim_sizes[1];
        sds[ib].rowsperscan = (int)(NUM1KMROWPERSCAN * sds[ib].Np / (float)NUM1KMCOLPERSCAN + 0.5);
        sds[ib].start[1] = 0;
        sds[ib].edges[0] = sds[ib].rowsperscan;
        sds[ib].edges[1] = sds[ib].Np;
        break;
      case 3:
        sds[ib].Nl = sds[ib].dim_sizes[1];
        sds[ib].Np = sds[ib].dim_sizes[2];
        sds[ib].rowsperscan = (int)(NUM1KMROWPERSCAN * sds[ib].Np / (float)NUM1KMCOLPERSCAN + 0.5);
        sds[ib].start[0] = indexlocator[ib];
        sds[ib].start[2] = 0;
        sds[ib].edges[0] = 1;
        sds[ib].edges[1] = sds[ib].rowsperscan;
        sds[ib].edges[2] = sds[ib].Np;
        break;
      default:
        fprintf(stderr, "SDS rank must be 2 or 3.\n");
        continue;
    }
    if (verbose)
      printf("SDS \"%s\": %dx%d   scale factor: %g  offset: %g\n", sds[ib].name, sds[ib].Np, sds[ib].Nl, sds[ib].factor, sds[ib].offset);
    if (sds[ib].num_type != numtypelocator[ib]) {
      fprintf(stderr, "SDS \"%s\" has not the expected data type.\n", sds[ib].name);
      exit(-1);
    }
    sds[ib].data = malloc(sds[ib].Np * sds[ib].rowsperscan * DFKNTsize(sds[ib].num_type));
    if (!sds[ib].data) {
      (void) fputs("Error allocating memory.\n", stderr);
      exit(1);
      }
  }

	if (sealevel || TOA) {
		dem.id = -1;
		dem.Nl = dem.Np = 0;
		}
	else {
		/* dem.name = strdup(DEMSDSNAME); */
		dem.name = DEMSDSNAME;

		if ( (dem.index = SDnametoindex(dem.file_id, dem.name)) == -1 ) {
			fprintf(stderr, "Cannot find SDS %s in file %s.\n", dem.name, dem.filename);
			exit(1);
			}

		if ( (dem.id = SDselect(dem.file_id, dem.index)) == -1 ) {
			fprintf(stderr, "Cannot select SDS no. %d\n", dem.index);
			exit(1);
			}
		if (SDgetinfo(dem.id, dummy, &dem.rank, dem.dim_sizes, &dem.num_type, &dem.n_attr) == -1) {
			fprintf(stderr, "Can't get info from SDS \"%s\" in file %s.\n", dem.name, dem.filename);
			SDendaccess(dem.id);
			exit(1);
			}

		dem.Nl = dem.dim_sizes[0];
		dem.Np = dem.dim_sizes[1];
		dem.rowsperscan = (int)(NUM1KMROWPERSCAN * dem.Np / (float)NUM1KMCOLPERSCAN + 0.5);
		}

  if ( sds[SOLZ].id == -1 ||
       sds[SOLA].id == -1 ||
       sds[SENZ].id == -1 ||
       sds[SENA].id == -1 ||
       sds[LON].id == -1 ||
       sds[LAT].id == -1 ||
       ((dem.id == -1) && !sealevel && !TOA) ) {
    fprintf(stderr, "Solar and Sensor angles and DEM are necessary to process granule.\n");
    exit(1);
  }

  if ( sds[REFSDS].Np != sds[SOLZ].Np ||
       sds[REFSDS].Np != sds[SOLA].Np ||
       sds[REFSDS].Np != sds[SENZ].Np ||
       sds[REFSDS].Np != sds[SENA].Np ||
       sds[REFSDS].Np != sds[LON].Np ||
       sds[REFSDS].Np != sds[LAT].Np ) {
    fprintf(stderr, "Solar and Sensor angles must have identical dimensions.\n");
    exit(1);
  }

	ib = 0;
	while (sds[ib].id == -1) ib++;
	if (ib >= Nbands) {
		fprintf(stderr, "No L1B SDS can be read successfully.\n");
		exit(1);
		}
 
	Nscans = sds[ib].Nl / sds[ib].rowsperscan;


	/* finally, open output file */
	if ( (sd_id = SDstart(filename, write_mode)) == -1 ) {
		fprintf(stderr, "Cannot open output file %s.\n", filename);
		exit(1);
		}

	if (!append) {
		if (write_global_attributes(sd_id, MOD021KMfile, MOD02HKMfile,
			MOD02QKMfile, maxsolz, sealevel, TOA, nearest)) {
			fputs("Error writing global attributes.\n", stderr);
			exit(1);
			}
		}

	/* create output SDSs and set SDS-specific attributes and dimension names */
	if (init_output_sds(sd_id, process, outsds, sds, gzip, verbose)) exit(1);


	mus = (float *) malloc(sds[REFSDS].rowsperscan * sds[REFSDS].Np * sizeof(float));
	height.data = (int16 *) malloc(sds[REFSDS].rowsperscan * sds[REFSDS].Np * sizeof(int16));
	if (!mus || !height.data) {
		(void) fputs("Error allocating memory.\n", stderr);
		exit(1);
		}

	if (sealevel || TOA)
		dem.data = (void *) NULL;
	else {
		dem.data = (int16 *) malloc(dem.Nl * dem.Np * sizeof(int16));
		if (!dem.data) {
			(void) fputs("Error allocating memory.\n", stderr);
			exit(1);
			}
		}

	if (!TOA) {
		nbytes = Nbands * sds[REFSDS].rowsperscan * sds[REFSDS].Np * sizeof(float);

		rhoray =      (float *) malloc(nbytes);
		sphalb =      (float *) malloc(nbytes);
		TtotraytH2O = (float *) malloc(nbytes);
		tOG =         (float *) malloc(nbytes);

		if (!rhoray || !sphalb || !TtotraytH2O || !tOG) {
			(void) fputs("Error allocating memory.\n", stderr);
			exit(1);
			}
		}

	solz = sds[SOLZ].data;
	sola = sds[SOLA].data;
	senz = sds[SENZ].data;
	sena = sds[SENA].data;
	solzfill = sds[SOLZ].fillvalue;
	lon = sds[LON].data;
	lat = sds[LAT].data;
	lonfill = sds[LON].fillvalue;
	latfill = sds[LAT].fillvalue;
	for (ib = 0; ib < Nbands; ib++) l1bdata[ib] = sds[ib].data;

	/* don't need DEM if --sealevel or --toa specified */
	if (!sealevel && !TOA) {
		dem.start[0] = 0;
		dem.start[1] = 0;
		dem.edges[0] = dem.Nl;
		dem.edges[1] = dem.Np;
		if (SDreaddata(dem.id, dem.start, NULL, dem.edges, dem.data) == -1) {
			fprintf(stderr, "  Can't read DEM SDS \"%s\"\n", dem.name);
			exit(-1);
			}
		(void) SDendaccess(dem.id);
		(void) SDend(dem.file_id);
		}

	/* loop over each MODIS scan */
	for (iscan = 0; iscan < Nscans; iscan++) {
		if ((iscan % NUM1KMROWPERSCAN == 0) && verbose)
			printf("Processing scan %d...\n", iscan);

		/* Fill scan buffer for each band to be processed.
		Exit scan loop if error occurred while reading. */
		if (read_scan(iscan, sds)) break;

		for (idx = 0; idx < sds[REFSDS].rowsperscan*sds[REFSDS].Np; idx++) {
			if (solz[idx] * sds[SOLZ].factor >= maxsolz)
				solz[idx] = *solzfill;

			if (!sealevel &&
				(lon[idx] == *lonfill || lat[idx] == *latfill))
				solz[idx] = *solzfill;

			if (solz[idx] != *solzfill) {
				mus[idx] = cos(solz[idx] * sds[SOLZ].factor * DEG2RAD);

				if (sealevel || TOA)
					((int16 *)height.data)[idx] = 0;
				else
					((int16 *)height.data)[idx] =
						(int16) interp_dem(lat[idx],
						lon[idx], &dem);
				}
			}


		if (!TOA) {
			for (irow=0; irow<sds[REFSDS].rowsperscan; irow++) {
				for (jcol=0; jcol<sds[REFSDS].Np; jcol++) {
					idx = irow * sds[REFSDS].Np + jcol;
					if (solz[idx] == *solzfill) continue;
					phi = sola[idx] * sds[SOLA].factor - sena[idx] * sds[SENA].factor;
					muv = cos(senz[idx] * sds[SENZ].factor * DEG2RAD);
					if ( getatmvariables(mus[idx], muv, phi, ((int16 *)height.data)[idx],
						process,
						&sphalb[idx * Nbands], &rhoray[idx * Nbands],
						&TtotraytH2O[idx * Nbands], &tOG[idx * Nbands]) == -1 )
						solz[idx] = *solzfill;
/*						printf(" some data %f %f %f %f %f \n",senz[idx],phi,mus[idx],rhoray[idx * Nbands],tOG[idx * Nbands]);*/
					}
				}
			}

		for (ib=0; ib<Nbands; ib++) {
			if (! process[ib]) continue;
			aggfactor = outsds[ib].rowsperscan / sds[REFSDS].rowsperscan;
			for (irow=0; irow<outsds[ib].rowsperscan; irow++) {
				if (!nearest) {
					fractrow = (float)irow / aggfactor - 0.5;	/* We want fractrow integer on coarse pixel center */
					crsrow1 = floor(fractrow);
					crsrow2 = crsrow1 + 1;
					if (crsrow1 < 0) crsrow1 = crsrow2 + 1;
					if (crsrow2 > sds[REFSDS].rowsperscan - 1) crsrow2 = crsrow1 - 1;
					t = (fractrow - crsrow1) / (crsrow2 - crsrow1);
					}

				for (jcol=0; jcol<outsds[ib].Np; jcol++) {
					idx = irow * outsds[ib].Np + jcol;
					crsidx = (int)(irow / aggfactor) * sds[REFSDS].Np + (int)(jcol / aggfactor);
					if ( solz[crsidx] == *solzfill  ||	/* Bad geolocation or night pixel */
						l1bdata[ib][idx] >= 65528 ) {	/* VIIRS SDR is read as uint16, fills start at 65528 */
						if (l1bdata[ib][idx] == (65536 + MISSING))
							((int16 *)outsds[ib].data)[idx] = 32768 + MISSING;
						else
							((int16 *)outsds[ib].data)[idx] = *(int16 *)outsds[ib].fillvalue;

						continue;
						}

					if (nearest) {
						mus0 = mus[crsidx];
						if (! TOA) {
							rhoray0 = rhoray[crsidx * Nbands + ib];
							sphalb0 = sphalb[crsidx * Nbands + ib];
							if ( sphalb0 <= 0.0F ) {	/* Atm variables not computed successfully in this band */
								((int16 *)outsds[ib].data)[idx] = *(int16 *)outsds[ib].fillvalue;
								continue;
								}
							}
						}
					else {
						fractcol = ((float) jcol) / aggfactor - 0.5F;	/* We want fractcol integer on coarse pixel center */
						crscol1 = (int) floor(fractcol);
						crscol2 = crscol1 + 1;
						if (crscol1 < 0) crscol1 = crscol2 + 1;
						if (crscol2 > sds[REFSDS].Np - 1) crscol2 = crscol1 - 1;
						u = (fractcol - crscol1) / (crscol2 - crscol1);		/* We want u=0 on coarse pixel center */
						crsidx11 = crsrow1 * sds[REFSDS].Np + crscol1;
						crsidx12 = crsrow1 * sds[REFSDS].Np + crscol2;
						crsidx21 = crsrow2 * sds[REFSDS].Np + crscol1;
						crsidx22 = crsrow2 * sds[REFSDS].Np + crscol2;
/*						mus0 = t * u * mus[crsidx22] + (1.0F - t) * u * mus[crsidx12] + t * (1.0F - u) * mus[crsidx21] + (1.0F - t) * (1.0F - u) * mus[crsidx11];

						bad = (solz[crsidx11] == *solzfill) ||
							(solz[crsidx12] == *solzfill) ||
							(solz[crsidx21] == *solzfill) ||
							(solz[crsidx22] == *solzfill);
commented by eric to handle the viirs fill value hardcoding */ 

						bad = (solz[crsidx11] <-900.) ||
							(solz[crsidx12] <-900.) ||
							(solz[crsidx21] <-900.) ||
							(solz[crsidx22] <-900.);
 
						if (bad) {
							((int16 *)outsds[ib].data)[idx] = *(int16 *)outsds[ib].fillvalue;
							continue;
							}

						if (! TOA) {
							rhoray11 = rhoray[crsidx11 * Nbands + ib];
							rhoray12 = rhoray[crsidx12 * Nbands + ib];
							rhoray21 = rhoray[crsidx21 * Nbands + ib];
							rhoray22 = rhoray[crsidx22 * Nbands + ib];
							rhoray0 = t * u * rhoray22 + (1.0F - t) * u * rhoray12 + t * (1.0F - u) * rhoray21 + (1.0F - t) * (1.0F - u) * rhoray11;
							sphalb11 = sphalb[crsidx11 * Nbands + ib];
							sphalb12 = sphalb[crsidx12 * Nbands + ib];
							sphalb21 = sphalb[crsidx21 * Nbands + ib];
							sphalb22 = sphalb[crsidx22 * Nbands + ib];

							bad = (sphalb11 <= 0.0F) ||
								(sphalb12 <= 0.0F) ||
								(sphalb21 <= 0.0F) ||
								(sphalb22 <= 0.0F);

							if (bad) {
								((int16 *)outsds[ib].data)[idx] = *(int16 *)outsds[ib].fillvalue;
								continue;
								}
							sphalb0 = t * u * sphalb22 + (1.0F - t) * u * sphalb12 + t * (1.0F - u) * sphalb21 + (1.0F - t) * (1.0F - u) * sphalb11;
							}
						}

					/* TOA reflectance */
					/*printf(" mus0 is %f\n",mus0);*/
					refl = (l1bdata[ib][idx] - sds[ib].offset) * sds[ib].factor /*/ mus0 commented by Eric who suspected something*/;

					/* corrected reflectance */
					if (!TOA)
						refl = correctedrefl(refl, TtotraytH2O[crsidx * Nbands + ib],
							tOG[crsidx * Nbands + ib], rhoray0, sphalb0);

					/* reflectance bounds checking */
					if (refl > reflmax) refl = reflmax;
					if (refl < reflmin) refl = reflmin;

					((int16 *)outsds[ib].data)[idx] = (int16) (refl / outsds[ib].factor + 0.5);
					}
				}
			}


		/* write current scan line for all processed bands */
		if (write_scan(iscan, process, outsds)) {
			fprintf(stderr, "Cannot write scan %d of SDS %s\n",
				iscan, outsds[ib].name);
			exit(1);
			}

		} /* end of scan loop */


	for (ib = 0; ib < Nitems; ib++)
		if (sds[ib].id != -1) SDendaccess(sds[ib].id);

	for (ib = 0; ib < Nbands; ib++)
		if (process[ib]) SDendaccess(outsds[ib].id);

	SDend(MOD02QKMfile_id);
	SDend(MOD02HKMfile_id);
	SDend(MOD021KMfile_id);
	SDend(sd_id);


	/* ----- free memory ----- */

	for (ib = 0; ib < Nitems; ib++) {
		if (sds[ib].fillvalue) free(sds[ib].fillvalue);
		if (sds[ib].data) free(sds[ib].data);
		}

	free(height.data);
	free(mus);

	if (!TOA) {
		free(tOG);
		free(TtotraytH2O);
		free(sphalb);
		free(rhoray);
		}

	/* not allocated if --sealevel specified */
	if (dem.data) free(dem.data);


	return 0;
}