Example #1
0
/******************************************************************************
!Description: 'OpenInput' sets up the 'input' data structure, opens the
 input file for read access, allocates space, and stores some of the metadata.
 
!Input Parameters:
 file_name      input file name

!Output Parameters:
 (returns)      populated 'input' data structure or NULL when an error occurs

HISTORY:
Date        Programmer       Reason
--------    ---------------  -------------------------------------
2/13/2014   Gail Schmidt     Modified to work with ESPA internal raw binary
                             file format

!Design Notes:
******************************************************************************/
Input_t *OpenInput
(
    Espa_internal_meta_t *metadata /* I: input metadata */
)
{
    Input_t *this = NULL;
    char *error_string = NULL;
    int i;                      /* looping variable */
    int ib;                     /* band looping variable */
    int16 *buf = NULL;
    FILE *dsun_in = NULL;       /* EarthSunDistance.txt file pointer */
    char *path = NULL;
    char full_path[MAX_STR_LEN];

    /* Create the Input data structure */
    this = (Input_t *) malloc (sizeof (Input_t));
    if (this == NULL)
        RETURN_ERROR ("allocating Input data structure", "OpenInput", NULL);

    /* Initialize and get input from header file */
    if (!GetXMLInput (this, metadata))
    {
        free (this);
        this = NULL;
        RETURN_ERROR ("getting input from header file", "OpenInput", NULL);
    }

    /* Open TOA reflectance files for access */
    for (ib = 0; ib < this->nband; ib++)
    {
        printf ("DEBUG: band %d filename: %s\n", ib, this->file_name[ib]);
        this->fp_bin[ib] = open_raw_binary (this->file_name[ib], "r");
        if (this->fp_bin[ib] == NULL)
        {
            RETURN_ERROR ("opening input TOA binary file", "OpenInput", NULL);
        }
        this->open[ib] = true;
    }

    /* Open thermal file for access */
    printf ("DEBUG: thermal band filename: %s\n", this->file_name_therm);
    this->fp_bin_therm = open_raw_binary (this->file_name_therm, "r");
    if (this->fp_bin_therm == NULL)
        error_string = "opening thermal binary file";
    else
        this->open_therm = true;

    /* Allocate input buffers.  Thermal band only has one band.  Image and QA
       buffers have multiple bands. */
    buf = calloc ((size_t) (this->size.s * this->nband), sizeof (int16));
    if (buf == NULL)
        error_string = "allocating input buffer";
    else
    {
        this->buf[0] = buf;
        for (ib = 1; ib < this->nband; ib++)
            this->buf[ib] = this->buf[ib - 1] + this->size.s;
    }

    this->therm_buf = calloc ((size_t) (this->size.s), sizeof (int16));
    if (this->therm_buf == NULL)
        error_string = "allocating input thermal buffer";

    if (error_string != NULL)
    {
        FreeInput (this);
        CloseInput (this);
        RETURN_ERROR (error_string, "OpenInput", NULL);
    }

    path = getenv ("ESUN");
    if (path == NULL)
    {
        error_string = "ESUN environment variable is not set";
        RETURN_ERROR (error_string, "OpenInput", NULL);
    }

    sprintf (full_path, "%s/%s", path, "EarthSunDistance.txt");
    dsun_in = fopen (full_path, "r");
    if (dsun_in == NULL)
    {
        error_string = "Can't open EarthSunDistance.txt file";
        RETURN_ERROR (error_string, "OpenInput", NULL);
    }

    for (i = 0; i < 366; i++)
    {
        if (fscanf (dsun_in, "%f", &this->dsun_doy[i]) == EOF)
        {
            error_string = "End of file (EOF) is met before 336 lines";
            RETURN_ERROR (error_string, "OpenInput", NULL);
        }
    }
    fclose (dsun_in);

    /* Calculate maximum TOA reflectance values and put them in metadata */
    dn_to_toa_saturation (this);

    /* Calculate maximum BT values and put them in metadata */
    dn_to_bt_saturation (this);

    return this;
}
/******************************************************************************
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);
}
Example #4
0
/******************************************************************************
!Description: 'OpenInput' sets up the 'input' data structure, opens the
 input file for read access, allocates space, and stores some of the metadata.
 
!Input Parameters:
 file_name      input file name

!Output Parameters:
 (returns)      populated 'input' data structure or NULL when an error occurs

HISTORY:
Date        Programmer       Reason
--------    ---------------  -------------------------------------
Oct/2014    Ron Dilley       Modified to work with ESPA internal raw binary
                             file format

!Design Notes:
******************************************************************************/
Input_t *OpenInput
(
    Espa_internal_meta_t *metadata /* I: input metadata */
)
{
    Input_t *this = NULL;
    char *error_string = NULL;
    int ib;                     /* band looping variable */
    int16 *buf = NULL;
    char *path = NULL;

    /* Create the Input data structure */
    this = (Input_t *) malloc (sizeof (Input_t));
    if (this == NULL)
        RETURN_ERROR ("allocating Input data structure", "OpenInput", NULL);

    /* Initialize and get input from header file */
    if (!GetXMLInput (this, metadata))
    {
        free (this);
        this = NULL;
        RETURN_ERROR ("getting input from header file", "OpenInput", NULL);
    }

    /* Open TOA reflectance files for access */
    for (ib = 0; ib < this->nband; ib++)
    {
        printf ("DEBUG: band %d filename: %s\n", ib, this->file_name[ib]);
        this->fp_bin[ib] = open_raw_binary (this->file_name[ib], "r");
        if (this->fp_bin[ib] == NULL)
        {
            RETURN_ERROR ("opening input TOA binary file", "OpenInput", NULL);
        }
        this->open[ib] = true;
    }

    /* Open thermal file for access */
    printf ("DEBUG: thermal band filename: %s\n", this->file_name_therm);
    this->fp_bin_therm = open_raw_binary (this->file_name_therm, "r");
    if (this->fp_bin_therm == NULL)
        error_string = "opening thermal binary file";
    else
        this->open_therm = true;

    /* Allocate input buffers.  Thermal band only has one band.  Image and QA
       buffers have multiple bands. */
    buf = calloc ((size_t) (this->size.s * this->nband), sizeof (int16));
    if (buf == NULL)
        error_string = "allocating input buffer";
    else
    {
        this->buf[0] = buf;
        for (ib = 1; ib < this->nband; ib++)
            this->buf[ib] = this->buf[ib - 1] + this->size.s;
    }

    this->therm_buf = calloc ((size_t) (this->size.s), sizeof (int16));
    if (this->therm_buf == NULL)
        error_string = "allocating input thermal buffer";

    if (error_string != NULL)
    {
        FreeInput (this);
        CloseInput (this);
        RETURN_ERROR (error_string, "OpenInput", NULL);
    }

    path = getenv ("ESUN");
    if (path == NULL)
    {
        error_string = "ESUN environment variable is not set";
        RETURN_ERROR (error_string, "OpenInput", NULL);
    }

    /* Calculate maximum TOA reflectance values and put them in metadata */
    dn_to_toa_saturation (this);

    /* Calculate maximum BT values and put them in metadata */
    dn_to_bt_saturation (this);

    return this;
}
/******************************************************************************
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);
}
int read_cfmask
(
    int  curr_scene_num, /* I:   current num. in list of scenes to read       */
    char *data_type,     /* I:   type of flies, tifs or single BIP            */
    char **scene_list,   /* I:   current scene name in list of sceneIDs       */
    int  row,            /* I:   the row (Y) location within img/grid         */
    int  col,            /* I:   the col (X) location within img/grid         */
    int  num_samples,    /* I:   number of image samples (X width)            */
    FILE ***fp_tifs,     /* I/O: file ptr array for tif band file names       */
    FILE **fp_bip,       /* I/O: file pointer array for BIP file names        */
    unsigned char *fmask_buf,/* O:   pointer to cfmask band values            */
                         /* I/O: Worldwide Reference System path and row for  */
                         /* I/O: the current swath, this group of variables   */
                         /* I/O: is for filtering out swath overlap, and      */
    int *prev_wrs_path,  /* I/O: using the first of two scenes in a swath,    */
    int *prev_wrs_row,   /* I/O: , because it is recommended to use the meta  */
    int *prev_year,      /* I/O: data from the first for things like sun      */
    int *prev_jday,      /* I/O: angle, etc. However, always removing a       */
    unsigned char *prev_fmask_buf,/* I/O: redundant x/y location specified    */
    int *valid_scene_count,/* I/O: x/y is not always valid for gridded data,  */
    int *swath_overlap_count,/* I/O: it may/may not be in swap overlap area.  */
    char **valid_scene_list,/* I/O: 2-D array for list of filtered            */
    int *clear_sum,      /* I/O: Total number of clear cfmask pixels          */
    int *water_sum,      /* I/O: counter for cfmask water pixels.             */
    int *shadow_sum,     /* I/O: counter for cfmask shadow pixels.            */
    int *sn_sum,         /* I/O: Total number of snow cfmask pixels           */
    int *cloud_sum,      /* I/O: counter for cfmask cloud pixels.             */
    int *fill_sum,       /* I/O: counter for cfmask fill pixels.              */
    int *all_sum,        /* I/O: Total of all cfmask pixels                   */
    unsigned char *updated_fmask_buf, /* I/O: new entry in valid fmask values */
    int *updated_sdate_array, /* I/O: new buf of valid date values            */
    int *sdate,          /* I:   Original array of julian date values         */
    int *valid_num_scenes/* I/O: number of valid scenes after reading cfmask  */
)

{

    int len;             /* for strlen call                             */
    int landsat_number;  /* mission number for determining file names   */
    char scene_name[MAX_STR_LEN]; /* current scene id name              */
    char filename[MAX_STR_LEN];   /* temp for constructing file name    */
    int wrs_path;        /* Worldwide Reference System path             */
    int wrs_row = 0;     /* WRS row                                     */
    int year;            /* Year of acquisition date of current scene   */
    int jday;            /* Julian day since 0 of current scene date    */
    bool debug = 1;      /* for debug printing                          */
    int status;          /* for return status of function calls         */
    char short_scene[MAX_STR_LEN]; /* for parsing file names            */
    char directory[MAX_STR_LEN]; /* for parsing file names              */
    char tmpstr[MAX_STR_LEN]; /* for parsing file names                 */
    char errmsg[MAX_STR_LEN]; /* for printing errors before log/quit    */
    char FUNC_NAME[] = "read_cfmask"; /* for printing errors messages   */
    int int_buf;         /* for reading cfmask value then type cast     */

    if (strcmp(data_type, "tifs") == 0)
    {

        /**************************************************************/
        /*                                                            */
        /* Determine the cfmask file name to read.                    */
        /*                                                            */
        /**************************************************************/
    
        len = strlen(scene_list[curr_scene_num]);
        landsat_number = atoi(sub_string(scene_list[curr_scene_num],(len-19),1));
        wrs_path = atoi(sub_string(scene_list[curr_scene_num],(len-18),3));
        wrs_row =  atoi(sub_string(scene_list[curr_scene_num],(len-15),3));
        year = atoi(sub_string(scene_list[curr_scene_num],(len-12),4));
        jday = atoi(sub_string(scene_list[curr_scene_num],(len- 8),3));
        sprintf(filename, "%s_cfmask.img", scene_list[curr_scene_num]);
    
        /**************************************************************/
        /*                                                            */
        /* Open the cfmask file, fseek and read.                      */
        /* if the path, year, and jdate of adjacent sorted scenes are */
        /* the same, and the rows are different by 1, and both fmask  */
        /* values are NOT fill, then this is a case of swath (pixel)  */
        /* overlap, so use the lesser row number of the two, and      */
        /* throw away the grerater row of the two, and update the     */
        /* valid scene list accordingly.   If only one of the two     */
        /* fmask values are FILL, then we are not in an area of swath */
        /* overlap, and the later check for fill will elinimate the   */
        /* uneccesary scene pixels.                                   */
        /*                                                            */
        /**************************************************************/
    
        fp_tifs[CFMASK_BAND][curr_scene_num] = open_raw_binary(filename,"rb");
        if (fp_tifs[CFMASK_BAND][curr_scene_num] == NULL)
            printf("error open %d scene, %d bands files\n", curr_scene_num, CFMASK_BAND+1);
    
        fseek(fp_tifs[CFMASK_BAND][curr_scene_num], (row * num_samples + col)*sizeof(unsigned char), 
            SEEK_SET);
    
        if (read_raw_binary(fp_tifs[CFMASK_BAND][curr_scene_num], 1, 1,
            sizeof(unsigned char), &fmask_buf[curr_scene_num]) != 0)
            printf("error reading %d scene, %d bands\n", curr_scene_num, CFMASK_BAND+1);

        close_raw_binary(fp_tifs[CFMASK_BAND][curr_scene_num]);
    }

    else if (strcmp(data_type, "bip") == 0)

    {

        len = strlen(scene_list[curr_scene_num]);
        strncpy(short_scene, scene_list[curr_scene_num], len-5);
        split_directory_scenename(scene_list[curr_scene_num], directory, scene_name);
        if (strncmp(short_scene, ".", 1) == 0)
        {
            strncpy(tmpstr, short_scene + 2, len - 2);
            sprintf(filename, "%s/%s_MTLstack", tmpstr, scene_name);
        }
        else
            sprintf(filename, "%s/%s_MTLstack", short_scene, scene_name);
        fp_bip[curr_scene_num] = open_raw_binary(filename,"rb");
        if (fp_bip[curr_scene_num] == NULL)
        {
            sprintf(errmsg, "Opening %d scene files\n", curr_scene_num);
            RETURN_ERROR (errmsg, FUNC_NAME, ERROR);
        }
        fseek(fp_bip[curr_scene_num], ((row - 1)* num_samples + col - 1) *
              TOTAL_BANDS * sizeof(short int) + (TOTAL_IMAGE_BANDS * sizeof(short int)), SEEK_SET);

        if (read_raw_binary(fp_bip[curr_scene_num], 1, 1,
                sizeof(short int), &int_buf) != 0)
        {
            sprintf(errmsg, "error reading %d scene, %d bands\n",curr_scene_num, CFMASK_BAND+1);
            RETURN_ERROR(errmsg, FUNC_NAME, FAILURE);
        }

        fmask_buf[curr_scene_num] = (unsigned char)int_buf;

        close_raw_binary(fp_bip[curr_scene_num]);

    }

    /******************************************************************/
    /*                                                                */
    /* Check for swath overlap pixels.  If consecutive temporal       */
    /* are in the same path, and in adjacent rows, are not fill, and  */
    /* have the same acquisition date, then they are essentially the  */
    /* same pixel, so use the first, because the metadata such as     */
    /* sun angle, etc. are more closely associated with the first.    */
    /*                                                                */
    /******************************************************************/

    if ((wrs_path == *prev_wrs_path) && (wrs_row == (*prev_wrs_row - 1)) &&
        (year == *prev_year) && (jday == *prev_jday) &&
        (fmask_buf[curr_scene_num] != CFMASK_FILL) && (*prev_fmask_buf != CFMASK_FILL))

    {
        (*swath_overlap_count)++;
        strcpy(valid_scene_list[(*valid_scene_count) - 1], scene_list[curr_scene_num]);
        if (debug)
        {
            printf("i = %d swath overlap %s\n", curr_scene_num, scene_list[curr_scene_num -1]);
        }
    }

    else

    {
        strcpy(valid_scene_list[*valid_scene_count], scene_list[curr_scene_num]);

        /**************************************************************/
        /*                                                            */
        /* Call the function with the case statement for totalling    */
        /* cfmask values, because it is used for all input type       */
        /* options, and we put it in a function so we did not have to */
        /* make multiple updates if something changed.                */
        /*                                                            */
        /**************************************************************/

        status = assign_cfmask_values (fmask_buf[curr_scene_num], clear_sum,
                                       water_sum, shadow_sum, sn_sum,
                                       cloud_sum, fill_sum, all_sum);
        if (status != SUCCESS)
        {
            RETURN_ERROR ("Calling assign_cfmask_values", 
                          "read_cfmask", FAILURE);
        }

        /**************************************************************/
        /*                                                            */
        /* After succesfully reading the cfmask data, update the list */
        /* of valid julian dates.                                     */
        /*                                                            */
        /**************************************************************/

        if (fmask_buf[curr_scene_num] < CFMASK_FILL)
        {
            updated_fmask_buf[*valid_scene_count] = fmask_buf[curr_scene_num];
            updated_sdate_array[*valid_scene_count] = sdate[curr_scene_num];
            (*valid_scene_count)++;
            (*valid_num_scenes)++;
        }
    }

    *prev_wrs_path = wrs_path;
    *prev_wrs_row  = wrs_row;
    *prev_year = year;
    *prev_jday = jday;
    *prev_fmask_buf = fmask_buf[curr_scene_num];

    return(SUCCESS);

}
int read_bip
(
    char *curr_scene_name, /* I:   current file name in list of sceneIDs  */
    FILE **fp_bip,            /* I/O: file pointer array for BIP  file names */
    int  curr_scene_num,      /* I:   current num. in list of scenes to read */
    int  row,                 /* I:   the row (Y) location within img/grid   */
    int  col,                 /* I:   the col (X) location within img/grid   */
    int  num_samples,         /* I:   number of image samples (X width)      */
    int  **image_buf          /* O:   pointer to 2-D image band values array */
)

{

    int  k;                     /* band loop counter.                   */
    int  len;                   /* for string length call.              */
    char filename[MAX_STR_LEN]; /* file name constructed from sceneID   */
    char shorter_name[MAX_STR_LEN]; /* file name constructed from sceneID*/
    char directory[MAX_STR_LEN];
    char scene_name[MAX_STR_LEN];
    char tmpstr[MAX_STR_LEN];   /* for string manipulation              */
    char errmsg[MAX_STR_LEN];   /* for printing error text to the log.  */
    bool debug = true;          /* for debug printing                   */


    /******************************************************************/
    /*                                                                */
    /* Determine the BIP file name, open, fseek.                      */
    /*                                                                */
    /******************************************************************/

    len = strlen(curr_scene_name);
    strncpy(shorter_name, curr_scene_name, len-5);
    // somebody is trashing memory and I cannot find him...
    shorter_name[len-5] = '\0';

    split_directory_scenename(curr_scene_name, directory, scene_name);

    if (strncmp(shorter_name, ".", 1) == 0)
    {
        strncpy(tmpstr, shorter_name + 2, len - 2);
        sprintf(filename, "%s/%s_MTLstack", tmpstr, scene_name);
    }
    else
        sprintf(filename, "%s/%s_MTLstack", shorter_name, scene_name);

    fp_bip[curr_scene_num] = open_raw_binary(filename,"rb");
    if (fp_bip[curr_scene_num] == NULL)
    {
        sprintf(errmsg, "Opening %d scene files\n", curr_scene_num);
        printf(errmsg);
        return (FAILURE);
    }

    fseek(fp_bip[curr_scene_num], ((row - 1)* num_samples + col - 1) * 
          TOTAL_BANDS * sizeof(short int), SEEK_SET);

    /******************************************************************/
    /*                                                                */
    /* Read the image bands for this scene.                           */
    /*                                                                */
    /******************************************************************/

    for (k = 0; k < TOTAL_IMAGE_BANDS; k++)
    {
        if (read_raw_binary(fp_bip[curr_scene_num], 1, 1,
                sizeof(short int), &image_buf[k][curr_scene_num]) != 0)
        {
    	    sprintf(errmsg, "error reading %d scene, %d bands\n",curr_scene_num, k+1);
            printf(errmsg);
            return (FAILURE);
        }
        if (debug)
            printf("%d ", (short int)image_buf[k][curr_scene_num]);
    }
        close_raw_binary(fp_bip[curr_scene_num]);

    return (SUCCESS);
}
int read_tifs
(
    char *sceneID_name,  /* I:   current file name in list of sceneIDs  */
    FILE ***fp_tifs,     /* I/O: file pointer array for band file names */
    int  curr_scene_num, /* I:   current num. in list of scenes to read */
    int  row,            /* I:   the row (Y) location within img/grid   */
    int  col,            /* I:   the col (X) location within img/grid   */
    int  num_samples,    /* I:   number of image samples (X width)      */
    bool debug,          /* I:   flag for printing debug messages       */
    int  **image_buf     /* O:   pointer to 2-D image band values array */
)

{
    int  k;                     /* band loop counter.                   */
    int  len;                   /* for string length call.              */
    int  landsat_number;        /* numeric mission number to make names */
    char filename[MAX_STR_LEN]; /* file name constructed from sceneID   */
    int  status;                /* return status of system call(s)      */


    /******************************************************************/
    /*                                                                */
    /* Read the image bands for this scene. using the                 */
    /*                                                                */
    /******************************************************************/

    for (k = 0; k < TOTAL_IMAGE_BANDS; k++)
    {
        len = strlen(sceneID_name);
        landsat_number = atoi(sub_string(sceneID_name,(len-19),1));
        if (landsat_number != 8)
        {
            if (k == 5)
                sprintf(filename, "%s_sr_band%d.img", sceneID_name, k+2);
            else if (k == 6)
                sprintf(filename, "%s_toa_band6.img", sceneID_name);
            else
                sprintf(filename, "%s_sr_band%d.img", sceneID_name, k+1);
        }
        else
        {
            if (k == 6)
                sprintf(filename, "%s_toa_band10.img", sceneID_name);
            else 
                sprintf(filename, "%s_sr_band%d.img",  sceneID_name, k+2);
        }

        fp_tifs[k][curr_scene_num] = open_raw_binary(filename,"rb");
        if (fp_tifs[k][curr_scene_num] == NULL)
            printf("error open %d scene, %d bands files\n",curr_scene_num, k+1);

        status = fseek(fp_tifs[k][curr_scene_num], ((row * num_samples) + col) * sizeof(short int), SEEK_SET);
        if (status != 0)
            printf("error seeking %d scene, %d bands\n", curr_scene_num, (k + 1));

        if (read_raw_binary(fp_tifs[k][curr_scene_num], 1, 1, sizeof(short int), &image_buf[k][curr_scene_num]) != 0)
            printf("error reading %d scene, %d bands\n", curr_scene_num, (k + 1));
    
        close_raw_binary(fp_tifs[k][curr_scene_num]);

        if (debug)
        {
            printf("%d ", (short int)image_buf[k][curr_scene_num]);
        }

    }

    return (SUCCESS);
}