예제 #1
0
파일: structures.c 프로젝트: alecs1/home
S_metadata* init_file_struct(S_metadata *md) {
    if (md == NULL) {
        md = init_metadata_struct(TYPE_NONE);
        md->type = TYPE_FILE;
    }

    S_file_metadata *file_md = (S_file_metadata*)malloc(sizeof(S_dir_metadata));
    file_md->size = 0;
    file_md->fragments_count = 0;
    file_md->first_fragment_address = 0;
    file_md->fragment_addresses = NULL;

    md->specific = file_md;

    return md;
}
예제 #2
0
파일: structures.c 프로젝트: alecs1/home
S_metadata* init_dir_struct(S_metadata *md) {
    if (md == NULL) {
        md = init_metadata_struct(TYPE_NONE);
        md->type = TYPE_DIR;
    }
    
    S_dir_metadata *dir_md = (S_dir_metadata*)malloc(sizeof(S_dir_metadata));
    dir_md->child_count = 0;
    dir_md->child_list_address = 0;
    dir_md->in_mem_addresses_count = 0;
    dir_md->in_mem_addresses = NULL;
    
    md->specific = dir_md;

    return md;
}
/******************************************************************************
MODULE:  convert_espa_to_gtif

PURPOSE: Converts the internal ESPA raw binary file to GeoTIFF file format.

RETURN VALUE:
Type = int
Value           Description
-----           -----------
ERROR           Error converting to GeoTIFF
SUCCESS         Successfully converted to GeoTIFF

HISTORY:
Date         Programmer       Reason
----------   --------------   -------------------------------------
1/9/2014     Gail Schmidt     Original development
4/2/2014     Gail Schmidt     Added support for a flag to delete the source
                              .img and .hdr files
4/3/2014     Gail Schmidt     Remove the .xml file as well if source files are
                              specified to be deleted
4/30/2014    Gail Schmidt     Remove the .tif.aux.xml files that were created
                              by GDAL in the conversion to GeoTIFF

NOTES:
  1. The GDAL tools will be used for converting the raw binary (ENVI format)
     files to GeoTIFF.
  2. An associated .tfw (ESRI world file) will be generated for each GeoTIFF
     file.
******************************************************************************/
int convert_espa_to_gtif
(
    char *espa_xml_file,   /* I: input ESPA XML metadata filename */
    char *gtif_file,       /* I: base output GeoTIFF filename */
    bool del_src           /* I: should the source files be removed after
                                 conversion? */
)
{
    char FUNC_NAME[] = "convert_espa_to_gtif";  /* function name */
    char errmsg[STR_SIZE];      /* error message */
    char gdal_cmd[STR_SIZE];    /* command string for GDAL call */
    char gtif_band[STR_SIZE];   /* name of the GeoTIFF file for this band */
    char hdr_file[STR_SIZE];    /* name of the header file for this band */
    char xml_file[STR_SIZE];    /* new XML file for the GeoTIFF product */
    char tmpfile[STR_SIZE];     /* filename of file.tif.aux.xml */
    char *cptr = NULL;          /* pointer to empty space in the band name */
    int i;                      /* looping variable for each band */
    int count;                  /* number of chars copied in snprintf */
    Espa_internal_meta_t xml_metadata;  /* XML metadata structure to be
                                   populated by reading the XML metadata file */

    /* Validate the input metadata file */
    if (validate_xml_file (espa_xml_file) != SUCCESS)
    {  /* Error messages already written */
        return (ERROR);
    }

    /* Initialize the metadata structure */
    init_metadata_struct (&xml_metadata);

    /* Parse the metadata file into our internal metadata structure; also
       allocates space as needed for various pointers in the global and band
       metadata */
    if (parse_metadata (espa_xml_file, &xml_metadata) != SUCCESS)
    {  /* Error messages already written */
        return (ERROR);
    }

    /* Loop through the bands in the XML file and convert them to GeoTIFF.
       The filenames will have the GeoTIFF base name followed by _ and the
       band name of each band in the XML file.  Blank spaced in the band name
       will be replaced with underscores. */
    for (i = 0; i < xml_metadata.nbands; i++)
    {
        /* Determine the output GeoTIFF band name */
        count = snprintf (gtif_band, sizeof (gtif_band), "%s_%s.tif",
            gtif_file, xml_metadata.band[i].name);
        if (count < 0 || count >= sizeof (gtif_band))
        {
            sprintf (errmsg, "Overflow of gtif_file string");
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }

        /* Loop through this filename and replace any occurances of blank
           spaces with underscores */
        while ((cptr = strchr (gtif_band, ' ')) != NULL)
            *cptr = '_';

        /* Convert the files */
        printf ("Converting %s to %s\n", xml_metadata.band[i].file_name,
            gtif_band);
        count = snprintf (gdal_cmd, sizeof (gdal_cmd),
            "gdal_translate -of Gtiff -a_nodata %ld -co \"TFW=YES\" -q %s %s",
            xml_metadata.band[i].fill_value, xml_metadata.band[i].file_name,
            gtif_band);
        if (count < 0 || count >= sizeof (gdal_cmd))
        {
            sprintf (errmsg, "Overflow of gdal_cmd string");
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }

        if (system (gdal_cmd) == -1)
        {
            sprintf (errmsg, "Running gdal_translate: %s", gdal_cmd);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }

        /* Remove the {gtif_name}.tif.aux.xml file since it's not needed and
           clutters the results.  Don't worry about testing the unlink
           results.  If it doesn't unlink it's not fatal. */
        count = snprintf (tmpfile, sizeof (tmpfile), "%s.aux.xml", gtif_band);
        if (count < 0 || count >= sizeof (tmpfile))
        {
            sprintf (errmsg, "Overflow of tmpfile string");
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
        unlink (tmpfile);

        /* Remove the source file if specified */
        if (del_src)
        {
            /* .img file */
            printf ("  Removing %s\n", xml_metadata.band[i].file_name);
            if (unlink (xml_metadata.band[i].file_name) != 0)
            {
                sprintf (errmsg, "Deleting source file: %s",
                    xml_metadata.band[i].file_name);
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }

            /* .hdr file */
            count = snprintf (hdr_file, sizeof (hdr_file), "%s",
                xml_metadata.band[i].file_name);
            if (count < 0 || count >= sizeof (hdr_file))
            {
                sprintf (errmsg, "Overflow of hdr_file string");
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }

            cptr = strrchr (hdr_file, '.');
            strcpy (cptr, ".hdr");
            printf ("  Removing %s\n", hdr_file);
            if (unlink (hdr_file) != 0)
            {
                sprintf (errmsg, "Deleting source file: %s", hdr_file);
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }
        }

        /* Update the XML file to use the new GeoTIFF band name */
        strcpy (xml_metadata.band[i].file_name, gtif_band);
    }

    /* Remove the source XML if specified */
    if (del_src)
    {
        printf ("  Removing %s\n", espa_xml_file);
        if (unlink (espa_xml_file) != 0)
        {
            sprintf (errmsg, "Deleting source file: %s", espa_xml_file);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }

    /* Create the XML file for the GeoTIFF product */
    count = snprintf (xml_file, sizeof (xml_file), "%s_gtif.xml", gtif_file);
    if (count < 0 || count >= sizeof (xml_file))
    {
        sprintf (errmsg, "Overflow of xml_file string");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Write the new XML file containing the GeoTIFF band names */
    if (write_metadata (&xml_metadata, xml_file) != SUCCESS)
    {
        sprintf (errmsg, "Error writing updated XML for the GeoTIFF product: "
            "%s", xml_file);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Free the metadata structure */
    free_metadata (&xml_metadata);

    /* Successful conversion */
    return (SUCCESS);
}
예제 #4
0
/******************************************************************************
METHOD:  l8cfmask

PURPOSE:  the main routine for fmask in C

RETURN VALUE:
Type = int
Value           Description
-----           -----------
ERROR           An error occurred during processing of the l8cfmask
SUCCESS         Processing was successful

PROJECT:  Land Satellites Data System Science Research and Development (LSRD)
at the USGS EROS

HISTORY:
Date        Programmer       Reason
--------    ---------------  -------------------------------------
3/15/2013   Song Guo         Original Development
5/14/2013   Song Guo         Added in Polar Stereographic support
7/17/2013   Song Guo         Added in Map info 
8/15/2013   Song Guo         Modified to use TOA reflectance file 
                             as input instead of metadata file
Oct/2014    Ron Dilley       Modified to utilize the ESPA internal raw binary
                             file format

NOTES: type ./l8cfmask --help for information to run the code
******************************************************************************/
int
main (int argc, char *argv[])
{
    char errstr[MAX_STR_LEN];     /* error string */
    char *cptr = NULL;            /* pointer to the file extension */
    char *xml_name = NULL;        /* input XML filename */
    char directory[MAX_STR_LEN];  /* input/output data directory */
    char extension[MAX_STR_LEN];  /* input TOA file extension */
    int ib;                       /* band counters */
    Input_t *input = NULL;        /* input data and meta data */
    char envi_file[MAX_STR_LEN];  /* output ENVI file name */
    char scene_name[MAX_STR_LEN]; /* input data scene name */
    unsigned char **pixel_mask;   /* pixel mask */
    unsigned char **conf_mask;    /* confidence mask */
    int status;               /* return value from function call */
    float clear_ptm;          /* percent of clear-sky pixels */
    float t_templ = 0.0;      /* percentile of low background temperature */
    float t_temph = 0.0;      /* percentile of high background temperature */
    Output_t *output = NULL;  /* output structure and metadata */
    bool verbose;             /* verbose flag for printing messages */
    bool use_l8_cirrus;       /* should we use L8 cirrus cloud bit results? */
    int cldpix = 2;           /* Default buffer for cloud pixel dilate */
    int sdpix = 2;            /* Default buffer for shadow pixel dilate */
    float cloud_prob;         /* Default cloud probability */
    float sun_azi_temp = 0.0; /* Keep the original sun azimuth angle */
    int max_cloud_pixels; /* Maximum cloud pixel number in cloud division */
    Espa_internal_meta_t xml_metadata; /* XML metadata structure */
    Envi_header_t envi_hdr;            /* output ENVI header information */

    time_t now;
    time (&now);
    printf ("CFmask start_time=%s\n", ctime (&now));

    /* Read the command-line arguments, including the name of the input
       Landsat TOA reflectance product and the DEM */
    status = get_args (argc, argv, &xml_name, &cloud_prob, &cldpix,
                       &sdpix, &max_cloud_pixels, &use_l8_cirrus, &verbose);
    if (status != SUCCESS)
    {
        sprintf (errstr, "calling get_args");
        CFMASK_ERROR (errstr, "main");
    }

    /* Validate the input metadata file */
    if (validate_xml_file (xml_name) != SUCCESS)
    {                           /* Error messages already written */
        CFMASK_ERROR (errstr, "main");
    }

    /* Initialize the metadata structure */
    init_metadata_struct (&xml_metadata);

    /* Parse the metadata file into our internal metadata structure; also
       allocates space as needed for various pointers in the global and band
       metadata */
    if (parse_metadata (xml_name, &xml_metadata) != SUCCESS)
    {                           /* Error messages already written */
        CFMASK_ERROR (errstr, "main");
    }

    /* Verify supported satellites */
    if (strcmp (xml_metadata.global.satellite, "LANDSAT_8") != 0)
    {
        sprintf (errstr, "Unsupported satellite sensor");
        CFMASK_ERROR (errstr, "main");
    }

    /* Split the filename to obtain the directory, scene name, and extension */
    split_filename (xml_name, directory, scene_name, extension);
    if (verbose)
        printf ("directory, scene_name, extension=%s,%s,%s\n",
                directory, scene_name, extension);

    /* Open input file, read metadata, and set up buffers */
    input = OpenInput (&xml_metadata);
    if (input == NULL)
    {
        sprintf (errstr, "opening the TOA and brightness temp files in: %s",
                 xml_name);
        CFMASK_ERROR (errstr, "main");
    }

    if (verbose)
    {
        /* Print some info to show how the input metadata works */
        printf ("DEBUG: Number of input TOA bands: %d\n", input->nband);
        printf ("DEBUG: Number of input thermal bands: %d\n", 1);
        printf ("DEBUG: Number of input TOA lines: %d\n", input->size.l);
        printf ("DEBUG: Number of input TOA samples: %d\n", input->size.s);
        printf ("DEBUG: ACQUISITION_DATE.DOY is %d\n",
                input->meta.acq_date.doy);
        printf ("DEBUG: Fill value is %d\n", input->meta.fill);
        for (ib = 0; ib < input->nband; ib++)
        {
            printf ("DEBUG: Band %d-->\n", ib);
            printf ("DEBUG:   band satu_value_ref: %d\n",
                    input->meta.satu_value_ref[ib]);
            printf ("DEBUG:   band satu_value_max: %d\n",
                    input->meta.satu_value_max[ib]);
            printf ("DEBUG:   band gains: %f, band biases: %f\n",
                    input->meta.gain[ib], input->meta.bias[ib]);
        }
        printf ("DEBUG: Thermal Band (Band 10) -->\n");
        printf ("DEBUG:   therm_satu_value_ref: %d\n",
                input->meta.therm_satu_value_ref);
        printf ("DEBUG:   therm_satu_value_max: %d\n",
                input->meta.therm_satu_value_max);
        printf ("DEBUG:   therm_gain: %f, therm_bias: %f\n",
                input->meta.gain_th, input->meta.bias_th);

        printf ("DEBUG: SUN AZIMUTH is %f\n", input->meta.sun_az);
        printf ("DEBUG: SUN ZENITH is %f\n", input->meta.sun_zen);
    }

    /* If the scene is an ascending polar scene (flipped upside down), then
       the solar azimuth needs to be adjusted by 180 degrees.  The scene in
       this case would be north down and the solar azimuth is based on north
       being up clock-wise direction. Flip the south to be up will not change
       the actual sun location, with the below relations, the solar azimuth
       angle will need add in 180.0 for correct sun location */
    if (input->meta.ul_corner.is_fill &&
        input->meta.lr_corner.is_fill &&
        (input->meta.ul_corner.lat - input->meta.lr_corner.lat) < MINSIGMA)
    {
        /* Keep the original solar azimuth angle */
        sun_azi_temp = input->meta.sun_az;
        input->meta.sun_az += 180.0;
        if ((input->meta.sun_az - 360.0) > MINSIGMA)
            input->meta.sun_az -= 360.0;
        if (verbose)
            printf ("  Polar or ascending scene."
                    "  Readjusting solar azimuth by 180 degrees.\n"
                    "  New value: %f degrees\n", input->meta.sun_az);
    }

    /* Dynamic allocate the 2d mask memory */
    pixel_mask = (unsigned char **) allocate_2d_array (input->size.l,
                                                       input->size.s,
                                                       sizeof (unsigned char));
    if (pixel_mask == NULL)
    {
        sprintf (errstr, "Allocating pixel mask memory");
        CFMASK_ERROR (errstr, "main");
    }

    conf_mask = (unsigned char **) allocate_2d_array (input->size.l,
                                                      input->size.s,
                                                      sizeof (unsigned char));
    if (conf_mask == NULL)
    {
        sprintf (errstr, "Allocating confidence mask memory");
        CFMASK_ERROR (errstr, "main");
    }

    /* Initialize the mask to clear data */
    int row, col;
    for (row = 0; row < input->size.l; row++)
        for (col = 0; col < input->size.s; col++)
        {
            pixel_mask[row][col] = MASK_CLEAR_LAND;
            conf_mask[row][col] = CLOUD_CONFIDENCE_NONE;
        }

    /* Build the potential cloud, shadow, snow, water mask */
    status = potential_cloud_shadow_snow_mask (input, cloud_prob, &clear_ptm,
                                               &t_templ, &t_temph, pixel_mask,
                                               conf_mask, use_l8_cirrus,
                                               verbose);
    if (status != SUCCESS)
    {
        sprintf (errstr, "processing potential_cloud_shadow_snow_mask");
        CFMASK_ERROR (errstr, "main");
    }

    printf ("Pcloud done, starting cloud/shadow match\n");

    /* Build the final cloud shadow based on geometry matching and
       combine the final cloud, shadow, snow, water masks into fmask
       the pixel_mask is a bit mask as input and a value mask as output */
    status = object_cloud_shadow_match (input, clear_ptm, t_templ, t_temph,
                                        cldpix, sdpix, max_cloud_pixels,
                                        pixel_mask, verbose);
    if (status != SUCCESS)
    {
        sprintf (errstr, "processing object_cloud_and_shadow_match");
        CFMASK_ERROR (errstr, "main");
    }

    /* Reassign solar azimuth angle for output purpose if south up north
       down scene is involved */
    if (input->meta.ul_corner.is_fill &&
        input->meta.lr_corner.is_fill &&
        (input->meta.ul_corner.lat - input->meta.lr_corner.lat) < MINSIGMA)
        input->meta.sun_az = sun_azi_temp;

    /* Open the output file */
    output = OpenOutput (&xml_metadata, input);
    if (output == NULL)
    {                           /* error message already printed */
        sprintf (errstr, "Opening output file");
        CFMASK_ERROR (errstr, "main");
    }

    if (!PutOutput (output, pixel_mask))
    {
        sprintf (errstr, "Writing output fmask files\n");
        CFMASK_ERROR (errstr, "main");
    }

    /* Close the output file */
    if (!CloseOutput (output))
    {
        sprintf (errstr, "closing output file");
        CFMASK_ERROR (errstr, "main");
    }

    /* Create the ENVI header file this band */
    if (create_envi_struct (&output->metadata.band[0], &xml_metadata.global,
                            &envi_hdr) != SUCCESS)
    {
        sprintf (errstr, "Creating ENVI header structure.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Write the ENVI header */
    strcpy (envi_file, output->metadata.band[0].file_name);
    cptr = strchr (envi_file, '.');
    if (cptr == NULL)
    {
        sprintf (errstr, "error in ENVI header filename");
        CFMASK_ERROR (errstr, "main");
    }

    strcpy (cptr, ".hdr");
    if (write_envi_hdr (envi_file, &envi_hdr) != SUCCESS)
    {
        sprintf (errstr, "Writing ENVI header file.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Append the cfmask band to the XML file */
    if (append_metadata (output->nband, output->metadata.band, xml_name)
        != SUCCESS)
    {
        sprintf (errstr, "Appending spectral index bands to XML file.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Free the structure */
    if (!FreeOutput (output))
    {
        sprintf (errstr, "freeing output file structure");
        CFMASK_ERROR (errstr, "main");
    }

    output = OpenOutputConfidence (&xml_metadata, input);
    if (output == NULL)
    {                           /* error message already printed */
        sprintf (errstr, "Opening output file");
        CFMASK_ERROR (errstr, "main");
    }

    if (!PutOutput (output, conf_mask))
    {
        sprintf (errstr, "Writing output fmask files\n");
        CFMASK_ERROR (errstr, "main");
    }

    /* Close the output file */
    if (!CloseOutput (output))
    {
        sprintf (errstr, "closing output file");
        CFMASK_ERROR (errstr, "main");
    }

    /* Create the ENVI header file this band */
    if (create_envi_struct (&output->metadata.band[0], &xml_metadata.global,
                            &envi_hdr) != SUCCESS)
    {
        sprintf (errstr, "Creating ENVI header structure.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Write the ENVI header */
    strcpy (envi_file, output->metadata.band[0].file_name);
    cptr = strchr (envi_file, '.');
    if (cptr == NULL)
    {
        sprintf (errstr, "error in ENVI header filename");
        CFMASK_ERROR (errstr, "main");
    }

    strcpy (cptr, ".hdr");
    if (write_envi_hdr (envi_file, &envi_hdr) != SUCCESS)
    {
        sprintf (errstr, "Writing ENVI header file.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Append the cfmask band to the XML file */
    if (append_metadata (output->nband, output->metadata.band, xml_name)
        != SUCCESS)
    {
        sprintf (errstr, "Appending spectral index bands to XML file.");
        CFMASK_ERROR (errstr, "main");
    }

    /* Free the structure */
    if (!FreeOutput (output))
    {
        sprintf (errstr, "freeing output file structure");
        CFMASK_ERROR (errstr, "main");
    }

    /* Free the metadata structure */
    free_metadata (&xml_metadata);

    /* Free the pixel mask */
    status = free_2d_array ((void **) pixel_mask);
    if (status != SUCCESS)
    {
        sprintf (errstr, "Freeing pixel mask memory");
        CFMASK_ERROR (errstr, "main");
    }

    status = free_2d_array ((void **) conf_mask);
    if (status != SUCCESS)
    {
        sprintf (errstr, "Freeing confidence mask memory");
        CFMASK_ERROR (errstr, "main");
    }

    /* Close the input file and free the structure */
    CloseInput (input);
    FreeInput (input);

    free (xml_name);

    printf ("Processing complete.\n");
    time (&now);
    printf ("CFmask end_time=%s\n", ctime (&now));

    return SUCCESS;
}
예제 #5
0
/******************************************************************************
MODULE:  open_output

PURPOSE:  Set up the output data structure.  Open the output file for write
and read access.

RETURN VALUE:
Type = Output_t
Value          Description
-----          -----------
NULL           Error occurred opening the file
not-NULL       Successful completion

NOTES:
******************************************************************************/
Output_t *open_output
(
    Espa_internal_meta_t *in_meta,  /* I: input metadata structure */
    Input_t *input,                 /* I: input band data structure */
    bool toa                        /* I: set this structure up for the TOA
                                          bands vs. the SR bands */
)
{
    Output_t *this = NULL;
    char FUNC_NAME[] = "open_output";   /* function name */
    char errmsg[STR_SIZE];       /* error message */
    char *upper_str = NULL;      /* upper case version of the SI short name */
    char *mychar = NULL;         /* pointer to '_' */
    char scene_name[STR_SIZE];   /* scene name for the current scene */
    char production_date[MAX_DATE_LEN+1]; /* current date/time for production */
    time_t tp;                   /* time structure */
    struct tm *tm = NULL;        /* time structure for UTC time */
    int ib;    /* looping variable for bands */
    int refl_indx = -1;          /* band index in XML file for the reflectance
                                    band */
    Espa_band_meta_t *bmeta = NULL;  /* pointer to the band metadata array
                                        within the output structure */

    int nband = NBAND_TTL_OUT;   /* number of output bands to be created */

    /* Create the Output data structure */
    this = (Output_t *) malloc (sizeof (Output_t));
    if (this == NULL) 
    {
        sprintf (errmsg, "Error allocating Output data structure");
        error_handler (true, FUNC_NAME, errmsg);
        return (NULL);
    }
  
    /* Find the representative band for metadata information.  Use band 1. */
    for (ib = 0; ib < in_meta->nbands; ib++)
    {
        if (!strcmp (in_meta->band[ib].name, "band1") &&
            !strncmp (in_meta->band[ib].product, "L1", 2))
        {
            /* this is the index we'll use for reflectance band info */
            refl_indx = ib;
            break;
        }
    }

    /* Make sure we found the L1G/T band 1 */
    if (refl_indx == -1)
    {
        sprintf (errmsg, "Unable to find the L1G/T band 1 bands in the "
            "XML file for initializing the output metadata.");
        error_handler (true, FUNC_NAME, errmsg);
        return (NULL);
    }

    /* Initialize the internal metadata for the output product. The global
       metadata won't be updated, however the band metadata will be updated
       and used later for appending to the original XML file. */
    init_metadata_struct (&this->metadata);

    /* Copy the instrument type */
    this->inst = input->meta.inst;

    /* Allocate memory for the total bands */
    if (allocate_band_metadata (&this->metadata, nband) != SUCCESS)
    {
        sprintf (errmsg, "Allocating band metadata.");
        error_handler (true, FUNC_NAME, errmsg);
        return (NULL);
    }
    bmeta = this->metadata.band;

    /* Determine the scene name */
    strcpy (scene_name, in_meta->band[refl_indx].file_name);
    mychar = strrchr (scene_name, '_');
    if (mychar != NULL)
      *mychar = '\0';
  
    /* Get the current date/time (UTC) for the production date of each band */
    if (time (&tp) == -1)
    {
        sprintf (errmsg, "Unable to obtain the current time.");
        error_handler (true, FUNC_NAME, errmsg);
        return (NULL);
    }
  
    tm = gmtime (&tp);
    if (tm == NULL)
    {
        sprintf (errmsg, "Converting time to UTC.");
        error_handler (true, FUNC_NAME, errmsg);
        return (NULL);
    }
  
    if (strftime (production_date, MAX_DATE_LEN, "%Y-%m-%dT%H:%M:%SZ", tm) == 0)
    {
        sprintf (errmsg, "Formatting the production date/time.");
        error_handler (true, FUNC_NAME, errmsg);
        return (NULL);
    }

    /* Populate the data structure, using information from the reflectance
       bands */
    this->open = false;
    this->nband = nband;
    this->nlines = input->size.nlines;
    this->nsamps = input->size.nsamps;
    for (ib = 0; ib < this->nband; ib++)
        this->fp_bin[ib] = NULL;
 
    for (ib = 0; ib < nband; ib++)
    {
        strncpy (bmeta[ib].short_name, in_meta->band[refl_indx].short_name, 3);
        bmeta[ib].short_name[3] = '\0';
        if (toa)
        {
            strcat (bmeta[ib].short_name, "TOA");
            if ((ib == SR_BAND10) || (ib == SR_BAND11))
                strcpy (bmeta[ib].product, "toa_bt");
            else
                strcpy (bmeta[ib].product, "toa_refl");
        }
        else
        {
            strcat (bmeta[ib].short_name, "SR");
            strcpy (bmeta[ib].product, "sr_refl");
        }

        bmeta[ib].nlines = this->nlines;
        bmeta[ib].nsamps = this->nsamps;
        bmeta[ib].pixel_size[0] = input->size.pixsize[0];
        bmeta[ib].pixel_size[1] = input->size.pixsize[1];
        strcpy (bmeta[ib].pixel_units, "meters");
        sprintf (bmeta[ib].app_version, "l8_surface_reflectance_%s",
            SR_VERSION);
        strcpy (bmeta[ib].production_date, production_date);

        /* Handle the cloud band differently.  If this is only TOA then we
           don't need to process the cloud mask.  If this is SR, then we don't
           need to process the cirrus or thermal bands. */
        if (toa && ib == SR_CLOUD)
            continue;
        else if (!toa &&
            ((ib == SR_BAND9) || (ib == SR_BAND10) || (ib == SR_BAND11)))
            continue;
        else if (ib == SR_CLOUD)
        {
            bmeta[ib].data_type = ESPA_UINT8;
            bmeta[ib].fill_value = CLOUD_FILL_VALUE;
            strcpy (bmeta[ib].name, "sr_cloud");
            strcpy (bmeta[ib].long_name, "surface reflectance cloud mask");
            strcpy (bmeta[ib].category, "qa");
            strcpy (bmeta[ib].data_units, "bitmap");

            /* Set up cloud bitmap information */
            if (allocate_bitmap_metadata (&bmeta[ib], 8) != SUCCESS)
            {
                sprintf (errmsg, "Allocating cloud bitmap.");
                error_handler (true, FUNC_NAME, errmsg);
                return (NULL);
            }
          
            /* Identify the bitmap values for the mask */
            strcpy (bmeta[ib].bitmap_description[0], "cirrus cloud");
            strcpy (bmeta[ib].bitmap_description[1], "cloud");
            strcpy (bmeta[ib].bitmap_description[2], "adjacent to cloud");
            strcpy (bmeta[ib].bitmap_description[3], "cloud shadow");
            strcpy (bmeta[ib].bitmap_description[4], "aerosol");
            strcpy (bmeta[ib].bitmap_description[5], "aerosol");
            strcpy (bmeta[ib].bitmap_description[6], "unused");
            strcpy (bmeta[ib].bitmap_description[7], "internal test");
        }
        else
        {
            bmeta[ib].data_type = ESPA_INT16;
            bmeta[ib].fill_value = FILL_VALUE;
            strcpy (bmeta[ib].category, "image");
            strcpy (bmeta[ib].data_units, "reflectance");

            if (ib == SR_BAND10 || ib == SR_BAND11)  /* thermal bands */
            {
                bmeta[ib].scale_factor = SCALE_FACTOR_TH;
                bmeta[ib].valid_range[0] = MIN_VALID_TH;
                bmeta[ib].valid_range[1] = MAX_VALID_TH;
            }
            else
            {
                bmeta[ib].scale_factor = SCALE_FACTOR;
                bmeta[ib].valid_range[0] = MIN_VALID;
                bmeta[ib].valid_range[1] = MAX_VALID;
            }

            if (ib >= SR_BAND1 && ib <= SR_BAND7)
            {
                if (toa)
                {
                    sprintf (bmeta[ib].name, "toa_band%d", ib+1);
                    sprintf (bmeta[ib].long_name, "band %d top-of-atmosphere "
                        "reflectance", ib+1);
                }
                else
                {
                    sprintf (bmeta[ib].name, "sr_band%d", ib+1);
                    sprintf (bmeta[ib].long_name, "band %d surface reflectance",
                        ib+1);
                }
            }
            else if (ib == SR_BAND9)  /* cirrus band */
            {  /* band 9 is only atmospherically corrected */
                sprintf (bmeta[ib].name, "toa_band%d", ib+2);
                sprintf (bmeta[ib].long_name, "band %d top-of-atmosphere "
                    "reflectance", ib+2);
            }
            else if (ib == SR_BAND10 || ib == SR_BAND11)  /* thermal bands */
            {
                sprintf (bmeta[ib].name, "toa_band%d", ib+2);
                sprintf (bmeta[ib].long_name, "band %d at-satellite brightness "
                    "temperature", ib+2);
                sprintf (bmeta[ib].data_units, "temperature (kelvin)");
            }
        }

        /* Set up the filename with the scene name and band name and open the
           file for read/write access.  Don't open if this is OLI-only and
           these are the thermal bands. */
        if ((ib != SR_BAND10 && ib != SR_BAND11) || this->inst != INST_OLI)
        {
            sprintf (bmeta[ib].file_name, "%s_%s.img", scene_name,
                bmeta[ib].name);
            this->fp_bin[ib] = open_raw_binary (bmeta[ib].file_name, "w+");
            if (this->fp_bin[ib] == NULL)
            {
                sprintf (errmsg, "Unable to open output band %d file: %s", ib,
                    bmeta[ib].file_name);
                error_handler (true, FUNC_NAME, errmsg);
                return (NULL);
            }
        }

        /* Free the memory for the upper-case string */
        free (upper_str);
    }  /* for ib */
    this->open = true;

    /* Successful completion */
    return this;
}
/******************************************************************************
MODULE:  convert_espa_to_raw_binary_bip

PURPOSE: Converts the internal ESPA raw binary file to a raw binary band
interleave by pixel format.

RETURN VALUE:
Type = int
Value           Description
-----           -----------
ERROR           Error converting to BIP
SUCCESS         Successfully converted to BIP

NOTES:
  1. The bands in the XML file will be written, in order, to the BIP file.
     These bands must be of the same datatype and same size, otherwise this
     function will exit with an error.
  2. If the data types are not the same, the convert_qa flag will allow the
     user to specify that the QA bands (uint8) should be included in the output
     BIP product however the QA bands will be converted to the same data type
     as the first band in the XML file.
******************************************************************************/
int convert_espa_to_raw_binary_bip
(
    char *espa_xml_file,   /* I: input ESPA XML metadata filename */
    char *bip_file,        /* I: output BIP filename */
    bool convert_qa,       /* I: should the QA bands (uint8) be converted to
                                 the data type of band 1 (if QA bands are of
                                 a different data type)? */
    bool del_src           /* I: should the source files be removed after
                                 conversion? */
)
{
    char FUNC_NAME[] = "convert_espa_to_raw_binary_bip";  /* function name */
    char errmsg[STR_SIZE];      /* error message */
    char hdr_file[STR_SIZE];    /* name of the header file for this band */
    char xml_file[STR_SIZE];    /* new XML file for the BIP product */
    char envi_file[STR_SIZE];   /* name of the output ENVI header file */
    char *cptr = NULL;          /* pointer to empty space in the band name */
    int i;                      /* looping variable for each band */
    int l;                      /* looping variable for each line */
    int s;                      /* looping variable for each sample */
    int nbytes;                 /* number of bytes per pixel in the data type */
    int nbytes_line;            /* number of bytes per line in the data type */
    int count;                  /* number of chars copied in snprintf */
    int curr_pix;               /* index for current pixel for QA conversion */
    int curr_ipix;              /* index for current input pixel */
    int curr_opix;              /* index for current output pixel */
    int number_elements;        /* number of elements per line for all bands */
    void *file_buf = NULL;      /* pointer to correct input file buffer */
    uint8 *tmp_buf_u8 = NULL;   /* buffer for uint8 QA data to be read */
    uint8 *file_buf_u8 = NULL;  /* buffer for uint8 data to be read */
    int16 *file_buf_i16 = NULL; /* buffer for int16 data to be read */
    int16 *file_buf_u16 = NULL; /* buffer for uint16 data to be read */
    void *ofile_buf = NULL;     /* pointer to correct output file buffer */
    uint8 *ofile_buf_u8 = NULL; /* buffer for output uint8 data to be written */
    int16 *ofile_buf_i16 = NULL;/* buffer for output int16 data to be written */
    int16 *ofile_buf_u16 = NULL;/* buffer for output uint16 data to be
                                   written */
    FILE **fp_rb = NULL;        /* array of file pointers for the input raw
                                   binary files */
    FILE *fp_bip = NULL;        /* file pointer for the BIP raw binary file */
    Espa_internal_meta_t xml_metadata;  /* XML metadata structure to be
                                   populated by reading the input XML metadata
                                   file */
    Espa_band_meta_t *bmeta=NULL; /* pointer to the array of bands metadata */
    Espa_global_meta_t *gmeta=NULL; /* pointer to the global metadata
                                   structure */
    Envi_header_t envi_hdr;     /* output ENVI header information */

    /* Validate the input metadata file */
    if (validate_xml_file (espa_xml_file) != SUCCESS)
    {  /* Error messages already written */
        return (ERROR);
    }

    /* Initialize the metadata structure */
    init_metadata_struct (&xml_metadata);

    /* Parse the metadata file into our internal metadata structure; also
       allocates space as needed for various pointers in the global and band
       metadata */
    if (parse_metadata (espa_xml_file, &xml_metadata) != SUCCESS)
    {  /* Error messages already written */
        return (ERROR);
    }
    bmeta = xml_metadata.band;
    gmeta = &xml_metadata.global;
    printf ("convert_espa_to_raw_binary_bip processing %d bands ...\n",
        xml_metadata.nbands);

    /* Allocate file pointers for each band */
    fp_rb = calloc (xml_metadata.nbands, sizeof (FILE *));
    if (fp_rb == NULL)
    {
        sprintf (errmsg, "Allocating file pointers for all %d bands.",
            xml_metadata.nbands);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Loop through the bands in the XML file and verify they are all of the
       same data type and the same size */
    for (i = 1; i < xml_metadata.nbands; i++)
    {
        if (bmeta[i].data_type != bmeta[0].data_type)
        {
            /* Convert uint8 data types that are flagged as QA */
            if (convert_qa && bmeta[i].data_type == ESPA_UINT8 &&
                !strcmp (bmeta[i].category, "qa"))
            {
                /* all is good, data type will be converted */
                printf ("Band %s will be converted to native data type.\n",
                    bmeta[i].name);
            }
            else
            {
                sprintf (errmsg, "Data type for band %d (%s) in the XML file "
                    "does not match that of the first band.  All bands must "
                    "have the same data type to be written to BIP raw binary. "
                    "Otherwise convert_qa can be specified to convert the QA "
                    "bands (UINT8).", i+1, bmeta[i].name);
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }
        }
        else if (bmeta[i].nlines != bmeta[0].nlines)
        {
            sprintf (errmsg, "Number of lines for band %d (%s) in the XML file "
                "does not match that of the first band.  All bands must be of "
                "the same image size to be written to BIP raw binary.", i+1,
                bmeta[i].name);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
        else if (bmeta[i].nsamps != bmeta[0].nsamps)
        {
            sprintf (errmsg, "Number of samples for band %d (%s) in the XML "
                "file does not match that of the first band.  All bands must "
                "be of the same image size to be written to BIP raw binary.",
                i+1, bmeta[i].name);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }

    /* Loop through the bands in the XML file and open each band file for
       reading */
    for (i = 0; i < xml_metadata.nbands; i++)
    {
        /* Open the file for this band of data to allow for reading */
        fp_rb[i] = open_raw_binary (bmeta[i].file_name, "rb");
        if (fp_rb[i] == NULL)
        {
            sprintf (errmsg, "Opening the input raw binary file: %s",
                bmeta[i].file_name);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }

    /* Open the output BIP file to allow for writing */
    fp_bip = open_raw_binary (bip_file, "wb");
    if (fp_bip == NULL)
    {
        sprintf (errmsg, "Opening the output raw binary BIP file: %s",
            bip_file);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Allocate memory for a single line of the image and all the bands, based
       on the input data type of the first band */
    switch (bmeta[0].data_type)
    {
        case ESPA_UINT8:
            nbytes = sizeof (uint8);
            break;
        case ESPA_INT16:
            nbytes = sizeof (int16);
            break;
        case ESPA_UINT16:
            nbytes = sizeof (uint16);
            break;
        default:
            sprintf (errmsg, "Unsupported data type.  Currently only uint8, "
                "int16, and uint16 are supported.");
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
    }

    /* Input data */
    file_buf = calloc (bmeta[0].nsamps * xml_metadata.nbands, nbytes);
    if (file_buf == NULL)
    {
        sprintf (errmsg, "Allocating memory for a line of %d-byte data "
            "containing %d samples for all %d bands.", nbytes, bmeta[0].nsamps,
            xml_metadata.nbands);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Output data */
    ofile_buf = calloc (bmeta[0].nsamps * xml_metadata.nbands, nbytes);
    if (ofile_buf == NULL)
    {
        sprintf (errmsg, "Allocating memory for a line of %d-byte data "
            "containing %d samples for all %d bands.", nbytes, bmeta[0].nsamps,
            xml_metadata.nbands);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Assign the datatype-specific pointer to the void pointer to be used
       in the data conversion later for QA pixels */
    switch (bmeta[0].data_type)
    {
        case ESPA_UINT8:
            file_buf_u8 = file_buf;
            ofile_buf_u8 = ofile_buf;
            break;
        case ESPA_INT16:
            file_buf_i16 = file_buf;
            ofile_buf_i16 = ofile_buf;
            break;
        case ESPA_UINT16:
            file_buf_u16 = file_buf;
            ofile_buf_u16 = ofile_buf;
            break;
        default:
            sprintf (errmsg, "Unsupported data type.  Currently only uint8, "
                "int16, and uint16 are supported.");
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
    }

    /* The QA bands will be converted so allocate space for a temporary UINT8
       input array */
    if (convert_qa)
    {
        tmp_buf_u8 = calloc (bmeta[0].nsamps, sizeof (uint8));
        if (tmp_buf_u8 == NULL)
        {
            sprintf (errmsg, "Allocating memory for a line of QA data "
                "containing %d samples.", bmeta[0].nsamps);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }

    /* Loop through the lines in the input raw binary file.  Read each line
       for each band, put into the output BIP buffer, and write to the output
       file. */
    nbytes_line = nbytes * bmeta[0].nsamps;
    for (l = 0; l < bmeta[0].nlines; l++)
    {
        if (l % 100 == 0)
            printf ("Line %d\n", l);

        for (i = 0; i < xml_metadata.nbands; i++)
        {
            /* Check to make sure the current band data type is the same as 
               the output data type, otherwise this is a QA band that will
               get converted to the output data type */
            if ((bmeta[0].data_type != bmeta[i].data_type) &&
                (bmeta[i].data_type == ESPA_UINT8) && convert_qa)
            {
                /* Read the current line from the raw binary file into the
                   temporary UINT8 buffer */
                if (read_raw_binary (fp_rb[i], 1, bmeta[0].nsamps,
                    sizeof (uint8), tmp_buf_u8) != SUCCESS)
                {
                    sprintf (errmsg, "Reading QA data from the raw binary "
                        "file for line %d and band %d", l, i);
                    error_handler (true, FUNC_NAME, errmsg);
                    return (ERROR);
                }

                /* Convert the data and write it to the output buffer */
                if (bmeta[0].data_type == ESPA_INT16)
                {
                    curr_pix = i * bmeta[0].nsamps;
                    for (s = 0; s < bmeta[0].nsamps; s++, curr_pix++)
                        file_buf_i16[curr_pix] = (int16) tmp_buf_u8[s];
                }
                else if (bmeta[0].data_type == ESPA_UINT16)
                {
                    curr_pix = i * bmeta[0].nsamps;
                    for (s = 0; s < bmeta[0].nsamps; s++, curr_pix++)
                        file_buf_u16[curr_pix] = (uint16) tmp_buf_u8[s];
                }
            }
            else
            {
                /* Read the current line from the raw binary file */
                if (read_raw_binary (fp_rb[i], 1, bmeta[0].nsamps, nbytes,
                    file_buf + (i*nbytes_line)) != SUCCESS)
                {
                    sprintf (errmsg, "Reading image data from the raw binary "
                        "file for line %d and band %d", l, i);
                    error_handler (true, FUNC_NAME, errmsg);
                    return (ERROR);
                }
            }
        }  /* end for i */

        /* Loop through the samples and put each band for each pixel into the
           output buffer */
        for (s = 0; s < bmeta[0].nsamps; s++)
        {
            curr_opix = s * xml_metadata.nbands;
            for (i = 0; i < xml_metadata.nbands; i++, curr_opix++)
            {
                curr_ipix = i * bmeta[0].nsamps + s;
                if (bmeta[0].data_type == ESPA_UINT8)
                {
                    ofile_buf_u8[curr_opix] = file_buf_u8[curr_ipix];
                }
                else if (bmeta[0].data_type == ESPA_INT16)
                {
                    ofile_buf_i16[curr_opix] = file_buf_i16[curr_ipix];
                }
                else if (bmeta[0].data_type == ESPA_UINT16)
                {
                    ofile_buf_u16[curr_opix] = file_buf_u16[curr_ipix];
                }
            }
        }

        /* Write the current line of data containing all the bands to the
           output file */
        number_elements = bmeta[0].nsamps * xml_metadata.nbands;
        if (fwrite (ofile_buf, nbytes, number_elements, fp_bip) !=
            number_elements)
        {
            sprintf (errmsg, "Writing data to the BIP raw binary file for "
                "line %d", l);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }  /* end for l */

    /* Close the raw binary files */
    for (i = 0; i < xml_metadata.nbands; i++)
        close_raw_binary (fp_rb[i]);
    close_raw_binary (fp_bip);

    /* Free the memory */
    free (tmp_buf_u8);
    free (file_buf_u8);
    free (file_buf_i16);
    free (file_buf_u16);
    free (ofile_buf_u8);
    free (ofile_buf_i16);
    free (ofile_buf_u16);

    /* Create the ENVI header file for this BIP product */
    if (create_envi_struct (&bmeta[0], gmeta, &envi_hdr) != SUCCESS)
    {
        sprintf (errmsg, "Creating the ENVI header structure for this file.");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Update the ENVI header (created by default for a single BSQ band) to
       represent that this product is a multi-band, BIP file */
    envi_hdr.nbands = xml_metadata.nbands;

    count = snprintf (envi_hdr.interleave, sizeof (envi_hdr.interleave), "%s",
        "BIP");
    if (count < 0 || count >= sizeof (envi_hdr.interleave))
    {
        sprintf (errmsg, "Overflow of envi_hdr.interleave");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    for (i = 0; i < xml_metadata.nbands; i++)
    {
        count = snprintf (envi_hdr.band_names[i],
            sizeof (envi_hdr.band_names[i]), "%s", bmeta[i].name);
        if (count < 0 || count >= sizeof (envi_hdr.band_names))
        {
            sprintf (errmsg, "Overflow of envi_hdr.band_names");
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }

    /* Write the ENVI header */
    count = snprintf (envi_file, sizeof (envi_file), "%s", bip_file);
    if (count < 0 || count >= sizeof (envi_file))
    {
        sprintf (errmsg, "Overflow of envi_file string");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    cptr = strchr (envi_file, '.');
    if (cptr != NULL)
    {
        /* File extension found.  Replace it with the new extension */
        *cptr = '\0';
        strcpy (cptr, ".hdr");
    }
    else
    {
        /* No file extension found.  Just append the new extension */
        strcat (envi_file, ".hdr");
    }

    if (write_envi_hdr (envi_file, &envi_hdr) != SUCCESS)
    {
        sprintf (errmsg, "Writing the ENVI header file: %s.", envi_file);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Remove the source files if specified */
    if (del_src)
    {
        /* Remove the image and header files for each band */
        for (i = 0; i < xml_metadata.nbands; i++)
        {
            printf ("  Removing %s\n", xml_metadata.band[i].file_name);
            if (unlink (xml_metadata.band[i].file_name) != 0)
            {
                sprintf (errmsg, "Deleting source file: %s",
                    xml_metadata.band[i].file_name);
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }

            /* .hdr file */
            count = snprintf (hdr_file, sizeof (hdr_file), "%s",
                xml_metadata.band[i].file_name);
            if (count < 0 || count >= sizeof (hdr_file))
            {
                sprintf (errmsg, "Overflow of hdr_file string");
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }

            cptr = strrchr (hdr_file, '.');
            strcpy (cptr, ".hdr");
            printf ("  Removing %s\n", hdr_file);
            if (unlink (hdr_file) != 0)
            {
                sprintf (errmsg, "Deleting source file: %s", hdr_file);
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }
        }

        /* Remove the source XML */
        printf ("  Removing %s\n", espa_xml_file);
        if (unlink (espa_xml_file) != 0)
        {
            sprintf (errmsg, "Deleting source file: %s", espa_xml_file);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }

    /* Use the input XML file structure for the output XML file since it's the
       same except for the band filenames.  Loop through the bands in the XML
       file and change the filenames to be the single output BIP filename. */
    for (i = 0; i < xml_metadata.nbands; i++)
    {
        count = snprintf (bmeta[i].file_name, sizeof (bmeta[i].file_name), "%s",
            bip_file);
        if (count < 0 || count >= sizeof (bmeta[i].file_name))
        {
            sprintf (errmsg, "Overflow of bmeta.file_name string");
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }

    /* Create the XML file for the BIP product */
    count = snprintf (xml_file, sizeof (xml_file), "%s", bip_file);
    if (count < 0 || count >= sizeof (xml_file))
    {
        sprintf (errmsg, "Overflow of xml_file string");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    cptr = strrchr (xml_file, '.');
    if (cptr != NULL)
    {
        /* File extension found.  Replace it with the new extension */
        *cptr = '\0';
        strcpy (cptr, "_bip.xml");
    }
    else
    {
        /* No file extension found.  Just append the new extension */
        strcat (xml_file, "_bip.xml");
    }

    /* Write the new XML file */
    if (write_metadata (&xml_metadata, xml_file) != SUCCESS)
    {
        sprintf (errmsg, "Error writing updated XML for the GeoTIFF product: "
            "%s", xml_file);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Free the metadata structure */
    free_metadata (&xml_metadata);

    /* Successful conversion */
    return (SUCCESS);
}
예제 #7
0
int main (int argc, const char **argv) {
  Param_t *param = NULL;
  Input_t *input = NULL;
  Lut_t *lut = NULL;
  Output_t *output = NULL;
  Output_t *output_th = NULL;
  int iline, isamp,oline, ib, jb, iz, val;
  unsigned char *line_in = NULL;
  unsigned char *line_in_thz = NULL;
  unsigned char *line_out_qa = NULL;
  int16 *line_out = NULL;
  int16 *line_out_th = NULL;
  int16 *line_out_thz = NULL;
  Cal_stats_t cal_stats;
  Cal_stats6_t cal_stats6;
  int nps,nls, nps6, nls6;
  int zoomx, zoomy;
  int i,odometer_flag=0;
  char msgbuf[1024];
  char envi_file[STR_SIZE]; /* name of the output ENVI header file */
  char *cptr=NULL;          /* pointer to the file extension */
  size_t input_psize;
  int qa_band = QA_BAND_NUM;
  int nband_refl = NBAND_REFL_MAX;
  int ifill, num_zero;
  int maxth=0;
  int mss_flag=0;
  Espa_internal_meta_t xml_metadata;  /* XML metadata structure */
  Envi_header_t envi_hdr;   /* output ENVI header information */

  printf ("\nRunning lndcal ...\n");
  for (i=1; i<argc; i++)if ( !strcmp(argv[i],"-o") )odometer_flag=1;

  /* Read the parameters from the input parameter file */
  param = GetParam(argc, argv);
  if (param == (Param_t *)NULL) EXIT_ERROR("getting runtime parameters",
    "main");

  /* Validate the input metadata file */
  if (validate_xml_file (param->input_xml_file_name) != SUCCESS)
  {  /* Error messages already written */
      EXIT_ERROR("Failure validating XML file", "main");
  }

  /* Initialize the metadata structure */
  init_metadata_struct (&xml_metadata);

  /* Parse the metadata file into our internal metadata structure; also
     allocates space as needed for various pointers in the global and band
     metadata */
  if (parse_metadata (param->input_xml_file_name, &xml_metadata) != SUCCESS)
  {  /* Error messages already written */
    EXIT_ERROR("parsing XML file", "main");
  }

  /* Check to see if the gain and bias values were specified */
  if (!existRadGB (&xml_metadata))
    EXIT_ERROR("Gains and biases don't exist in XML file (TOA radiance gain "
      "and bias fields) for each band.  Make sure to utilize the latest LPGS "
      "MTL file for conversion to the ESPA internal raw binary format as the "
      "gains and biases should be in that file.", "main");
  
  /* Open input file */
  input = OpenInput (&xml_metadata);
  if (input == (Input_t *)NULL)
    EXIT_ERROR("setting up input from XML structure", "main");

  /* Get Lookup table */
  lut = GetLut(param, input->nband, input);
  if (lut == (Lut_t *)NULL) EXIT_ERROR("bad lut file", "main");

  nps6=  input->size_th.s;
  nls6=  input->size_th.l;
  nps =  input->size.s;
  nls =  input->size.l;
  zoomx= nint( (float)nps / (float)nps6 );
  zoomy= nint( (float)nls / (float)nls6 );

  for (ib = 0; ib < input->nband; ib++) 
    cal_stats.first[ib] = true;
  cal_stats6.first = true;
  if (input->meta.inst == INST_MSS)mss_flag=1; 

  /* Open the output files.  Raw binary band files will be be opened. */
  output = OpenOutput(&xml_metadata, input, param, lut, false /*not thermal*/,
    mss_flag);
  if (output == NULL) EXIT_ERROR("opening output file", "main");

  /* Allocate memory for the input buffer, enough for all reflectance bands */
  input_psize = sizeof(unsigned char);
  line_in = calloc (input->size.s * nband_refl, input_psize);
   if (line_in == NULL) 
     EXIT_ERROR("allocating input line buffer", "main");

  /* Create and open output thermal band, if one exists */
  if ( input->nband_th > 0 ) {
    output_th = OpenOutput (&xml_metadata, input, param, lut, true /*thermal*/,
      mss_flag);
    if (output_th == NULL)
      EXIT_ERROR("opening output therm file", "main");

    /* Allocate memory for the thermal input and output buffer, only holds
       one band */
    line_out_th = calloc(input->size_th.s, sizeof(int16));
    if (line_out_th == NULL) 
      EXIT_ERROR("allocating thermal output line buffer", "main");

    if (zoomx == 1) {
      line_out_thz = line_out_th;
      line_in_thz = line_in;
    }
    else {
      line_out_thz = calloc (input->size.s, sizeof(int16));
      if (line_out_thz == NULL) 
        EXIT_ERROR("allocating thermal zoom output line buffer", "main");
      line_in_thz = calloc (input->size.s, input_psize);
      if (line_in_thz == NULL) 
        EXIT_ERROR("allocating thermal zoom input line buffer", "main");
    }
  } else {
    printf("*** no output thermal file ***\n"); 
  }

  /* Allocate memory for output lines for both the image and QA data */
  line_out = calloc (input->size.s, sizeof (int16));
  if (line_out == NULL) 
    EXIT_ERROR("allocating output line buffer", "main");

  line_out_qa = calloc (input->size.s, sizeof(unsigned char));
  if (line_out_qa == NULL) 
    EXIT_ERROR("allocating qa output line buffer", "main");
  memset (line_out_qa, 0, input->size.s * sizeof(unsigned char));    

  /* Do for each THERMAL line */
  oline= 0;
  if (input->nband_th > 0) {
    ifill= (int)lut->in_fill;
    for (iline = 0; iline < input->size_th.l; iline++) {
      ib=0;
      if (!GetInputLineTh(input, iline, line_in))
        EXIT_ERROR("reading input data for a line", "main");

      if ( odometer_flag && ( iline==0 || iline ==(nls-1) || iline%100==0  ) ){ 
        if ( zoomy == 1 )
          printf("--- main loop BAND6 Line %d --- \r",iline); 
        else
          printf("--- main loop BAND6 Line in=%d out=%d --- \r",iline,oline); 
        fflush(stdout); 
      }

      memset(line_out_qa, 0, input->size.s*sizeof(unsigned char));    
      if (!Cal6(lut, input, line_in, line_out_th, line_out_qa, &cal_stats6,
        iline))
        EXIT_ERROR("doing calibration for a line", "main");

      if ( zoomx>1 ) {
        zoomIt(line_out_thz, line_out_th, nps/zoomx, zoomx );
        zoomIt8(line_in_thz, line_in, nps/zoomx, zoomx );
      }

      for ( iz=0; iz<zoomy; iz++ ) {
        for (isamp = 0; isamp < input->size.s; isamp++) {
          val= getValue(line_in_thz, isamp);
          if ( val> maxth) maxth=val;
          if ( val==ifill) line_out_qa[isamp] = lut->qa_fill; 
          else if ( val>=SATU_VAL6 ) line_out_qa[isamp] = ( 0x000001 << 6 ); 
        }

        if ( oline<nls ) {
          if (!PutOutputLine(output_th, ib, oline, line_out_thz)) {
            sprintf(msgbuf,"write thermal error ib=%d oline=%d iline=%d",ib,
              oline,iline);
            EXIT_ERROR(msgbuf, "main");
          }

          if (input->meta.inst != INST_MSS) 
            if (!PutOutputLine(output_th, ib+1, oline, line_out_qa)) {
	          sprintf(msgbuf,"write thermal QA error ib=%d oline=%d iline=%d",
                ib+1,oline,iline);
              EXIT_ERROR(msgbuf, "main");
            }
        }
        oline++;
      }
    } /* end loop for each thermal line */
  }
  if (odometer_flag) printf("\n");

  if (input->nband_th > 0)
    if (!CloseOutput(output_th))
      EXIT_ERROR("closing output thermal file", "main");

  /* Do for each REFLECTIVE line */
  ifill= (int)lut->in_fill;
  for (iline = 0; iline < input->size.l; iline++){
    /* Do for each band */

    if ( odometer_flag && ( iline==0 || iline ==(nls-1) || iline%100==0  ) )
     {printf("--- main reflective loop Line %d ---\r",iline); fflush(stdout);}

    memset(line_out_qa, 0, input->size.s*sizeof(unsigned char));
    
    for (ib = 0; ib < input->nband; ib++) {
      if (!GetInputLine(input, ib, iline, &line_in[ib*nps]))
        EXIT_ERROR("reading input data for a line", "main");
    }
    
    for (isamp = 0; isamp < input->size.s; isamp++){
      num_zero=0;
      for (ib = 0; ib < input->nband; ib++) {
        jb= (ib != 5 ) ? ib+1 : ib+2;
        val= getValue((unsigned char *)&line_in[ib*nps], isamp);
	    if ( val==ifill   )num_zero++;
        if ( val==SATU_VAL[ib] ) line_out_qa[isamp]|= ( 0x000001 <<jb ); 
      }
      /* Feng fixed bug by changing "|=" to "=" below (4/17/09) */
      if ( num_zero >  0 )line_out_qa[isamp] = lut->qa_fill; 
    }

    for (ib = 0; ib < input->nband; ib++) {
      if (!Cal(lut, ib, input, &line_in[ib*nps], line_out, line_out_qa,
        &cal_stats,iline))
        EXIT_ERROR("doing calibraton for a line", "main");

      if (!PutOutputLine(output, ib, iline, line_out))
        EXIT_ERROR("reading input data for a line", "main");
    } /* End loop for each band */
        
    if (input->meta.inst != INST_MSS) 
      if (!PutOutputLine(output, qa_band, iline, line_out_qa))
        EXIT_ERROR("writing qa data for a line", "main");
  } /* End loop for each line */

  if ( odometer_flag )printf("\n");

  for (ib = 0; ib < input->nband; ib++) {
    printf(
      " band %d rad min %8.5g max %8.4f  |  ref min  %8.5f max  %8.4f\n", 
      input->meta.iband[ib], cal_stats.rad_min[ib], cal_stats.rad_max[ib],
      cal_stats.ref_min[ib], cal_stats.ref_max[ib]);
  }

  if ( input->nband_th > 0 )
    printf(
      " band %d rad min %8.5g max %8.4f  |  tmp min  %8.5f max  %8.4f\n", 6,
      cal_stats6.rad_min,  cal_stats6.rad_max,
      cal_stats6.temp_min, cal_stats6.temp_max);

  /* Close input and output files */
  if (!CloseInput(input)) EXIT_ERROR("closing input file", "main");
  if (!CloseOutput(output)) EXIT_ERROR("closing input file", "main");

  /* Write the ENVI header for reflectance files */
  for (ib = 0; ib < output->nband; ib++) {
    /* Create the ENVI header file this band */
    if (create_envi_struct (&output->metadata.band[ib], &xml_metadata.global,
      &envi_hdr) != SUCCESS)
        EXIT_ERROR("Creating the ENVI header structure for this file.", "main");

    /* Write the ENVI header */
    strcpy (envi_file, output->metadata.band[ib].file_name);
    cptr = strchr (envi_file, '.');
    strcpy (cptr, ".hdr");
    if (write_envi_hdr (envi_file, &envi_hdr) != SUCCESS)
        EXIT_ERROR("Writing the ENVI header file.", "main");
  }

  /* Write the ENVI header for thermal files */
  for (ib = 0; ib < output_th->nband; ib++) {
    /* Create the ENVI header file this band */
    if (create_envi_struct (&output_th->metadata.band[ib], &xml_metadata.global,
      &envi_hdr) != SUCCESS)
        EXIT_ERROR("Creating the ENVI header structure for this file.", "main");

    /* Write the ENVI header */
    strcpy (envi_file, output_th->metadata.band[ib].file_name);
    cptr = strchr (envi_file, '.');
    strcpy (cptr, ".hdr");
    if (write_envi_hdr (envi_file, &envi_hdr) != SUCCESS)
        EXIT_ERROR("Writing the ENVI header file.", "main");
  }

  /* Append the reflective and thermal bands to the XML file */
  if (append_metadata (output->nband, output->metadata.band,
    param->input_xml_file_name) != SUCCESS)
    EXIT_ERROR("appending reflectance and QA bands", "main");
  if (input->nband_th > 0) {
    if (append_metadata (output_th->nband, output_th->metadata.band,
      param->input_xml_file_name) != SUCCESS)
      EXIT_ERROR("appending thermal and QA bands", "main");
  }

  /* Free the metadata structure */
  free_metadata (&xml_metadata);

  /* Free memory */
  if (!FreeParam(param)) 
    EXIT_ERROR("freeing parameter stucture", "main");

  if (!FreeInput(input)) 
    EXIT_ERROR("freeing input file stucture", "main");

  if (!FreeLut(lut)) 
    EXIT_ERROR("freeing lut file stucture", "main");

  if (!FreeOutput(output)) 
    EXIT_ERROR("freeing output file stucture", "main");

  free(line_out);
  line_out = NULL;
  free(line_in);
  line_in = NULL;
  free(line_out_qa);
  line_out_qa = NULL;
  free(line_out_th);
  line_out_th = NULL;
  if (zoomx != 1) {
    free(line_in_thz);
    free(line_out_thz);
  }
  line_in_thz = NULL;
  line_out_thz = NULL;

  /* All done */
  printf ("lndcal complete.\n");
  return (EXIT_SUCCESS);
}
예제 #8
0
/*****************************************************************************
METHOD:  cfmask

PURPOSE:  The main routine for fmask written in C

RETURN VALUE: Type = int
    Value           Description
    -----           -----------
    ERROR           An error occurred during processing of cfmask
    SUCCESS         Processing was successful
*****************************************************************************/
int
main (int argc, char *argv[])
{
    char *FUNC_NAME = "main";
    char *ext = NULL;            /* pointer to the file extension */
    char *xml_name = NULL;       /* input XML filename */
    char envi_file[MAX_STR_LEN]; /* output ENVI file name */
    char temp_file[MAX_STR_LEN]; /* temp file name */

    int status;
    int band_index;

    bool verbose;            /* verbose flag for printing messages */
    bool use_cirrus;         /* should we use Cirrus during determination? */
    bool use_thermal;        /* should we use Thermal during determination? */

    Input_t *input = NULL;    /* input data and meta data */
    Output_t *output = NULL;  /* output structure and metadata */
    Espa_internal_meta_t xml_metadata; /* XML metadata structure */
    Envi_header_t envi_hdr;            /* output ENVI header information */

    unsigned char *pixel_mask = NULL; /* pixel mask */
    unsigned char *conf_mask = NULL;  /* confidence mask */

    float clear_ptm;          /* percent of clear-sky pixels */
    float t_templ = 0.0;      /* percentile of low background temperature */
    float t_temph = 0.0;      /* percentile of high background temperature */

    int cldpix = 2;           /* Default buffer for cloud pixel dilate */
    int sdpix = 2;            /* Default buffer for shadow pixel dilate */
    float cloud_prob;         /* Default cloud probability */
    float sun_azi_temp = 0.0; /* Keep the original sun azimuth angle */

    int pixel_count;
    int pixel_index;

    time_t now;
    time(&now);

    /* Read the command-line arguments, including the name of the input
       Landsat TOA reflectance product and the DEM */
    status = get_args(argc, argv, &xml_name, &cloud_prob, &cldpix,
                      &sdpix, &use_cirrus, &use_thermal, &verbose);
    if (status != SUCCESS)
    {
        RETURN_ERROR("calling get_args", FUNC_NAME, EXIT_FAILURE);
    }

    printf("CFmask start_time=%s\n", ctime(&now));

    /* Validate the input metadata file */
    if (validate_xml_file(xml_name) != SUCCESS)
    {
        RETURN_ERROR("XML validation error", FUNC_NAME, EXIT_FAILURE);
    }

    /* Initialize the metadata structure */
    init_metadata_struct(&xml_metadata);

    /* Parse the metadata file into our internal metadata structure; also
       allocates space as needed for various pointers in the global and band
       metadata */
    if (parse_metadata(xml_name, &xml_metadata) != SUCCESS)
    {
        RETURN_ERROR("XML parsing error", FUNC_NAME, EXIT_FAILURE);
    }

    /* Open input file, read metadata, and set up buffers */
    input = OpenInput(&xml_metadata, use_thermal);
    if (input == NULL)
    {
        RETURN_ERROR("opening input data specified in input XML",
                     FUNC_NAME, EXIT_FAILURE);
    }

    if (verbose)
    {
        /* Print some info to show how the input metadata works */
        printf("Number of input TOA bands: %d\n", input->num_toa_bands);
        printf("Number of input thermal bands: %d\n", 1);
        printf("Number of input TOA lines: %d\n", input->size.l);
        printf("Number of input TOA samples: %d\n", input->size.s);
        printf("Fill value is %d\n", input->meta.fill);
        for (band_index = 0; band_index < MAX_BAND_COUNT; band_index++)
        {
            printf("Band %d-->\n", band_index);
            if (input->satellite != IS_LANDSAT_8)
            {
                /* Landsat 8 doesn't have saturation issues */
                printf("  band satu_value_ref: %d\n",
                       input->meta.satu_value_ref[band_index]);
                printf("  band satu_value_max: %d\n",
                       input->meta.satu_value_max[band_index]);
            }
            printf("  band gain: %f, band bias: %f\n",
                   input->meta.gain[band_index], input->meta.bias[band_index]);
        }

        printf("SUN AZIMUTH is %f\n", input->meta.sun_az);
        printf("SUN ZENITH is %f\n", input->meta.sun_zen);
    }

    /* If the scene is an ascending polar scene (flipped upside down), then
       the solar azimuth needs to be adjusted by 180 degrees.  The scene in
       this case would be north down and the solar azimuth is based on north
       being up clock-wise direction. Flip the south to be up will not change
       the actual sun location, with the below relations, the solar azimuth
       angle will need add in 180.0 for correct sun location */
    if (input->meta.ul_corner.lat < input->meta.lr_corner.lat)
    {
        /* Keep the original solar azimuth angle */
        sun_azi_temp = input->meta.sun_az;
        input->meta.sun_az += 180.0;
        if (input->meta.sun_az > 360.0)
        {
            input->meta.sun_az -= 360.0;
        }
        if (verbose)
        {
            printf("Polar or ascending scene."
                    "  Readjusting solar azimuth by 180 degrees.\n"
                    "  New value: %f degrees\n", input->meta.sun_az);
        }
    }

    pixel_count = input->size.l * input->size.s;

    /* Dynamic allocate the 2d mask memory */
    pixel_mask = calloc(pixel_count, sizeof(unsigned char));
    if (pixel_mask == NULL)
    {
        RETURN_ERROR("Allocating pixel mask memory", FUNC_NAME, EXIT_FAILURE);
    }

    conf_mask = calloc(pixel_count, sizeof(unsigned char));
    if (conf_mask == NULL)
    {
        RETURN_ERROR("Allocating confidence mask memory",
                     FUNC_NAME, EXIT_FAILURE);
    }

    /* Initialize the mask to clear data */
    for (pixel_index = 0; pixel_index < pixel_count; pixel_index++)
    {
        pixel_mask[pixel_index] = CF_NO_BITS;
        conf_mask[pixel_index] = CLOUD_CONFIDENCE_NONE;
    }

    /* Build the potential cloud, shadow, snow, water mask */
    status = potential_cloud_shadow_snow_mask(input, cloud_prob, &clear_ptm,
                                              &t_templ, &t_temph, pixel_mask,
                                              conf_mask, use_cirrus,
                                              use_thermal, verbose);
    if (status != SUCCESS)
    {
        RETURN_ERROR("processing potential_cloud_shadow_snow_mask",
                     FUNC_NAME, EXIT_FAILURE);
    }
    printf("Potential Cloud Shadow: Done\n");

    /* Build the final cloud shadow based on geometry matching and
       combine the final cloud, shadow, snow, water masks into fmask
       the pixel_mask is a bit mask as input and a value mask as output */
    int data_count = 0;
    status = object_cloud_shadow_match(input, clear_ptm, t_templ, t_temph,
                                       cldpix, sdpix, pixel_mask, &data_count,
                                       use_thermal, verbose);
    if (status != SUCCESS)
    {
        RETURN_ERROR("processing object_cloud_and_shadow_match",
                     FUNC_NAME, EXIT_FAILURE);
    }
    printf("Object Cloud Shadow Matching: Done\n");

    /* Convert the pixel_mask to a value mask
       Also retrieve and report statistics */
    float clear_percent = 0; /* Percent of clear pixels in the image data */
    float cloud_percent = 0; /* Percent of cloud pixels in the image data */
    float cloud_shadow_percent = 0; /* Percent of cloud shadow pixels in the
                                       image data */
    float water_percent = 0; /* Percent of water pixels in the image data */
    float snow_percent = 0;  /* Percent of snow pixels in the image data */
    convert_and_generate_statistics(verbose, pixel_mask,
                                    input->size.l * input->size.s,
                                    data_count, &clear_percent,
                                    &cloud_percent, &cloud_shadow_percent,
                                    &water_percent, &snow_percent);
    printf("Statistics Generation: Done\n");

    /* Reassign solar azimuth angle for output purpose if south up north
       down scene is involved */
    if (input->meta.ul_corner.lat < input->meta.lr_corner.lat)
    {
        input->meta.sun_az = sun_azi_temp;
    }

    /* Open the output file */
    output = OpenOutputCFmask(&xml_metadata, input, clear_percent,
                              cloud_percent, cloud_shadow_percent,
                              water_percent, snow_percent);
    if (output == NULL)
    {
        RETURN_ERROR("Opening output file", FUNC_NAME, EXIT_FAILURE);
    }

    if (!PutOutput(output, pixel_mask))
    {
        RETURN_ERROR("Writing output fmask files", FUNC_NAME, EXIT_FAILURE);
    }

    /* Close the output file */
    if (!CloseOutput(output))
    {
        RETURN_ERROR("closing output file", FUNC_NAME, EXIT_FAILURE);
    }

    /* Create the ENVI header file this band */
    if (create_envi_struct(&output->metadata.band[0], &xml_metadata.global,
                           &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR("Creating ENVI header structure.", FUNC_NAME,
                     EXIT_FAILURE);
    }

    /* Write the ENVI header */
    snprintf(temp_file, sizeof(temp_file), "%s",
             output->metadata.band[0].file_name);
    ext = strrchr(temp_file, '.');
    if (ext == NULL)
    {
        RETURN_ERROR("error in ENVI header filename", FUNC_NAME, EXIT_FAILURE);
    }

    ext[0] = '\0';
    snprintf(envi_file, sizeof(envi_file), "%s.hdr", temp_file);
    if (write_envi_hdr(envi_file, &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR("Writing ENVI header file.", FUNC_NAME, EXIT_FAILURE);
    }

    /* Append the cfmask band to the XML file */
    if (append_metadata(output->nband, output->metadata.band, xml_name)
        != SUCCESS)
    {
        RETURN_ERROR("Appending spectral index bands to XML file.",
                     FUNC_NAME, EXIT_FAILURE);
    }

    /* Free the structure */
    if (!FreeOutput(output))
    {
        RETURN_ERROR("freeing output file structure", FUNC_NAME, EXIT_FAILURE);
    }

    output = OpenOutputConfidence(&xml_metadata, input);
    if (output == NULL)
    {
        RETURN_ERROR("Opening output file", FUNC_NAME, EXIT_FAILURE);
    }

    if (!PutOutput(output, conf_mask))
    {
        RETURN_ERROR("Writing output fmask files", FUNC_NAME, EXIT_FAILURE);
    }

    /* Close the output file */
    if (!CloseOutput(output))
    {
        RETURN_ERROR("closing output file", FUNC_NAME, EXIT_FAILURE);
    }

    /* Create the ENVI header file this band */
    if (create_envi_struct(&output->metadata.band[0], &xml_metadata.global,
                           &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR("Creating ENVI header structure.", FUNC_NAME,
                     EXIT_FAILURE);
    }

    /* Write the ENVI header */
    snprintf(temp_file, sizeof(temp_file), "%s",
             output->metadata.band[0].file_name);
    ext = strrchr(temp_file, '.');
    if (ext == NULL)
    {
        RETURN_ERROR("error in ENVI header filename", FUNC_NAME, EXIT_FAILURE);
    }

    ext[0] = '\0';
    snprintf(envi_file, sizeof(envi_file), "%s.hdr", temp_file);
    if (write_envi_hdr(envi_file, &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR("Writing ENVI header file.", FUNC_NAME, EXIT_FAILURE);
    }

    /* Append the cfmask band to the XML file */
    if (append_metadata(output->nband, output->metadata.band,
                        xml_name) != SUCCESS)
    {
        RETURN_ERROR("Appending spectral index bands to XML file.",
                     FUNC_NAME, EXIT_FAILURE);
    }

    /* Free the structure */
    if (!FreeOutput(output))
    {
        RETURN_ERROR("freeing output file structure", FUNC_NAME, EXIT_FAILURE);
    }

    /* Free the metadata structure */
    free_metadata(&xml_metadata);

    /* Free the pixel mask */
    free(pixel_mask);
    pixel_mask = NULL;
    free(conf_mask);
    conf_mask = NULL;

    /* Close the input file and free the structure */
    CloseInput(input);
    FreeInput(input);

    free(xml_name);
    xml_name = NULL;

    printf("Processing complete.\n");
    time(&now);
    printf("CFmask end_time=%s\n", ctime(&now));

    return SUCCESS;
}
예제 #9
0
/******************************************************************************
METHOD:  lst

PURPOSE:  The main routine for scene based LST (Land Surface Temperature).

RETURN VALUE:
Type = int
Value           Description
-----           -----------
ERROR           An error occurred during processing of the scene_based_lst
SUCCESS         Processing was successful

PROJECT:  Land Satellites Data System Science Research and Development (LSRD)
          at the USGS EROS
******************************************************************************/
int
main (int argc, char *argv[])
{
    char FUNC_NAME[] = "main";

    Espa_internal_meta_t xml_metadata;  /* XML metadata structure */

    char msg_str[MAX_STR_LEN];
    char xml_filename[PATH_MAX];        /* input XML filename */
    char dem_filename[PATH_MAX];        /* input DEM filename */
    char emissivity_filename[PATH_MAX]; /* input Emissivity filename */
    char command[PATH_MAX];

    Input_t *input = NULL;          /* input data and meta data */
    //    Output_t *output = NULL; /* output structure and metadata */

    bool use_tape6;             /* Use the tape6 output */
    bool verbose;               /* verbose flag for printing messages */
    bool debug;                 /* debug flag for debug output */

    int modtran_run;

    double alb = 0.1;
    double **modtran_results = NULL;

    char *tmp_env = NULL;

    REANALYSIS_POINTS points;

    time_t now;

    /* Display the starting time of the application */
    time (&now);
    snprintf (msg_str, sizeof(msg_str),
              "LST start_time [%s]", ctime (&now));
    LOG_MESSAGE (msg_str, FUNC_NAME);

    /* Read the command-line arguments, including the name of the input
       Landsat TOA reflectance product and the DEM */
    if (get_args (argc, argv, xml_filename, dem_filename, emissivity_filename,
                  &use_tape6, &verbose, &debug) != SUCCESS)
    {
        RETURN_ERROR ("calling get_args", FUNC_NAME, EXIT_FAILURE);
    }

    /* Verify the existence of required environment variables */
    /* Grab the environment path to the LST_DATA_DIR */
    tmp_env = getenv ("LST_DATA_DIR");
    if (tmp_env == NULL)
    {
        RETURN_ERROR ("LST_DATA_DIR environment variable is not set",
                      FUNC_NAME, EXIT_FAILURE);
    }

    /* Validate the input metadata file */
    if (validate_xml_file (xml_filename) != SUCCESS)
    {
        /* Error messages already written */
        return EXIT_FAILURE;
    }

    /* Initialize the metadata structure */
    init_metadata_struct (&xml_metadata);

    /* Parse the metadata file into our internal metadata structure; also
       allocates space as needed for various pointers in the global and band
       metadata */
    if (parse_metadata (xml_filename, &xml_metadata) != SUCCESS)
    {
        /* Error messages already written */
        return EXIT_FAILURE;
    }

    /* Open input file, read metadata, and set up buffers */
    input = OpenInput (&xml_metadata);
    if (input == NULL)
    {
        RETURN_ERROR ("opening input files", FUNC_NAME, EXIT_FAILURE);
    }

    if (verbose)
    {
        /* Print some info to show how the input metadata works */
        printf ("Satellite: %d\n", input->meta.satellite);
        printf ("Instrument: %d\n", input->meta.instrument);

        printf ("Number of input lines: %d\n", input->thermal.size.l);
        printf ("Number of input samples: %d\n", input->thermal.size.s);

        printf ("Fill value is %d\n", input->thermal.fill_value);

        printf ("Thermal Band -->\n");
        printf ("  therm_gain: %f\n  therm_bias: %f\n",
                input->thermal.rad_gain, input->thermal.rad_bias);

        printf ("Year, Month, Day, Hour, Minute, Second:"
                " %d, %d, %d, %d, %d, %f\n",
                input->meta.acq_date.year, input->meta.acq_date.month,
                input->meta.acq_date.day, input->meta.acq_date.hour,
                input->meta.acq_date.minute, input->meta.acq_date.second);
        printf ("ACQUISITION_DATE.DOY is %d\n",
                input->meta.acq_date.doy);

        printf ("UL_MAP_CORNER: %f, %f\n", input->meta.ul_map_corner.x,
                input->meta.ul_map_corner.y);
        printf ("LR_MAP_CORNER: %f, %f\n", input->meta.lr_map_corner.x,
                input->meta.lr_map_corner.y);
        printf ("UL_GEO_CORNER: %f, %f\n",
                input->meta.ul_geo_corner.lat, input->meta.ul_geo_corner.lon);
        printf ("LR_GEO_CORNER: %f, %f\n",
                input->meta.lr_geo_corner.lat, input->meta.lr_geo_corner.lon);
    }

    /* Build the points that will be used */
    if (build_points (input, &points) != SUCCESS)
    {
        RETURN_ERROR ("Building POINTS input\n", FUNC_NAME, EXIT_FAILURE);
    }

    if (verbose)
    {
        printf ("Number of Points: %d\n", points.num_points);
    }

    /* Call build_modtran_input to generate the tape5 file input and
       the MODTRAN commands for each point and height */
    if (build_modtran_input (input, &points, verbose, debug)
        != SUCCESS)
    {
        RETURN_ERROR ("Building MODTRAN input\n", FUNC_NAME, EXIT_FAILURE);
    }

    /* Perform MODTRAN runs by calling each command */
    for (modtran_run = 0; modtran_run < points.num_modtran_runs; modtran_run++)
    {
        snprintf (msg_str, sizeof(msg_str),
                  "Executing MODTRAN [%s]",
                   points.modtran_runs[modtran_run].command);
        LOG_MESSAGE (msg_str, FUNC_NAME);

#if RUN_MODTRAN
        if (system (points.modtran_runs[modtran_run].command) != SUCCESS)
        {
            RETURN_ERROR ("Error executing MODTRAN", FUNC_NAME,
                          EXIT_FAILURE);
        }
#endif
    }

    /* PARSING MODTRAN RESULTS:
       for each case in caseList (for each modtran run),
       parse wavelength and total radiance from tape6 file into parsed */
    for (modtran_run = 0; modtran_run < points.num_modtran_runs; modtran_run++)
    {
        if (use_tape6)
        {
            /* Use modtran generated tape6 output */
            snprintf (command, sizeof (command),
                      "lst_extract_modtran_results.py"
                      " --tape6"
                      " --input-path %s"
                      " --output-path %s",
                      points.modtran_runs[modtran_run].path,
                      points.modtran_runs[modtran_run].path);
        }
        else
        {
            /* Use modtran generated pltout.asc output */
            snprintf (command, sizeof (command),
                      "lst_extract_modtran_results.py"
                      " --pltout"
                      " --input-path %s"
                      " --output-path %s",
                      points.modtran_runs[modtran_run].path,
                      points.modtran_runs[modtran_run].path);
        }

        snprintf (msg_str, sizeof(msg_str), "Executing [%s]", command);
        LOG_MESSAGE (msg_str, FUNC_NAME);

#if EXTRACT_TAPE6_RESULTS
        if (system (command) != SUCCESS)
        {
            RETURN_ERROR ("Failed executing lst_extract_tape6_results.py",
                          FUNC_NAME, EXIT_FAILURE);
        }
#endif
    }

    /* Allocate memory for MODTRAN results */
    modtran_results =
        (double **) allocate_2d_array (points.num_points * NUM_ELEVATIONS,
                                       MGPE_NUM_ELEMENTS, sizeof (double));
    if (modtran_results == NULL)
    {
        RETURN_ERROR ("Allocating MODTRAN results memory", FUNC_NAME,
                      EXIT_FAILURE);
    }

    /* Generate parameters for each height and NARR point */
    if (calculate_point_atmospheric_parameters (input, &points, alb,
                                                modtran_results, verbose)
        != SUCCESS)
    {
        RETURN_ERROR ("Calculating point atmospheric parameters\n",
                      FUNC_NAME, EXIT_FAILURE);
    }

    /* Generate parameters for each Landsat pixel */
    if (calculate_pixel_atmospheric_parameters (input, &points,
                                                xml_filename,
                                                dem_filename,
                                                emissivity_filename,
                                                modtran_results, verbose)
        != SUCCESS)
    {
        RETURN_ERROR ("Calculating per/pixel atmospheric parameters\n",
                      FUNC_NAME, EXIT_FAILURE);
    }

    /* Free memory allocation */
    free_points_memory (&points);

#if NOT_TESTED
    /* Open the output file */
    output = OpenOutput (&xml_metadata, input);
    if (output == NULL)
    {                           /* error message already printed */
        RETURN_ERROR ("Opening output file", FUNC_NAME, EXIT_FAILURE);
    }

    if (!PutOutput (output, pixel_mask))
    {
        RETURN_ERROR ("Writing output LST in HDF files\n", FUNC_NAME,
                      EXIT_FAILURE);
    }

    /* Close the output file */
    if (!CloseOutput (output))
    {
        RETURN_ERROR ("closing output file", FUNC_NAME, EXIT_FAILURE);
    }

    /* Create the ENVI header file this band */
    if (create_envi_struct (&output->metadata.band[0], &xml_metadata.global,
                            &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR ("Creating ENVI header structure.", FUNC_NAME,
                      EXIT_FAILURE);
    }

    /* Write the ENVI header */
    strcpy (envi_file, output->metadata.band[0].file_name);
    cptr = strchr (envi_file, '.');
    if (cptr == NULL)
    {
        RETURN_ERROR ("error in ENVI header filename", FUNC_NAME,
                      EXIT_FAILURE);
    }

    strcpy (cptr, ".hdr");
    if (write_envi_hdr (envi_file, &envi_hdr) != SUCCESS)
    {
        RETURN_ERROR ("Writing ENVI header file.", FUNC_NAME, EXIT_FAILURE);
    }

    /* Append the LST band to the XML file */
    if (append_metadata (output->nband, output->metadata.band, xml_filename)
        != SUCCESS)
    {
        RETURN_ERROR ("Appending spectral index bands to XML file.",
                      FUNC_NAME, EXIT_FAILURE);
    }

    /* Free the structure */
    if (!FreeOutput (output))
    {
        RETURN_ERROR ("freeing output file structure", FUNC_NAME,
                      EXIT_FAILURE);
    }
#endif

    /* Free the metadata structure */
    free_metadata (&xml_metadata);

    /* Close the input file and free the structure */
    CloseInput (input);
    FreeInput (input);

    /* Free memory allocations */
    if (free_2d_array ((void **) modtran_results) != SUCCESS)
    {
        RETURN_ERROR ("Freeing memory: MODTRAN results\n", FUNC_NAME,
                      EXIT_FAILURE);
    }

    if (!debug)
    {
        /* Delete temporary file */
        if (unlink ("atmospheric_parameters.txt") != SUCCESS)
        {
            RETURN_ERROR ("Deleting atmospheric_parameters.txt files\n",
                          FUNC_NAME, EXIT_FAILURE);
        }

        if (unlink ("base_head.txt") != SUCCESS)
        {
            RETURN_ERROR ("Deleting baseHead.txt files\n", FUNC_NAME,
                          EXIT_FAILURE);
        }

        if (unlink ("new_tail.txt") != SUCCESS)
        {
            RETURN_ERROR ("Deleting newTail.txt files\n", FUNC_NAME,
                          EXIT_FAILURE);
        }

        if (unlink ("temp_layers.txt") != SUCCESS)
        {
            RETURN_ERROR ("Deleting tempLayers.txt file\n", FUNC_NAME,
                          EXIT_FAILURE);
        }

        if (unlink ("used_points.txt") != SUCCESS)
        {
            RETURN_ERROR ("Deleting used_points.txt file\n", FUNC_NAME,
                          EXIT_FAILURE);
        }
    }

    time (&now);
    snprintf (msg_str, sizeof(msg_str),
              "scene_based_lst end_time=%s\n", ctime (&now));
    LOG_MESSAGE (msg_str, FUNC_NAME);

    return EXIT_SUCCESS;
}
예제 #10
0
/*****************************************************************************
  NAME:  get_args

  PURPOSE:  Gets the command line arguments and validates that the required
            arguments were specified.

  RETURN VALUE:  Type = int
      Value    Description
      -------  ---------------------------------------------------------------
      ERROR    Error getting the command line arguments or a command line
               argument and associated value were not specified.
      SUCCESS  No errors encountered.
*****************************************************************************/
int
get_args
(
    int argc,                    /* I: number of cmd-line args */
    char *argv[],                /* I: string of cmd-line args */
    char **xml_filename,         /* O: input XML filename */
    Espa_internal_meta_t *xml_metadata, /* O: input metadata */
    bool *use_zeven_thorne_flag, /* O: use zeven thorne */
    bool *use_toa_flag,          /* O: process using TOA */
    bool *include_tests_flag,    /* O: include raw DSWE with output */
    bool *include_ps_flag,       /* O: include percent slope with output */
    bool *include_hs_flag,       /* O: include hillshade with output */
    float *wigt,                 /* O: tolerance value */
    float *awgt,                 /* O: tolerance value */
    float *pswt_1_mndwi,         /* O: tolerance value */
    int *pswt_1_nir,             /* O: tolerance value */
    int *pswt_1_swir1,           /* O: tolerance value */
    float *pswt_1_ndvi,          /* O: tolerance value */
    float *pswt_2_mndwi,         /* O: tolerance value */
    int *pswt_2_blue,            /* O: tolerance value */
    int *pswt_2_nir,             /* O: tolerance value */
    int *pswt_2_swir1,           /* O: tolerance value */
    int *pswt_2_swir2,           /* O: tolerance value */
    float *percent_slope_high,   /* O: slope tolerance for high confidence 
                                       water */
    float *percent_slope_moderate, /* O: slope tolerance for moderate 
                                       confidence water */
    float *percent_slope_wetland, /* O: slope tolerance for potential wetland */
    float *percent_slope_low,    /* O: slope tolerance for low confidence 
                                       water or wetland */
    int *hillshade,              /* O: hillshade tolerance value */ 
    bool *verbose_flag           /* O: verbose messaging */
)
{
    int c;
    int option_index;
    char msg[256];
    int tmp_zeven_thorne_flag = false;
    int tmp_toa_flag = false;
    int tmp_verbose_flag = false;
    int tmp_include_tests_flag = false;
    int tmp_include_ps_flag = false;
    int tmp_include_hs_flag = false;

    struct option long_options[] = {
        /* These options set a flag */
        {"use_zeven_thorne", no_argument, &tmp_zeven_thorne_flag, true},
        {"use_toa", no_argument, &tmp_toa_flag, true},

        {"include_tests", no_argument, &tmp_include_tests_flag, true},
        {"include_ps", no_argument, &tmp_include_ps_flag, true},
        {"include_hs", no_argument, &tmp_include_hs_flag, true},

        /* These options provide values */
        {"xml", required_argument, 0, 'x'},

        {"wigt", required_argument, 0, 'w'},
        {"awgt", required_argument, 0, 'a'},

        {"pswt_1_mndwi", required_argument, 0, 'z'},
        {"pswt_1_nir", required_argument, 0, 'n'},
        {"pswt_1_swir1", required_argument, 0, 'r'},
        {"pswt_1_ndvi", required_argument, 0, 'y'},

        {"pswt_2_mndwi", required_argument, 0, 'q'},
        {"pswt_2_blue", required_argument, 0, 'b'},
        {"pswt_2_nir", required_argument, 0, 'i'},
        {"pswt_2_swir1", required_argument, 0, '1'},
        {"pswt_2_swir2", required_argument, 0, '2'},

        {"percent_slope_high", required_argument, 0, 'g'},
        {"percent_slope_moderate", required_argument, 0, 'm'},
        {"percent_slope_wetland", required_argument, 0, 'd'},
        {"percent_slope_low", required_argument, 0, 'l'},
        {"hillshade", required_argument, 0, 's'},

        /* Special options */
        {"verbose", no_argument, &tmp_verbose_flag, true},
        {"version", no_argument, 0, 'v'},

        /* The help option */
        {"help", no_argument, 0, 'h'},

        /* The option termination set */
        {0, 0, 0, 0}
    };

    if (argc == 1)
    {
        ERROR_MESSAGE ("Missing required command line arguments\n\n",
                       MODULE_NAME);

        usage ();
        return ERROR;
    }

    /* Initialize to the not set values */
    *wigt = NOT_SET;
    *awgt = NOT_SET;
    *pswt_1_mndwi = NOT_SET;
    *pswt_1_nir = NOT_SET;
    *pswt_1_swir1 = NOT_SET;
    *pswt_1_ndvi = NOT_SET;
    *pswt_2_mndwi = NOT_SET;
    *pswt_2_blue = NOT_SET;
    *pswt_2_nir = NOT_SET;
    *pswt_2_swir1 = NOT_SET;
    *pswt_2_swir2 = NOT_SET;
    *percent_slope_high = NOT_SET;
    *percent_slope_moderate = NOT_SET;
    *percent_slope_wetland = NOT_SET;
    *percent_slope_low = NOT_SET;
    *hillshade = NOT_SET;

    /* loop through all the cmd-line options */
    opterr = 0; /* turn off getopt_long error msgs as we'll print our own */
    while (1)
    {
        c = getopt_long (argc, argv, "", long_options, &option_index);
        if (c == -1)
        {
            /* out of cmd-line options */
            break;
        }

        switch (c)
        {
        case 0:
            /* If this option set a flag, do nothing else now. */
            if (long_options[option_index].flag != 0)
                break;

        case 'h':
            usage ();
            exit (SUCCESS);
            break;

        case 'v':
            version ();
            exit (SUCCESS);
            break;

        case 'x':
            *xml_filename = strdup (optarg);
            break;

        case 'w':
            *wigt = atof (optarg);
            break;
        case 'a':
            *awgt = atof (optarg);
            break;

        case 'z':
            *pswt_1_mndwi = atof (optarg);
            break;
        case 'n':
            *pswt_1_nir = atof (optarg);
            break;
        case 'r':
            *pswt_1_swir1 = atoi (optarg);
            break;
        case 'y':
            *pswt_1_ndvi = atof (optarg);
            break;

        case 'q':
            *pswt_2_mndwi = atof (optarg);
            break;
        case 'b':
            *pswt_2_blue = atoi (optarg);
            break;
        case 'i':
            *pswt_2_nir = atoi (optarg);
            break;
        case '1':
            *pswt_2_swir1 = atoi (optarg);
            break;
        case '2':
            *pswt_2_swir2 = atoi (optarg);
            break;

        case 'g':
            *percent_slope_high = atof (optarg);
            break;
        case 'm':
            *percent_slope_moderate = atof (optarg);
            break;
        case 'd':
            *percent_slope_wetland = atof (optarg);
            break;
        case 'l':
            *percent_slope_low = atof (optarg);
            break;

        case 's':
            *hillshade = atoi (optarg);
            break;

        case '?':
        default:
            snprintf (msg, sizeof (msg),
                      "Unknown option %s\n\n", argv[optind - 1]);
            ERROR_MESSAGE (msg, MODULE_NAME);
            usage ();
            return ERROR;
            break;
        }
    }

    /* Grab the boolean command line options */
    if (tmp_zeven_thorne_flag)
        *use_zeven_thorne_flag = true;
    else
        *use_zeven_thorne_flag = false;

    if (tmp_toa_flag)
        *use_toa_flag = true;
    else
        *use_toa_flag = false;

    if (tmp_include_tests_flag)
        *include_tests_flag = true;
    else
        *include_tests_flag = false;

    if (tmp_include_ps_flag)
        *include_ps_flag = true;
    else
        *include_ps_flag = false;

    if (tmp_include_hs_flag)
        *include_hs_flag = true;
    else
        *include_hs_flag = false;

    if (tmp_verbose_flag)
        *verbose_flag = true;
    else
        *verbose_flag = false;

    /* Make sure the XML was specified */
    if (*xml_filename == NULL)
    {
        ERROR_MESSAGE ("XML input file is a required command line"
                       " argument\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    /* Validate the input XML metadata file */
    if (validate_xml_file (*xml_filename) != SUCCESS)
    {
        /* Error messages already written */
        return ERROR;
    }

    /* Initialize the metadata structure */
    init_metadata_struct (xml_metadata);

    /* Parse the metadata file into our internal metadata structure; also
       allocates space as needed for various pointers in the global and band
       metadata */
    if (parse_metadata (*xml_filename, xml_metadata) != SUCCESS)
    {
        /* Error messages already written */
        return ERROR;
    }

    /* Assign the default values if not provided on the command line */
    if (strcmp(xml_metadata->global.satellite, "LANDSAT_8") == 0)
    {
        if (*wigt == NOT_SET)
            *wigt = wigt_l8_default;

        if (*awgt == NOT_SET)
            *awgt = awgt_l8_default;

        if (*pswt_1_mndwi == NOT_SET)
            *pswt_1_mndwi = pswt_1_mndwi_l8_default;

        if (*pswt_1_nir == NOT_SET)
            *pswt_1_nir = pswt_1_nir_l8_default;

        if (*pswt_1_swir1 == NOT_SET)
            *pswt_1_swir1 = pswt_1_swir1_l8_default;

        if (*pswt_1_ndvi == NOT_SET)
            *pswt_1_ndvi = pswt_1_ndvi_l8_default;

        if (*pswt_2_mndwi == NOT_SET)
            *pswt_2_mndwi = pswt_2_mndwi_l8_default;

        if (*pswt_2_blue == NOT_SET)
            *pswt_2_blue = pswt_2_blue_l8_default;

        if (*pswt_2_nir == NOT_SET)
            *pswt_2_nir = pswt_2_nir_l8_default;

        if (*pswt_2_swir1 == NOT_SET)
            *pswt_2_swir1 = pswt_2_swir1_l8_default;

        if (*pswt_2_swir2 == NOT_SET)
            *pswt_2_swir2 = pswt_2_swir2_l8_default;
    }
    else
    {
        if (*wigt == NOT_SET)
            *wigt = wigt_l47_default;

        if (*awgt == NOT_SET)
            *awgt = awgt_l47_default;

        if (*pswt_1_mndwi == NOT_SET)
            *pswt_1_mndwi = pswt_1_mndwi_l47_default;

        if (*pswt_1_nir == NOT_SET)
            *pswt_1_nir = pswt_1_nir_l47_default;

        if (*pswt_1_swir1 == NOT_SET)
            *pswt_1_swir1 = pswt_1_swir1_l47_default;

        if (*pswt_1_ndvi == NOT_SET)
            *pswt_1_ndvi = pswt_1_ndvi_l47_default;

        if (*pswt_2_mndwi == NOT_SET)
            *pswt_2_mndwi = pswt_2_mndwi_l47_default;

        if (*pswt_2_blue == NOT_SET)
            *pswt_2_blue = pswt_2_blue_l47_default;

        if (*pswt_2_nir == NOT_SET)
            *pswt_2_nir = pswt_2_nir_l47_default;

        if (*pswt_2_swir1 == NOT_SET)
            *pswt_2_swir1 = pswt_2_swir1_l47_default;

        if (*pswt_2_swir2 == NOT_SET)
            *pswt_2_swir2 = pswt_2_swir2_l47_default;
    }

    if (*percent_slope_high == NOT_SET)
        *percent_slope_high = percent_slope_high_default;
    if (*percent_slope_moderate == NOT_SET)
        *percent_slope_moderate = percent_slope_moderate_default;
    if (*percent_slope_wetland == NOT_SET)
        *percent_slope_wetland = percent_slope_wetland_default;
    if (*percent_slope_low == NOT_SET)
        *percent_slope_low = percent_slope_low_default;

    if (*hillshade == NOT_SET)
        *hillshade = hillshade_default;


    /* ---------- Validate the parameters ---------- */
    if ((*wigt < 0.0) || (*wigt > 2.0))
    {
        ERROR_MESSAGE ("WIGT is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if ((*awgt < -2.0) || (*awgt > 2.0))
    {
        ERROR_MESSAGE ("AWGT is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if ((*pswt_1_mndwi < -2.0) || (*pswt_1_mndwi > 2.0))
    {
        ERROR_MESSAGE ("PSWT_1_MNDWI is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if (*pswt_1_nir < 0)
    {
        ERROR_MESSAGE ("PSWT_1_NIR is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if (*pswt_1_swir1 < 0)
    {
        ERROR_MESSAGE ("PSWT_1_SWIR1 is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if ((*pswt_1_ndvi < 0.0) || (*pswt_1_ndvi > 2.0))
    {
        ERROR_MESSAGE ("PSWT_1_NDVI is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }


    if ((*pswt_2_mndwi < -2.0) || (*pswt_2_mndwi > 2.0))
    {
        ERROR_MESSAGE ("PSWT_2_MNDWI is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if (*pswt_2_blue < 0)
    {
        ERROR_MESSAGE ("PSWT_2_BLUE is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if (*pswt_2_nir < 0)
    {
        ERROR_MESSAGE ("PSWT_2_NIR is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if (*pswt_2_swir1 < 0)
    {
        ERROR_MESSAGE ("PSWT_2_SWIR1 is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if (*pswt_2_swir2 < 0)
    {
        ERROR_MESSAGE ("PSWT_2_SWIR2 is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if ((*percent_slope_high < 0.0) || (*percent_slope_high > 100.0))
    {
        ERROR_MESSAGE ("Percent Slope high is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if ((*percent_slope_moderate < 0.0) || (*percent_slope_moderate > 100.0))
    {
        ERROR_MESSAGE ("Percent Slope moderate is out of range\n\n", 
            MODULE_NAME);

        usage ();
        return ERROR;
    }

    if ((*percent_slope_wetland < 0.0) || (*percent_slope_wetland > 100.0))
    {
        ERROR_MESSAGE ("Percent Slope wetland is out of range\n\n", 
            MODULE_NAME);

        usage ();
        return ERROR;
    }

    if ((*percent_slope_low < 0.0) || (*percent_slope_low > 100.0))
    {
        ERROR_MESSAGE ("Percent Slope low is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    if ((*hillshade < 0) || (*hillshade > 255))
    {
        ERROR_MESSAGE ("Hillshade threshold is out of range\n\n", MODULE_NAME);

        usage ();
        return ERROR;
    }

    return SUCCESS;
}
/******************************************************************************
MODULE:  main

PURPOSE: Creates the Landsat solar and view/satellite per-pixel angles.  Both
the zenith and azimuth angles are created for each angle type for the
representative band.

RETURN VALUE:
Type = int
Value           Description
-----           -----------
ERROR           Error creating the angle bands
SUCCESS         No errors encountered

NOTES:
1. Angles are written in degrees and scaled by 100.
2. There are 4 bands written for the representative band: solar zenith, solar
   azimuth, sensor zenith, sensor azimuth.
3. The landsat_per_pixel_angles library expects an array of solar/satellite
   azimuth/zenith pointers for all the input bands, as that's the possible
   full list of output bands.  So, even though we are not processing all the
   bands in the output list, we still need to provide an array of that size.
   This requires us to keep track of the indices for each of the output bands
   into the array of input bands, for both ETM and TM arrays.
******************************************************************************/
int main (int argc, char** argv)
{
    char FUNC_NAME[] = "create_angle_bands";  /* function name */
    char errmsg[STR_SIZE];       /* error message */
    char tmpstr[STR_SIZE];       /* temporary string */
    char tmpfile[STR_SIZE];      /* temporary filename */
    char ang_infile[STR_SIZE];   /* input angle coefficient filename */
    char outfile[STR_SIZE];      /* output base filename for angle bands */
    char band_list[STR_SIZE];    /* char array of list of bands to process */
    char etm_list[] = "4";       /* list of ETM bands to process */
    char tm_list[] = "4";        /* list of TM bands to process */
    char production_date[MAX_DATE_LEN+1]; /* current date/year for production */
    char band_angle[NANGLE_BANDS][STR_SIZE] = {"solar zenith", "solar azimuth",
                                    "sensor zenith", "sensor azimuth"};
    char *cptr = NULL;           /* pointer to file extension */
    char *xml_infile = NULL;     /* input XML filename */
    bool process_l7 = false;     /* are we processing L7 vs. L4-5 */
    bool process_l45 = false;    /* are we processing L4-5 vs. L7 */
    int i;                       /* looping variable for bands */
    int curr_bnd;                /* current input band location */
    int curr_band;               /* current input band number */
    int curr_bndx;               /* index of current input band */
    int curr_index;              /* index of current output band in the input
                                    band array */
    int etm_nbands = 1;          /* number of ETM bands to process for PPA */
    int tm_nbands = 1;           /* number of TM bands to process for PPA */
    int landsat_nbands;          /* number of bands to process for PPA */
    int *landsat_bands = NULL;   /* array of output bands to be processed;
                                    set to point to either etm_bands or
                                    tm_bands */
    int etm_bands[] = {4};       /* output bands to be processed */
    int tm_bands[] = {4};        /* output bands to be processed */
    int *band_indx = NULL;       /* array of indices for the output bands within
                                    the full set of input bands; set to point
                                    to either etm_band_indx or tm_band_indx */
    int etm_band_indx[] = {3};   /* index in the overall input bands for
                                    the output bands [1,2,3,4,5,61,62,7,8] */
    int tm_band_indx[] = {3};    /* index in the overall input bands for
                                    the output bands [1,2,3,4,5,6,7,8] */
    int out_nbands;              /* number of output bands to be written */
    int nlines[L7_NBANDS];       /* number of lines for each band */
    int nsamps[L7_NBANDS];       /* number of samples for each band */
    Angle_band_t ang;            /* looping variable for solar/senor angle */
    short *solar_zenith[L7_NBANDS];  /* array of pointers for the solar zenith
                                        angle array, one per band */
    short *solar_azimuth[L7_NBANDS]; /* array of pointers for the solar azimuth
                                        angle array, one per band */
    short *sat_zenith[L7_NBANDS];    /* array of pointers for the satellite
                                        zenith angle array, one per band */
    short *sat_azimuth[L7_NBANDS];   /* array of pointers for the satellite
                                        azimuth angle array, one per band */
    short *curr_angle = NULL;      /* pointer to the current angle array */
    time_t tp;                     /* time structure */
    struct tm *tm = NULL;          /* time structure for UTC time */
    FILE *fptr=NULL;               /* file pointer */
    Envi_header_t envi_hdr;        /* output ENVI header information */
    Espa_internal_meta_t xml_metadata;
                                   /* XML metadata structure to be populated by
                                      reading the input XML metadata file */
    Espa_band_meta_t *bmeta=NULL;    /* pointer to array of bands metadata */
    Espa_global_meta_t *gmeta=NULL;  /* pointer to the global metadata struct */
    Espa_band_meta_t *out_bmeta = NULL; /* band metadata for angle bands */
    Espa_internal_meta_t out_meta;      /* output metadata for angle bands */

    /* Read the command-line arguments */
    if (get_args (argc, argv, &xml_infile) != SUCCESS)
    {   /* get_args already printed the error message */
        exit (ERROR);
    }
    printf ("Processing the per-pixel angle bands for L4-7 ...\n");

    /* Validate the input metadata file */
    if (validate_xml_file (xml_infile) != SUCCESS)
    {  /* Error messages already written */
        return (ERROR);
    }

    /* Initialize the metadata structure */
    init_metadata_struct (&xml_metadata);

    /* Parse the metadata file into our internal metadata structure; also
       allocates space as needed for various pointers in the global and band
       metadata */
    if (parse_metadata (xml_infile, &xml_metadata) != SUCCESS)
    {  /* Error messages already written */
        return (ERROR);
    }
    bmeta = xml_metadata.band;
    gmeta = &xml_metadata.global;

    /* Determine which instrument is being processed */
    if (!strncmp (gmeta->instrument, "ETM", 3))
        process_l7 = true;
    else
        process_l45 = true;

    /* Determine the angle coefficient filename and the output file basename */
    strcpy (ang_infile, xml_infile);
    cptr = strchr (ang_infile, '.');
    strcpy (cptr, "_ANG.txt");

    strcpy (outfile, xml_infile);
    cptr = strchr (outfile, '.');
    *cptr = '\0';

    /* Initialize the output metadata structure.  The global metadata will
       not be used and will not be valid. */
    init_metadata_struct (&out_meta);

    /* Determine the number of output bands */
    if (process_l7)
    {
        landsat_bands = etm_bands;
        landsat_nbands = etm_nbands;
        out_nbands = landsat_nbands * NANGLE_BANDS;
        band_indx = etm_band_indx;
        strcpy (band_list, etm_list);
    }
    else
    {
        landsat_bands = tm_bands;
        landsat_nbands = tm_nbands;
        out_nbands = landsat_nbands * NANGLE_BANDS;
        band_indx = tm_band_indx;
        strcpy (band_list, tm_list);
    }

    /* Allocate memory for the output bands */
    if (allocate_band_metadata (&out_meta, out_nbands) != SUCCESS)
    {
        sprintf (errmsg, "Cannot allocate memory for the %d angle bands",
            out_nbands);
        error_handler (true, FUNC_NAME, errmsg);
        exit (ERROR);
    }

    /* Get the current date/time (UTC) for the production date of each band */
    if (time (&tp) == -1)
    {
        sprintf (errmsg, "Unable to obtain the current time.");
        error_handler (true, FUNC_NAME, errmsg);
        exit (ERROR);
    }

    tm = gmtime (&tp);
    if (tm == NULL)
    {
        sprintf (errmsg, "Converting time to UTC.");
        error_handler (true, FUNC_NAME, errmsg);
        exit (ERROR);
    }

    if (strftime (production_date, MAX_DATE_LEN, "%Y-%m-%dT%H:%M:%SZ", tm) == 0)
    {
        sprintf (errmsg, "Formatting the production date/time.");
        error_handler (true, FUNC_NAME, errmsg);
        exit (ERROR);
    }

    /* Initialize the Landsat angle bands to NULL */
    init_per_pixel_angles (solar_zenith, solar_azimuth, sat_zenith,
        sat_azimuth);

    /* Create the Landsat angle bands for the specified bands.  Create a full
       resolution product. */
    if (landsat_per_pixel_angles (ang_infile, 1, band_list, solar_zenith,
        solar_azimuth, sat_zenith, sat_azimuth, nlines, nsamps) != SUCCESS)
    {  /* Error messages already written */
        free_per_pixel_angles (solar_zenith, solar_azimuth, sat_zenith,
            sat_azimuth);
        exit (ERROR);
    }

    /* Setup the XML file for these bands */
    for (i = 0; i < out_nbands; i++)
    {
        /* Set up the band metadata for the current band */
        out_bmeta = &out_meta.band[i];
        strcpy (out_bmeta->product, "angle_bands");
        strcpy (out_bmeta->source, "level1");
        strcpy (out_bmeta->category, "image");

        /* Setup filename-related items for all four bands: solar zenith,
           solar azimuth, sensor zenith, sensor azimuth.  L4-5 and L8 band
           numbers follow a normal numbering scheme.  L7 band numbering
           needs a little help to get it correct. */
        curr_bnd = i / NANGLE_BANDS + 1;  /* current input band number */
        curr_bndx = curr_bnd - 1;         /* index of current input band */
        curr_band = landsat_bands[curr_bndx]; /* actual band number */
        curr_index = band_indx[curr_bndx];    /* index in output array */

        switch (i % NANGLE_BANDS)
        {
            case (SOLAR_ZEN):  /* solar zenith */
                /* Determine the output file for the solar zenith band */
                snprintf (tmpfile, sizeof (tmpfile),
                    "%s_b%d_solar_zenith.img", outfile, curr_band);
                sprintf (out_bmeta->name, "solar_zenith_band%d", curr_band);
                strncpy (tmpstr, bmeta[curr_bndx].short_name, 4);
                tmpstr[4] = '\0';
                sprintf (out_bmeta->short_name, "%sSOLZEN", tmpstr);
                sprintf (out_bmeta->long_name,
                    "band %d solar zenith angles", curr_band);
                break;

            case (SOLAR_AZ):  /* solar azimuth */
                /* Determine the output file for the solar azimuth band */
                snprintf (tmpfile, sizeof (tmpfile),
                    "%s_b%d_solar_azimuth.img", outfile, curr_band);
                sprintf (out_bmeta->name, "solar_azimuth_band%d",
                    curr_band);
                strncpy (tmpstr, bmeta[curr_bndx].short_name, 4);
                tmpstr[4] = '\0';
                sprintf (out_bmeta->short_name, "%sSOLAZ", tmpstr);
                sprintf (out_bmeta->long_name,
                    "band %d solar azimuth angles", curr_band);
                break;

            case (SENSOR_ZEN):  /* sensor zenith */
                /* Determine the output file for the sensor zenith band */
                snprintf (tmpfile, sizeof (tmpfile),
                    "%s_b%d_sensor_zenith.img", outfile, curr_band);
                sprintf (out_bmeta->name, "sensor_zenith_band%d",
                    curr_band);
                strncpy (tmpstr, bmeta[curr_bndx].short_name, 4);
                tmpstr[4] = '\0';
                sprintf (out_bmeta->short_name, "%sSENZEN", tmpstr);
                sprintf (out_bmeta->long_name,
                    "band %d sensor zenith angles", curr_band);
                break;

            case (SENSOR_AZ):  /* sensor azimuth */
                /* Determine the output file for the sensor azimuth band */
                snprintf (tmpfile, sizeof (tmpfile),
                    "%s_b%d_sensor_azimuth.img", outfile, curr_band);
                sprintf (out_bmeta->name, "sensor_azimuth_band%d",
                    curr_band);
                strncpy (tmpstr, bmeta[curr_bndx].short_name, 4);
                tmpstr[4] = '\0';
                sprintf (out_bmeta->short_name, "%sSENAZ", tmpstr);
                sprintf (out_bmeta->long_name,
                    "band %d sensor azimuth angles", curr_band);
                break;
        }

        snprintf (out_bmeta->file_name, sizeof (out_bmeta->file_name), "%s",
            tmpfile);
        out_bmeta->data_type = ESPA_INT16;
        out_bmeta->fill_value = ANGLE_BAND_FILL;
        out_bmeta->scale_factor = ANGLE_BAND_SCALE_FACT;
        strcpy (out_bmeta->data_units, "degrees");
        out_bmeta->nlines = nlines[curr_index];
        out_bmeta->nsamps = nsamps[curr_index];
        out_bmeta->pixel_size[0] = bmeta[curr_bndx].pixel_size[0];
        out_bmeta->pixel_size[1] = bmeta[curr_bndx].pixel_size[1];
        strcpy (out_bmeta->pixel_units, bmeta[curr_bndx].pixel_units);
        sprintf (out_bmeta->app_version, "create_angle_bands_%s",
            ESPA_COMMON_VERSION);
        strcpy (out_bmeta->production_date, production_date);
    }

    /* Loop through the four different angle files and write them for each
       band */
    for (ang = 0; ang < NANGLE_BANDS; ang++)
    {
        /* Write the angle bands */
        for (i = 0; i < landsat_nbands; i++)
        {
            /* Determine the index of this band in the overall list of input
               bands */
            curr_index = band_indx[i];

            /* Grab the correct data array to be written for this angle
               band */
            switch (ang)
            {
                case (SOLAR_ZEN):
                    curr_angle = &solar_zenith[curr_index][0];
                    break;
                case (SOLAR_AZ):
                    curr_angle = &solar_azimuth[curr_index][0];
                    break;
                case (SENSOR_ZEN):
                    curr_angle = &sat_zenith[curr_index][0];
                    break;
                case (SENSOR_AZ):
                    curr_angle = &sat_azimuth[curr_index][0];
                    break;
                default:
                    free_per_pixel_angles (solar_zenith, solar_azimuth,
                        sat_zenith, sat_azimuth);
                    sprintf (errmsg, "Invalid angle type %d", ang);
                    error_handler (true, FUNC_NAME, errmsg);
                    exit (ERROR);
            }

            /* Open the output file for this band */
            out_bmeta = &out_meta.band[i*NANGLE_BANDS + ang];
            fptr = open_raw_binary (out_bmeta->file_name, "wb");
            if (!fptr)
            {
                free_per_pixel_angles (solar_zenith, solar_azimuth, sat_zenith,
                    sat_azimuth);
                sprintf (errmsg, "Unable to open the %s file",
                    band_angle[ang]);
                error_handler (true, FUNC_NAME, errmsg);
                exit (ERROR);
            }

            /* Write the data for this band */
            if (write_raw_binary (fptr, nlines[curr_index], nsamps[curr_index],
                sizeof (short), curr_angle) != SUCCESS)
            {
                free_per_pixel_angles (solar_zenith, solar_azimuth, sat_zenith,
                    sat_azimuth);
                sprintf (errmsg, "Unable to write to the %s file",
                    band_angle[ang]);
                error_handler (true, FUNC_NAME, errmsg);
                exit (ERROR);
            }

            /* Close the file for this band */
            close_raw_binary (fptr);

            /* Create the ENVI header */
            if (create_envi_struct (out_bmeta, gmeta, &envi_hdr) != SUCCESS)
            {
                free_per_pixel_angles (solar_zenith, solar_azimuth, sat_zenith,
                    sat_azimuth);
                sprintf (errmsg, "Error creating the ENVI header file.");
                error_handler (true, FUNC_NAME, errmsg);
                exit (ERROR);
            }

            /* Write the ENVI header */
            sprintf (tmpfile, "%s", out_bmeta->file_name);
            sprintf (&tmpfile[strlen(tmpfile)-3], "hdr");
            if (write_envi_hdr (tmpfile, &envi_hdr) != SUCCESS)
            {
                free_per_pixel_angles (solar_zenith, solar_azimuth, sat_zenith,
                    sat_azimuth);
                sprintf (errmsg, "Writing the ENVI header file: %s.",
                    tmpfile);
                error_handler (true, FUNC_NAME, errmsg);
                exit (ERROR);
            }
        }  /* for i < landsat_nbands */
    }  /* for ang < NANGLE_BANDS */

    /* Free the pointers */
    free_per_pixel_angles (solar_zenith, solar_azimuth, sat_zenith,
        sat_azimuth);

    /* Append the solar/sensor angle bands to the XML file */
    if (append_metadata (out_nbands, out_meta.band, xml_infile) != SUCCESS)
    {
        sprintf (errmsg, "Appending solar/sensor angle bands to the XML file.");
        error_handler (true, FUNC_NAME, errmsg);
        exit (ERROR);
    }

    /* Free the input and output XML metadata */
    free_metadata (&xml_metadata);
    free_metadata (&out_meta);

    /* Free the pointers */
    free (xml_infile);

    /* Successful completion */
    exit (SUCCESS);
}