Пример #1
0
def get_atl_alongtrack(df, atl03struct=None):
    easting = np.array(df['easting'])
    northing = np.array(df['northing'])

    if atl03struct:
        R_mat = atl03struct.rotationData.R_mat
        xRotPt = atl03struct.rotationData.xRotPt
        yRotPt = atl03struct.rotationData.yRotPt
        desiredAngle = 90
        crossTrack, alongTrack, R_mat, xRotPt, yRotPt, phi = \
        getCoordRotFwd(easting, northing, R_mat, xRotPt, yRotPt, [])
    else:
        desiredAngle = 90
        crossTrack, alongTrack, R_mat, xRotPt, yRotPt, phi = \
        getCoordRotFwd(easting, northing, [], [], [], desiredAngle)

    if 'crosstrack' not in list(df.columns):
        df = pd.concat(
            [df, pd.DataFrame(crossTrack, columns=['crosstrack'])], axis=1)
        df = pd.concat(
            [df, pd.DataFrame(alongTrack, columns=['alongtrack'])], axis=1)
    else:
        print('Warning: Overwriting Existing Alongtrack/Crosstrack')
        df = df.drop(columns=['crosstrack'])
        df = df.drop(columns=['alongtrack'])
        df = pd.concat(
            [df, pd.DataFrame(crossTrack, columns=['crosstrack'])], axis=1)
        df = pd.concat(
            [df, pd.DataFrame(alongTrack, columns=['alongtrack'])], axis=1)

    rotation_data = AtlRotationStruct(R_mat, xRotPt, yRotPt, desiredAngle, phi)

    return df, rotation_data
Пример #2
0
def getAtlTruthSwath(atlMeasuredData, headerData, rotationData,
                     useExistingTruth, truthSwathDir, buffer, outFilePath,
                     createTruthFile):

    # Start timer
    timeStart = runTime.time()

    # Print message
    print('   Ground Track Number: %s' % atlMeasuredData.gtNum)

    # Initialze truthFilePath/truthDir
    truthFilePath = []
    truthDir = []
    # atlTruthDataFiltered = []

    # Initialize dem/lidar flags
    demfilecheck = False
    lidarfilecheck = False

    # Determine if truthSwathDir is folder or file
    if os.path.isfile(truthSwathDir) == True:
        file = ntpath.basename(truthSwathDir)
        truthFilePath = truthSwathDir
        extension = file.split('.')[-1]
        if (extension == 'las') or (extension == 'laz'):
            print('File is lidar LAS/LAZ File')
            lidarfilecheck = True
        else:
            print('File is DSM/DTM .tif File')
            demfilecheck = True
        # endIf
    else:
        truthDir = truthSwathDir
    # endIf

    # Get rotation data
    R_mat = rotationData.R_mat
    xRotPt = rotationData.xRotPt
    yRotPt = rotationData.yRotPt
    desiredAngle = rotationData.desiredAngle
    phi = rotationData.phi

    # If truth swath exists, read .las file
    if (useExistingTruth and truthFilePath and demfilecheck == False):

        # Read in truth file .las file
        print('   Reading in Lidar Truth File: %s' % truthFilePath)
        lasTruthData = readLas(truthFilePath)

        # Rotate TRUTH data to CT/AT plane
        print('   Rotating Data to CT/AT Frame...')
        lasTruthData_x_newRot, lasTruthData_y_newRot, _, _, _, _ = \
        getCoordRotFwd(lasTruthData.x, lasTruthData.y,
                       R_mat, xRotPt, yRotPt, desiredAngle)

        #        # Store data as object
        #        atlTruthData = atlTruthStruct(lasTruthData.x, lasTruthData.y,
        #                                      lasTruthData_x_newRot,
        #                                      lasTruthData_y_newRot,
        #                                      lasTruthData.z,
        #                                      lasTruthData.classification,
        #                                      lasTruthData.intensity,
        #                                      headerData.zone, headerData.hemi)

        # Store data as object (CHANGE AFTER DEMO!!!)
        atlTruthData = atlTruthStruct(
            lasTruthData.x, lasTruthData.y, lasTruthData_x_newRot,
            lasTruthData_y_newRot, lasTruthData.z, lasTruthData.classification,
            lasTruthData.intensity, atlMeasuredData.zone, atlMeasuredData.hemi)

    elif (demfilecheck == True):
        ###New

        # 1. Find EPSG Code from DEM
        epsg_dem = readDEMepsg(truthFilePath)

        # 2. Determine if EPSG Code is the same for the ATL03 Measured
        epsg_atl = identifyEPSG(atlMeasuredData.hemi, atlMeasuredData.zone)
        epsg_atl = epsg_atl.split(':')[-1]

        if epsg_atl == epsg_dem:
            print('   DEM Projection matches target')
            # 3b. If EPSG code is the same, set DEM as a target
            truthFilePathDEM = truthFilePath
        else:
            print('   Reprojecting DEM')
            # 3a. If EPSG code does not match, use GDAL Warp to create new DEM
            file = ntpath.basename(truthSwathDir)
            truthFilePath = truthSwathDir
            originalname = file.split('.')[0]
            newname = originalname + "_projected.tif"
            truthFilePathDEM = os.path.normpath(
                os.path.join(outFilePath, newname))
            srs = ogr.osr.SpatialReference()
            srs.ImportFromEPSG(np.int(epsg_atl))
            warpoptions = gdal.WarpOptions(dstSRS=srs)
            gdal.Warp(truthFilePathDEM, truthFilePath, options=warpoptions)

        # 4. Call the Format DEM Function
        print('   Reading in DEM Truth File: %s' % truthFilePathDEM)
        xarr, yarr, zarr, intensity, classification, epsg = \
        formatDEM(truthFilePathDEM)

        # 5. Run a quick filter to remove points not even remotely close
        print('   Running Quick Filter')
        xmin = np.min(atlMeasuredData.easting.flatten()) - 100
        xmax = np.max(atlMeasuredData.easting.flatten()) + 100
        ymin = np.min(atlMeasuredData.northing.flatten()) - 100
        ymax = np.max(atlMeasuredData.northing.flatten()) + 100

        quickfilter = np.where((xarr > xmin) & (xarr < xmax) & (yarr > ymin)
                               & (yarr < ymax))

        xcoord = xarr[quickfilter]
        ycoord = yarr[quickfilter]
        zarr = zarr[quickfilter]
        intensity = intensity[quickfilter]
        classification = classification[quickfilter]

        #        ###Original
        #
        #
        #        # Apply EPSG code to X,Y
        #        # 'epsg:32613'
        #        epsg_in = 'epsg:' + str(epsg)
        #        epsg_out = identifyEPSG(atlMeasuredData.hemi,atlMeasuredData.zone)
        #
        #        if epsg_in == epsg_out:
        #            print('   DEM and Measured Match EPSG Code')
        #            xcoord = xarr
        #            ycoord = yarr
        #        else:
        #            print('   Transforming Projection for DEM')
        #            xx,yy = zip(*[transform(epsg_in, epsg_out, xarr[i],yarr[i])  \
        #                          for i in range(0,len(xarr))])
        #            xcoord = np.asarray(xx)
        #            ycoord = np.asarray(yy)

        # Rotate Data for along-track/cross-track
        print('   Rotating Data to CT/AT Frame...')
        x_newRot, y_newRot, _, _, _, _ = getCoordRotFwd(
            xcoord, ycoord, R_mat, xRotPt, yRotPt, desiredAngle)

        # Store Data as Object
        atlTruthData = atlTruthStruct(xcoord, ycoord, x_newRot, y_newRot, zarr,
                                      classification, intensity,
                                      atlMeasuredData.zone,
                                      atlMeasuredData.hemi)
        print('   DEM being used for ATL Truth Data')

    else:

        # Create new truth .las file
        print('   Creating new Truth File...')

        # Get MEASURED rotated buffer bounds data
        xRotL = atlMeasuredData.crossTrack - buffer
        xRotR = atlMeasuredData.crossTrack + buffer
        yRot = atlMeasuredData.alongTrack

        # Get MEASURED buffer bounds data in easting/northing plane
        xL, yL, _, _, _ = getCoordRotRev(xRotL, yRot, R_mat, xRotPt, yRotPt)
        xR, yR, _, _, _ = getCoordRotRev(xRotR, yRot, R_mat, xRotPt, yRotPt)

        # Rotate truth header file min/max x,y points to CT/AT plane
        xMinyMinHeaderRotX, _, _, _, _, _ = getCoordRotFwd(
            headerData.xmin, headerData.ymin, R_mat, xRotPt, yRotPt,
            desiredAngle)
        xMinyMaxHeaderRotX, _, _, _, _, _ = getCoordRotFwd(
            headerData.xmin, headerData.ymax, R_mat, xRotPt, yRotPt,
            desiredAngle)
        xMaxyMinHeaderRotX, _, _, _, _, _ = getCoordRotFwd(
            headerData.xmax, headerData.ymin, R_mat, xRotPt, yRotPt,
            desiredAngle)
        xMaxyMaxHeaderRotX, _, _, _, _, _ = getCoordRotFwd(
            headerData.xmax, headerData.ymax, R_mat, xRotPt, yRotPt,
            desiredAngle)

        # Find min/max x/y header points inside min/max x buffer points
        xMinyMinXPtsInBuffer = (xMinyMinHeaderRotX >= xRotL.min()) & \
        (xMinyMinHeaderRotX <= xRotR.max())
        xMinyMaxXPtsInBuffer = (xMinyMaxHeaderRotX >= xRotL.min()) & \
        (xMinyMaxHeaderRotX <= xRotR.max())
        xMaxyMinXPtsInBuffer = (xMaxyMinHeaderRotX >= xRotL.min()) & \
        (xMaxyMinHeaderRotX <= xRotR.max())
        xMaxyMaxXPtsInBuffer = (xMaxyMaxHeaderRotX >= xRotL.min()) & \
        (xMaxyMaxHeaderRotX <= xRotR.max())

        # Get header points inside MEASURED buffer points
        xHeaderPtsInBuffer = xMinyMinXPtsInBuffer | xMinyMaxXPtsInBuffer | xMaxyMinXPtsInBuffer | xMaxyMaxXPtsInBuffer

        # Find min/max x buffer points inside min/max x/y header points
        xyMinMaxHeaderRot = np.concatenate(
            (xMinyMinHeaderRotX, xMinyMaxHeaderRotX, xMaxyMinHeaderRotX,
             xMaxyMaxHeaderRotX),
            axis=1)
        xyMinHeaderRot = np.c_[np.amin(xyMinMaxHeaderRot, axis=1)]
        xyMaxHeaderRot = np.c_[np.amax(xyMinMaxHeaderRot, axis=1)]
        xMinBufferPtsInFile = (xRotL.min() >= xyMinHeaderRot) & (
            xRotL.min() <= xyMaxHeaderRot)
        xMaxBufferPtsInFile = (xRotR.max() >= xyMinHeaderRot) & (
            xRotR.max() <= xyMaxHeaderRot)

        # Get MEASURED buffer points inside header points
        xBufferPtsInHeader = xMinBufferPtsInFile | xMaxBufferPtsInFile

        # Get any points where buffer points are inside header and vice versa
        xPtsInFile = xHeaderPtsInBuffer | xBufferPtsInHeader

        # Get matching truth file names and x/y min/max points
        matchingFiles = headerData.tileName[xPtsInFile]
        matchingHeaderXmin = headerData.xmin[xPtsInFile]
        matchingHeaderXmax = headerData.xmax[xPtsInFile]
        matchingHeaderYmin = headerData.ymin[xPtsInFile]
        matchingHeaderYmax = headerData.ymax[xPtsInFile]

        # Get all MEASURED x,y buffer points
        xAll = np.concatenate((xL, xR))
        yAll = np.concatenate((yL, yR))

        # Initialize loop variables
        counter = 0
        subData_x_old = []
        subData_y_old = []
        subData_z_old = []
        subData_classification_old = []
        subData_intensity_old = []

        # Find matching truth files
        print('   Looking in Truth File Path: %s' % truthDir)
        print('   Matching Truth .las Files:')
        for i in range(0, len(matchingFiles)):

            # Determine TRUTH files where MEASURED data actually crosses over
            xPtsInFile = (xAll >= matchingHeaderXmin[i]) & (
                xAll <= matchingHeaderXmax[i])
            yPtsInFile = (yAll >= matchingHeaderYmin[i]) & (
                yAll <= matchingHeaderYmax[i])
            anyPtsInFile = any(xPtsInFile & yPtsInFile)

            # If a TRUTH file is a match, use it
            if (anyPtsInFile):

                # Print TRUTH file name to screen
                fileNum = counter + 1
                print('   %s) %s' % (fileNum, matchingFiles[i]))

                # Build path to TRUTH file
                truthLasFile = os.path.normpath(truthDir + '/' +
                                                matchingFiles[i])

                # Try to read .las file
                try:

                    # Read TRUTH .las/.laz file
                    # truthLasFile = truthLasFile.split('.')[0][:-3] + 'las.las'
                    # print(truthLasFile)
                    lasData = readLas(truthLasFile)

                except:

                    # Print Error message
                    print('    ERROR: Could not read file.')
                    lasData = False

                # endTry

                # If there is .las data, process it
                if (lasData):

                    # Covert to UTM coords if in lat/lon
                    if (headerData.coordType == 'Lat/Lon'):
                        lasDataNewX, lasDataNewY, _, _ = getLatLon2UTM(
                            lasData.x, lasData.y)
                        lasData = atlTruthStruct(lasDataNewX, lasDataNewY,
                                                 lasData.z,
                                                 lasData.classification,
                                                 lasData.intensity,
                                                 headerData.zone,
                                                 headerData.hemi)
                    # endif

                    # Rotate TRUTH lasData to CT/AT plane
                    xRotLasData, yRotLasData, _, _, _, _ = getCoordRotFwd(
                        lasData.x, lasData.y, R_mat, xRotPt, yRotPt,
                        desiredAngle)

                    # Find TRUTH lasData points inside TRUTH buffer
                    yRotLocalInds = (yRot >= yRotLasData.min()) & (
                        yRot <= yRotLasData.max())
                    xRotLocalL = xRotL[yRotLocalInds]
                    xRotLocalR = xRotR[yRotLocalInds]
                    xyBufferInds = (xRotLasData >= xRotLocalL.min()) & (
                        xRotLasData <= xRotLocalR.max())

                    # Extract TRUTH lasData points inside TRUTH buffer
                    subData_x = lasData.x[xyBufferInds]
                    subData_y = lasData.y[xyBufferInds]
                    subData_z = lasData.z[xyBufferInds]
                    subData_classification = lasData.classification[
                        xyBufferInds]
                    subData_intensity = lasData.intensity[xyBufferInds]

                    # Compute ACE
                    subData_x, subData_y, subData_z, subData_classification, subData_intensity = get_ace(
                        subData_x, subData_y, subData_z,
                        subData_classification, subData_intensity)

                    # Append TRUTH buffer points onto previous data
                    subData_x_new = np.append(subData_x_old, subData_x)
                    subData_y_new = np.append(subData_y_old, subData_y)
                    subData_z_new = np.append(subData_z_old, subData_z)
                    subData_classification_new = np.append(
                        subData_classification_old, subData_classification)
                    subData_intensity_new = np.append(subData_intensity_old,
                                                      subData_intensity)

                    # Store old TRUTH buffer data
                    subData_x_old = subData_x_new
                    subData_y_old = subData_y_new
                    subData_z_old = subData_z_new
                    subData_classification_old = subData_classification_new
                    subData_intensity_old = subData_intensity_new

                # endIf

                # Increment counter
                counter += 1

            # endIf
        # endFor

        # Store TRUTH swath data if it exists
        if ('subData_x_new' in locals()):

            # Rotate TRUTH data to CT/AT plane
            print('   Rotating Data to CT/AT Frame...')
            subData_x_newRot, subData_y_newRot, _, _, _, _ = getCoordRotFwd(
                subData_x_new, subData_y_new, R_mat, xRotPt, yRotPt,
                desiredAngle)

            # Store data in class structure
            atlTruthData = atlTruthStruct(subData_x_new, subData_y_new,
                                          subData_x_newRot, subData_y_newRot,
                                          subData_z_new,
                                          subData_classification_new,
                                          subData_intensity_new,
                                          headerData.zone, headerData.hemi)

            # Apply geoid model Z corrections if necessary
            regionName = atlMeasuredData.kmlRegionName

            # Initialize geoidFile variable
            geoidFile = False

            # Determine geoid model to use
            if ('sonoma' in regionName.lower()
                    or 'indiana' in regionName.lower()):
                geoidFile = 'geoid12b_latlon.mat'
            elif ('finland' in regionName.lower()):
                geoidFile = 'geoidFin2005N00_latlon.mat'
            elif ('rangiora' in regionName.lower()
                  or 'wellington' in regionName.lower()):
                geoidFile = 'geoidNZ_latlon.mat'
            # endif

            if (geoidFile):

                # Print status message
                print('')
                print(
                    '   STATUS: Applying Truth Z Correction for %s (Geoid File = %s).'
                    % (regionName, geoidFile))

                # Load Geoid file
                geoidData = readGeoidFile(geoidFile)

                # Get geoidal heights and add to orthometric heights
                atlTruthData = getGeoidHeight(geoidData, atlTruthData)

            # EndIf

        else:

            # Set to false
            print('   STATUS: No Truth Data Stored for this Track.')
            atlTruthData = False

        # endIf

    # endIf

    # Create output file
    if (createTruthFile and atlTruthData):

        print('   Writing truth .las file...')
        outName = atlMeasuredData.atl03FileName + '_' + atlMeasuredData.gtNum + '_REFERENCE_' + str(
            buffer) + 'L' + str(buffer) + 'Rm_buffer.las'
        outPath = os.path.normpath(outFilePath + '/' + outName)

        # If output directory does not exist, create it
        if (not os.path.exists(os.path.normpath(outFilePath))):
            os.mkdir(os.path.normpath(outFilePath))
        # EndIf

        # Write .las file
        writeLas(np.ravel(atlTruthData.easting),
                 np.ravel(atlTruthData.northing), np.ravel(atlTruthData.z),
                 'utm', outPath, np.ravel(atlTruthData.classification),
                 np.ravel(atlTruthData.intensity), None, atlTruthData.hemi,
                 atlTruthData.zone)

    # endIf

    # End timer
    timeEnd = runTime.time()
    timeElapsedTotal = timeEnd - timeStart
    timeElapsedMin = np.floor(timeElapsedTotal / 60)
    timeElapsedSec = timeElapsedTotal % 60

    # Print completion message
    print('   Module Completed in %d min %d sec.' %
          (timeElapsedMin, timeElapsedSec))
    print('\n')

    # Return object
    return atlTruthData
def getAtlMeasuredSwath(atl03FilePath=False,
                        atl08FilePath=False,
                        outFilePath=False,
                        gtNum='gt1r',
                        trimInfo='auto',
                        createAtl03LasFile=False,
                        createAtl03KmlFile=False,
                        createAtl08KmlFile=False,
                        createAtl03CsvFile=False,
                        createAtl08CsvFile=False,
                        logFileID=False):
    # pklHeaderFile = None, LAS_DIR = None):

    # Initialize outputs
    atl03Data = []
    headerData = False
    rotationData = False

    # Initialize ATL08 data
    atl08Data = []
    atl08_lat = []
    atl08_lon = []
    atl08_maxCanopy = []
    atl08_teBestFit = []
    atl08_teMedian = []
    atl08_time = []
    atl08_easting = []
    atl08_northing = []
    atl08_crossTrack = []
    atl08_alongTrack = []
    atl08_classification = []
    atl08_intensity = []

    # pklHeader = False
    # if type(pklHeaderFile) != type(None):
    #     pklHeader = True
    #     if type(LAS_DIR) == type(None):
    #         raise ValueError('LAS_DIR == None, please input LAS_DIR argument')

    # Only execute code if input ATL03 .h5 file and output path declared
    if (atl03FilePath and outFilePath):

        # Start timer
        timeStart = runTime.time()

        # Get beam # and S/W
        beamNum = GtToBeamNum(atl03FilePath, gtNum)
        beamStrength = GtToBeamSW(atl03FilePath, gtNum)

        # Print message
        writeLog(
            '   Ground Track Number: %s (Beam #%s, Beam Strength: %s)\n' %
            (gtNum, beamNum, beamStrength), logFileID)

        # Get ATL03 file path/name
        atl03FilePath = os.path.normpath(os.path.abspath(atl03FilePath))
        atl03FileName = os.path.splitext(os.path.basename(atl03FilePath))[0]

        # Read ATL03 data from h5 file
        writeLog('   Reading ATL03 .h5 file: %s' % atl03FilePath, logFileID)
        lat_all = readAtl03H5(atl03FilePath, '/heights/lat_ph', gtNum)
        lon_all = readAtl03H5(atl03FilePath, '/heights/lon_ph', gtNum)
        z_all = readAtl03H5(atl03FilePath, '/heights/h_ph', gtNum)
        deltaTime_all = readAtl03H5(atl03FilePath, '/heights/delta_time',
                                    gtNum)
        signalConf_all = readAtl03H5(atl03FilePath, '/heights/signal_conf_ph',
                                     gtNum)
        zGeoidal = readAtl03H5(atl03FilePath, '/geophys_corr/geoid', gtNum)
        zGeoidal_deltaTime = readAtl03H5(atl03FilePath,
                                         '/geophys_corr/delta_time', gtNum)
        zGeoidal_all = interp_vals(zGeoidal_deltaTime,
                                   zGeoidal,
                                   deltaTime_all,
                                   removeThresh=True)
        zMsl_all = z_all - zGeoidal_all
        atl03_ph_index_beg, atl03_segment_id = readAtl03DataMapping(
            atl03FilePath, gtNum)

        badVars = []
        if (len(lat_all) == 0):
            badVar = 'Latitude (lat_ph)'
            badVars.append(badVar)
        # endIf

        if (len(lon_all) == 0):
            badVar = 'Longitude (lon_ph)'
            badVars.append(badVar)
        # endIf

        if (len(z_all) == 0):
            badVar = 'Height (h_ph)'
            badVars.append(badVar)
        # endIf

        if (len(deltaTime_all) == 0):
            badVar = 'Delta Time (delta_time)'
            badVars.append(badVar)
        # endIf

        if (len(signalConf_all) == 0):
            badVar = 'Signal Confidence (signal_conf_ph)'
            badVars.append(badVar)
        # endIf

        if (len(badVars) == 0):

            # Get time from delta time
            min_delta_time = np.min(deltaTime_all)
            time_all = deltaTime_all - min_delta_time

            # Get track direction
            if (np.abs(lat_all[-1]) >= np.abs(lat_all[0])):
                trackDirection = 'Ascending'
            else:
                trackDirection = 'Descending'
            # endIf

            writeLog('   Track Direction: %s' % trackDirection, logFileID)

            # Extract metadata from ATL03 file name
            atl03h5Info = getNameParts(atl03FileName)

            # Map ATL08 to ATL03 ground photons
            if (atl08FilePath):

                # Get ATL08 file path/name
                atl08FilePath = os.path.normpath(
                    os.path.abspath(atl08FilePath))
                atl08FileName = os.path.splitext(
                    os.path.basename(atl08FilePath))[0]
                atl08h5Info = getNameParts(atl08FileName)

                # Read ATL08 data from .h5 file
                writeLog('   Reading ATL08 .h5 file: %s' % atl08FilePath,
                         logFileID)
                atl08_lat = readAtl08H5(atl08FilePath,
                                        '/land_segments/latitude', gtNum)
                atl08_lon = readAtl08H5(atl08FilePath,
                                        '/land_segments/longitude', gtNum)
                atl08_maxCanopy = readAtl08H5(
                    atl08FilePath, '/land_segments/canopy/h_max_canopy_abs',
                    gtNum)
                atl08_teBestFit = readAtl08H5(
                    atl08FilePath, '/land_segments/terrain/h_te_best_fit',
                    gtNum)
                atl08_teMedian = readAtl08H5(
                    atl08FilePath, '/land_segments/terrain/h_te_median', gtNum)
                atl08_deltaTime = readAtl08H5(atl08FilePath,
                                              '/land_segments/delta_time',
                                              gtNum)
                atl08_zGeoidal = interp_vals(zGeoidal_deltaTime,
                                             zGeoidal,
                                             atl08_deltaTime,
                                             removeThresh=True)
                atl08_maxCanopyMsl = atl08_maxCanopy - atl08_zGeoidal
                atl08_teBestFitMsl = atl08_teBestFit - atl08_zGeoidal
                atl08_teMedianMsl = atl08_teMedian - atl08_zGeoidal
                atl08_classed_pc_indx, atl08_classed_pc_flag, atl08_segment_id = readAtl08DataMapping(
                    atl08FilePath, gtNum)
                atl08_signalConf = np.zeros(np.size(atl08_lat))
                atl08_classification = np.zeros(np.size(atl08_lat))
                atl08_intensity = np.zeros(np.size(atl08_lat))

                if ((len(atl08_lat) > 0) and (len(atl08_lon) > 0)):

                    # Get time from delta time
                    atl08_time = atl08_deltaTime - min_delta_time

                    # Do ATL08 to ATL03 mapping
                    writeLog('   Mapping ATL08 to ATL03 Ground Photons...',
                             logFileID)
                    try:
                        classification_all = getAtl08Mapping(
                            atl03_ph_index_beg, atl03_segment_id,
                            atl08_classed_pc_indx, atl08_classed_pc_flag,
                            atl08_segment_id)
                    except:
                        writeLog(
                            '   WARNING: Could not map ATL08 to ATL03 Ground Photons.',
                            logFileID)
                        classification_all = atl08_classification
                    # endTry

                    # Get length to trim data by
                    class_length = len(classification_all)
                    lat_length = len(lat_all)
                    data_length = np.min([class_length, lat_length])

                    # Trim ATL03 data down to size of classification array
                    atl03_lat = lat_all[0:data_length]
                    atl03_lon = lon_all[0:data_length]
                    atl03_z = z_all[0:data_length]
                    atl03_zMsl = zMsl_all[0:data_length]
                    atl03_time = time_all[0:data_length]
                    atl03_deltaTime = deltaTime_all[0:data_length]
                    atl03_signalConf = signalConf_all[0:data_length]
                    atl03_classification = classification_all[0:data_length]
                    atl03_intensity = np.zeros(np.size(atl03_lat))
                    dataIsMapped = True

                else:

                    writeLog(
                        '   WARNING: ATL08 file does not contain usable data.',
                        logFileID)

                    atl08FilePath = False

                    # Store data
                    atl03_lat = lat_all
                    atl03_lon = lon_all
                    atl03_z = z_all
                    atl03_zMsl = zMsl_all
                    atl03_time = time_all
                    atl03_deltaTime = deltaTime_all
                    atl03_signalConf = signalConf_all
                    atl03_classification = np.zeros(np.size(atl03_lat))
                    atl03_intensity = np.zeros(np.size(atl03_lat))
                    dataIsMapped = False

                # endIf

            else:

                # Message to screen
                writeLog('   Not Mapping ATL08 to ATL03 Ground Photons',
                         logFileID)

                # Store data
                atl03_lat = lat_all
                atl03_lon = lon_all
                atl03_z = z_all
                atl03_zMsl = zMsl_all
                atl03_time = time_all
                atl03_deltaTime = deltaTime_all
                atl03_signalConf = signalConf_all
                atl03_classification = np.zeros(np.size(atl03_lat))
                atl03_intensity = np.zeros(np.size(atl03_lat))
                dataIsMapped = False

            # endIf

            # Get trim options
            trimParts = trimInfo.split(',')
            trimMode = trimParts[0]
            trimType = 'None'
            if (('manual' in trimMode.lower()) and (len(trimParts) > 1)):
                trimType = trimParts[1]
                trimMin = float(trimParts[2])
                trimMax = float(trimParts[3])
            # endIf

            # If selected to manually trim data, do this first
            if ('manual' in trimMode.lower()):

                # Trim by lat or time
                if ('lonlat' in trimType.lower()):
                    lonMin, lonMax = float(trimParts[2]), float(trimParts[3])
                    latMin, latMax = float(trimParts[4]), float(trimParts[5])
                    writeLog(
                        '   Manual Trim Mode (Min Lon: %s, Max Lon: %s)' %
                        (lonMin, lonMax), logFileID)
                    writeLog(
                        '   Manual Trim Mode (Min Lat: %s, Max Lat: %s)' %
                        (latMin, latMax), logFileID)
                    atl03IndsToKeepLon = (atl03_lon >= lonMin) & (atl03_lon <=
                                                                  lonMax)
                    atl03IndsToKeepLat = (atl03_lat >= latMin) & (atl03_lat <=
                                                                  latMax)
                    atl03IndsToKeep = atl03IndsToKeepLon & atl03IndsToKeepLat

                    if (atl08FilePath):
                        atl08IndsToKeepLon = (atl08_lon >=
                                              lonMin) & (atl08_lon <= lonMax)
                        atl08IndsToKeepLat = (atl08_lat >=
                                              latMin) & (atl08_lat <= latMax)
                        atl08IndsToKeep = atl08IndsToKeepLon & atl08IndsToKeepLat

                elif ('lat' in trimType.lower()):
                    writeLog(
                        '   Manual Trim Mode (Min Lat: %s, Max Lat: %s)' %
                        (trimMin, trimMax), logFileID)
                    atl03IndsToKeep = (atl03_lat >= trimMin) & (atl03_lat <=
                                                                trimMax)

                    if (atl08FilePath):
                        atl08IndsToKeep = (atl08_lat >= trimMin) & (atl08_lat
                                                                    <= trimMax)
                    # endIf

                elif ('lon' in trimType.lower()):
                    writeLog(
                        '   Manual Trim Mode (Min Lon: %s, Max Lon: %s)' %
                        (trimMin, trimMax), logFileID)
                    atl03IndsToKeep = (atl03_lon >= trimMin) & (atl03_lon <=
                                                                trimMax)

                    if (atl08FilePath):
                        atl08IndsToKeep = (atl03_lon >= trimMin) & (atl03_lon
                                                                    <= trimMax)
                    # endIf

                elif ('time' in trimType.lower()):
                    writeLog(
                        '   Manual Trim Mode (Min Time: %s, Max Time: %s)' %
                        (trimMin, trimMax), logFileID)
                    atl03IndsToKeep = (atl03_time >= trimMin) & (atl03_time <=
                                                                 trimMax)

                    if (atl08FilePath):
                        atl08IndsToKeep = (atl08_time >=
                                           trimMin) & (atl08_time <= trimMax)
                    # endIf
                else:
                    writeLog(
                        '   Manual Trim Mode is Missing Args, Not Trimming Data',
                        logFileID)
                    atl03IndsToKeep = np.ones(np.shape(atl03_lat), dtype=bool)

                    if (atl08FilePath):
                        atl08IndsToKeep = np.ones(np.shape(atl08_lat),
                                                  dtype=bool)
                    # endIf
                # endif

                # Trim ATL03 data
                if atl03IndsToKeep.sum() == 0:
                    # no data left given manual constraints
                    return atl03Data, atl08Data, headerData, rotationData
                # endIf

                atl03_lat = atl03_lat[atl03IndsToKeep]
                atl03_lon = atl03_lon[atl03IndsToKeep]
                atl03_z = atl03_z[atl03IndsToKeep]
                atl03_zMsl = atl03_zMsl[atl03IndsToKeep]
                atl03_time = atl03_time[atl03IndsToKeep]
                atl03_deltaTime = atl03_deltaTime[atl03IndsToKeep]
                atl03_signalConf = atl03_signalConf[atl03IndsToKeep]
                atl03_classification = atl03_classification[atl03IndsToKeep]
                atl03_intensity = atl03_intensity[atl03IndsToKeep]

                # Trim ATL08 data
                if (atl08FilePath):
                    atl08_lat = atl08_lat[atl08IndsToKeep]
                    atl08_lon = atl08_lon[atl08IndsToKeep]
                    atl08_maxCanopy = atl08_maxCanopy[atl08IndsToKeep]
                    atl08_teBestFit = atl08_teBestFit[atl08IndsToKeep]
                    atl08_teMedian = atl08_teMedian[atl08IndsToKeep]
                    atl08_maxCanopyMsl = atl08_maxCanopyMsl[atl08IndsToKeep]
                    atl08_teBestFitMsl = atl08_teBestFitMsl[atl08IndsToKeep]
                    atl08_teMedianMsl = atl08_teMedianMsl[atl08IndsToKeep]
                    atl08_time = atl08_time[atl08IndsToKeep]
                    atl08_deltaTime = atl08_deltaTime[atl08IndsToKeep]
                    atl08_signalConf = atl08_signalConf[atl08IndsToKeep]
                    atl08_classification = atl08_classification[
                        atl08IndsToKeep]
                    atl08_intensity = atl08_intensity[atl08IndsToKeep]
                # endIf

            elif ('none' in trimMode.lower()):

                writeLog('   Trim Mode: None', logFileID)

            # endIf

            # Remove ATL08 points above 1e30
            if (atl08FilePath):
                indsBelowThresh = (atl08_maxCanopy <= 1e30) | (
                    atl08_teBestFit <= 1e30) | (atl08_teMedian <= 1e30)
                atl08_lat = atl08_lat[indsBelowThresh]
                atl08_lon = atl08_lon[indsBelowThresh]
                atl08_maxCanopy = atl08_maxCanopy[indsBelowThresh]
                atl08_teBestFit = atl08_teBestFit[indsBelowThresh]
                atl08_teMedian = atl08_teMedian[indsBelowThresh]
                atl08_maxCanopyMsl = atl08_maxCanopyMsl[indsBelowThresh]
                atl08_teBestFitMsl = atl08_teBestFitMsl[indsBelowThresh]
                atl08_teMedianMsl = atl08_teMedianMsl[indsBelowThresh]
                atl08_time = atl08_time[indsBelowThresh]
                atl08_deltaTime = atl08_deltaTime[indsBelowThresh]
                atl08_signalConf = atl08_signalConf[indsBelowThresh]
                atl08_classification = atl08_classification[indsBelowThresh]
                atl08_intensity = atl08_intensity[indsBelowThresh]
            # endIf

            # If selected to auto trim data, then trim if truth region exists
            if ('auto' in trimMode.lower()):

                # Message to user
                writeLog('   Trim Mode: Auto', logFileID)

                # Read kmlBounds.txt file to get min/max extents to auto trim
                kmlBoundsTextFile = 'kmlBounds.txt'
                kmlRegionName = False
                if (os.path.exists(kmlBoundsTextFile)):  # and not pklHeader:

                    # Message to user
                    writeLog('   Finding Reference Region...', logFileID)

                    try:

                        # Read kmlBounds.txt file and get contents
                        kmlInfo = readTruthRegionsTxtFile(kmlBoundsTextFile)

                        # Loop through kmlBounds.txt and find matching TRUTH area
                        maxCounter = len(kmlInfo.regionName)
                        counter = 0
                        while (not kmlRegionName):

                            latInFile = (
                                atl03_lat >= kmlInfo.latMin[counter]) & (
                                    atl03_lat <= kmlInfo.latMax[counter])
                            lonInFile = (
                                atl03_lon >= kmlInfo.lonMin[counter]) & (
                                    atl03_lon <= kmlInfo.lonMax[counter])
                            trackInRegion = any(latInFile & lonInFile)

                            if (trackInRegion):

                                # Get truth region info
                                kmlRegionName = kmlInfo.regionName[counter]
                                kmlLatMin = kmlInfo.latMin[counter]
                                kmlLatMax = kmlInfo.latMax[counter]
                                kmlLonMin = kmlInfo.lonMin[counter]
                                kmlLonMax = kmlInfo.lonMax[counter]

                                # Print truth region
                                writeLog(
                                    '   Reference File Region: %s' %
                                    kmlRegionName, logFileID)

                            # endIf

                            if (counter >= maxCounter):

                                # Send message to user
                                writeLog(
                                    '   No Reference File Region Found in kmlBounds.txt',
                                    logFileID)
                                break

                            # endIf

                            # Increment counter
                            counter += 1

                        # endWhile

                    except:
                        pass
                    # endTry
                # endIf

                if (kmlRegionName):

                    # Trim ATL03 data based on TRUTH region
                    writeLog(
                        '   Auto-Trimming Data Based on Reference Region...',
                        logFileID)
                    atl03IndsInRegion = (atl03_lat >= kmlLatMin) & (
                        atl03_lat <= kmlLatMax) & (atl03_lon >= kmlLonMin) & (
                            atl03_lon <= kmlLonMax)
                    atl03_lat = atl03_lat[atl03IndsInRegion]
                    atl03_lon = atl03_lon[atl03IndsInRegion]
                    atl03_z = atl03_z[atl03IndsInRegion]
                    atl03_zMsl = atl03_zMsl[atl03IndsInRegion]
                    atl03_time = atl03_time[atl03IndsInRegion]
                    atl03_deltaTime = atl03_deltaTime[atl03IndsInRegion]
                    atl03_signalConf = atl03_signalConf[atl03IndsInRegion]
                    atl03_classification = atl03_classification[
                        atl03IndsInRegion]
                    atl03_intensity = atl03_intensity[atl03IndsInRegion]

                    # Trim ATL08 data based on TRUTH region
                    if (atl08FilePath):
                        atl08IndsInRegion = (atl08_lat >= kmlLatMin) & (
                            atl08_lat <= kmlLatMax
                        ) & (atl08_lon >= kmlLonMin) & (atl08_lon <= kmlLonMax)
                        atl08_lat = atl08_lat[atl08IndsInRegion]
                        atl08_lon = atl08_lon[atl08IndsInRegion]
                        atl08_maxCanopy = atl08_maxCanopy[atl08IndsInRegion]
                        atl08_teBestFit = atl08_teBestFit[atl08IndsInRegion]
                        atl08_teMedian = atl08_teMedian[atl08IndsInRegion]
                        atl08_maxCanopyMsl = atl08_maxCanopyMsl[
                            atl08IndsInRegion]
                        atl08_teBestFitMsl = atl08_teBestFitMsl[
                            atl08IndsInRegion]
                        atl08_teMedianMsl = atl08_teMedianMsl[
                            atl08IndsInRegion]
                        atl08_time = atl08_time[atl08IndsInRegion]
                        atl08_deltaTime = atl08_deltaTime[atl08IndsInRegion]
                        atl08_signalConf = atl08_signalConf[atl08IndsInRegion]
                        atl08_classification = atl08_classification[
                            atl08IndsInRegion]
                        atl08_intensity = atl08_intensity[atl08IndsInRegion]
                    #endIf
                # endIf
            # endIf

            # Convert lat/lon coordinates to UTM
            writeLog('   Converting Lat/Lon to UTM...', logFileID)

            # Allow function to determine UTM zone for ATL03
            atl03_easting, atl03_northing, zone, hemi = getLatLon2UTM(
                atl03_lon, atl03_lat)

            # Allow function to determine UTM zone for ATL03
            if (atl08FilePath):
                atl08_easting, atl08_northing, atl08_zone, atl08_hemi = getLatLon2UTM(
                    atl08_lon, atl08_lat)
            # endIf

            # Print UTM zone
            writeLog('   UTM Zone: %s %s' % (zone, hemi), logFileID)

            # Transform MEASURED data to CT/AT plane
            writeLog('   Computing CT/AT Frame Rotation...', logFileID)
            desiredAngle = 90
            atl03_crossTrack, atl03_alongTrack, R_mat, xRotPt, yRotPt, phi = getCoordRotFwd(
                atl03_easting, atl03_northing, [], [], [], desiredAngle)

            if (atl08FilePath):
                atl08_crossTrack, atl08_alongTrack, _, _, _, _ = getCoordRotFwd(
                    atl08_easting, atl08_northing, R_mat, xRotPt, yRotPt, [])
            # endIf

            # Store rotation object
            rotationData = atlRotationStruct(R_mat, xRotPt, yRotPt,
                                             desiredAngle, phi)

            # Reassign class -1 to 0 (NOTE: this may need to change later)
            inds_eq_neg1 = atl03_classification == -1
            atl03_classification[inds_eq_neg1] = 0

            # Store data in class structure
            atl03Data = atl03Struct(atl03_lat, atl03_lon, \
                                    atl03_easting, atl03_northing, \
                                    atl03_crossTrack, atl03_alongTrack, \
                                    atl03_z, \
                                    atl03_zMsl,
                                    atl03_time, \
                                    atl03_deltaTime, \
                                    atl03_signalConf, atl03_classification, atl03_intensity, \
                                    gtNum, beamNum, beamStrength, zone, hemi, \
                                    atl03FilePath, atl03FileName, \
                                    trackDirection, \
                                    atl03h5Info, \
                                    dataIsMapped)

            # Store data in class structure
            if (atl08FilePath):
                atl08Data = atl08Struct(atl08_lat, atl08_lon, \
                                        atl08_easting, atl08_northing, \
                                        atl08_crossTrack, atl08_alongTrack, \
                                        atl08_maxCanopy, atl08_teBestFit, atl08_teMedian, \
                                        atl08_maxCanopyMsl, atl08_teBestFitMsl, atl08_teMedianMsl, \
                                        atl08_time, \
                                        atl08_deltaTime, \
                                        atl08_signalConf, atl08_classification, atl08_intensity, \
                                        gtNum, atl08_zone, atl08_hemi, \
                                        atl08FilePath, atl08FileName, \
                                        trackDirection, \
                                        atl08h5Info, \
                                        dataIsMapped)
            # endIf

            # Create output ATL03 .las file
            if (createAtl03LasFile):

                writeLog('   Writing ATL03 .las file...', logFileID)
                outName = atl03Data.atl03FileName + '_' + atl03Data.gtNum + '.las'
                outPath = os.path.normpath(outFilePath + '/' + outName)

                # If output directory does not exist, create it
                if (not os.path.exists(os.path.normpath(outFilePath))):
                    os.mkdir(os.path.normpath(outFilePath))
                # EndIf

                # Get projection
                if (atl03Data.zone == '3413' or atl03Data.zone == '3976'):

                    # NSIDC Polar Stereographic North/South cases (3413 = Arctic, 3976 = Antarctic)
                    lasProjection = atl03Data.hemi

                    # Write .las file
                    writeLas(np.ravel(atl03Data.easting),
                             np.ravel(atl03Data.northing),
                             np.ravel(atl03Data.z), lasProjection, outPath,
                             np.ravel(atl03Data.classification),
                             np.ravel(atl03Data.intensity),
                             np.ravel(atl03Data.signalConf))

                else:

                    # Write .las file for UTM projection case
                    writeLas(np.ravel(atl03Data.easting),
                             np.ravel(atl03Data.northing),
                             np.ravel(atl03Data.z), 'utm', outPath,
                             np.ravel(atl03Data.classification),
                             np.ravel(atl03Data.intensity),
                             np.ravel(atl03Data.signalConf), atl03Data.hemi,
                             atl03Data.zone)

                # endIf

            # endIf

            # Create output ATL03 .kml file
            if (createAtl03KmlFile):

                writeLog('   Writing ATL03 .kml file...', logFileID)
                outName = atl03Data.atl03FileName + '_' + atl03Data.gtNum + '.kml'
                outPath = os.path.normpath(outFilePath + '/' + outName)

                # If output directory does not exist, create it
                if (not os.path.exists(os.path.normpath(outFilePath))):
                    os.mkdir(os.path.normpath(outFilePath))
                # EndIf

                # Get array of input time values
                timeStep = 1  # seconds
                timeVals = np.arange(np.min(atl03Data.time),
                                     np.max(atl03Data.time) + 1, timeStep)

                # Get closest time values from IceSat MEASURED data
                timeIn, indsToUse = getClosest(atl03Data.time, timeVals)

                # Reduce lat/lon values to user-specified time scale
                lonsIn = atl03Data.lon[indsToUse]
                latsIn = atl03Data.lat[indsToUse]

                # Write .kml file
                writeKml(latsIn, lonsIn, timeIn, outPath)

            # endIf

            # Create output ATL08 .kml file
            if (createAtl08KmlFile):

                if (atl08FilePath):

                    writeLog('   Writing ATL08 .kml file...', logFileID)
                    outName = atl08Data.atl08FileName + '_' + atl08Data.gtNum + '.kml'
                    outPath = os.path.normpath(outFilePath + '/' + outName)

                    # If output directory does not exist, create it
                    if (not os.path.exists(os.path.normpath(outFilePath))):
                        os.mkdir(os.path.normpath(outFilePath))
                    # EndIf

                    # Get array of input time values
                    timeStep = 1  # seconds
                    timeVals = np.arange(np.min(atl08Data.time),
                                         np.max(atl08Data.time) + 1, timeStep)

                    # Get closest time values from IceSat MEASURED data
                    timeIn, indsToUse = getClosest(atl08Data.time, timeVals)

                    # Reduce lat/lon values to user-specified time scale
                    lonsIn = atl08Data.lon[indsToUse]
                    latsIn = atl08Data.lat[indsToUse]

                    # Write .kml file
                    writeKml(latsIn, lonsIn, timeIn, outPath)

                # endIf

            # endIf

            # Create output ATL03 .csv file
            if (createAtl03CsvFile):

                writeLog('   Writing ATL03 .csv file...', logFileID)
                outName = atl03Data.atl03FileName + '_' + atl03Data.gtNum + '.csv'
                outPath = os.path.normpath(outFilePath + '/' + outName)

                # If output directory does not exist, create it
                if (not os.path.exists(os.path.normpath(outFilePath))):
                    os.mkdir(os.path.normpath(outFilePath))
                # EndIf

                # Write .csv file
                if (atl03Data.zone == '3413' or atl03Data.zone == '3976'):

                    namelist = ['Time (sec)', 'Delta Time (sec)', \
                                'Latitude (deg)', 'Longitude (deg)', \
                                'Polar Stereo X (m)', 'Polar Stereo Y (m)', \
                                'Cross-Track (m)', 'Along-Track (m)', \
                                'Height (m HAE)', 'Height (m MSL)', \
                                'Classification', 'Signal Confidence']
                else:

                    namelist = ['Time (sec)', 'Delta Time (sec)', \
                                'Latitude (deg)', 'Longitude (deg)', \
                                'Easting (m)', 'Northing (m)', \
                                'Cross-Track (m)', 'Along-Track (m)', \
                                'Height (m HAE)', 'Height (m MSL)', \
                                'Classification', 'Signal Confidence']
                # endIf

                datalist = [atl03Data.time, atl03Data.deltaTime, \
                            atl03Data.lat, atl03Data.lon, \
                            atl03Data.easting, atl03Data.northing, \
                            atl03Data.crossTrack, atl03Data.alongTrack,\
                            atl03Data.z, atl03Data.zMsl, \
                            atl03Data.classification, atl03Data.signalConf]

                writeArrayToCSV(outPath, namelist, datalist)

            # endIf

            # Create output ATL08 .csv file
            if (createAtl08CsvFile):

                if (atl08FilePath):

                    writeLog('   Writing ATL08 .csv file...', logFileID)
                    outName = atl08Data.atl08FileName + '_' + atl08Data.gtNum + '.csv'
                    outPath = os.path.normpath(outFilePath + '/' + outName)

                    # If output directory does not exist, create it
                    if (not os.path.exists(os.path.normpath(outFilePath))):
                        os.mkdir(os.path.normpath(outFilePath))
                    # EndIf

                    # Write .csv file
                    if (atl03Data.zone == '3413' or atl03Data.zone == '3976'):

                        namelist = ['Time (sec)', 'Delta Time (sec)', \
                                    'Latitude (deg)', 'Longitude (deg)', \
                                    'Polar Stereo X (m)', 'Polar Stereo Y (m)', \
                                    'Cross-Track (m)', 'Along-Track (m)', \
                                    'Max Canopy (m)', \
                                    'Terrain Best Fit (m)', 'Terrain Median (m)']
                    else:

                        namelist = ['Time (sec)', 'Delta Time (sec)', \
                                    'Latitude (deg)', 'Longitude (deg)', \
                                    'Easting (m)', 'Northing (m)', \
                                    'Cross-Track (m)', 'Along-Track (m)', \
                                    'Max Canopy (m)', \
                                    'Terrain Best Fit (m)', 'Terrain Median (m)']
                    # endIf

                    datalist = [atl08Data.time, atl08Data.deltaTime, \
                                atl08Data.lat, atl08Data.lon, \
                                atl08Data.easting, atl08Data.northing, \
                                atl08Data.crossTrack, atl08Data.alongTrack,\
                                atl08Data.maxCanopy, \
                                atl08Data.teBestFit, atl08Data.teMedian]

                    writeArrayToCSV(outPath, namelist, datalist)

                # endIf

            # endIf

            # End timer
            timeEnd = runTime.time()
            timeElapsedTotal = timeEnd - timeStart
            timeElapsedMin = np.floor(timeElapsedTotal / 60)
            timeElapsedSec = timeElapsedTotal % 60

            # Print completion message
            writeLog('', logFileID)
            writeLog(
                '   Module Completed in %d min %d sec.' %
                (timeElapsedMin, timeElapsedSec), logFileID)
            writeLog('\n', logFileID)

        else:

            writeLog('\n', logFileID)
            writeLog('   *** Could not process data.', logFileID)
            writeLog('   *** ATL03 .h5 file missing these fields:', logFileID)
            for i in range(0, len(badVars)):
                writeLog('          %s) %s' % (i + 1, badVars[i]), logFileID)
            writeLog('\n', logFileID)

        # endIf

    else:

        # Message to user
        writeLog('Input correct ATL03 input .h5 file and/or output path.',
                 logFileID)

    # endIf

    # Return object
    return atl03Data, atl08Data, rotationData
Пример #4
0
def getAtlMeasuredSwath(atl03FilePath=False,
                        atl08FilePath=False,
                        outFilePath=False,
                        gtNum='gt1r',
                        trimInfo='auto',
                        createLasFile=False,
                        createKmlFile=False,
                        createCsvFile=False):

    # Initialize outputs
    atlMeasuredData = False
    headerData = False
    coordType = False
    rotationData = False

    # Only execute code if input ATL03 .h5 file and output path declared
    if (atl03FilePath and outFilePath):

        # Start timer
        timeStart = runTime.time()

        # Print message
        print('   Ground Track Number: %s' % gtNum)

        # Get ATL03 file path/name
        atl03FilePath = os.path.normpath(os.path.abspath(atl03FilePath))
        atl03FileName = os.path.splitext(os.path.basename(atl03FilePath))[0]

        # Read ATL03 data from h5 file
        print('   Reading ATL03 .h5 file: %s' % atl03FilePath)
        lat_all = readAtl03H5(atl03FilePath, 'lat_ph', gtNum)
        lon_all = readAtl03H5(atl03FilePath, 'lon_ph', gtNum)
        z_all = readAtl03H5(atl03FilePath, 'h_ph', gtNum)
        deltaTime_all = readAtl03H5(atl03FilePath, 'delta_time', gtNum)
        signalConf_all = readAtl03H5(atl03FilePath, 'signal_conf_ph', gtNum)
        atl03_ph_index_beg, atl03_segment_id = readAtl03DataMapping(
            atl03FilePath, gtNum)

        # Get time from delta time
        time_all = deltaTime_all - np.min(deltaTime_all)

        # Get track direction
        if (lat_all[-1] > lat_all[0]):
            trackDirection = 'Ascending'
        else:
            trackDirection = 'Descending'
        # endIf

        # Extract metadata from ATL03 file name
        atl03h5Info = getNameParts(atl03FileName)

        # Map ATL08 to ATL03 ground photons
        if (atl08FilePath):

            # Get ATL08 file path/name
            atl08FilePath = os.path.normpath(os.path.abspath(atl08FilePath))

            # Message to screen
            print('   Reading ATL08 .h5 file: %s' % atl08FilePath)
            atl08_classed_pc_indx, atl08_classed_pc_flag, atl08_segment_id = readAtl08DataMapping(
                atl08FilePath, gtNum)

            print('   Mapping ATL08 to ATL03 Ground Photons...')
            classification = getAtl08Mapping(atl03_ph_index_beg,
                                             atl03_segment_id,
                                             atl08_classed_pc_indx,
                                             atl08_classed_pc_flag,
                                             atl08_segment_id)

            # Get length to trim data by
            class_length = len(classification)
            lat_length = len(lat_all)
            data_length = np.min([class_length, lat_length])

            # Trim ATL03 data down to size of classification array
            lat = lat_all[0:data_length]
            lon = lon_all[0:data_length]
            z = z_all[0:data_length]
            time = time_all[0:data_length]
            signalConf = signalConf_all[0:data_length]
            classification = classification[0:data_length]
            dataIsMapped = True

        else:

            # Message to screen
            print('   Not Mapping ATL08 to ATL03 Ground Photons')

            # Store data
            lat = lat_all
            lon = lon_all
            z = z_all
            time = time_all
            signalConf = signalConf_all
            classification = np.zeros(np.size(lat_all))
            dataIsMapped = False

        # endIf

        # Get trim options
        trimParts = trimInfo.split(',')
        trimMode = trimParts[0]
        trimType = 'None'
        if (('manual' in trimMode.lower()) and (len(trimParts) > 1)):
            trimType = trimParts[1]
            trimMin = float(trimParts[2])
            trimMax = float(trimParts[3])
        # endIf

        # If selected to manually trim data, do this first
        if ('manual' in trimMode.lower()):

            # Trim by lat or time
            if ('lat' in trimType.lower()):
                print('   Manual Trim Mode (Min Lat: %s, Max Lat: %s)' %
                      (trimMin, trimMax))
                indsToKeep = (lat >= trimMin) & (lat <= trimMax)
            elif ('time' in trimType.lower()):
                print('   Manual Trim Mode (Min Time: %s, Max Time: %s)' %
                      (trimMin, trimMax))
                indsToKeep = (time >= trimMin) & (time <= trimMax)
            else:
                print('   Manual Trim Mode is Missing Args, Not Trimming Data')
                indsToKeep = np.ones(np.shape(lat), dtype=bool)
            # endif

            # Trim data
            lat = lat[indsToKeep]
            lon = lon[indsToKeep]
            z = z[indsToKeep]
            time = time[indsToKeep]
            signalConf = signalConf[indsToKeep]
            classification = classification[indsToKeep]

        # EndIf

        # Determine if ATL03 track goes over a lidar truth region
        kmlBoundsTextFile = 'kmlBounds.txt'
        kmlRegionName = False
        headerFilePath = False
        truthFilePath = False
        if (os.path.exists(kmlBoundsTextFile)):

            # Message to user
            print('   Finding Truth Region...')

            try:

                # Read kmlBounds.txt file and get contents
                kmlInfo = readTruthRegionsTxtFile(kmlBoundsTextFile)

                # Loop through kmlBounds.txt and find matching TRUTH area
                maxCounter = len(kmlInfo.regionName)
                counter = 0
                while (not kmlRegionName):
                    latInFile = (lat >= kmlInfo.latMin[counter]) & (
                        lat <= kmlInfo.latMax[counter])
                    lonInFile = (lon >= kmlInfo.lonMin[counter]) & (
                        lon <= kmlInfo.lonMax[counter])
                    trackInRegion = any(latInFile & lonInFile)
                    if (trackInRegion):

                        # Get truth region info
                        kmlRegionName = kmlInfo.regionName[counter]
                        headerFilePath = os.path.normpath(
                            kmlInfo.headerFilePath[counter])
                        truthFilePath = os.path.normpath(
                            kmlInfo.truthFilePath[counter])
                        kmlLatMin = kmlInfo.latMin[counter]
                        kmlLatMax = kmlInfo.latMax[counter]
                        kmlLonMin = kmlInfo.lonMin[counter]
                        kmlLonMax = kmlInfo.lonMax[counter]

                        # Print truth region
                        print('   Truth File Region: %s' % kmlRegionName)

                        # Read truth header .mat file
                        headerData = readHeaderMatFile(headerFilePath)
                        coordType = headerData.coordType

                    # endIf

                    # Increment counter
                    counter += 1

                    if (counter >= maxCounter):

                        # Send message to user
                        print('   No Truth File Region Found in kmlBounds.txt')
                        break

                    # endIf
                # endWhile

            except:

                # Could not read kmlBounds.txt file
                print(
                    '   Could not read truth header .mat file. Auto-assigning UTM zone.'
                )

        # endIf

        # If selected to auto trim data, then trim if truth region exists
        if ('auto' in trimMode.lower()):

            if (kmlRegionName):

                # Trim data based on TRUTH region
                print(
                    '   Auto Trim Mode (Trimming Data Based on Truth Region)...'
                )
                indsInRegion = (lat >= kmlLatMin) & (lat <= kmlLatMax) & (
                    lon >= kmlLonMin) & (lon <= kmlLonMax)
                lat = lat[indsInRegion]
                lon = lon[indsInRegion]
                z = z[indsInRegion]
                time = time[indsInRegion]
                signalConf = signalConf[indsInRegion]
                classification = classification[indsInRegion]

            # endIf
        # endIf

        # Convert lat/lon coordinates to UTM
        print('   Converting Lat/Lon to UTM...')
        if (kmlRegionName and coordType == 'UTM'):

            # Force UTM zone to match region header file
            zoneToUse = headerData.zone
            hemiToUse = headerData.hemi
            easting, northing, zone, hemi = getLatLon2UTM(
                lon, lat, zoneToUse, hemiToUse)

        else:

            # Allow function to determine UTM zone
            easting, northing, zone, hemi = getLatLon2UTM(lon, lat)

        # endIf

        # Print UTM zone
        print('   UTM Zone: %s' % zone)

        # Transform MEASURED data to CT/AT plane
        print('   Computing CT/AT Frame Rotation...')
        desiredAngle = 90
        crossTrack, alongTrack, R_mat, xRotPt, yRotPt, phi = getCoordRotFwd(
            easting, northing, [], [], [], desiredAngle)

        # Store rotation object
        rotationData = atlRotationStruct(R_mat, xRotPt, yRotPt, desiredAngle,
                                         phi)

        # Store data in class structure
        atlMeasuredData = atlMeasuredStruct(lat, lon, \
                                            easting, northing, \
                                            crossTrack, alongTrack, \
                                            z, time, \
                                            signalConf, classification, \
                                            gtNum, zone, hemi, \
                                            kmlRegionName, headerFilePath, truthFilePath, \
                                            atl03FilePath, atl03FileName, \
                                            atl08FilePath, atl03FileName, \
                                            trackDirection, \
                                            atl03h5Info, \
                                            dataIsMapped)

        # Create output .las file
        if (createLasFile):

            print('   Writing measured .las file...')
            outName = atlMeasuredData.atl03FileName + '_' + atlMeasuredData.gtNum + '_MEASURED.las'
            outPath = os.path.normpath(outFilePath + '/' + outName)

            # If output directory does not exist, create it
            if (not os.path.exists(os.path.normpath(outFilePath))):
                os.mkdir(os.path.normpath(outFilePath))
            # EndIf

            # Write .las file
            writeLas(np.ravel(atlMeasuredData.easting),
                     np.ravel(atlMeasuredData.northing),
                     np.ravel(atlMeasuredData.z), 'utm', outPath,
                     np.ravel(atlMeasuredData.classification),
                     np.ravel(atlMeasuredData.intensity), atlMeasuredData.hemi,
                     atlMeasuredData.zone)

        # endIf

        # Create output .kml file
        if (createKmlFile):

            print('   Writing measured .kml file...')
            outName = atlMeasuredData.atl03FileName + '_' + atlMeasuredData.gtNum + '_MEASURED.kml'
            outPath = os.path.normpath(outFilePath + '/' + outName)

            # If output directory does not exist, create it
            if (not os.path.exists(os.path.normpath(outFilePath))):
                os.mkdir(os.path.normpath(outFilePath))
            # EndIf

            # Get array of input time values
            timeStep = 1  # seconds
            timeVals = np.arange(np.min(atlMeasuredData.time),
                                 np.max(atlMeasuredData.time) + 1, timeStep)

            # Get closest time values from IceSat MEASURED data
            timeIn, indsToUse = getClosest(atlMeasuredData.time, timeVals)

            # Reduce lat/lon values to user-specified time scale
            lonsIn = atlMeasuredData.lon[indsToUse]
            latsIn = atlMeasuredData.lat[indsToUse]

            # Write .kml file
            writeKml(latsIn, lonsIn, timeIn, outPath)

        # endIf

        # Create output .csv file
        if (createCsvFile):

            print('   Writing measured .csv file...')
            outName = atlMeasuredData.atl03FileName + '_' + atlMeasuredData.gtNum + '_MEASURED.csv'
            outPath = os.path.normpath(outFilePath + '/' + outName)

            # If output directory does not exist, create it
            if (not os.path.exists(os.path.normpath(outFilePath))):
                os.mkdir(os.path.normpath(outFilePath))
            # EndIf

            # Write .csv file
            namelist = ['Time (sec)', 'Latitude (deg)', 'Longitude (deg)', \
                        'Easting (m)', 'Northing (m)', \
                        'Cross-Track (m)', 'Along-Track (m)', \
                        'Height (m)', \
                        'Classification', 'Signal Confidence']
            datalist = [atlMeasuredData.time, atlMeasuredData.lat, atlMeasuredData.lon, \
                        atlMeasuredData.easting, atlMeasuredData.northing, \
                        atlMeasuredData.crossTrack, atlMeasuredData.alongTrack,\
                        atlMeasuredData.z, \
                        atlMeasuredData.classification, atlMeasuredData.signalConf]
            writeArrayToCSV(outPath, namelist, datalist)

        # endIf

        # End timer
        timeEnd = runTime.time()
        timeElapsedTotal = timeEnd - timeStart
        timeElapsedMin = np.floor(timeElapsedTotal / 60)
        timeElapsedSec = timeElapsedTotal % 60

        # Print completion message
        print('   Module Completed in %d min %d sec.' %
              (timeElapsedMin, timeElapsedSec))
        print('\n')

    else:

        # Message to user
        print('Input correct ATL03 input .h5 file and/or output path.')

    # endIf

    # Return object
    return atlMeasuredData, headerData, rotationData