def get_atl03_classification(atl03filepath, atl08filepath, df, gt): # Read ATL03 metrics for class mapping atl03_ph_index_beg, atl03_segment_id = \ readAtl03DataMapping(atl03filepath,gt) # Read ATL08 for class mapping atl08_classed_pc_indx, atl08_classed_pc_flag, atl08_segment_id = \ readAtl08DataMapping(atl08filepath, gt) # Map ATL08 classifications to ATL03 Photons allph_classed = getAtl08Mapping(atl03_ph_index_beg, atl03_segment_id, atl08_classed_pc_indx, atl08_classed_pc_flag, atl08_segment_id) # Add classifications to ATL03 DF df = pd.concat( [df, pd.DataFrame(allph_classed, columns=['classification'])], axis=1) # Replace nan with -1 (unclassified) df.replace({'classification': np.nan}, -1) return df
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
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