ISCE_INSAR/components/isceobj/ScansarProc/ScansarProc.py

568 lines
20 KiB
Python

#
# Author: Piyush Agram
# Copyright 2018
#
import os
import logging
import logging.config
from iscesys.Component.Component import Component
from iscesys.DateTimeUtil.DateTimeUtil import DateTimeUtil as DTU
from iscesys.Compatibility import Compatibility
MASTER_SLC_PRODUCT = Component.Parameter('masterSlcProduct',
public_name='master slc product',
default='master',
type=str,
mandatory=False,
doc='Directory name of the master SLC product')
SLAVE_SLC_PRODUCT = Component.Parameter('slaveSlcProduct',
public_name='slave slc product',
default='slave',
type=str,
mandatory=False,
doc='Directory name of the slave SLC product')
NUMBER_COMMON_BURSTS = Component.Parameter('numberOfCommonBursts',
public_name = 'number of common bursts',
default = None,
type = int,
container=list,
mandatory = False,
doc = 'Number of common bursts between slave and master')
DEM_FILENAME = Component.Parameter('demFilename',
public_name='dem image name',
default = None,
type = str,
mandatory = False,
doc = 'Name of the dem file')
GEOMETRY_DIRNAME = Component.Parameter('geometryDirname',
public_name='geometry directory name',
default='geom_master',
type=str,
mandatory=False,
doc = 'Geometry directory')
COMMON_RANGE_SPECTRA_SLC_DIRECTORY = Component.Parameter('commonRangeSpectraSlcDirectory',
public_name='equalized slc directory name',
default='commonrangespectra_slc',
type=str,
mandatory=False,
doc='directory with common range spectral slcs')
RANGE_SPECTRA_OVERLAP_THRESHOLD = Component.Parameter('rangeSpectraOverlapThreshold',
public_name='range spectra overlap threshold',
default=3.0e6,
type=float,
mandatory=False,
doc='Minimum range spectra overlap needed')
EQUALIZED_SLC_DIRECTORY = Component.Parameter('equalizedSlcDirectory',
public_name='equalized slc directory',
default='equalized_slc',
type=str,
mandatory=False,
doc='Directory with equalized slcs')
BURST_SYNC_DIRECTORY = Component.Parameter('burstSyncDirectory',
public_name='bursy sync directory',
default='burst_sync',
type=str,
mandatory=False,
doc='Directory with burst sync information')
COARSE_OFFSETS_DIRECTORY = Component.Parameter('coarseOffsetsDirname',
public_name = 'coarse offsets directory name',
default = 'coarse_offsets',
type = str,
mandatory = False,
doc = 'coarse offsets directory name')
COARSE_COREG_DIRECTORY = Component.Parameter('coarseCoregDirname',
public_name = 'coarse coreg directory name',
default = 'coarse_coreg',
type = str,
mandatory = False,
doc = 'coarse coregistered slc directory name')
COARSE_IFG_DIRECTORY = Component.Parameter('coarseIfgDirname',
public_name = 'coarse interferogram directory name',
default = 'coarse_interferogram',
type = str,
mandatory = False,
doc = 'Coarse interferogram directory')
FINE_OFFSETS_DIRECTORY = Component.Parameter('fineOffsetsDirname',
public_name = 'fine offsets directory name',
default = 'fine_offsets',
type = str,
mandatory = False,
doc = 'fine offsets directory name')
FINE_COREG_DIRECTORY = Component.Parameter('fineCoregDirname',
public_name = 'fine coreg directory name',
default = 'fine_coreg',
type = str,
mandatory = False,
doc = 'fine coregistered slc directory name')
FINE_IFG_DIRECTORY = Component.Parameter('fineIfgDirname',
public_name = 'fine interferogram directory name',
default = 'fine_interferogram',
type = str,
mandatory = False,
doc = 'Fine interferogram directory')
MERGED_DIRECTORY = Component.Parameter('mergedDirname',
public_name = 'merged products directory name',
default = 'merged',
type = str,
mandatory = False,
doc = 'Merged product directory')
OVERLAPS_SUBDIRECTORY = Component.Parameter('overlapsSubDirname',
public_name = 'overlaps subdirectory name',
default = 'overlaps',
type = str,
mandatory = False,
doc = 'Overlap region processing directory')
NUMBER_OF_SWATHS = Component.Parameter('numberOfSwaths',
public_name = 'number of swaths',
default=0,
type=int,
mandatory = False,
doc = 'Number of swaths')
MERGED_IFG_NAME = Component.Parameter(
'mergedIfgname',
public_name='merged interferogram name',
default='topophase.flat',
type=str,
mandatory=False,
doc='Filename of the merged interferogram.'
)
MERGED_LOS_NAME = Component.Parameter(
'mergedLosName',
public_name = 'merged los name',
default = 'los.rdr',
type = str,
mandatory = False,
doc = 'Merged los file name')
COHERENCE_FILENAME = Component.Parameter('coherenceFilename',
public_name='coherence name',
default='phsig.cor',
type=str,
mandatory=False,
doc='Coherence file name')
CORRELATION_FILENAME = Component.Parameter('correlationFilename',
public_name='correlation name',
default='topophase.cor',
type=str,
mandatory=False,
doc='Correlation file name')
FILTERED_INT_FILENAME = Component.Parameter('filtFilename',
public_name = 'filtered interferogram name',
default = 'filt_topophase.flat',
type = str,
mandatory = False,
doc = 'Filtered interferogram filename')
UNWRAPPED_INT_FILENAME = Component.Parameter('unwrappedIntFilename',
public_name='unwrapped interferogram filename',
default='filt_topophase.unw',
type=str,
mandatory=False,
doc='')
UNWRAPPED_2STAGE_FILENAME = Component.Parameter('unwrapped2StageFilename',
public_name='unwrapped 2Stage filename',
default='filt_topophase_2stage.unw',
type=str,
mandatory=False,
doc='Output File name of 2Stage unwrapper')
CONNECTED_COMPONENTS_FILENAME = Component.Parameter(
'connectedComponentsFilename',
public_name='connected component filename',
default=None,
type=str,
mandatory=False,
doc=''
)
DEM_CROP_FILENAME = Component.Parameter('demCropFilename',
public_name='dem crop file name',
default='dem.crop',
type=str,
mandatory=False,
doc='')
GEOCODE_LIST = Component.Parameter('geocode_list',
public_name='geocode list',
default=[COHERENCE_FILENAME,
CORRELATION_FILENAME,
UNWRAPPED_INT_FILENAME,
MERGED_LOS_NAME,
MERGED_IFG_NAME,
FILTERED_INT_FILENAME,
UNWRAPPED_2STAGE_FILENAME,
],
container=list,
type=str,
mandatory=False,
doc='List of files to geocode'
)
UNMASKED_PREFIX = Component.Parameter('unmaskedPrefix',
public_name='unmasked filename prefix',
default='unmasked',
type=str,
mandatory=False,
doc='Prefix prepended to the image filenames that have not been water masked')
####Adding things from topsOffsetApp for integration
OFFSET_TOP = Component.Parameter(
'offset_top',
public_name='Top offset location',
default=None,
type=int,
mandatory=False,
doc='Ampcor-calculated top offset location. Overridden by workflow.'
)
OFFSET_LEFT = Component.Parameter(
'offset_left',
public_name='Left offset location',
default=None,
type=int,
mandatory=False,
doc='Ampcor-calculated left offset location. Overridden by workflow.'
)
OFFSET_WIDTH = Component.Parameter(
'offset_width',
public_name='Offset image nCols',
default=None,
type=int,
mandatory=False,
doc='Number of columns in the final offset field (calculated in DenseAmpcor).'
)
OFFSET_LENGTH = Component.Parameter(
'offset_length',
public_name='Offset image nRows',
default=None,
type=int,
mandatory=False,
doc='Number of rows in the final offset field (calculated in DenseAmpcor).'
)
OFFSET_OUTPUT_FILE = Component.Parameter(
'offsetfile',
public_name='Offset filename',
default='dense_offsets.bil',
type=str,
mandatory=False,
doc='Filename for gross dense offsets BIL. Used in runDenseOffsets.'
)
OFFSET_SNR_FILE = Component.Parameter(
'snrfile',
public_name='Offset SNR filename',
default='dense_offsets_snr.bil',
type=str,
mandatory=False,
doc='Filename for gross dense offsets SNR. Used in runDenseOffsets.')
FILT_OFFSET_OUTPUT_FILE = Component.Parameter(
'filt_offsetfile',
public_name='Filtered offset filename',
default='filt_dense_offsets.bil',
type=str,
mandatory=False,
doc='Filename for filtered dense offsets BIL.'
)
OFFSET_GEOCODE_LIST = Component.Parameter('off_geocode_list',
public_name='offset geocode list',
default = [OFFSET_OUTPUT_FILE,
OFFSET_SNR_FILE,
FILT_OFFSET_OUTPUT_FILE],
container = list,
type=str,
mandatory=False,
doc = 'List of files on offset grid to geocode')
class ScansarProc(Component):
"""
This class holds the properties, along with methods (setters and getters)
to modify and return their values.
"""
parameter_list = (MASTER_SLC_PRODUCT,
SLAVE_SLC_PRODUCT,
DEM_FILENAME,
GEOMETRY_DIRNAME,
COMMON_RANGE_SPECTRA_SLC_DIRECTORY,
RANGE_SPECTRA_OVERLAP_THRESHOLD,
EQUALIZED_SLC_DIRECTORY,
BURST_SYNC_DIRECTORY,
COARSE_OFFSETS_DIRECTORY,
COARSE_COREG_DIRECTORY,
COARSE_IFG_DIRECTORY,
FINE_OFFSETS_DIRECTORY,
FINE_COREG_DIRECTORY,
FINE_IFG_DIRECTORY,
OVERLAPS_SUBDIRECTORY,
MERGED_DIRECTORY,
MERGED_IFG_NAME,
MERGED_LOS_NAME,
COHERENCE_FILENAME,
FILTERED_INT_FILENAME,
UNWRAPPED_INT_FILENAME,
UNWRAPPED_2STAGE_FILENAME,
CONNECTED_COMPONENTS_FILENAME,
DEM_CROP_FILENAME,
GEOCODE_LIST,
UNMASKED_PREFIX,
CORRELATION_FILENAME,
OFFSET_TOP,
OFFSET_LEFT,
OFFSET_LENGTH,
OFFSET_WIDTH,
OFFSET_OUTPUT_FILE,
OFFSET_SNR_FILE,
FILT_OFFSET_OUTPUT_FILE,
OFFSET_GEOCODE_LIST)
facility_list = ()
family='scansarcontext'
def __init__(self, name='', procDoc=None):
#self.updatePrivate()
super().__init__(family=self.__class__.family, name=name)
self.procDoc = procDoc
return None
def _init(self):
"""
Method called after Parameters are configured.
Determine whether some Parameters still have unresolved
Parameters as their default values and resolve them.
"""
#Determine whether the geocode_list still contains Parameters
#and give those elements the proper value. This will happen
#whenever the user doesn't provide as input a geocode_list for
#this component.
mergedir = self.mergedDirname
for i, x in enumerate(self.geocode_list):
if isinstance(x, Component.Parameter):
y = getattr(self, getattr(x, 'attrname'))
self.geocode_list[i] = os.path.join(mergedir, y)
for i,x in enumerate(self.off_geocode_list):
if isinstance(x, Component.Parameter):
y = getattr(self, getattr(x, 'attrname'))
self.off_geocode_list[i] = os.path.join(mergedir, y)
return
def loadProduct(self, xmlname):
'''
Load the product using Product Manager.
'''
from iscesys.Component.ProductManager import ProductManager as PM
pm = PM()
pm.configure()
obj = pm.loadProduct(xmlname)
return obj
def saveProduct(self, obj, xmlname):
'''
Save the product to an XML file using Product Manager.
'''
from iscesys.Component.ProductManager import ProductManager as PM
pm = PM()
pm.configure()
pm.dumpProduct(obj, xmlname)
return None
def getMergedOrbit(self, products):
from isceobj.Orbit.Orbit import Orbit
###Create merged orbit
orb = Orbit()
orb.configure()
burst = product[0]
#Add first burst orbit to begin with
for sv in burst.orbit:
orb.addStateVector(sv)
for pp in product:
##Add all state vectors
for sv in pp.orbit:
if (sv.time< orb.minTime) or (sv.time > orb.maxTime):
orb.addStateVector(sv)
pp.orbit = orb
return orb
def getInputSwathList(self, inlist):
'''
To be used to get list of swaths that user wants us to process.
'''
if len(inlist) == 0:
return [x+1 for x in range(self.numberOfSwaths)]
else:
return inlist
def getValidSwathList(self, inlist):
'''
Used to get list of swaths left after applying all filters - e.g, region of interest.
'''
import glob
inswaths = glob.glob( os.path.join(self.masterSlcProduct, 's*.xml'))
swaths = []
for x in inswaths:
swaths.append( int(os.path.splitext(os.path.basename(x))[0][-1]))
return sorted(swaths)
def hasGPU(self):
'''
Determine if GPU modules are available.
'''
flag = False
try:
from zerodop.GPUtopozero.GPUtopozero import PyTopozero
from zerodop.GPUgeo2rdr.GPUgeo2rdr import PyGeo2rdr
flag = True
except:
pass
return flag
def getOverlapFrequency(self, centerfreq1, bandwidth1,
centerfreq2, bandwidth2):
startfreq1 = centerfreq1 - bandwidth1 / 2.0
endingfreq1 = centerfreq1 + bandwidth1 / 2.0
startfreq2 = centerfreq2 - bandwidth2 / 2.0
endingfreq2 = centerfreq2 + bandwidth2 / 2.0
overlapfreq = []
if startfreq2 <= startfreq1 <= endingfreq2:
overlapfreq.append(startfreq1)
if startfreq2 <= endingfreq1 <= endingfreq2:
overlapfreq.append(endingfreq1)
if startfreq1 < startfreq2 < endingfreq1:
overlapfreq.append(startfreq2)
if startfreq1 < endingfreq2 < endingfreq1:
overlapfreq.append(endingfreq2)
if len(overlapfreq) != 2:
#no overlap bandwidth
return None
else:
startfreq = min(overlapfreq)
endingfreq = max(overlapfreq)
return [startfreq, endingfreq]
@property
def commonRangeSpectraMasterSlcProduct(self):
infile = self.masterSlcProduct
if infile[-1] == os.path.sep:
infile = infile[:-1]
base = os.path.sep.join( infile.split(os.path.sep)[-2:])
return os.path.join( self.commonRangeSpectraSlcDirectory, base)
@property
def commonRangeSpectraSlaveSlcProduct(self):
infile = self.slaveSlcProduct
if infile[-1] == os.path.sep:
infile = infile[:-1]
base = os.path.sep.join( infile.split(os.path.sep)[-2:])
return os.path.join( self.commonRangeSpectraSlcDirectory, base)
@property
def equalizedMasterSlcProduct(self):
infile = self.masterSlcProduct
if infile[-1] == os.path.sep:
infile = infile[:-1]
base = os.path.sep.join(infile.split(os.path.sep)[-2:])
return os.path.join( self.equalizedSlcDirectory, base)
@property
def equalizedSlaveSlcProduct(self):
infile = self.slaveSlcProduct
if infile[-1] == os.path.sep:
infile = infile[:-1]
base = os.path.sep.join(infile.split(os.path.sep)[-2:])
return os.path.join( self.equalizedSlcDirectory, base)
def writeBurstSyncFile(self, outfile, rgoff, azoff,
nb, nc,
unsynLines, synLines):
with open(outfile, 'w') as fid:
fid.write('image pair range offset: {0}\n'.format(rgoff))
fid.write('image pair azimuth offset: {0}\n'.format(azoff))
fid.write('number of lines in a burst: {0}\n'.format(nb))
fid.write('number of lines in a burst cycle: {0}\n'.format(nc))
fid.write('number of unsynchronized lines in a burst: {0}\n'.format(unsynLines))
fid.write('burst synchronization: {0}%'.format((synLines/nb)*100.0))