2019-01-16 19:40:08 +00:00
#
# Author: Cunren Liang
# Copyright 2018
# California Institute of Technology
#
import os
import shutil
import datetime
import numpy as np
import numpy . matlib
import isceobj
import logging
from isceobj . Constants import SPEED_OF_LIGHT
from isceobj . TopsProc . runBurstIfg import loadVirtualArray
2021-08-09 20:31:40 +00:00
from isceobj . Alos2Proc . runIonFilt import reformatMaskedAreas
2019-01-16 19:40:08 +00:00
logger = logging . getLogger ( ' isce.topsinsar.ion ' )
#should get rid of the coherence thresholds in the future
##WARNING: when using the original full-bandwidth swath xml file, should also consider burst.image.filename
class dummy ( object ) :
pass
def setup ( self ) :
'''
setup parameters for processing
'''
#initialize parameters for ionospheric correction
ionParam = dummy ( )
#The step names in the list below are exactly the function names in 'def runIon(self):'
#when adding a new step, only put its function name (in right order) in the list,
#and put the function (in right order) in 'def runIon(self):'
ionParam . allSteps = [ ' subband ' , ' rawion ' , ' grd2ion ' , ' filt_gaussian ' , ' ionosphere_shift ' , ' ion2grd ' , ' esd ' ]
###################################################################
#users are supposed to change parameters of this section ONLY
#SECTION 1. PROCESSING CONTROL PARAMETERS
#1. suggested default values of the parameters
ionParam . doIon = False
2020-10-20 02:49:28 +00:00
ionParam . considerBurstProperties = False
2019-01-16 19:40:08 +00:00
ionParam . startStep = ionParam . allSteps [ 0 ]
ionParam . endStep = ionParam . allSteps [ - 1 ]
#ionospheric layer height (km)
ionParam . ionHeight = 200.0
#before filtering ionosphere, if applying polynomial fitting
#False: no fitting
#True: with fitting
ionParam . ionFit = True
#window size for filtering ionosphere
ionParam . ionFilteringWinsizeMax = 200
ionParam . ionFilteringWinsizeMin = 100
#window size for filtering azimuth shift caused by ionosphere
ionParam . ionshiftFilteringWinsizeMax = 150
ionParam . ionshiftFilteringWinsizeMin = 75
#correct phase error caused by non-zero center frequency and azimuth shift caused by ionosphere
#0: no correction
#1: use mean value of a burst
#2: use full burst
ionParam . azshiftFlag = 1
#better NOT try changing the following two parameters, since they are related
#to the filtering parameters above
#number of azimuth looks in the processing of ionosphere estimation
ionParam . numberAzimuthLooks = 50
#number of range looks in the processing of ionosphere estimation
ionParam . numberRangeLooks = 200
#number of azimuth looks of the interferogram to be unwrapped
ionParam . numberAzimuthLooks0 = 5 * 2
#number of range looks of the interferogram to be unwrapped
ionParam . numberRangeLooks0 = 20 * 2
#2. accept the above parameters from topsApp.py
ionParam . doIon = self . ION_doIon
2020-10-20 02:49:28 +00:00
ionParam . considerBurstProperties = self . ION_considerBurstProperties
2019-01-16 19:40:08 +00:00
ionParam . startStep = self . ION_startStep
ionParam . endStep = self . ION_endStep
ionParam . ionHeight = self . ION_ionHeight
ionParam . ionFit = self . ION_ionFit
ionParam . ionFilteringWinsizeMax = self . ION_ionFilteringWinsizeMax
ionParam . ionFilteringWinsizeMin = self . ION_ionFilteringWinsizeMin
ionParam . ionshiftFilteringWinsizeMax = self . ION_ionshiftFilteringWinsizeMax
ionParam . ionshiftFilteringWinsizeMin = self . ION_ionshiftFilteringWinsizeMin
ionParam . azshiftFlag = self . ION_azshiftFlag
2021-08-09 20:31:40 +00:00
ionParam . maskedAreas = self . ION_maskedAreas
2019-01-16 19:40:08 +00:00
ionParam . numberAzimuthLooks = self . ION_numberAzimuthLooks
ionParam . numberRangeLooks = self . ION_numberRangeLooks
ionParam . numberAzimuthLooks0 = self . ION_numberAzimuthLooks0
ionParam . numberRangeLooks0 = self . ION_numberRangeLooks0
#3. check parameters
#convert to m
ionParam . ionHeight * = 1000.0
#check number of looks
if not ( ( ionParam . numberAzimuthLooks % ionParam . numberAzimuthLooks0 == 0 ) and \
( 1 < = ionParam . numberAzimuthLooks0 < = ionParam . numberAzimuthLooks ) ) :
raise Exception ( ' numberAzimuthLooks must be integer multiples of numberAzimuthLooks0 ' )
if not ( ( ionParam . numberRangeLooks % ionParam . numberRangeLooks0 == 0 ) and \
( 1 < = ionParam . numberRangeLooks0 < = ionParam . numberRangeLooks ) ) :
raise Exception ( ' numberRangeLooks must be integer multiples of numberRangeLooks0 ' )
#check steps for ionospheric correction
if ionParam . startStep not in ionParam . allSteps :
print ( ' all steps for ionospheric correction in order: {} ' . format ( ionParam . allSteps ) )
raise Exception ( ' please specify the correct start step for ionospheric correction from above list ' )
if ionParam . endStep not in ionParam . allSteps :
print ( ' all steps for ionospheric correction in order: {} ' . format ( ionParam . allSteps ) )
raise Exception ( ' please specify the correct start step for ionospheric correction from above list ' )
if ionParam . allSteps . index ( ionParam . startStep ) > ionParam . allSteps . index ( ionParam . endStep ) :
print ( ' correct relationship: start step <= end step ' )
raise Exception ( ' error: start step is after end step. ' )
###################################################################
###################################################################
#routines that require setting parameters
#def ionosphere(self, ionParam):
#def ionSwathBySwath(self, ionParam):
#def filt_gaussian(self, ionParam):
#def ionosphere_shift(self, ionParam):
#def ion2grd(self, ionParam):
#def esd(self, ionParam):
###################################################################
#SECTION 2. DIRECTORIES AND FILENAMES
#directories
ionParam . ionDirname = ' ion '
ionParam . lowerDirname = ' lower '
ionParam . upperDirname = ' upper '
ionParam . ioncalDirname = ' ion_cal '
ionParam . ionBurstDirname = ' ion_burst '
#these are same directory names as topsApp.py/TopsProc.py
2020-07-02 19:40:49 +00:00
#ionParam.referenceSlcProduct = 'reference'
#ionParam.secondarySlcProduct = 'secondary'
2019-01-16 19:40:08 +00:00
#ionParam.fineCoregDirname = 'fine_coreg'
ionParam . fineIfgDirname = ' fine_interferogram '
ionParam . mergedDirname = ' merged '
#filenames
ionParam . ionRawNoProj = ' raw_no_projection.ion '
ionParam . ionCorNoProj = ' raw_no_projection.cor '
ionParam . ionRaw = ' raw.ion '
ionParam . ionCor = ' raw.cor '
ionParam . ionFilt = ' filt.ion '
ionParam . ionShift = ' azshift.ion '
ionParam . warning = ' warning.txt '
#SECTION 3. DATA PARAMETERS
#earth's radius (m)
ionParam . earthRadius = 6371 * 1000.0
#reference range (m) for moving range center frequency to zero, center of center swath
ionParam . rgRef = 875714.0
#range bandwidth (Hz) for splitting, range processingBandwidth: [5.650000000000000e+07, 4.830000000000000e+07, 4.278991840322842e+07]
ionParam . rgBandwidthForSplit = 40.0 * 10 * * 6
ionParam . rgBandwidthSub = ionParam . rgBandwidthForSplit / 3.0
#SECTION 4. DEFINE WAVELENGTHS AND DETERMINE IF CALCULATE IONOSPHERE WITH MERGED INTERFEROGRAM
getParamFromData = False
2020-07-02 19:40:49 +00:00
referenceStartingRange = np . zeros ( 3 )
secondaryStartingRange = np . zeros ( 3 )
2019-01-16 19:40:08 +00:00
swathList = self . _insar . getValidSwathList ( self . swaths )
for swath in swathList :
2020-07-02 19:40:49 +00:00
####Load secondary metadata
reference = self . _insar . loadProduct ( os . path . join ( self . _insar . referenceSlcProduct , ' IW {0} .xml ' . format ( swath ) ) )
secondary = self . _insar . loadProduct ( os . path . join ( self . _insar . secondarySlcProduct , ' IW {0} .xml ' . format ( swath ) ) )
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
####Indices w.r.t reference
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
secondaryBurstStart , secondaryBurstEnd = self . _insar . commonSecondaryBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
if minBurst == maxBurst :
#print('Skipping processing of swath {0}'.format(swath))
continue
else :
ii = minBurst
2020-07-02 19:40:49 +00:00
jj = secondaryBurstStart + ii - minBurst
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
masBurst = reference . bursts [ ii ]
slvBurst = secondary . bursts [ jj ]
2019-01-16 19:40:08 +00:00
#use the 1/3, 1/3, 1/3 scheme for splitting
ionParam . radarWavelength = masBurst . radarWavelength
ionParam . radarWavelengthLower = SPEED_OF_LIGHT / ( SPEED_OF_LIGHT / ionParam . radarWavelength - ionParam . rgBandwidthForSplit / 3.0 )
ionParam . radarWavelengthUpper = SPEED_OF_LIGHT / ( SPEED_OF_LIGHT / ionParam . radarWavelength + ionParam . rgBandwidthForSplit / 3.0 )
#use this to determine which polynomial to use to calculate a ramp when calculating ionosphere for cross A/B interferogram
ionParam . passDirection = masBurst . passDirection . lower ( )
2020-07-02 19:40:49 +00:00
referenceStartingRange [ swath - 1 ] = masBurst . startingRange
secondaryStartingRange [ swath - 1 ] = slvBurst . startingRange
2019-01-16 19:40:08 +00:00
getParamFromData = True
#determine if calculate ionosphere using merged interferogram
2020-07-02 19:40:49 +00:00
if np . sum ( referenceStartingRange == secondaryStartingRange ) != 3 :
2019-01-16 19:40:08 +00:00
ionParam . calIonWithMerged = False
else :
ionParam . calIonWithMerged = True
2020-08-03 21:09:22 +00:00
#for cross Sentinel-1A/B interferogram, always not using merged interferogram
if reference . mission != secondary . mission :
ionParam . calIonWithMerged = False
2019-01-16 19:40:08 +00:00
#there is no need to process swath by swath when there is only one swath
#ionSwathBySwath only works when number of swaths >=2
if len ( swathList ) == 1 :
ionParam . calIonWithMerged = True
#determine if remove an empirical ramp
2020-07-02 19:40:49 +00:00
if reference . mission == secondary . mission :
2019-01-16 19:40:08 +00:00
ionParam . rampRemovel = 0
else :
#estimating ionospheric phase for cross Sentinel-1A/B interferogram
#an empirical ramp will be removed from the estimated ionospheric phase
2020-07-02 19:40:49 +00:00
if reference . mission == ' S1A ' and secondary . mission == ' S1B ' :
2019-01-16 19:40:08 +00:00
ionParam . rampRemovel = 1
else :
ionParam . rampRemovel = - 1
if getParamFromData == False :
raise Exception ( ' cannot get parameters from data ' )
return ionParam
def next_pow2 ( a ) :
x = 2
while x < a :
x * = 2
return x
def removeHammingWindow ( inputfile , outputfile , bandwidth , samplingRate , alpha , virtual = True ) :
'''
This function removes the range Hamming window imposed on the signal
bandwidth : range bandwidth
samplingRate : range sampling rate
alpha : alpha of the Hamming window
'''
#(length, width) = slc.shape
inImg = isceobj . createSlcImage ( )
inImg . load ( inputfile + ' .xml ' )
width = inImg . getWidth ( )
length = inImg . getLength ( )
if not virtual :
slc = np . memmap ( inputfile , dtype = np . complex64 , mode = ' r ' , shape = ( length , width ) )
else :
slc = loadVirtualArray ( inputfile + ' .vrt ' )
#fft length
nfft = next_pow2 ( width )
#Hamming window length
nwin = np . int ( np . around ( bandwidth / samplingRate * nfft ) )
#make it a even number, since we are going to use even fft length
nwin = ( ( nwin + 1 ) / / 2 ) * 2
#the starting and ending index of window in the spectrum
start = np . int ( np . around ( ( nfft - nwin ) / 2 ) )
end = np . int ( np . around ( start + nwin - 1 ) )
hammingWindow = alpha - ( 1.0 - alpha ) * np . cos ( np . linspace ( - np . pi , np . pi , num = nwin , endpoint = True ) )
hammingWindow = 1.0 / np . fft . fftshift ( hammingWindow )
spec = np . fft . fft ( slc , n = nfft , axis = 1 )
spec = np . fft . fftshift ( spec , axes = 1 )
spec [ : , start : end + 1 ] * = hammingWindow [ None , : ]
spec = np . fft . fftshift ( spec , axes = 1 )
spec = np . fft . ifft ( spec , n = nfft , axis = 1 )
slcd = spec [ : , 0 : width ] * ( ( slc . real != 0 ) | ( slc . imag != 0 ) )
#after these fft and ifft, the values are not scaled by constant.
slcd . astype ( np . complex64 ) . tofile ( outputfile )
inImg . setFilename ( outputfile )
inImg . extraFilename = outputfile + ' .vrt '
inImg . setAccessMode ( ' READ ' )
inImg . renderHdr ( )
return slcd
def runCmd ( cmd , silent = 0 ) :
if silent == 0 :
print ( " {} " . format ( cmd ) )
status = os . system ( cmd )
if status != 0 :
raise Exception ( ' error when running: \n {} \n ' . format ( cmd ) )
2020-07-02 19:40:49 +00:00
def adjustValidLineSample ( reference , secondary ) :
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
reference_lastValidLine = reference . firstValidLine + reference . numValidLines - 1
reference_lastValidSample = reference . firstValidSample + reference . numValidSamples - 1
secondary_lastValidLine = secondary . firstValidLine + secondary . numValidLines - 1
secondary_lastValidSample = secondary . firstValidSample + secondary . numValidSamples - 1
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
igram_lastValidLine = min ( reference_lastValidLine , secondary_lastValidLine )
igram_lastValidSample = min ( reference_lastValidSample , secondary_lastValidSample )
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
reference . firstValidLine = max ( reference . firstValidLine , secondary . firstValidLine )
reference . firstValidSample = max ( reference . firstValidSample , secondary . firstValidSample )
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
reference . numValidLines = igram_lastValidLine - reference . firstValidLine + 1
reference . numValidSamples = igram_lastValidSample - reference . firstValidSample + 1
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
def multiply2 ( referencename , secondaryname , fact , rngname = None , ionname = None , infname = None , overlapBox = None , valid = True , virtual = True ) :
2019-01-16 19:40:08 +00:00
'''
This routine forms interferogram and possibly removes topographic and ionospheric phases .
all the following indexes start from 1
overlapBox [ 0 ] : first line
overlapBox [ 1 ] : last line
overlapBox [ 2 ] : first sample
overlapBox [ 3 ] : last sample
'''
2020-07-02 19:40:49 +00:00
#use reference image
2019-01-16 19:40:08 +00:00
img = isceobj . createSlcImage ( )
2020-07-02 19:40:49 +00:00
img . load ( referencename + ' .xml ' )
2019-01-16 19:40:08 +00:00
width = img . getWidth ( )
length = img . getLength ( )
2020-07-02 19:40:49 +00:00
#reference
2019-01-16 19:40:08 +00:00
if not virtual :
2020-07-02 19:40:49 +00:00
reference = np . memmap ( referencename , dtype = np . complex64 , mode = ' r ' , shape = ( length , width ) )
2019-01-16 19:40:08 +00:00
else :
2020-07-02 19:40:49 +00:00
reference = loadVirtualArray ( referencename + ' .vrt ' )
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
#secondary
secondary = np . memmap ( secondaryname , dtype = np . complex64 , mode = ' r ' , shape = ( length , width ) )
2019-01-16 19:40:08 +00:00
#interferogram
cJ = np . complex64 ( - 1 j )
2020-07-02 19:40:49 +00:00
inf = reference [ overlapBox [ 0 ] - 1 : overlapBox [ 1 ] - 1 + 1 , overlapBox [ 2 ] - 1 : overlapBox [ 3 ] - 1 + 1 ] \
* np . conj ( secondary [ overlapBox [ 0 ] - 1 : overlapBox [ 1 ] - 1 + 1 , overlapBox [ 2 ] - 1 : overlapBox [ 3 ] - 1 + 1 ] )
2019-01-16 19:40:08 +00:00
#topography
if rngname != None :
rng2 = np . memmap ( rngname , dtype = np . float32 , mode = ' r ' , shape = ( length , width ) )
inf * = np . exp ( cJ * fact * rng2 [ overlapBox [ 0 ] - 1 : overlapBox [ 1 ] - 1 + 1 , overlapBox [ 2 ] - 1 : overlapBox [ 3 ] - 1 + 1 ] )
#ionosphere
if ionname != None :
ion = np . memmap ( ionname , dtype = np . float32 , mode = ' r ' , shape = ( length , width ) )
inf * = np . exp ( cJ * ion [ overlapBox [ 0 ] - 1 : overlapBox [ 1 ] - 1 + 1 , overlapBox [ 2 ] - 1 : overlapBox [ 3 ] - 1 + 1 ] )
if valid == True :
inf2 = inf
else :
inf2 = np . zeros ( ( length , width ) , dtype = np . complex64 )
inf2 [ overlapBox [ 0 ] - 1 : overlapBox [ 1 ] - 1 + 1 , overlapBox [ 2 ] - 1 : overlapBox [ 3 ] - 1 + 1 ] = inf
2020-07-02 19:40:49 +00:00
#inf = reference[overlapBox[0]-1:overlapBox[1]-1+1, overlapBox[2]-1:overlapBox[3]-1+1] \
# * np.conj(secondary[overlapBox[0]-1:overlapBox[1]-1+1, overlapBox[2]-1:overlapBox[3]-1+1]) \
2019-01-16 19:40:08 +00:00
# * np.exp(cJ*ion[overlapBox[0]-1:overlapBox[1]-1+1, overlapBox[2]-1:overlapBox[3]-1+1]) \
# * np.exp(cJ*fact*rng2[overlapBox[0]-1:overlapBox[1]-1+1, overlapBox[2]-1:overlapBox[3]-1+1])
if infname != None :
inf2 . astype ( np . complex64 ) . tofile ( infname )
img = isceobj . createIntImage ( )
img . setFilename ( infname )
img . extraFilename = infname + ' .vrt '
if valid == True :
img . setWidth ( overlapBox [ 3 ] - overlapBox [ 2 ] + 1 )
img . setLength ( overlapBox [ 1 ] - overlapBox [ 0 ] + 1 )
else :
img . setWidth ( width )
img . setLength ( length )
img . setAccessMode ( ' READ ' )
img . renderHdr ( )
return inf2
def subband ( self , ionParam ) :
'''
generate subband images
'''
from isceobj . Sensor . TOPS import createTOPSSwathSLCProduct
from isceobj . Util . Poly2D import Poly2D
from contrib . alos2proc . alos2proc import rg_filter
2020-07-02 19:40:49 +00:00
from isceobj . TopsProc . runFineResamp import resampSecondary
2019-01-16 19:40:08 +00:00
from isceobj . TopsProc . runFineResamp import getRelativeShifts
from isceobj . TopsProc . runFineResamp import adjustValidSampleLine
from isceobj . TopsProc . runFineResamp import getValidLines
#from isceobj.TopsProc.runBurstIfg import adjustValidLineSample
print ( ' processing subband burst interferograms ' )
virtual = self . useVirtualFiles
swathList = self . _insar . getValidSwathList ( self . swaths )
for swath in swathList :
2020-07-02 19:40:49 +00:00
####Load secondary metadata
reference = self . _insar . loadProduct ( os . path . join ( self . _insar . referenceSlcProduct , ' IW {0} .xml ' . format ( swath ) ) )
secondary = self . _insar . loadProduct ( os . path . join ( self . _insar . secondarySlcProduct , ' IW {0} .xml ' . format ( swath ) ) )
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
dt = secondary . bursts [ 0 ] . azimuthTimeInterval
dr = secondary . bursts [ 0 ] . rangePixelSize
2019-01-16 19:40:08 +00:00
###Directory with offsets
offdir = os . path . join ( self . _insar . fineOffsetsDirname , ' IW {0} ' . format ( swath ) )
2020-07-02 19:40:49 +00:00
####Indices w.r.t reference
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
secondaryBurstStart , secondaryBurstEnd = self . _insar . commonSecondaryBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
if minBurst == maxBurst :
print ( ' Skipping processing of swath {0} ' . format ( swath ) )
continue
#create dirs
lowerDir = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . fineIfgDirname , ' IW {0} ' . format ( swath ) )
upperDir = os . path . join ( ionParam . ionDirname , ionParam . upperDirname , ionParam . fineIfgDirname , ' IW {0} ' . format ( swath ) )
2020-04-13 19:40:32 +00:00
os . makedirs ( lowerDir , exist_ok = True )
os . makedirs ( upperDir , exist_ok = True )
2019-01-16 19:40:08 +00:00
##############################################################
#for resampling
2020-07-02 19:40:49 +00:00
relShifts = getRelativeShifts ( reference , secondary , minBurst , maxBurst , secondaryBurstStart )
2019-01-16 19:40:08 +00:00
print ( ' Shifts IW- {0} : ' . format ( swath ) , relShifts )
####Can corporate known misregistration here
apoly = Poly2D ( )
apoly . initPoly ( rangeOrder = 0 , azimuthOrder = 0 , coeffs = [ [ 0. ] ] )
rpoly = Poly2D ( )
rpoly . initPoly ( rangeOrder = 0 , azimuthOrder = 0 , coeffs = [ [ 0. ] ] )
2020-07-02 19:40:49 +00:00
misreg_az = self . _insar . secondaryTimingCorrection / dt
misreg_rg = self . _insar . secondaryRangeCorrection / dr
2019-01-16 19:40:08 +00:00
##############################################################
fineIfgLower = createTOPSSwathSLCProduct ( )
fineIfgLower . configure ( )
fineIfgUpper = createTOPSSwathSLCProduct ( )
fineIfgUpper . configure ( )
#only process common bursts
for ii in range ( minBurst , maxBurst ) :
2020-07-02 19:40:49 +00:00
jj = secondaryBurstStart + ii - minBurst
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
masBurst = reference . bursts [ ii ]
slvBurst = secondary . bursts [ jj ]
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
print ( ' processing reference burst: %02d , secondary burst: %02d , swath: %d ' % ( ii + 1 , jj + 1 , swath ) )
2019-01-16 19:40:08 +00:00
################################################################
#1. removing window and subband
2020-07-02 19:40:49 +00:00
for ms in [ ' reference ' , ' secondary ' ] :
2019-01-16 19:40:08 +00:00
#setup something
2020-07-02 19:40:49 +00:00
if ms == ' reference ' :
2019-01-16 19:40:08 +00:00
burst = masBurst
#put the temporary file in the lower directory
2020-07-02 19:40:49 +00:00
tmpFilename = os . path . join ( lowerDir , ' reference_dw_ ' + os . path . basename ( burst . image . filename ) )
tmpFilename2 = ' reference_ ' + os . path . basename ( burst . image . filename )
2019-01-16 19:40:08 +00:00
else :
burst = slvBurst
#put the temporary file in the lower directory
2020-07-02 19:40:49 +00:00
tmpFilename = os . path . join ( lowerDir , ' secondary_dw_ ' + os . path . basename ( burst . image . filename ) )
tmpFilename2 = ' secondary_ ' + os . path . basename ( burst . image . filename )
2019-01-16 19:40:08 +00:00
#removing window
rangeSamplingRate = SPEED_OF_LIGHT / ( 2.0 * burst . rangePixelSize )
if burst . rangeWindowType == ' Hamming ' :
removeHammingWindow ( burst . image . filename , tmpFilename , burst . rangeProcessingBandwidth , rangeSamplingRate , burst . rangeWindowCoefficient , virtual = virtual )
else :
raise Exception ( ' Range weight window type: {} is not supported yet! ' . format ( burst . rangeWindowType ) )
#subband
rg_filter ( tmpFilename ,
2020-03-29 02:19:21 +00:00
#burst.numberOfSamples,
2019-01-16 19:40:08 +00:00
2 ,
[ os . path . join ( lowerDir , tmpFilename2 ) , os . path . join ( upperDir , tmpFilename2 ) ] ,
[ ionParam . rgBandwidthSub / rangeSamplingRate , ionParam . rgBandwidthSub / rangeSamplingRate ] ,
[ - ionParam . rgBandwidthForSplit / 3.0 / rangeSamplingRate , ionParam . rgBandwidthForSplit / 3.0 / rangeSamplingRate ] ,
129 ,
512 ,
0.1 ,
0 ,
( burst . startingRange - ionParam . rgRef ) / burst . rangePixelSize
)
#remove temporary file
os . remove ( tmpFilename )
os . remove ( tmpFilename + ' .xml ' )
os . remove ( tmpFilename + ' .vrt ' )
#2. resampling and form interferogram
#resampling
try :
offset = relShifts [ jj ]
except :
2020-07-02 19:40:49 +00:00
raise Exception ( ' Trying to access shift for secondary burst index {0} , which may not overlap with reference for swath {1} ' . format ( jj , swath ) )
2019-01-16 19:40:08 +00:00
####Setup initial polynomials
### If no misregs are given, these are zero
### If provided, can be used for resampling without running to geo2rdr again for fast results
rdict = { ' azpoly ' : apoly ,
' rgpoly ' : rpoly ,
' rangeOff ' : os . path . join ( offdir , ' range_ %02d .off ' % ( ii + 1 ) ) ,
' azimuthOff ' : os . path . join ( offdir , ' azimuth_ %02d .off ' % ( ii + 1 ) ) }
###For future - should account for azimuth and range misreg here .. ignoring for now.
2020-07-02 19:40:49 +00:00
azCarrPoly , dpoly = secondary . estimateAzimuthCarrierPolynomials ( slvBurst , offset = - 1.0 * offset )
2019-01-16 19:40:08 +00:00
rdict [ ' carrPoly ' ] = azCarrPoly
rdict [ ' doppPoly ' ] = dpoly
for lu in [ ' lower ' , ' upper ' ] :
masBurst2 = masBurst . clone ( )
slvBurst2 = slvBurst . clone ( )
slvBurstResamp2 = masBurst . clone ( )
if lu == ' lower ' :
masBurst2 . radarWavelength = ionParam . radarWavelengthLower
masBurst2 . rangeProcessingBandwidth = ionParam . rgBandwidthSub
2020-07-02 19:40:49 +00:00
masBurst2 . image . filename = os . path . join ( lowerDir , ' reference_ ' + os . path . basename ( masBurst . image . filename ) )
2019-01-16 19:40:08 +00:00
slvBurst2 . radarWavelength = ionParam . radarWavelengthLower
slvBurst2 . rangeProcessingBandwidth = ionParam . rgBandwidthSub
2020-07-02 19:40:49 +00:00
slvBurst2 . image . filename = os . path . join ( lowerDir , ' secondary_ ' + os . path . basename ( slvBurst . image . filename ) )
2019-01-16 19:40:08 +00:00
slvBurstResamp2 . radarWavelength = ionParam . radarWavelengthLower
slvBurstResamp2 . rangeProcessingBandwidth = ionParam . rgBandwidthSub
2020-07-02 19:40:49 +00:00
slvBurstResamp2 . image . filename = os . path . join ( lowerDir , ' reference_ ' + os . path . basename ( masBurst . image . filename ) )
outname = os . path . join ( lowerDir , ' secondary_resamp_ ' + os . path . basename ( slvBurst . image . filename ) )
2019-01-16 19:40:08 +00:00
ifgdir = lowerDir
else :
masBurst2 . radarWavelength = ionParam . radarWavelengthUpper
masBurst2 . rangeProcessingBandwidth = ionParam . rgBandwidthSub
2020-07-02 19:40:49 +00:00
masBurst2 . image . filename = os . path . join ( upperDir , ' reference_ ' + os . path . basename ( masBurst . image . filename ) )
2019-01-16 19:40:08 +00:00
slvBurst2 . radarWavelength = ionParam . radarWavelengthUpper
slvBurst2 . rangeProcessingBandwidth = ionParam . rgBandwidthSub
2020-07-02 19:40:49 +00:00
slvBurst2 . image . filename = os . path . join ( upperDir , ' secondary_ ' + os . path . basename ( slvBurst . image . filename ) )
2019-01-16 19:40:08 +00:00
slvBurstResamp2 . radarWavelength = ionParam . radarWavelengthUpper
slvBurstResamp2 . rangeProcessingBandwidth = ionParam . rgBandwidthSub
2020-07-02 19:40:49 +00:00
slvBurstResamp2 . image . filename = os . path . join ( upperDir , ' reference_ ' + os . path . basename ( masBurst . image . filename ) )
outname = os . path . join ( upperDir , ' secondary_resamp_ ' + os . path . basename ( slvBurst . image . filename ) )
2019-01-16 19:40:08 +00:00
ifgdir = upperDir
2020-07-02 19:40:49 +00:00
outimg = resampSecondary ( masBurst2 , slvBurst2 , rdict , outname )
2019-01-16 19:40:08 +00:00
minAz , maxAz , minRg , maxRg = getValidLines ( slvBurst2 , rdict , outname ,
misreg_az = misreg_az - offset , misreg_rng = misreg_rg )
adjustValidSampleLine ( slvBurstResamp2 , slvBurst2 ,
minAz = minAz , maxAz = maxAz ,
minRng = minRg , maxRng = maxRg )
slvBurstResamp2 . image . filename = outimg . filename
#forming interferogram
2020-07-02 19:40:49 +00:00
referencename = masBurst2 . image . filename
secondaryname = slvBurstResamp2 . image . filename
2019-01-16 19:40:08 +00:00
rngname = os . path . join ( offdir , ' range_ %02d .off ' % ( ii + 1 ) )
infname = os . path . join ( ifgdir , ' burst_ %02d .int ' % ( ii + 1 ) )
fact = 4.0 * np . pi * slvBurstResamp2 . rangePixelSize / slvBurstResamp2 . radarWavelength
adjustValidLineSample ( masBurst2 , slvBurstResamp2 )
#in original runBurstIfg.py, valid samples in the interferogram are the following (indexes in the numpy matrix):
2020-07-02 19:40:49 +00:00
#referenceFrame.firstValidLine:referenceFrame.firstValidLine + referenceFrame.numValidLines, referenceFrame.firstValidSample:referenceFrame.firstValidSample + referenceFrame.numValidSamples
2019-01-16 19:40:08 +00:00
#after the following processing, valid samples in the interferogram are the following (indexes in the numpy matrix):
#[masBurst.firstValidLine:masBurst.firstValidLine + masBurst.numValidLines, masBurst.firstValidSample:masBurst.firstValidSample + masBurst.numValidSamples]
#SO THEY ARE EXACTLY THE SAME
firstline = masBurst2 . firstValidLine + 1
lastline = firstline + masBurst2 . numValidLines - 1
firstcolumn = masBurst2 . firstValidSample + 1
lastcolumn = firstcolumn + masBurst2 . numValidSamples - 1
overlapBox = [ firstline , lastline , firstcolumn , lastcolumn ]
2020-07-02 19:40:49 +00:00
multiply2 ( referencename , secondaryname , fact , rngname = rngname , ionname = None , infname = infname , overlapBox = overlapBox , valid = False , virtual = virtual )
2019-01-16 19:40:08 +00:00
#directly from multiply() of runBurstIfg.py
img = isceobj . createIntImage ( )
img . setFilename ( infname )
img . setWidth ( masBurst2 . numberOfSamples )
img . setLength ( masBurst2 . numberOfLines )
img . setAccessMode ( ' READ ' )
#img.renderHdr()
#save it for deleting later
masBurst2_filename = masBurst2 . image . filename
#change it for interferogram
masBurst2 . image = img
if lu == ' lower ' :
fineIfgLower . bursts . append ( masBurst2 )
else :
fineIfgUpper . bursts . append ( masBurst2 )
2020-07-02 19:40:49 +00:00
#remove reference and secondary subband slcs
2019-01-16 19:40:08 +00:00
os . remove ( masBurst2_filename )
os . remove ( masBurst2_filename + ' .xml ' )
os . remove ( masBurst2_filename + ' .vrt ' )
os . remove ( slvBurst2 . image . filename )
os . remove ( slvBurst2 . image . filename + ' .xml ' )
os . remove ( slvBurst2 . image . filename + ' .vrt ' )
os . remove ( slvBurstResamp2 . image . filename )
os . remove ( slvBurstResamp2 . image . filename + ' .xml ' )
os . remove ( slvBurstResamp2 . image . filename + ' .vrt ' )
fineIfgLower . numberOfBursts = len ( fineIfgLower . bursts )
fineIfgUpper . numberOfBursts = len ( fineIfgUpper . bursts )
self . _insar . saveProduct ( fineIfgLower , os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . fineIfgDirname , ' IW {0} .xml ' . format ( swath ) ) )
self . _insar . saveProduct ( fineIfgUpper , os . path . join ( ionParam . ionDirname , ionParam . upperDirname , ionParam . fineIfgDirname , ' IW {0} .xml ' . format ( swath ) ) )
def cal_coherence ( inf , win = 5 , edge = 0 ) :
'''
compute coherence uisng only interferogram ( phase ) .
This routine still follows the regular equation for computing coherence ,
2020-07-02 19:40:49 +00:00
but assumes the amplitudes of reference and secondary are one , so that coherence
2019-01-16 19:40:08 +00:00
can be computed using phase only .
inf : interferogram
win : window size
edge : 0 : remove all non - full convolution samples
1 : remove samples computed from less than half convolution
( win = 5 used to illustration below )
* * *
* * *
* * *
* * *
* * *
2 : remove samples computed from less than quater convolution
( win = 5 used to illustration below )
* * *
* * *
* * *
3 : remove non - full convolution samples on image edges
4 : keep all samples
'''
2019-12-16 18:22:01 +00:00
import scipy . signal as ss
2019-01-16 19:40:08 +00:00
if win % 2 != 1 :
raise Exception ( ' window size must be odd! ' )
hwin = np . int ( np . around ( ( win - 1 ) / 2 ) )
filt = np . ones ( ( win , win ) )
amp = np . absolute ( inf )
cnt = ss . convolve2d ( ( amp != 0 ) , filt , mode = ' same ' )
cor = ss . convolve2d ( inf / ( amp + ( amp == 0 ) ) , filt , mode = ' same ' )
cor = ( amp != 0 ) * np . absolute ( cor ) / ( cnt + ( cnt == 0 ) )
#trim edges
if edge == 0 :
num = win * win
cor [ np . nonzero ( cnt < num ) ] = 0.0
elif edge == 1 :
num = win * ( hwin + 1 )
cor [ np . nonzero ( cnt < num ) ] = 0.0
elif edge == 2 :
num = ( hwin + 1 ) * ( hwin + 1 )
cor [ np . nonzero ( cnt < num ) ] = 0.0
elif edge == 3 :
cor [ 0 : hwin , : ] = 0.0
cor [ - hwin : , : ] = 0.0
cor [ : , 0 : hwin ] = 0.0
cor [ : , - hwin : ] = 0.0
else :
pass
#print("coherence, max: {} min: {}".format(np.max(cor[np.nonzero(cor!=0)]), np.min(cor[np.nonzero(cor!=0)])))
return cor
def getMergeBox ( self , xmlDirname , numberRangeLooks = 1 , numberAzimuthLooks = 1 ) :
'''
xmlDirname : directory containing xml file
numberRangeLooks : number of range looks to take after merging
numberAzimuthLooks : number of azimuth looks to take after merging
'''
from isceobj . TopsProc . runMergeBursts import mergeBox
from isceobj . TopsProc . runMergeBursts import adjustValidWithLooks
swathList = self . _insar . getValidSwathList ( self . swaths )
#get bursts
frames = [ ]
for swath in swathList :
2020-07-02 19:40:49 +00:00
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
if minBurst == maxBurst :
#print('Skipping processing of swath {0}'.format(swath))
continue
#since burst directory does not necessarily has IW*.xml, we use the following dir
#ifg = self._insar.loadProduct( os.path.join(self._insar.fineIfgDirname, 'IW{0}.xml'.format(swath)))
#use lower
#dirname = os.path.join(ionParam.ionDirname, ionParam.lowerDirname, ionParam.fineIfgDirname)
ifg = self . _insar . loadProduct ( os . path . join ( xmlDirname , ' IW {0} .xml ' . format ( swath ) ) )
frames . append ( ifg )
#determine merged size
box = mergeBox ( frames )
#adjust valid with looks, 'frames' ARE CHANGED AFTER RUNNING THIS
( burstValidBox , burstValidBox2 , message ) = adjustValidWithLooks ( frames , box , numberAzimuthLooks , numberRangeLooks , edge = 0 , avalid = ' strict ' , rvalid = ' strict ' )
return ( box , burstValidBox , burstValidBox2 , frames )
def merge ( self , ionParam ) :
'''
merge burst interferograms and compute coherence
'''
from isceobj . TopsProc . runMergeBursts import mergeBox
from isceobj . TopsProc . runMergeBursts import adjustValidWithLooks
from isceobj . TopsProc . runMergeBursts import mergeBurstsVirtual
from isceobj . TopsProc . runMergeBursts import multilook as multilook2
#merge burst interferograms
mergeFilename = self . _insar . mergedIfgname
xmlDirname = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . fineIfgDirname )
dirs = [ ionParam . lowerDirname , ionParam . upperDirname ]
for dirx in dirs :
mergeDirname = os . path . join ( ionParam . ionDirname , dirx , ionParam . mergedDirname )
burstDirname = os . path . join ( ionParam . ionDirname , dirx , ionParam . fineIfgDirname )
frames = [ ]
burstList = [ ]
swathList = self . _insar . getValidSwathList ( self . swaths )
for swath in swathList :
2020-07-02 19:40:49 +00:00
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
if minBurst == maxBurst :
continue
ifg = self . _insar . loadProduct ( os . path . join ( xmlDirname , ' IW {0} .xml ' . format ( swath ) ) )
frames . append ( ifg )
burstList . append ( [ os . path . join ( burstDirname , ' IW {0} ' . format ( swath ) , ' burst_ %02d .int ' % ( x + 1 ) ) for x in range ( minBurst , maxBurst ) ] )
2020-04-13 19:40:32 +00:00
os . makedirs ( mergeDirname , exist_ok = True )
2019-01-16 19:40:08 +00:00
suffix = ' .full '
if ( ionParam . numberRangeLooks0 == 1 ) and ( ionParam . numberAzimuthLooks0 == 1 ) :
suffix = ' '
box = mergeBox ( frames )
#adjust valid with looks, 'frames' ARE CHANGED AFTER RUNNING THIS
#here numberRangeLooks, instead of numberRangeLooks0, is used, since we need to do next step multilooking after unwrapping. same for numberAzimuthLooks.
( burstValidBox , burstValidBox2 , message ) = adjustValidWithLooks ( frames , box , ionParam . numberAzimuthLooks , ionParam . numberRangeLooks , edge = 0 , avalid = ' strict ' , rvalid = ' strict ' )
mergeBurstsVirtual ( frames , burstList , box , os . path . join ( mergeDirname , mergeFilename + suffix ) )
if suffix not in [ ' ' , None ] :
multilook2 ( os . path . join ( mergeDirname , mergeFilename + suffix ) ,
outname = os . path . join ( mergeDirname , mergeFilename ) ,
alks = ionParam . numberAzimuthLooks0 , rlks = ionParam . numberRangeLooks0 )
#this is never used for ionosphere correction
else :
print ( ' Skipping multi-looking .... ' )
#The orginal coherence calculated by topsApp.py is not good at all, use the following coherence instead
lowerintfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname , self . _insar . mergedIfgname )
upperintfile = os . path . join ( ionParam . ionDirname , ionParam . upperDirname , ionParam . mergedDirname , self . _insar . mergedIfgname )
corfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname , self . _insar . correlationFilename )
img = isceobj . createImage ( )
img . load ( lowerintfile + ' .xml ' )
width = img . width
length = img . length
lowerint = np . fromfile ( lowerintfile , dtype = np . complex64 ) . reshape ( length , width )
upperint = np . fromfile ( upperintfile , dtype = np . complex64 ) . reshape ( length , width )
#compute coherence only using interferogram
#here I use differential interferogram of lower and upper band interferograms
#so that coherence is not affected by fringes
cord = cal_coherence ( lowerint * np . conjugate ( upperint ) , win = 3 , edge = 4 )
cor = np . zeros ( ( length * 2 , width ) , dtype = np . float32 )
cor [ 0 : length * 2 : 2 , : ] = np . sqrt ( ( np . absolute ( lowerint ) + np . absolute ( upperint ) ) / 2.0 )
cor [ 1 : length * 2 : 2 , : ] = cord
cor . astype ( np . float32 ) . tofile ( corfile )
#create xml and vrt
#img.scheme = 'BIL'
#img.bands = 2
#img.filename = corfile
#img.renderHdr()
#img = isceobj.Image.createUnwImage()
img = isceobj . createOffsetImage ( )
img . setFilename ( corfile )
img . extraFilename = corfile + ' .vrt '
img . setWidth ( width )
img . setLength ( length )
img . renderHdr ( )
def renameFile ( oldname , newname ) :
img = isceobj . createImage ( )
img . load ( oldname + ' .xml ' )
img . setFilename ( newname )
img . extraFilename = newname + ' .vrt '
img . renderHdr ( )
os . rename ( oldname , newname )
os . remove ( oldname + ' .xml ' )
os . remove ( oldname + ' .vrt ' )
def maskUnwrap ( unwfile , maskfile ) :
tmpfile = ' tmp.unw '
renameFile ( unwfile , tmpfile )
cmd = " imageMath.py -e= ' a_0*(abs(b)!=0);a_1*(abs(b)!=0) ' --a= {0} --b= {1} -s BIL -o= {2} " . format ( tmpfile , maskfile , unwfile )
runCmd ( cmd )
os . remove ( tmpfile )
os . remove ( tmpfile + ' .xml ' )
os . remove ( tmpfile + ' .vrt ' )
def snaphuUnwrap ( self , xmlDirname , wrapName , corrfile , unwrapName , nrlks , nalks , costMode = ' DEFO ' , initMethod = ' MST ' , defomax = 4.0 , initOnly = False ) :
#runUnwrap(self, costMode = 'SMOOTH',initMethod = 'MCF', defomax = 2, initOnly = True)
'''
xmlDirname : xml dir name
wrapName : input interferogram
corrfile : input coherence file
unwrapName : output unwrapped interferogram
nrlks : number of range looks of the interferogram
nalks : number of azimuth looks of the interferogram
'''
from contrib . Snaphu . Snaphu import Snaphu
from isceobj . Planet . Planet import Planet
img = isceobj . createImage ( )
img . load ( wrapName + ' .xml ' )
width = img . getWidth ( )
#get altitude
swathList = self . _insar . getValidSwathList ( self . swaths )
for swath in swathList [ 0 : 1 ] :
ifg = self . _insar . loadProduct ( os . path . join ( xmlDirname , ' IW {0} .xml ' . format ( swath ) ) )
wavelength = ifg . bursts [ 0 ] . radarWavelength
####tmid
tstart = ifg . bursts [ 0 ] . sensingStart
tend = ifg . bursts [ - 1 ] . sensingStop
tmid = tstart + 0.5 * ( tend - tstart )
#14-APR-2018
burst_index = np . int ( np . around ( len ( ifg . bursts ) / 2 ) )
orbit = ifg . bursts [ burst_index ] . orbit
peg = orbit . interpolateOrbit ( tmid , method = ' hermite ' )
refElp = Planet ( pname = ' Earth ' ) . ellipsoid
llh = refElp . xyz_to_llh ( peg . getPosition ( ) )
hdg = orbit . getENUHeading ( tmid )
refElp . setSCH ( llh [ 0 ] , llh [ 1 ] , hdg )
earthRadius = refElp . pegRadCur
altitude = llh [ 2 ]
rangeLooks = nrlks
azimuthLooks = nalks
azfact = 0.8
rngfact = 0.8
corrLooks = rangeLooks * azimuthLooks / ( azfact * rngfact )
maxComponents = 20
snp = Snaphu ( )
snp . setInitOnly ( initOnly )
snp . setInput ( wrapName )
snp . setOutput ( unwrapName )
snp . setWidth ( width )
snp . setCostMode ( costMode )
snp . setEarthRadius ( earthRadius )
snp . setWavelength ( wavelength )
snp . setAltitude ( altitude )
snp . setCorrfile ( corrfile )
snp . setInitMethod ( initMethod )
snp . setCorrLooks ( corrLooks )
snp . setMaxComponents ( maxComponents )
snp . setDefoMaxCycles ( defomax )
snp . setRangeLooks ( rangeLooks )
snp . setAzimuthLooks ( azimuthLooks )
#snp.setCorFileFormat('FLOAT_DATA')
snp . prepare ( )
snp . unwrap ( )
######Render XML
outImage = isceobj . Image . createUnwImage ( )
outImage . setFilename ( unwrapName )
outImage . setWidth ( width )
outImage . setAccessMode ( ' read ' )
outImage . renderVRT ( )
outImage . createImage ( )
outImage . finalizeImage ( )
outImage . renderHdr ( )
#####Check if connected components was created
if snp . dumpConnectedComponents :
connImage = isceobj . Image . createImage ( )
connImage . setFilename ( unwrapName + ' .conncomp ' )
connImage . setWidth ( width )
connImage . setAccessMode ( ' read ' )
connImage . setDataType ( ' BYTE ' )
connImage . renderVRT ( )
connImage . createImage ( )
connImage . finalizeImage ( )
connImage . renderHdr ( )
return
def unwrap ( self , ionParam ) :
'''
unwrap lower and upper band interferograms
'''
print ( ' unwrapping lower and upper band interferograms ' )
dirs = [ ionParam . lowerDirname , ionParam . upperDirname ]
#there is only one coherence file in lower directory
corfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname , self . _insar . correlationFilename )
for dirx in dirs :
procdir = os . path . join ( ionParam . ionDirname , dirx , ionParam . mergedDirname )
wrapName = os . path . join ( procdir , self . _insar . mergedIfgname )
unwrapName = os . path . join ( procdir , self . _insar . unwrappedIntFilename )
xmlDirname = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . fineIfgDirname )
#unwrap
snaphuUnwrap ( self , xmlDirname , wrapName , corfile , unwrapName , ionParam . numberRangeLooks0 , ionParam . numberAzimuthLooks0 , costMode = ' SMOOTH ' , initMethod = ' MCF ' , defomax = 2 , initOnly = True )
#remove wired things in no-data area
maskUnwrap ( unwrapName , wrapName )
if [ ionParam . numberRangeLooks0 , ionParam . numberAzimuthLooks0 ] != [ ionParam . numberRangeLooks , ionParam . numberAzimuthLooks ] :
multilook_unw ( self , ionParam , ionParam . mergedDirname )
def multilook_unw ( self , ionParam , mergedDirname ) :
'''
30 - APR - 2018
This routine moves the original unwrapped files to a directory and takes looks
'''
from isceobj . TopsProc . runMergeBursts import multilook as multilook2
oridir0 = ' {} rlks_ {} alks ' . format ( ionParam . numberRangeLooks0 , ionParam . numberAzimuthLooks0 )
dirs = [ ionParam . lowerDirname , ionParam . upperDirname ]
corName = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname , oridir0 , self . _insar . correlationFilename )
for dirx in dirs :
procdir = os . path . join ( ionParam . ionDirname , dirx , mergedDirname )
#create a directory for original files
oridir = os . path . join ( procdir , oridir0 )
2020-04-13 19:40:32 +00:00
os . makedirs ( oridir , exist_ok = True )
2019-01-16 19:40:08 +00:00
#move files, renameFile uses os.rename, which overwrites if file already exists in oridir. This can support re-run
filename0 = os . path . join ( procdir , self . _insar . mergedIfgname )
filename = os . path . join ( oridir , self . _insar . mergedIfgname )
if os . path . isfile ( filename0 ) :
renameFile ( filename0 , filename )
filename0 = os . path . join ( procdir , self . _insar . unwrappedIntFilename )
filename = os . path . join ( oridir , self . _insar . unwrappedIntFilename )
if os . path . isfile ( filename0 ) :
renameFile ( filename0 , filename )
filename0 = os . path . join ( procdir , self . _insar . unwrappedIntFilename + ' .conncomp ' )
filename = os . path . join ( oridir , self . _insar . unwrappedIntFilename + ' .conncomp ' )
if os . path . isfile ( filename0 ) :
renameFile ( filename0 , filename )
filename0 = os . path . join ( procdir , self . _insar . correlationFilename )
filename = os . path . join ( oridir , self . _insar . correlationFilename )
if os . path . isfile ( filename0 ) :
renameFile ( filename0 , filename )
#for topophase.flat.full, move directly
filename0 = os . path . join ( procdir , self . _insar . mergedIfgname + ' .full.vrt ' )
filename = os . path . join ( oridir , self . _insar . mergedIfgname + ' .full.vrt ' )
if os . path . isfile ( filename0 ) :
os . rename ( filename0 , filename )
filename0 = os . path . join ( procdir , self . _insar . mergedIfgname + ' .full.xml ' )
filename = os . path . join ( oridir , self . _insar . mergedIfgname + ' .full.xml ' )
if os . path . isfile ( filename0 ) :
os . rename ( filename0 , filename )
#multi-looking
nrlks = np . int ( np . around ( ionParam . numberRangeLooks / ionParam . numberRangeLooks0 ) )
nalks = np . int ( np . around ( ionParam . numberAzimuthLooks / ionParam . numberAzimuthLooks0 ) )
#coherence
if dirx == ionParam . lowerDirname :
corName0 = os . path . join ( oridir , self . _insar . correlationFilename )
corimg = isceobj . createImage ( )
corimg . load ( corName0 + ' .xml ' )
width = corimg . width
length = corimg . length
widthNew = np . int ( width / nrlks )
lengthNew = np . int ( length / nalks )
cor0 = ( np . fromfile ( corName0 , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
amp0 = ( np . fromfile ( corName0 , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
wgt = cor0 * * 2
a = multilook ( wgt , nalks , nrlks )
b = multilook ( cor0 , nalks , nrlks )
c = multilook ( amp0 * * 2 , nalks , nrlks )
d = multilook ( ( cor0 != 0 ) . astype ( np . int ) , nalks , nrlks )
#coherence after multiple looking
cor = np . zeros ( ( lengthNew * 2 , widthNew ) , dtype = np . float32 )
cor [ 0 : lengthNew * 2 : 2 , : ] = np . sqrt ( c / ( d + ( d == 0 ) ) )
cor [ 1 : lengthNew * 2 : 2 , : ] = b / ( d + ( d == 0 ) )
#output file
corName = os . path . join ( procdir , self . _insar . correlationFilename )
cor . astype ( np . float32 ) . tofile ( corName )
corimg . setFilename ( corName )
corimg . extraFilename = corName + ' .vrt '
corimg . setWidth ( widthNew )
corimg . setLength ( lengthNew )
corimg . renderHdr ( )
#unwrapped file
unwrapName0 = os . path . join ( oridir , self . _insar . unwrappedIntFilename )
unwimg = isceobj . createImage ( )
unwimg . load ( unwrapName0 + ' .xml ' )
unw0 = ( np . fromfile ( unwrapName0 , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
amp0 = ( np . fromfile ( unwrapName0 , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
e = multilook ( unw0 * wgt , nalks , nrlks )
f = multilook ( amp0 * * 2 , nalks , nrlks )
unw = np . zeros ( ( lengthNew * 2 , widthNew ) , dtype = np . float32 )
unw [ 0 : lengthNew * 2 : 2 , : ] = np . sqrt ( f / ( d + ( d == 0 ) ) )
unw [ 1 : lengthNew * 2 : 2 , : ] = e / ( a + ( a == 0 ) )
#output file
unwrapName = os . path . join ( procdir , self . _insar . unwrappedIntFilename )
unw . astype ( np . float32 ) . tofile ( unwrapName )
unwimg . setFilename ( unwrapName )
unwimg . extraFilename = unwrapName + ' .vrt '
unwimg . setWidth ( widthNew )
unwimg . setLength ( lengthNew )
unwimg . renderHdr ( )
#looks like the above is not a good coherence, re-calculate here
#here I use differential interferogram of lower and upper band interferograms
#so that coherence is not affected by fringes
lowerIntName0 = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , mergedDirname , oridir0 , self . _insar . mergedIfgname )
upperIntName0 = os . path . join ( ionParam . ionDirname , ionParam . upperDirname , mergedDirname , oridir0 , self . _insar . mergedIfgname )
lowerIntName = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , mergedDirname , self . _insar . mergedIfgname )
upperIntName = os . path . join ( ionParam . ionDirname , ionParam . upperDirname , mergedDirname , self . _insar . mergedIfgname )
#cmd = 'looks.py -i {} -o {} -r {} -a {}'.format(lowerIntName0, lowerIntName, nrlks, nalks)
#runCmd(cmd)
#cmd = 'looks.py -i {} -o {} -r {} -a {}'.format(upperIntName0, upperIntName, nrlks, nalks)
#runCmd(cmd)
multilook2 ( lowerIntName0 , outname = lowerIntName , alks = nalks , rlks = nrlks )
multilook2 ( upperIntName0 , outname = upperIntName , alks = nalks , rlks = nrlks )
lowerint = np . fromfile ( lowerIntName , dtype = np . complex64 ) . reshape ( lengthNew , widthNew )
upperint = np . fromfile ( upperIntName , dtype = np . complex64 ) . reshape ( lengthNew , widthNew )
cor = np . zeros ( ( lengthNew * 2 , widthNew ) , dtype = np . float32 )
cor [ 0 : length * 2 : 2 , : ] = np . sqrt ( ( np . absolute ( lowerint ) + np . absolute ( upperint ) ) / 2.0 )
cor [ 1 : length * 2 : 2 , : ] = cal_coherence ( lowerint * np . conjugate ( upperint ) , win = 3 , edge = 4 )
cor . astype ( np . float32 ) . tofile ( corName )
def create_multi_index2 ( width2 , l1 , l2 ) :
#for number of looks of l1 and l2
#calculate the correponding index number of l2 in the l1 array
#applies to both range and azimuth direction
return ( ( l2 - l1 ) / 2.0 + np . arange ( width2 ) * l2 ) / l1
def fit_surface ( x , y , z , wgt , order ) :
# x: x coordinate, a column vector
# y: y coordinate, a column vector
# z: z coordinate, a column vector
# wgt: weight of the data points, a column vector
#number of data points
m = x . shape [ 0 ]
l = np . ones ( ( m , 1 ) , dtype = np . float64 )
# #create polynomial
# if order == 1:
# #order of estimated coefficents: 1, x, y
# a1 = np.concatenate((l, x, y), axis=1)
# elif order == 2:
# #order of estimated coefficents: 1, x, y, x*y, x**2, y**2
# a1 = np.concatenate((l, x, y, x*y, x**2, y**2), axis=1)
# elif order == 3:
# #order of estimated coefficents: 1, x, y, x*y, x**2, y**2, x**2*y, y**2*x, x**3, y**3
# a1 = np.concatenate((l, x, y, x*y, x**2, y**2, x**2*y, y**2*x, x**3, y**3), axis=1)
# else:
# raise Exception('order not supported yet\n')
if order < 1 :
raise Exception ( ' order must be larger than 1. \n ' )
#create polynomial
a1 = l ;
for i in range ( 1 , order + 1 ) :
for j in range ( i + 1 ) :
a1 = np . concatenate ( ( a1 , x * * ( i - j ) * y * * ( j ) ) , axis = 1 )
#number of variable to be estimated
n = a1 . shape [ 1 ]
#do the least squares
a = a1 * np . matlib . repmat ( np . sqrt ( wgt ) , 1 , n )
b = z * np . sqrt ( wgt )
c = np . linalg . lstsq ( a , b , rcond = - 1 ) [ 0 ]
#type: <class 'numpy.ndarray'>
return c
def cal_surface ( x , y , c , order ) :
#x: x coordinate, a row vector
#y: y coordinate, a column vector
#c: coefficients of polynomial from fit_surface
#order: order of polynomial
if order < 1 :
raise Exception ( ' order must be larger than 1. \n ' )
#number of lines
length = y . shape [ 0 ]
#number of columns, if row vector, only one element in the shape tuple
#width = x.shape[1]
width = x . shape [ 0 ]
x = np . matlib . repmat ( x , length , 1 )
y = np . matlib . repmat ( y , 1 , width )
z = c [ 0 ] * np . ones ( ( length , width ) , dtype = np . float64 )
index = 0
for i in range ( 1 , order + 1 ) :
for j in range ( i + 1 ) :
index + = 1
z + = c [ index ] * x * * ( i - j ) * y * * ( j )
return z
def weight_fitting ( ionos , cor , width , length , nrli , nali , nrlo , nalo , order , coth ) :
'''
ionos : input ionospheric phase
cor : coherence of the interferogram
width : file width
length : file length
nrli : number of range looks of the input interferograms
nali : number of azimuth looks of the input interferograms
nrlo : number of range looks of the output ionosphere phase
nalo : number of azimuth looks of the ioutput ionosphere phase
order : the order of the polynomial for fitting ionosphere phase estimates
coth : coherence threshhold for ionosphere phase estimation
'''
lengthi = int ( length / nali )
widthi = int ( width / nrli )
lengtho = int ( length / nalo )
widtho = int ( width / nrlo )
#calculate output index
rgindex = create_multi_index2 ( widtho , nrli , nrlo )
azindex = create_multi_index2 ( lengtho , nali , nalo )
#convert coherence to weight
cor = cor * * 2 / ( 1.009 - cor * * 2 )
#look for data to use
flag = ( cor > coth ) * ( ionos != 0 )
point_index = np . nonzero ( flag )
m = point_index [ 0 ] . shape [ 0 ]
#calculate input index matrix
x0 = np . matlib . repmat ( np . arange ( widthi ) , lengthi , 1 )
y0 = np . matlib . repmat ( np . arange ( lengthi ) . reshape ( lengthi , 1 ) , 1 , widthi )
x = x0 [ point_index ] . reshape ( m , 1 )
y = y0 [ point_index ] . reshape ( m , 1 )
z = ionos [ point_index ] . reshape ( m , 1 )
w = cor [ point_index ] . reshape ( m , 1 )
#convert to higher precision type before use
x = np . asfarray ( x , np . float64 )
y = np . asfarray ( y , np . float64 )
z = np . asfarray ( z , np . float64 )
w = np . asfarray ( w , np . float64 )
coeff = fit_surface ( x , y , z , w , order )
#convert to higher precision type before use
rgindex = np . asfarray ( rgindex , np . float64 )
azindex = np . asfarray ( azindex , np . float64 )
phase_fit = cal_surface ( rgindex , azindex . reshape ( lengtho , 1 ) , coeff , order )
#format: widtho, lengtho, single band float32
return phase_fit
def computeIonosphere ( lowerUnw , upperUnw , cor , fl , fu , adjFlag , corThresholdAdj , dispersive ) :
'''
This routine computes ionosphere and remove the relative phase unwrapping errors
lowerUnw : lower band unwrapped interferogram
upperUnw : upper band unwrapped interferogram
cor : coherence
fl : lower band center frequency
fu : upper band center frequency
adjFlag : method for removing relative phase unwrapping errors
0 : mean value
1 : polynomial
corThresholdAdj : coherence threshold of samples used in removing relative phase unwrapping errors
dispersive : compute dispersive or non - dispersive
0 : dispersive
1 : non - dispersive
'''
#use image size from lower unwrapped interferogram
( length , width ) = lowerUnw . shape
##########################################################################################
# ADJUST PHASE USING MEAN VALUE
# #ajust phase of upper band to remove relative phase unwrapping errors
# flag = (lowerUnw!=0)*(cor>=ionParam.corThresholdAdj)
# index = np.nonzero(flag!=0)
# mv = np.mean((lowerUnw - upperUnw)[index], dtype=np.float64)
# print('mean value of phase difference: {}'.format(mv))
# flag2 = (lowerUnw!=0)
# index2 = np.nonzero(flag2)
# #phase for adjustment
# unwd = ((lowerUnw - upperUnw)[index2] - mv) / (2.0*np.pi)
# unw_adj = np.around(unwd) * (2.0*np.pi)
# #ajust phase of upper band
# upperUnw[index2] += unw_adj
# unw_diff = lowerUnw - upperUnw
# print('after adjustment:')
# print('max phase difference: {}'.format(np.amax(unw_diff)))
# print('min phase difference: {}'.format(np.amin(unw_diff)))
##########################################################################################
#adjust phase using mean value
if adjFlag == 0 :
flag = ( lowerUnw != 0 ) * ( cor > = corThresholdAdj )
index = np . nonzero ( flag != 0 )
mv = np . mean ( ( lowerUnw - upperUnw ) [ index ] , dtype = np . float64 )
print ( ' mean value of phase difference: {} ' . format ( mv ) )
diff = mv
#adjust phase using a surface
else :
diff = weight_fitting ( lowerUnw - upperUnw , cor , width , length , 1 , 1 , 1 , 1 , 2 , corThresholdAdj )
flag2 = ( lowerUnw != 0 )
index2 = np . nonzero ( flag2 )
#phase for adjustment
unwd = ( ( lowerUnw - upperUnw ) - diff ) [ index2 ] / ( 2.0 * np . pi )
unw_adj = np . around ( unwd ) * ( 2.0 * np . pi )
#ajust phase of upper band
upperUnw [ index2 ] + = unw_adj
unw_diff = ( lowerUnw - upperUnw ) [ index2 ]
print ( ' after adjustment: ' )
print ( ' max phase difference: {} ' . format ( np . amax ( unw_diff ) ) )
print ( ' min phase difference: {} ' . format ( np . amin ( unw_diff ) ) )
print ( ' max-min: {} ' . format ( np . amax ( unw_diff ) - np . amin ( unw_diff ) ) )
#ionosphere
#fl = SPEED_OF_LIGHT / ionParam.radarWavelengthLower
#fu = SPEED_OF_LIGHT / ionParam.radarWavelengthUpper
f0 = ( fl + fu ) / 2.0
#dispersive
if dispersive == 0 :
ionos = fl * fu * ( lowerUnw * fu - upperUnw * fl ) / f0 / ( fu * * 2 - fl * * 2 )
#non-dispersive phase
else :
ionos = f0 * ( upperUnw * fu - lowerUnw * fl ) / ( fu * * 2 - fl * * 2 )
return ionos
def ionosphere ( self , ionParam ) :
###################################
#SET PARAMETERS HERE
#THESE SHOULD BE GOOD ENOUGH, NO NEED TO SET IN setup(self)
corThresholdAdj = 0.85
###################################
print ( ' computing ionosphere ' )
#get files
lowerUnwfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname , self . _insar . unwrappedIntFilename )
upperUnwfile = os . path . join ( ionParam . ionDirname , ionParam . upperDirname , ionParam . mergedDirname , self . _insar . unwrappedIntFilename )
corfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname , self . _insar . correlationFilename )
#use image size from lower unwrapped interferogram
img = isceobj . createImage ( )
img . load ( lowerUnwfile + ' .xml ' )
width = img . width
length = img . length
lowerUnw = ( np . fromfile ( lowerUnwfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
upperUnw = ( np . fromfile ( upperUnwfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
lowerAmp = ( np . fromfile ( lowerUnwfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
upperAmp = ( np . fromfile ( upperUnwfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
cor = ( np . fromfile ( corfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
amp = np . sqrt ( lowerAmp * * 2 + upperAmp * * 2 )
2021-08-09 20:31:40 +00:00
#masked out user-specified areas
if ionParam . maskedAreas != None :
maskedAreas = reformatMaskedAreas ( ionParam . maskedAreas , length , width )
for area in maskedAreas :
lowerUnw [ area [ 0 ] : area [ 1 ] , area [ 2 ] : area [ 3 ] ] = 0
upperUnw [ area [ 0 ] : area [ 1 ] , area [ 2 ] : area [ 3 ] ] = 0
cor [ area [ 0 ] : area [ 1 ] , area [ 2 ] : area [ 3 ] ] = 0
2019-01-16 19:40:08 +00:00
#compute ionosphere
fl = SPEED_OF_LIGHT / ionParam . radarWavelengthLower
fu = SPEED_OF_LIGHT / ionParam . radarWavelengthUpper
adjFlag = 1
ionos = computeIonosphere ( lowerUnw , upperUnw , cor , fl , fu , adjFlag , corThresholdAdj , 0 )
#dump ionosphere
outDir = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname )
2020-04-13 19:40:32 +00:00
os . makedirs ( outDir , exist_ok = True )
2019-01-16 19:40:08 +00:00
outFilename = os . path . join ( outDir , ionParam . ionRawNoProj )
ion = np . zeros ( ( length * 2 , width ) , dtype = np . float32 )
ion [ 0 : length * 2 : 2 , : ] = amp
ion [ 1 : length * 2 : 2 , : ] = ionos
ion . astype ( np . float32 ) . tofile ( outFilename )
img . filename = outFilename
img . extraFilename = outFilename + ' .vrt '
img . renderHdr ( )
#dump coherence
outFilename = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionCorNoProj )
ion [ 1 : length * 2 : 2 , : ] = cor
ion . astype ( np . float32 ) . tofile ( outFilename )
img . filename = outFilename
img . extraFilename = outFilename + ' .vrt '
img . renderHdr ( )
def cal_cross_ab_ramp ( swathList , width , numberRangeLooks , passDirection ) :
'''
calculate an empirical ramp between Sentinel - 1 A / B
29 - JUN - 2018
swathList : self . _insar . getValidSwathList ( self . swaths )
width : single - look image width after merging
numberRangeLooks : number of range looks in the processing of ionosphere estimation
passDirection : descending / ascending
'''
#below is from processing chile_d156_160725(S1A)-160929(S1B)
#empirical polynomial
deg = 3
if passDirection . lower ( ) == ' descending ' :
p = np . array ( [ 0.95381267 , 2.95567604 , - 4.56047084 , 1.05443172 ] )
elif passDirection . lower ( ) == ' ascending ' :
#for ascending, the polynomial is left/right flipped
p = np . array ( [ - 0.95381267 , 5.81711404 , - 4.21231923 , 0.40344958 ] )
else :
raise Exception ( ' unknown passDirection! should be either descending or ascending ' )
#ca/a166/process/160807-170305 also has the swath offset almost equal to these
#swath offset in single-look range pixels
swath_offset = [ 0 , 19810 , 43519 ]
#total number of single-look range pixels
tnp = 69189
#getting x
nswath = len ( swathList )
if nswath == 3 :
width2 = np . int ( width / numberRangeLooks )
x = np . arange ( width2 ) / ( width2 - 1.0 )
else :
width2 = np . int ( width / numberRangeLooks )
#WARNING: what if the some swaths does not have bursts, and are not merged?
# here I just simply ignore this case
offset = swath_offset [ swathList [ 0 ] - 1 ]
x = offset / tnp + width / tnp * np . arange ( width2 ) / ( width2 - 1.0 )
#calculate ramp
y_fit = x * 0.0
for i in range ( deg + 1 ) :
y_fit + = p [ i ] * x * * [ deg - i ]
return y_fit
def ionSwathBySwath ( self , ionParam ) :
'''
This routine merge , unwrap and compute ionosphere swath by swath , and then
adjust phase difference between adjacent swaths caused by relative range timing
error between adjacent swaths .
This routine includes the following steps in the merged - swath processing :
merge ( self , ionParam )
unwrap ( self , ionParam )
ionosphere ( self , ionParam )
'''
from isceobj . TopsProc . runMergeBursts import mergeBox
from isceobj . TopsProc . runMergeBursts import adjustValidWithLooks
from isceobj . TopsProc . runMergeBursts import mergeBurstsVirtual
from isceobj . TopsProc . runMergeBursts import multilook as multilook2
#########################################
#SET PARAMETERS HERE
numberRangeLooks = ionParam . numberRangeLooks
numberAzimuthLooks = ionParam . numberAzimuthLooks
numberRangeLooks0 = ionParam . numberRangeLooks0
numberAzimuthLooks0 = ionParam . numberAzimuthLooks0
#THESE SHOULD BE GOOD ENOUGH, NO NEED TO SET IN setup(self)
corThresholdSwathAdj = 0.85
corThresholdAdj = 0.85
#########################################
print ( ' computing ionosphere swath by swath ' )
#if ionParam.calIonWithMerged == False:
warningInfo = ' {} calculating ionosphere swath by swath, there may be slight phase error between subswaths \n ' . format ( datetime . datetime . now ( ) )
with open ( os . path . join ( ionParam . ionDirname , ionParam . warning ) , ' a ' ) as f :
f . write ( warningInfo )
#get bursts
numValidSwaths = 0
swathList = self . _insar . getValidSwathList ( self . swaths )
for swath in swathList :
2020-07-02 19:40:49 +00:00
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
if minBurst == maxBurst :
#print('Skipping processing of swath {0}'.format(swath))
continue
numValidSwaths + = 1
if numValidSwaths < = 1 :
raise Exception ( ' There are less than one subswaths, no need to use swath-by-swath method to compute ionosphere! ' )
else :
xmlDirname = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . fineIfgDirname )
( box , burstValidBox , burstValidBox2 , frames ) = getMergeBox ( self , xmlDirname , numberRangeLooks = ionParam . numberRangeLooks , numberAzimuthLooks = ionParam . numberAzimuthLooks )
#compute ionosphere swath by swath
corList = [ ]
ampList = [ ]
ionosList = [ ]
nswath = len ( swathList )
ii = - 1
for i in range ( nswath ) :
swath = swathList [ i ]
2020-07-02 19:40:49 +00:00
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
if minBurst == maxBurst :
print ( ' Skipping processing of swath {0} ' . format ( swath ) )
continue
else :
ii + = 1
########################################################
#STEP 1. MERGE THE BURSTS OF A SWATH
########################################################
dirs = [ ionParam . lowerDirname , ionParam . upperDirname ]
for dirx in dirs :
outputFilename = self . _insar . mergedIfgname
outputDirname = os . path . join ( ionParam . ionDirname , dirx , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) )
2020-04-13 19:40:32 +00:00
os . makedirs ( outputDirname , exist_ok = True )
2019-01-16 19:40:08 +00:00
suffix = ' .full '
if ( numberRangeLooks0 == 1 ) and ( numberAzimuthLooks0 == 1 ) :
suffix = ' '
#merge
burstPattern = ' burst_ %02d .int '
burstDirname = os . path . join ( ionParam . ionDirname , dirx , ionParam . fineIfgDirname )
ifg = self . _insar . loadProduct ( os . path . join ( burstDirname , ' IW {0} .xml ' . format ( swath ) ) )
bst = [ os . path . join ( burstDirname , ' IW {0} ' . format ( swath ) , burstPattern % ( x + 1 ) ) for x in range ( minBurst , maxBurst ) ]
#doing adjustment before use
adjustValidWithLooks ( [ ifg ] , box , numberAzimuthLooks , numberRangeLooks , edge = 0 , avalid = ' strict ' , rvalid = np . int ( np . around ( numberRangeLooks / 8.0 ) ) )
mergeBurstsVirtual ( [ ifg ] , [ bst ] , box , os . path . join ( outputDirname , outputFilename + suffix ) )
#take looks
if suffix not in [ ' ' , None ] :
multilook2 ( os . path . join ( outputDirname , outputFilename + suffix ) ,
os . path . join ( outputDirname , outputFilename ) ,
numberAzimuthLooks0 ,
numberRangeLooks0 )
else :
print ( ' skipping multilooking ' )
#The orginal coherence calculated by topsApp.py is not good at all, use the following coherence instead
lowerintfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) , self . _insar . mergedIfgname )
upperintfile = os . path . join ( ionParam . ionDirname , ionParam . upperDirname , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) , self . _insar . mergedIfgname )
corfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) , self . _insar . correlationFilename )
img = isceobj . createImage ( )
img . load ( lowerintfile + ' .xml ' )
width = img . width
length = img . length
lowerint = np . fromfile ( lowerintfile , dtype = np . complex64 ) . reshape ( length , width )
upperint = np . fromfile ( upperintfile , dtype = np . complex64 ) . reshape ( length , width )
##########################################################################
#slight filtering to improve the estimation accurary of swath difference
if 1 and shutil . which ( ' psfilt1 ' ) != None :
cmd1 = ' mv {} tmp ' . format ( lowerintfile )
cmd2 = ' psfilt1 tmp {} {} .3 32 8 ' . format ( lowerintfile , width )
cmd3 = ' rm tmp '
cmd4 = ' mv {} tmp ' . format ( upperintfile )
cmd5 = ' psfilt1 tmp {} {} .3 32 8 ' . format ( upperintfile , width )
cmd6 = ' rm tmp '
runCmd ( cmd1 )
runCmd ( cmd2 )
runCmd ( cmd3 )
runCmd ( cmd4 )
runCmd ( cmd5 )
runCmd ( cmd6 )
##########################################################################
#compute coherence only using interferogram
#here I use differential interferogram of lower and upper band interferograms
#so that coherence is not affected by fringes
cord = cal_coherence ( lowerint * np . conjugate ( upperint ) , win = 3 , edge = 4 )
cor = np . zeros ( ( length * 2 , width ) , dtype = np . float32 )
cor [ 0 : length * 2 : 2 , : ] = np . sqrt ( ( np . absolute ( lowerint ) + np . absolute ( upperint ) ) / 2.0 )
cor [ 1 : length * 2 : 2 , : ] = cord
cor . astype ( np . float32 ) . tofile ( corfile )
#create xml and vrt
#img.scheme = 'BIL'
#img.bands = 2
#img.filename = corfile
#img.renderHdr()
#img = isceobj.Image.createUnwImage()
img = isceobj . createOffsetImage ( )
img . setFilename ( corfile )
img . extraFilename = corfile + ' .vrt '
img . setWidth ( width )
img . setLength ( length )
img . renderHdr ( )
########################################################
#STEP 2. UNWRAP SWATH INTERFEROGRAM
########################################################
dirs = [ ionParam . lowerDirname , ionParam . upperDirname ]
#there is only one coherence file in lower directory
corfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) , self . _insar . correlationFilename )
for dirx in dirs :
procdir = os . path . join ( ionParam . ionDirname , dirx , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) )
wrapName = os . path . join ( procdir , self . _insar . mergedIfgname )
unwrapName = os . path . join ( procdir , self . _insar . unwrappedIntFilename )
xmlDirname = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . fineIfgDirname )
#unwrap
snaphuUnwrap ( self , xmlDirname , wrapName , corfile , unwrapName , numberRangeLooks0 , numberAzimuthLooks0 , costMode = ' SMOOTH ' , initMethod = ' MCF ' , defomax = 2 , initOnly = True )
#remove wired things in no-data area
maskUnwrap ( unwrapName , wrapName )
if [ ionParam . numberRangeLooks0 , ionParam . numberAzimuthLooks0 ] != [ ionParam . numberRangeLooks , ionParam . numberAzimuthLooks ] :
multilook_unw ( self , ionParam , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) )
########################################################
#STEP 3. COMPUTE IONOSPHERE
########################################################
#get files
lowerUnwfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) , self . _insar . unwrappedIntFilename )
upperUnwfile = os . path . join ( ionParam . ionDirname , ionParam . upperDirname , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) , self . _insar . unwrappedIntFilename )
corfile = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . mergedDirname + ' _IW {0} ' . format ( swath ) , self . _insar . correlationFilename )
#use image size from lower unwrapped interferogram
img = isceobj . createImage ( )
img . load ( lowerUnwfile + ' .xml ' )
width = img . width
length = img . length
lowerUnw = ( np . fromfile ( lowerUnwfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
upperUnw = ( np . fromfile ( upperUnwfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
lowerAmp = ( np . fromfile ( lowerUnwfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
upperAmp = ( np . fromfile ( upperUnwfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
cor = ( np . fromfile ( corfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
amp = np . sqrt ( lowerAmp * * 2 + upperAmp * * 2 )
2021-08-09 20:31:40 +00:00
#masked out user-specified areas
if ionParam . maskedAreas != None :
maskedAreas = reformatMaskedAreas ( ionParam . maskedAreas , length , width )
for area in maskedAreas :
lowerUnw [ area [ 0 ] : area [ 1 ] , area [ 2 ] : area [ 3 ] ] = 0
upperUnw [ area [ 0 ] : area [ 1 ] , area [ 2 ] : area [ 3 ] ] = 0
cor [ area [ 0 ] : area [ 1 ] , area [ 2 ] : area [ 3 ] ] = 0
2019-01-16 19:40:08 +00:00
#compute ionosphere
fl = SPEED_OF_LIGHT / ionParam . radarWavelengthLower
fu = SPEED_OF_LIGHT / ionParam . radarWavelengthUpper
adjFlag = 1
ionos = computeIonosphere ( lowerUnw , upperUnw , cor , fl , fu , adjFlag , corThresholdAdj , 0 )
#dump result
outDir = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname + ' _IW {0} ' . format ( swath ) )
2020-04-13 19:40:32 +00:00
os . makedirs ( outDir , exist_ok = True )
2019-01-16 19:40:08 +00:00
outFilename = os . path . join ( outDir , ionParam . ionRawNoProj )
ion = np . zeros ( ( length * 2 , width ) , dtype = np . float32 )
ion [ 0 : length * 2 : 2 , : ] = amp
ion [ 1 : length * 2 : 2 , : ] = ionos
ion . astype ( np . float32 ) . tofile ( outFilename )
img . filename = outFilename
img . extraFilename = outFilename + ' .vrt '
img . renderHdr ( )
corList . append ( cor )
ampList . append ( amp )
ionosList . append ( ionos )
#do adjustment between ajacent swaths
if numValidSwaths == 3 :
adjustList = [ ionosList [ 0 ] , ionosList [ 2 ] ]
else :
adjustList = [ ionosList [ 0 ] ]
for adjdata in adjustList :
index = np . nonzero ( ( adjdata != 0 ) * ( ionosList [ 1 ] != 0 ) * ( corList [ 1 ] > corThresholdSwathAdj ) )
if index [ 0 ] . size < 5 :
print ( ' WARNING: too few samples available for adjustment between swaths: {} with coherence threshold: {} ' . format ( index [ 0 ] . size , corThresholdSwathAdj ) )
print ( ' no adjustment made ' )
print ( ' to do ajustment, please consider using lower coherence threshold ' )
else :
print ( ' number of samples available for adjustment in the overlap area: {} ' . format ( index [ 0 ] . size ) )
#diff = np.mean((ionosList[1] - adjdata)[index], dtype=np.float64)
#use weighted mean instead
wgt = corList [ 1 ] [ index ] * * 14
diff = np . sum ( ( ionosList [ 1 ] - adjdata ) [ index ] * wgt / np . sum ( wgt , dtype = np . float64 ) , dtype = np . float64 )
index2 = np . nonzero ( adjdata != 0 )
adjdata [ index2 ] = adjdata [ index2 ] + diff
#get merged ionosphere
ampMerged = np . zeros ( ( length , width ) , dtype = np . float32 )
corMerged = np . zeros ( ( length , width ) , dtype = np . float32 )
ionosMerged = np . zeros ( ( length , width ) , dtype = np . float32 )
for i in range ( numValidSwaths ) :
nBurst = len ( burstValidBox [ i ] )
for j in range ( nBurst ) :
#index after multi-looking in merged image, index starts from 1
first_line = np . int ( np . around ( ( burstValidBox [ i ] [ j ] [ 0 ] - 1 ) / numberAzimuthLooks + 1 ) )
last_line = np . int ( np . around ( burstValidBox [ i ] [ j ] [ 1 ] / numberAzimuthLooks ) )
first_sample = np . int ( np . around ( ( burstValidBox [ i ] [ j ] [ 2 ] - 1 ) / numberRangeLooks + 1 ) )
last_sample = np . int ( np . around ( burstValidBox [ i ] [ j ] [ 3 ] / numberRangeLooks ) )
corMerged [ first_line - 1 : last_line - 1 + 1 , first_sample - 1 : last_sample - 1 + 1 ] = \
corList [ i ] [ first_line - 1 : last_line - 1 + 1 , first_sample - 1 : last_sample - 1 + 1 ]
ampMerged [ first_line - 1 : last_line - 1 + 1 , first_sample - 1 : last_sample - 1 + 1 ] = \
ampList [ i ] [ first_line - 1 : last_line - 1 + 1 , first_sample - 1 : last_sample - 1 + 1 ]
ionosMerged [ first_line - 1 : last_line - 1 + 1 , first_sample - 1 : last_sample - 1 + 1 ] = \
ionosList [ i ] [ first_line - 1 : last_line - 1 + 1 , first_sample - 1 : last_sample - 1 + 1 ]
#remove an empirical ramp
if ionParam . rampRemovel != 0 :
warningInfo = ' {} calculating ionosphere for cross S-1A/B interferogram, an empirical ramp is removed from estimated ionosphere \n ' . format ( datetime . datetime . now ( ) )
with open ( os . path . join ( ionParam . ionDirname , ionParam . warning ) , ' a ' ) as f :
f . write ( warningInfo )
abramp = cal_cross_ab_ramp ( swathList , box [ 1 ] , numberRangeLooks , ionParam . passDirection )
if ionParam . rampRemovel == - 1 :
abramp * = - 1.0
#currently do not apply this
#ionosMerged -= abramp[None, :]
#dump ionosphere
outDir = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname )
2020-04-13 19:40:32 +00:00
os . makedirs ( outDir , exist_ok = True )
2019-01-16 19:40:08 +00:00
outFilename = os . path . join ( outDir , ionParam . ionRawNoProj )
ion = np . zeros ( ( length * 2 , width ) , dtype = np . float32 )
ion [ 0 : length * 2 : 2 , : ] = ampMerged
ion [ 1 : length * 2 : 2 , : ] = ionosMerged
ion . astype ( np . float32 ) . tofile ( outFilename )
img . filename = outFilename
img . extraFilename = outFilename + ' .vrt '
img . renderHdr ( )
#dump coherence
outFilename = os . path . join ( outDir , ionParam . ionCorNoProj )
ion [ 1 : length * 2 : 2 , : ] = corMerged
ion . astype ( np . float32 ) . tofile ( outFilename )
img . filename = outFilename
img . extraFilename = outFilename + ' .vrt '
img . renderHdr ( )
def multilookIndex ( first , last , nl ) :
'''
create the index after multilooking
the orginal 1 - look index can start from any number such as 0 , 1 or other number
after multilooking , the index still starts from the same number .
first : index of first pixel in the original 1 - look array
last : index of last pixel in the original 1 - look array
nl : number of looks ( nl can also be 1 ) . nl > = 1
'''
#number of pixels after multilooking
num = int ( ( last - first + 1 ) / nl )
offset = ( first + ( first + nl - 1 ) ) / 2.0
index = offset + np . arange ( num ) * nl
return index
def computeDopplerOffset ( burst , firstline , lastline , firstcolumn , lastcolumn , nrlks = 1 , nalks = 1 ) :
'''
compute offset corresponding to center Doppler frequency
firstline , lastline , firstcolumn , lastcolumn : index of original 1 - look burst , index starts from 1.
output : first lines > 0 , last lines < 0
'''
2019-12-16 18:22:01 +00:00
2019-01-16 19:40:08 +00:00
Vs = np . linalg . norm ( burst . orbit . interpolateOrbit ( burst . sensingMid , method = ' hermite ' ) . getVelocity ( ) )
Ks = 2 * Vs * burst . azimuthSteeringRate / burst . radarWavelength
#firstcolumn, lastcolumn: index starts from 1
rng = multilookIndex ( firstcolumn - 1 , lastcolumn - 1 , nrlks ) * burst . rangePixelSize + burst . startingRange
#firstline, lastline: index starts from 1
eta = ( multilookIndex ( firstline - 1 , lastline - 1 , nalks ) - ( burst . numberOfLines - 1.0 ) / 2.0 ) * burst . azimuthTimeInterval
f_etac = burst . doppler ( rng )
Ka = burst . azimuthFMRate ( rng )
eta_ref = ( burst . doppler ( burst . startingRange ) / burst . azimuthFMRate ( burst . startingRange ) ) - ( f_etac / Ka )
Kt = Ks / ( 1.0 - Ks / Ka )
#carr = np.pi * Kt[None,:] * ((eta[:,None] - eta_ref[None,:])**2)
#center doppler frequency due to rotation
dopplerOffset1 = ( eta [ : , None ] - eta_ref [ None , : ] ) * Kt / Ka [ None , : ] / ( burst . azimuthTimeInterval * nalks )
#center doppler frequency due to squint
dopplerOffset2 = ( f_etac [ None , : ] / Ka [ None , : ] ) / ( burst . azimuthTimeInterval * nalks )
dopplerOffset = dopplerOffset1 + dopplerOffset2
return ( dopplerOffset , Ka )
def grd2ion ( self , ionParam ) :
2020-04-13 19:11:04 +00:00
from scipy import interpolate
from scipy . interpolate import interp1d
2019-01-16 19:40:08 +00:00
print ( ' resampling ionosphere from ground to ionospheric layer ' )
#get files
corfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionCorNoProj )
ionfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionRawNoProj )
#use image size from lower unwrapped interferogram
img = isceobj . createImage ( )
img . load ( corfile + ' .xml ' )
width = img . width
length = img . length
cor = ( np . fromfile ( corfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
amp = ( np . fromfile ( ionfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
ionos = ( np . fromfile ( ionfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
2020-07-02 19:40:49 +00:00
#use the satellite height of the mid burst of first swath of reference acquistion
2019-01-16 19:40:08 +00:00
swathList = self . _insar . getValidSwathList ( self . swaths )
2020-07-02 19:40:49 +00:00
reference = self . _insar . loadProduct ( os . path . join ( self . _insar . referenceSlcProduct , ' IW {0} .xml ' . format ( swathList [ 0 ] ) ) )
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swathList [ 0 ] - 1 )
2019-01-16 19:40:08 +00:00
#no problem with this index at all
midBurst = np . int ( np . around ( ( minBurst + maxBurst - 1 ) / 2.0 ) )
2020-07-02 19:40:49 +00:00
masBurst = reference . bursts [ midBurst ]
2019-01-16 19:40:08 +00:00
#satellite height
satHeight = np . linalg . norm ( masBurst . orbit . interpolateOrbit ( masBurst . sensingMid , method = ' hermite ' ) . getPosition ( ) )
#orgininal doppler offset should be multiplied by this ratio
ratio = ionParam . ionHeight / ( satHeight - ionParam . earthRadius )
xmlDirname = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . fineIfgDirname )
( box , burstValidBox , burstValidBox2 , frames ) = getMergeBox ( self , xmlDirname , numberRangeLooks = ionParam . numberRangeLooks , numberAzimuthLooks = ionParam . numberAzimuthLooks )
##############################################################################################################
swathList = self . _insar . getValidSwathList ( self . swaths )
frames = [ ]
#for valid swaths and bursts, consistent with runMergeBursts.py
for swath in swathList :
2020-07-02 19:40:49 +00:00
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
if minBurst == maxBurst :
print ( ' Skipping processing of swath {0} ' . format ( swath ) )
continue
ifg = self . _insar . loadProduct ( os . path . join ( xmlDirname , ' IW {0} .xml ' . format ( swath ) ) )
frames . append ( ifg )
##############################################################################################################
for band in [ amp , ionos , cor ] :
nswath = len ( frames )
for i in range ( nswath ) :
nburst = len ( frames [ i ] . bursts )
for j in range ( nburst ) :
2020-07-02 19:40:49 +00:00
#according to runBurstIfg.py, this is originally from self._insar.referenceSlcProduct, 'IW{0}.xml'
2019-01-16 19:40:08 +00:00
masBurst = frames [ i ] . bursts [ j ]
( dopplerOffset , Ka ) = computeDopplerOffset ( masBurst , burstValidBox2 [ i ] [ j ] [ 0 ] , burstValidBox2 [ i ] [ j ] [ 1 ] , burstValidBox2 [ i ] [ j ] [ 2 ] , burstValidBox2 [ i ] [ j ] [ 3 ] , nrlks = ionParam . numberRangeLooks , nalks = ionParam . numberAzimuthLooks )
offset = ratio * dopplerOffset
# 0 1 2 3
#firstlineAdj, lastlineAdj, firstcolumnAdj, lastcolumnAdj,
#after multiplication, index starts from 1
firstline = np . int ( np . around ( ( burstValidBox [ i ] [ j ] [ 0 ] - 1 ) / ionParam . numberAzimuthLooks + 1 ) )
lastline = np . int ( np . around ( burstValidBox [ i ] [ j ] [ 1 ] / ionParam . numberAzimuthLooks ) )
firstcolumn = np . int ( np . around ( ( burstValidBox [ i ] [ j ] [ 2 ] - 1 ) / ionParam . numberRangeLooks + 1 ) )
lastcolumn = np . int ( np . around ( burstValidBox [ i ] [ j ] [ 3 ] / ionParam . numberRangeLooks ) )
#extract image
burstImage = band [ firstline - 1 : lastline , firstcolumn - 1 : lastcolumn ]
blength = lastline - firstline + 1
bwidth = lastcolumn - firstcolumn + 1
#interpolation
index0 = np . linspace ( 0 , blength - 1 , num = blength , endpoint = True )
for k in range ( bwidth ) :
index = index0 + offset [ : , k ]
value = burstImage [ : , k ]
f = interp1d ( index , value , kind = ' cubic ' , fill_value = " extrapolate " )
index_min = np . int ( np . around ( np . amin ( index ) ) )
index_max = np . int ( np . around ( np . amax ( index ) ) )
flag = index0 * 0.0
flag [ index_min : index_max + 1 ] = 1.0
#replace the original column with new column in burstImage
#this should also replace teh original column with new column in band
burstImage [ : , k ] = ( f ( index0 ) ) * flag
#dump ionosphere with projection
outDir = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname )
outFilename = os . path . join ( outDir , ionParam . ionRaw )
ion = np . zeros ( ( length * 2 , width ) , dtype = np . float32 )
ion [ 0 : length * 2 : 2 , : ] = amp
ion [ 1 : length * 2 : 2 , : ] = ionos
ion . astype ( np . float32 ) . tofile ( outFilename )
img . filename = outFilename
img . extraFilename = outFilename + ' .vrt '
img . renderHdr ( )
#dump coherence with projection
outFilename = os . path . join ( outDir , ionParam . ionCor )
ion [ 1 : length * 2 : 2 , : ] = cor
ion . astype ( np . float32 ) . tofile ( outFilename )
img . filename = outFilename
img . extraFilename = outFilename + ' .vrt '
img . renderHdr ( )
def gaussian ( size , sigma , scale = 1.0 ) :
if size % 2 != 1 :
raise Exception ( ' size must be odd ' )
hsize = ( size - 1 ) / 2
x = np . arange ( - hsize , hsize + 1 ) * scale
f = np . exp ( - x * * 2 / ( 2.0 * sigma * * 2 ) ) / ( sigma * np . sqrt ( 2.0 * np . pi ) )
f2d = np . matlib . repmat ( f , size , 1 ) * np . matlib . repmat ( f . reshape ( size , 1 ) , 1 , size )
return f2d / np . sum ( f2d )
def adaptive_gaussian ( ionos , wgt , size_max , size_min ) :
'''
This program performs Gaussian filtering with adaptive window size .
ionos : ionosphere
wgt : weight
size_max : maximum window size
size_min : minimum window size
'''
2019-12-16 18:22:01 +00:00
import scipy . signal as ss
2019-01-16 19:40:08 +00:00
length = ( ionos . shape ) [ 0 ]
width = ( ionos . shape ) [ 1 ]
flag = ( ionos != 0 ) * ( wgt != 0 )
ionos * = flag
wgt * = flag
size_num = 100
size = np . linspace ( size_min , size_max , num = size_num , endpoint = True )
std = np . zeros ( ( length , width , size_num ) )
flt = np . zeros ( ( length , width , size_num ) )
out = np . zeros ( ( length , width , 1 ) )
#calculate filterd image and standard deviation
#sigma of window size: size_max
sigma = size_max / 2.0
for i in range ( size_num ) :
size2 = np . int ( np . around ( size [ i ] ) )
if size2 % 2 == 0 :
size2 + = 1
if ( i + 1 ) % 10 == 0 :
print ( ' min win: %4d , max win: %4d , current win: %4d ' % ( np . int ( np . around ( size_min ) ) , np . int ( np . around ( size_max ) ) , size2 ) )
g2d = gaussian ( size2 , sigma * size2 / size_max , scale = 1.0 )
scale = ss . fftconvolve ( wgt , g2d , mode = ' same ' )
flt [ : , : , i ] = ss . fftconvolve ( ionos * wgt , g2d , mode = ' same ' ) / ( scale + ( scale == 0 ) )
#variance of resulting filtered sample
scale = scale * * 2
var = ss . fftconvolve ( wgt , g2d * * 2 , mode = ' same ' ) / ( scale + ( scale == 0 ) )
#in case there is a large area without data where scale is very small, which leads to wired values in variance
var [ np . nonzero ( var < 0 ) ] = 0
std [ : , : , i ] = np . sqrt ( var )
std_mv = np . mean ( std [ np . nonzero ( std != 0 ) ] , dtype = np . float64 )
diff_max = np . amax ( np . absolute ( std - std_mv ) ) + std_mv + 1
std [ np . nonzero ( std == 0 ) ] = diff_max
index = np . nonzero ( np . ones ( ( length , width ) ) ) + ( ( np . argmin ( np . absolute ( std - std_mv ) , axis = 2 ) ) . reshape ( length * width ) , )
out = flt [ index ]
out = out . reshape ( ( length , width ) )
#remove artifacts due to varying wgt
size_smt = size_min
if size_smt % 2 == 0 :
size_smt + = 1
g2d = gaussian ( size_smt , size_smt / 2.0 , scale = 1.0 )
scale = ss . fftconvolve ( ( out != 0 ) , g2d , mode = ' same ' )
out2 = ss . fftconvolve ( out , g2d , mode = ' same ' ) / ( scale + ( scale == 0 ) )
return out2
def filt_gaussian ( self , ionParam ) :
'''
This function filters image using gaussian filter
we projected the ionosphere value onto the ionospheric layer , and the indexes are integers .
this reduces the number of samples used in filtering
a better method is to project the indexes onto the ionospheric layer . This way we have orginal
number of samples used in filtering . but this requries more complicated operation in filtering
currently not implemented .
a less accurate method is to use ionsphere without any projection
'''
#################################################
#SET PARAMETERS HERE
#if applying polynomial fitting
#False: no fitting, True: with fitting
fit = ionParam . ionFit
#gaussian filtering window size
size_max = ionParam . ionFilteringWinsizeMax
size_min = ionParam . ionFilteringWinsizeMin
#THESE SHOULD BE GOOD ENOUGH, NO NEED TO SET IN setup(self)
corThresholdIon = 0.85
#################################################
print ( ' filtering ionosphere ' )
#I find it's better to use ionosphere that is not projected, it's mostly slowlying changing anyway.
#this should also be better for operational use.
ionfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionRawNoProj )
#since I decide to use ionosphere that is not projected, I should also use coherence that is not projected.
corfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionCorNoProj )
#use ionosphere and coherence that are projected.
#ionfile = os.path.join(ionParam.ionDirname, ionParam.ioncalDirname, ionParam.ionRaw)
#corfile = os.path.join(ionParam.ionDirname, ionParam.ioncalDirname, ionParam.ionCor)
outfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionFilt )
img = isceobj . createImage ( )
img . load ( ionfile + ' .xml ' )
width = img . width
length = img . length
ion = ( np . fromfile ( ionfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
cor = ( np . fromfile ( corfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
amp = ( np . fromfile ( ionfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
2021-08-09 20:31:40 +00:00
#masked out user-specified areas
if ionParam . maskedAreas != None :
maskedAreas = reformatMaskedAreas ( ionParam . maskedAreas , length , width )
for area in maskedAreas :
ion [ area [ 0 ] : area [ 1 ] , area [ 2 ] : area [ 3 ] ] = 0
cor [ area [ 0 ] : area [ 1 ] , area [ 2 ] : area [ 3 ] ] = 0
2019-01-16 19:40:08 +00:00
########################################################################################
#AFTER COHERENCE IS RESAMPLED AT grd2ion, THERE ARE SOME WIRED VALUES
cor [ np . nonzero ( cor < 0 ) ] = 0.0
cor [ np . nonzero ( cor > 1 ) ] = 0.0
########################################################################################
ion_fit = weight_fitting ( ion , cor , width , length , 1 , 1 , 1 , 1 , 2 , corThresholdIon )
#no fitting
if fit == False :
ion_fit * = 0
ion - = ion_fit * ( ion != 0 )
#minimize the effect of low coherence pixels
#cor[np.nonzero( (cor<0.85)*(cor!=0) )] = 0.00001
#filt = adaptive_gaussian(ion, cor, size_max, size_min)
#cor**14 should be a good weight to use. 22-APR-2018
filt = adaptive_gaussian ( ion , cor * * 14 , size_max , size_min )
filt + = ion_fit * ( filt != 0 )
ion = np . zeros ( ( length * 2 , width ) , dtype = np . float32 )
ion [ 0 : length * 2 : 2 , : ] = amp
ion [ 1 : length * 2 : 2 , : ] = filt
ion . astype ( np . float32 ) . tofile ( outfile )
img . filename = outfile
img . extraFilename = outfile + ' .vrt '
img . renderHdr ( )
def ionosphere_shift ( self , ionParam ) :
'''
calculate azimuth shift caused by ionosphere using ionospheric phase
'''
#################################################
#SET PARAMETERS HERE
#gaussian filtering window size
#size = np.int(np.around(width / 12.0))
#size = ionParam.ionshiftFilteringWinsize
size_max = ionParam . ionshiftFilteringWinsizeMax
size_min = ionParam . ionshiftFilteringWinsizeMin
#THESE SHOULD BE GOOD ENOUGH, NO NEED TO SET IN setup(self)
#if applying polynomial fitting
#0: no fitting, 1: with fitting
fit = 0
corThresholdIonshift = 0.85
#################################################
####################################################################
#STEP 1. GET DERIVATIVE OF IONOSPHERE
####################################################################
#get files
ionfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionFilt )
#we are using filtered ionosphere, so we should use coherence file that is not projected.
#corfile = os.path.join(ionParam.ionDirname, ionParam.ioncalDirname, ionParam.ionCor)
corfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionCorNoProj )
img = isceobj . createImage ( )
img . load ( ionfile + ' .xml ' )
width = img . width
length = img . length
amp = ( np . fromfile ( ionfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
ion = ( np . fromfile ( ionfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
cor = ( np . fromfile ( corfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
########################################################################################
#AFTER COHERENCE IS RESAMPLED AT grd2ion, THERE ARE SOME WIRED VALUES
cor [ np . nonzero ( cor < 0 ) ] = 0.0
cor [ np . nonzero ( cor > 1 ) ] = 0.0
########################################################################################
#get the azimuth derivative of ionosphere
dion = np . diff ( ion , axis = 0 )
dion = np . concatenate ( ( dion , np . zeros ( ( 1 , width ) ) ) , axis = 0 )
#remove the samples affected by zeros
flag_ion0 = ( ion != 0 )
#moving down by one line
flag_ion1 = np . roll ( flag_ion0 , 1 , axis = 0 )
flag_ion1 [ 0 , : ] = 0
#moving up by one line
flag_ion2 = np . roll ( flag_ion0 , - 1 , axis = 0 )
flag_ion2 [ - 1 , : ] = 0
#now remove the samples affected by zeros
flag_ion = flag_ion0 * flag_ion1 * flag_ion2
dion * = flag_ion
flag = flag_ion * ( cor > corThresholdIonshift )
index = np . nonzero ( flag )
####################################################################
#STEP 2. FIT A POLYNOMIAL TO THE DERIVATIVE OF IONOSPHERE
####################################################################
order = 3
#look for data to use
point_index = np . nonzero ( flag )
m = point_index [ 0 ] . shape [ 0 ]
#calculate input index matrix
x0 = np . matlib . repmat ( np . arange ( width ) , length , 1 )
y0 = np . matlib . repmat ( np . arange ( length ) . reshape ( length , 1 ) , 1 , width )
x = x0 [ point_index ] . reshape ( m , 1 )
y = y0 [ point_index ] . reshape ( m , 1 )
z = dion [ point_index ] . reshape ( m , 1 )
w = cor [ point_index ] . reshape ( m , 1 )
#convert to higher precision type before use
x = np . asfarray ( x , np . float64 )
y = np . asfarray ( y , np . float64 )
z = np . asfarray ( z , np . float64 )
w = np . asfarray ( w , np . float64 )
coeff = fit_surface ( x , y , z , w , order )
rgindex = np . arange ( width )
azindex = np . arange ( length ) . reshape ( length , 1 )
#convert to higher precision type before use
rgindex = np . asfarray ( rgindex , np . float64 )
azindex = np . asfarray ( azindex , np . float64 )
dion_fit = cal_surface ( rgindex , azindex , coeff , order )
#no fitting
if fit == 0 :
dion_fit * = 0
dion_res = ( dion - dion_fit ) * ( dion != 0 )
####################################################################
#STEP 3. FILTER THE RESIDUAL OF THE DERIVATIVE OF IONOSPHERE
####################################################################
#this will be affected by low coherence areas like water, so not use this.
#filter the derivation of ionosphere
#if size % 2 == 0:
# size += 1
#sigma = size / 2.0
#g2d = gaussian(size, sigma, scale=1.0)
#scale = ss.fftconvolve((dion_res!=0), g2d, mode='same')
#dion_filt = ss.fftconvolve(dion_res, g2d, mode='same') / (scale + (scale==0))
#minimize the effect of low coherence pixels
cor [ np . nonzero ( ( cor < 0.85 ) * ( cor != 0 ) ) ] = 0.00001
dion_filt = adaptive_gaussian ( dion_res , cor , size_max , size_min )
dion = ( dion_fit + dion_filt ) * ( dion != 0 )
#return dion
####################################################################
#STEP 4. CONVERT TO AZIMUTH SHIFT
####################################################################
2020-07-02 19:40:49 +00:00
#use the satellite height of the mid burst of first swath of reference acquistion
2019-01-16 19:40:08 +00:00
swathList = self . _insar . getValidSwathList ( self . swaths )
2020-07-02 19:40:49 +00:00
reference = self . _insar . loadProduct ( os . path . join ( self . _insar . referenceSlcProduct , ' IW {0} .xml ' . format ( swathList [ 0 ] ) ) )
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swathList [ 0 ] - 1 )
2019-01-16 19:40:08 +00:00
#no problem with this index at all
midBurst = np . int ( np . around ( ( minBurst + maxBurst - 1 ) / 2.0 ) )
2020-07-02 19:40:49 +00:00
masBurst = reference . bursts [ midBurst ]
2019-01-16 19:40:08 +00:00
#shift casued by ionosphere [unit: masBurst.azimuthTimeInterval]
rng = masBurst . rangePixelSize * ( ( np . arange ( width ) ) * ionParam . numberRangeLooks + ( ionParam . numberRangeLooks - 1.0 ) / 2.0 ) + masBurst . startingRange
Ka = masBurst . azimuthFMRate ( rng )
ionShift = dion / ( masBurst . azimuthTimeInterval * ionParam . numberAzimuthLooks ) / ( 4.0 * np . pi ) / Ka [ None , : ] / masBurst . azimuthTimeInterval
#output
outfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionShift )
tmp = np . zeros ( ( length * 2 , width ) , dtype = np . float32 )
tmp [ 0 : length * 2 : 2 , : ] = amp
tmp [ 1 : length * 2 : 2 , : ] = ionShift
tmp . astype ( np . float32 ) . tofile ( outfile )
img . filename = outfile
img . extraFilename = outfile + ' .vrt '
img . renderHdr ( )
def ion2grd ( self , ionParam ) :
2020-04-13 19:11:04 +00:00
from scipy import interpolate
from scipy . interpolate import interp1d
2019-01-16 19:40:08 +00:00
#################################################
#SET PARAMETERS HERE
#correct phase error caused by non-zero center frequency
#and azimuth shift caused by ionosphere
#0: no correction
#1: use mean value of a burst
#2: use full burst
azshiftFlag = ionParam . azshiftFlag
#################################################
print ( ' resampling ionosphere from ionospheric layer to ground ' )
#get files
ionFiltFile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionFilt )
dionfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionShift )
corfile = os . path . join ( ionParam . ionDirname , ionParam . ioncalDirname , ionParam . ionCorNoProj )
img = isceobj . createImage ( )
img . load ( ionFiltFile + ' .xml ' )
width = img . width
length = img . length
ion = ( np . fromfile ( ionFiltFile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
dion = ( np . fromfile ( dionfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
cor = ( np . fromfile ( corfile , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
print ( ' resampling ionosphere in range ' )
#in the following, column index of burst (one look) will never exceed merged image index (one look) on the left side.
#so we only add one multi-looked sample on the right side in case it exceeds on this side
#index starts from 0
ionOneRangeLook = np . zeros ( ( length , ( width + 1 ) * ionParam . numberRangeLooks ) , dtype = np . float32 )
if azshiftFlag == 2 :
dionOneRangeLook = np . zeros ( ( length , ( width + 1 ) * ionParam . numberRangeLooks ) , dtype = np . float32 )
indexRange = np . linspace ( 1 - 1 , ( width + 1 ) * ionParam . numberRangeLooks - 1 , num = ( width + 1 ) * ionParam . numberRangeLooks , endpoint = True )
indexRange2 = multilookIndex ( 1 - 1 , width * ionParam . numberRangeLooks - 1 , ionParam . numberRangeLooks )
for i in range ( length ) :
f = interp1d ( indexRange2 , ion [ i , : ] , kind = ' cubic ' , fill_value = " extrapolate " )
ionOneRangeLook [ i , : ] = f ( indexRange )
if azshiftFlag == 2 :
f2 = interp1d ( indexRange2 , dion [ i , : ] , kind = ' cubic ' , fill_value = " extrapolate " )
dionOneRangeLook [ i , : ] = f2 ( indexRange )
2020-07-02 19:40:49 +00:00
#use the satellite height of the mid burst of first swath of reference acquistion
2019-01-16 19:40:08 +00:00
swathList = self . _insar . getValidSwathList ( self . swaths )
2020-07-02 19:40:49 +00:00
reference = self . _insar . loadProduct ( os . path . join ( self . _insar . referenceSlcProduct , ' IW {0} .xml ' . format ( swathList [ 0 ] ) ) )
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swathList [ 0 ] - 1 )
2019-01-16 19:40:08 +00:00
#no problem with this index at all
midBurst = np . int ( np . around ( ( minBurst + maxBurst - 1 ) / 2.0 ) )
2020-07-02 19:40:49 +00:00
masBurst = reference . bursts [ midBurst ]
2019-01-16 19:40:08 +00:00
#satellite height
satHeight = np . linalg . norm ( masBurst . orbit . interpolateOrbit ( masBurst . sensingMid , method = ' hermite ' ) . getPosition ( ) )
#orgininal doppler offset should be multiplied by this ratio
ratio = ionParam . ionHeight / ( satHeight - ionParam . earthRadius )
xmlDirname = os . path . join ( ionParam . ionDirname , ionParam . lowerDirname , ionParam . fineIfgDirname )
( box , burstValidBox , burstValidBox2 , frames ) = getMergeBox ( self , xmlDirname , numberRangeLooks = ionParam . numberRangeLooks , numberAzimuthLooks = ionParam . numberAzimuthLooks )
##############################################################################################################
swathList = self . _insar . getValidSwathList ( self . swaths )
frames = [ ]
swathList2 = [ ]
minBurst2 = [ ]
#for valid swaths and bursts, consistent with runMergeBursts.py
for swath in swathList :
2020-07-02 19:40:49 +00:00
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
if minBurst == maxBurst :
print ( ' Skipping processing of swath {0} ' . format ( swath ) )
continue
ifg = self . _insar . loadProduct ( os . path . join ( xmlDirname , ' IW {0} .xml ' . format ( swath ) ) )
frames . append ( ifg )
swathList2 . append ( swath )
minBurst2 . append ( minBurst )
##############################################################################################################
print ( ' resampling ionosphere in azimuth ' )
nswath = len ( frames )
for i in range ( nswath ) :
nburst = len ( frames [ i ] . bursts )
###output directory for burst ionosphere
outdir = os . path . join ( ionParam . ionDirname , ionParam . ionBurstDirname , ' IW {0} ' . format ( swathList2 [ i ] ) )
2020-04-13 19:40:32 +00:00
os . makedirs ( outdir , exist_ok = True )
2019-01-16 19:40:08 +00:00
for j in range ( nburst ) :
2020-07-02 19:40:49 +00:00
#according to runBurstIfg.py, this is originally from self._insar.referenceSlcProduct, 'IW{0}.xml'
2019-01-16 19:40:08 +00:00
masBurst = frames [ i ] . bursts [ j ]
( dopplerOffset , Ka ) = computeDopplerOffset ( masBurst , 1 , masBurst . numberOfLines , 1 , masBurst . numberOfSamples , nrlks = 1 , nalks = 1 )
offset = ratio * dopplerOffset
#output ionosphere for this burst
burstIon = np . zeros ( ( masBurst . numberOfLines , masBurst . numberOfSamples ) , dtype = np . float32 )
burstDion = np . zeros ( ( masBurst . numberOfLines , masBurst . numberOfSamples ) , dtype = np . float32 )
# index in merged index in burst
lineOff = burstValidBox [ i ] [ j ] [ 0 ] - burstValidBox2 [ i ] [ j ] [ 0 ]
columnOff = burstValidBox [ i ] [ j ] [ 2 ] - burstValidBox2 [ i ] [ j ] [ 2 ]
#use index starts from 0
#1-look index of burst in the 1-look merged image
indexBurst0 = np . linspace ( 0 + lineOff , masBurst . numberOfLines - 1 + lineOff , num = masBurst . numberOfLines , endpoint = True )
#1-look index of multi-looked merged image in the 1-look merged image
indexMerged = multilookIndex ( 1 - 1 , length * ionParam . numberAzimuthLooks - 1 , ionParam . numberAzimuthLooks )
for k in range ( masBurst . numberOfSamples ) :
index = indexMerged
value = ionOneRangeLook [ : , k + columnOff ]
f = interp1d ( index , value , kind = ' cubic ' , fill_value = " extrapolate " )
indexBurst = indexBurst0 + offset [ : , k ]
burstIon [ : , k ] = f ( indexBurst )
if azshiftFlag == 2 :
value2 = dionOneRangeLook [ : , k + columnOff ]
f2 = interp1d ( index , value2 , kind = ' cubic ' , fill_value = " extrapolate " )
burstDion [ : , k ] = f2 ( indexBurst )
#calculate phase caused by ionospheric shift and non-zero center frequency
#index after multi-looking in merged image, index starts from 1
first_line = np . int ( np . around ( ( burstValidBox [ i ] [ j ] [ 0 ] - 1 ) / ionParam . numberAzimuthLooks + 1 ) )
last_line = np . int ( np . around ( burstValidBox [ i ] [ j ] [ 1 ] / ionParam . numberAzimuthLooks ) )
first_sample = np . int ( np . around ( ( burstValidBox [ i ] [ j ] [ 2 ] - 1 ) / ionParam . numberRangeLooks + 1 ) )
last_sample = np . int ( np . around ( burstValidBox [ i ] [ j ] [ 3 ] / ionParam . numberRangeLooks ) )
burstDionMultilook = dion [ first_line - 1 : last_line - 1 + 1 , first_sample - 1 : last_sample - 1 + 1 ]
#for avoid areas with strong decorrelation like water
burstCorMultilook = cor [ first_line - 1 : last_line - 1 + 1 , first_sample - 1 : last_sample - 1 + 1 ]
#index = np.nonzero(burstDionMultilook!=0)
index = np . nonzero ( burstCorMultilook > 0.85 )
if len ( index [ 0 ] ) < 10 :
dionMean = 0.0
else :
dionMean = np . mean ( burstDionMultilook [ index ] , dtype = np . float64 )
if azshiftFlag == 0 :
#no correction
burstIonShift = 0
elif azshiftFlag == 1 :
#use mean value
burstIonShift = 2.0 * np . pi * ( dopplerOffset * Ka [ None , : ] * ( masBurst . azimuthTimeInterval ) ) * ( dionMean * masBurst . azimuthTimeInterval )
elif azshiftFlag == 2 :
#use full burst
burstIonShift = 2.0 * np . pi * ( dopplerOffset * Ka [ None , : ] * ( masBurst . azimuthTimeInterval ) ) * ( burstDion * masBurst . azimuthTimeInterval )
else :
raise Exception ( ' unknown option for correcting azimuth shift caused by ionosphere! ' )
burstIon + = burstIonShift
print ( ' resampling burst %02d of swath %d , azimuth shift caused by ionosphere: %8.5f azimuth lines ' % ( minBurst2 [ i ] + j + 1 , swathList2 [ i ] , dionMean ) )
#create xml and vrt files
filename = os . path . join ( outdir , ' %s _ %02d .ion ' % ( ' burst ' , minBurst2 [ i ] + j + 1 ) )
burstIon . astype ( np . float32 ) . tofile ( filename )
burstImg = isceobj . createImage ( )
burstImg . setDataType ( ' FLOAT ' )
burstImg . setFilename ( filename )
burstImg . extraFilename = filename + ' .vrt '
burstImg . setWidth ( masBurst . numberOfSamples )
burstImg . setLength ( masBurst . numberOfLines )
burstImg . renderHdr ( )
print ( ' ' )
def multilook ( data , nalks , nrlks ) :
'''
doing multiple looking
ATTENTION :
NO AVERAGING BY DIVIDING THE NUMBER OF TOTAL SAMPLES IS DONE .
'''
( length , width ) = data . shape
width2 = np . int ( width / nrlks )
length2 = np . int ( length / nalks )
tmp2 = np . zeros ( ( length2 , width ) , dtype = data . dtype )
data2 = np . zeros ( ( length2 , width2 ) , dtype = data . dtype )
for i in range ( nalks ) :
tmp2 + = data [ i : length2 * nalks : nalks , : ]
for i in range ( nrlks ) :
data2 + = tmp2 [ : , i : width2 * nrlks : nrlks ]
return data2
def get_overlap_box ( swath , minBurst , maxBurst ) :
#number of burst
nBurst = maxBurst - minBurst
if nBurst < = 1 :
print ( ' number of burst: {} , no need to get overlap box ' . format ( nBurst ) )
return None
overlapBox = [ ]
overlapBox . append ( [ ] )
for ii in range ( minBurst + 1 , maxBurst ) :
topBurst = swath . bursts [ ii - 1 ]
curBurst = swath . bursts [ ii ]
#overlap lines, line index starts from 1
offLine = np . int ( np . round ( ( curBurst . sensingStart - topBurst . sensingStart ) . total_seconds ( ) / curBurst . azimuthTimeInterval ) )
firstLineTop = topBurst . firstValidLine + 1
lastLineTop = topBurst . firstValidLine + topBurst . numValidLines
firstLineCur = offLine + curBurst . firstValidLine + 1
lastLineCur = offLine + curBurst . firstValidLine + curBurst . numValidLines
if lastLineTop < firstLineCur :
raise Exception ( ' there is not enough overlap between burst {} and burst {} \n ' . format ( ii - 1 + 1 , ii + 1 ) )
firstLine = firstLineCur
lastLine = lastLineTop
#overlap samples, sample index starts from 1
offSample = np . int ( np . round ( ( curBurst . startingRange - topBurst . startingRange ) / curBurst . rangePixelSize ) )
firstSampleTop = topBurst . firstValidSample + 1
lastSampleTop = topBurst . firstValidSample + topBurst . numValidSamples
firstSampleCur = offSample + curBurst . firstValidSample + 1
lastSampleCur = offSample + curBurst . firstValidSample + curBurst . numValidSamples
firstSample = max ( firstSampleTop , firstSampleCur )
lastSample = min ( lastSampleTop , lastSampleCur )
#overlap area index. all indexes start from 1.
# | top burst | current burst |
# 0 1 2 3 4 5 6 7
overlapBox . append ( [ firstLine , lastLine , firstSample , lastSample , firstLine - offLine , lastLine - offLine , firstSample - offSample , lastSample - offSample ] )
return overlapBox
def esd ( self , ionParam ) :
'''
esd after ionosphere correction
'''
######################################
#SET PARAMETERS HERE
#THESE SHOULD BE GOOD ENOUGH, NO NEED TO SET IN setup(self)
nalks = 5
nrlks = 30
corThreshold = 0.75
######################################
print ( ' applying ESD to compensate phase error caused by residual misregistration ' )
virtual = self . useVirtualFiles
swathList = self . _insar . getValidSwathList ( self . swaths )
for swath in swathList :
2020-07-02 19:40:49 +00:00
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
nBurst = maxBurst - minBurst
if nBurst < = 1 :
continue
####Load relevant products
2020-07-02 19:40:49 +00:00
reference = self . _insar . loadProduct ( os . path . join ( self . _insar . referenceSlcProduct , ' IW {0} .xml ' . format ( swath ) ) )
secondary = self . _insar . loadProduct ( os . path . join ( self . _insar . fineCoregDirname , ' IW {0} .xml ' . format ( swath ) ) )
2019-01-16 19:40:08 +00:00
#get overlap area
for ii in range ( minBurst , maxBurst ) :
jj = ii - minBurst
####Process the top bursts
2020-07-02 19:40:49 +00:00
masBurst = reference . bursts [ ii ]
slvBurst = secondary . bursts [ jj ]
2019-01-16 19:40:08 +00:00
adjustValidLineSample ( masBurst , slvBurst )
2020-07-02 19:40:49 +00:00
overlapBox = get_overlap_box ( reference , minBurst , maxBurst )
2019-01-16 19:40:08 +00:00
#using esd to calculate mis-registration
misreg = np . array ( [ ] )
totalSamples = 0
for ii in range ( minBurst + 1 , maxBurst ) :
jj = ii - minBurst
####Process the top bursts
2020-07-02 19:40:49 +00:00
masBurstTop = reference . bursts [ ii - 1 ]
slvBurstTop = secondary . bursts [ jj - 1 ]
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
masBurstCur = reference . bursts [ ii ]
slvBurstCur = secondary . bursts [ jj ]
2019-01-16 19:40:08 +00:00
#get info
2020-07-02 19:40:49 +00:00
referencename = masBurstTop . image . filename
secondaryname = slvBurstTop . image . filename
2019-01-16 19:40:08 +00:00
ionname = os . path . join ( ionParam . ionDirname , ionParam . ionBurstDirname , ' IW {0} ' . format ( swath ) , ' %s _ %02d .ion ' % ( ' burst ' , ii + 1 - 1 ) )
rngname = os . path . join ( self . _insar . fineOffsetsDirname , ' IW {0} ' . format ( swath ) , ' range_ %02d .off ' % ( ii + 1 - 1 ) )
fact = 4.0 * np . pi * slvBurstTop . rangePixelSize / slvBurstTop . radarWavelength
2020-07-02 19:40:49 +00:00
#infTop = multiply2(referencename, secondaryname, ionname, rngname, fact, overlapBox[jj][0:4], virtual=virtual)
infTop = multiply2 ( referencename , secondaryname , fact , rngname = rngname , ionname = ionname , infname = None , overlapBox = overlapBox [ jj ] [ 0 : 4 ] , valid = True , virtual = virtual )
2019-01-16 19:40:08 +00:00
( dopTop , Ka ) = computeDopplerOffset ( masBurstTop , overlapBox [ jj ] [ 0 ] , overlapBox [ jj ] [ 1 ] , overlapBox [ jj ] [ 2 ] , overlapBox [ jj ] [ 3 ] , nrlks = nrlks , nalks = nalks )
#rng = multilookIndex(overlapBox[jj][2]-1, overlapBox[jj][3]-1, nrlks) * masBurstTop.rangePixelSize + masBurstTop.startingRange
#Ka = masBurstTop.azimuthFMRate(rng)
frqTop = dopTop * Ka [ None , : ] * ( masBurstTop . azimuthTimeInterval * nalks )
2020-07-02 19:40:49 +00:00
referencename = masBurstCur . image . filename
secondaryname = slvBurstCur . image . filename
2019-01-16 19:40:08 +00:00
ionname = os . path . join ( ionParam . ionDirname , ionParam . ionBurstDirname , ' IW {0} ' . format ( swath ) , ' %s _ %02d .ion ' % ( ' burst ' , ii + 1 ) )
rngname = os . path . join ( self . _insar . fineOffsetsDirname , ' IW {0} ' . format ( swath ) , ' range_ %02d .off ' % ( ii + 1 ) )
fact = 4.0 * np . pi * slvBurstCur . rangePixelSize / slvBurstCur . radarWavelength
2020-07-02 19:40:49 +00:00
#infCur = multiply2(referencename, secondaryname, ionname, rngname, fact, overlapBox[jj][4:8], virtual=virtual)
infCur = multiply2 ( referencename , secondaryname , fact , rngname = rngname , ionname = ionname , infname = None , overlapBox = overlapBox [ jj ] [ 4 : 8 ] , valid = True , virtual = virtual )
2019-01-16 19:40:08 +00:00
( dopCur , Ka ) = computeDopplerOffset ( masBurstCur , overlapBox [ jj ] [ 4 ] , overlapBox [ jj ] [ 5 ] , overlapBox [ jj ] [ 6 ] , overlapBox [ jj ] [ 7 ] , nrlks = nrlks , nalks = nalks )
#rng = multilookIndex(overlapBox[jj][6]-1, overlapBox[jj][7]-1, nrlks) * masBurstCur.rangePixelSize + masBurstCur.startingRange
#Ka = masBurstCur.azimuthFMRate(rng)
frqCur = dopCur * Ka [ None , : ] * ( masBurstCur . azimuthTimeInterval * nalks )
infTop = multilook ( infTop , nalks , nrlks )
infCur = multilook ( infCur , nalks , nrlks )
infDif = infTop * np . conjugate ( infCur )
cor = cal_coherence ( infDif , win = 3 , edge = 4 )
index = np . nonzero ( cor > corThreshold )
totalSamples + = infTop . size
if index [ 0 ] . size :
2020-07-02 19:40:49 +00:00
#misregistration in sec. it should be OK to only use reference frequency to compute ESD
2019-01-16 19:40:08 +00:00
misreg0 = np . angle ( infDif [ index ] ) / ( 2.0 * np . pi * ( frqTop [ index ] - frqCur [ index ] ) )
misreg = np . append ( misreg , misreg0 . flatten ( ) )
print ( " misregistration at burst %02d and burst %02d of swath %d : %10.5f azimuth lines " % ( ii + 1 - 1 , ii + 1 , swath , np . mean ( misreg0 , dtype = np . float64 ) / masBurstCur . azimuthTimeInterval ) )
else :
print ( " no samples available for ESD at burst %02d and burst %02d of swath %d " % ( ii + 1 - 1 , ii + 1 , swath ) )
percentage = 100.0 * len ( misreg ) / totalSamples
#number of samples per overlap: 100/5*23334/150 = 3111.2
print ( " samples available for ESD at swath %d : %d out of %d available, percentage: %5.1f %% " % ( swath , len ( misreg ) , totalSamples , percentage ) )
if len ( misreg ) < 1000 :
print ( " too few samples available for ESD, no ESD correction will be applied \n " )
misreg = 0
continue
else :
misreg = np . mean ( misreg , dtype = np . float64 )
2020-07-02 19:40:49 +00:00
print ( " misregistration from ESD: {} sec, {} azimuth lines \n " . format ( misreg , misreg / reference . bursts [ minBurst ] . azimuthTimeInterval ) )
2019-01-16 19:40:08 +00:00
#use mis-registration estimated from esd to compute phase error
for ii in range ( minBurst , maxBurst ) :
jj = ii - minBurst
####Process the top bursts
2020-07-02 19:40:49 +00:00
masBurst = reference . bursts [ ii ]
slvBurst = secondary . bursts [ jj ]
2019-01-16 19:40:08 +00:00
ionname = os . path . join ( ionParam . ionDirname , ionParam . ionBurstDirname , ' IW {0} ' . format ( swath ) , ' %s _ %02d .ion ' % ( ' burst ' , ii + 1 ) )
ion = np . fromfile ( ionname , dtype = np . float32 ) . reshape ( masBurst . numberOfLines , masBurst . numberOfSamples )
( dopplerOffset , Ka ) = computeDopplerOffset ( masBurst , 1 , masBurst . numberOfLines , 1 , masBurst . numberOfSamples , nrlks = 1 , nalks = 1 )
centerFrequency = dopplerOffset * Ka [ None , : ] * ( masBurst . azimuthTimeInterval )
ion + = 2.0 * np . pi * centerFrequency * misreg
#overwrite
ion . astype ( np . float32 ) . tofile ( ionname )
def esd_noion ( self , ionParam ) :
'''
esd after ionosphere correction
'''
######################################
#SET PARAMETERS HERE
#THESE SHOULD BE GOOD ENOUGH, NO NEED TO SET IN setup(self)
nalks = 5
nrlks = 30
corThreshold = 0.75
######################################
print ( ' applying ESD to compensate phase error caused by residual misregistration ' )
esddir = ' esd '
virtual = self . useVirtualFiles
swathList = self . _insar . getValidSwathList ( self . swaths )
for swath in swathList :
2020-07-02 19:40:49 +00:00
minBurst , maxBurst = self . _insar . commonReferenceBurstLimits ( swath - 1 )
2019-01-16 19:40:08 +00:00
nBurst = maxBurst - minBurst
if nBurst < = 1 :
continue
####Load relevant products
2020-07-02 19:40:49 +00:00
reference = self . _insar . loadProduct ( os . path . join ( self . _insar . referenceSlcProduct , ' IW {0} .xml ' . format ( swath ) ) )
secondary = self . _insar . loadProduct ( os . path . join ( self . _insar . fineCoregDirname , ' IW {0} .xml ' . format ( swath ) ) )
2019-01-16 19:40:08 +00:00
#get overlap area
for ii in range ( minBurst , maxBurst ) :
jj = ii - minBurst
####Process the top bursts
2020-07-02 19:40:49 +00:00
masBurst = reference . bursts [ ii ]
slvBurst = secondary . bursts [ jj ]
2019-01-16 19:40:08 +00:00
adjustValidLineSample ( masBurst , slvBurst )
2020-07-02 19:40:49 +00:00
overlapBox = get_overlap_box ( reference , minBurst , maxBurst )
2019-01-16 19:40:08 +00:00
#using esd to calculate mis-registration
misreg = np . array ( [ ] )
totalSamples = 0
for ii in range ( minBurst + 1 , maxBurst ) :
jj = ii - minBurst
####Process the top bursts
2020-07-02 19:40:49 +00:00
masBurstTop = reference . bursts [ ii - 1 ]
slvBurstTop = secondary . bursts [ jj - 1 ]
2019-01-16 19:40:08 +00:00
2020-07-02 19:40:49 +00:00
masBurstCur = reference . bursts [ ii ]
slvBurstCur = secondary . bursts [ jj ]
2019-01-16 19:40:08 +00:00
#get info
2020-07-02 19:40:49 +00:00
referencename = masBurstTop . image . filename
secondaryname = slvBurstTop . image . filename
2019-01-16 19:40:08 +00:00
ionname = os . path . join ( ionParam . ionDirname , ionParam . ionBurstDirname , ' IW {0} ' . format ( swath ) , ' %s _ %02d .ion ' % ( ' burst ' , ii + 1 - 1 ) )
rngname = os . path . join ( self . _insar . fineOffsetsDirname , ' IW {0} ' . format ( swath ) , ' range_ %02d .off ' % ( ii + 1 - 1 ) )
fact = 4.0 * np . pi * slvBurstTop . rangePixelSize / slvBurstTop . radarWavelength
2020-07-02 19:40:49 +00:00
#infTop = multiply2(referencename, secondaryname, ionname, rngname, fact, overlapBox[jj][0:4], virtual=virtual)
infTop = multiply2 ( referencename , secondaryname , fact , rngname = rngname , ionname = None , infname = None , overlapBox = overlapBox [ jj ] [ 0 : 4 ] , valid = True , virtual = virtual )
2019-01-16 19:40:08 +00:00
( dopTop , Ka ) = computeDopplerOffset ( masBurstTop , overlapBox [ jj ] [ 0 ] , overlapBox [ jj ] [ 1 ] , overlapBox [ jj ] [ 2 ] , overlapBox [ jj ] [ 3 ] , nrlks = nrlks , nalks = nalks )
#rng = multilookIndex(overlapBox[jj][2]-1, overlapBox[jj][3]-1, nrlks) * masBurstTop.rangePixelSize + masBurstTop.startingRange
#Ka = masBurstTop.azimuthFMRate(rng)
frqTop = dopTop * Ka [ None , : ] * ( masBurstTop . azimuthTimeInterval * nalks )
2020-07-02 19:40:49 +00:00
referencename = masBurstCur . image . filename
secondaryname = slvBurstCur . image . filename
2019-01-16 19:40:08 +00:00
ionname = os . path . join ( ionParam . ionDirname , ionParam . ionBurstDirname , ' IW {0} ' . format ( swath ) , ' %s _ %02d .ion ' % ( ' burst ' , ii + 1 ) )
rngname = os . path . join ( self . _insar . fineOffsetsDirname , ' IW {0} ' . format ( swath ) , ' range_ %02d .off ' % ( ii + 1 ) )
fact = 4.0 * np . pi * slvBurstCur . rangePixelSize / slvBurstCur . radarWavelength
2020-07-02 19:40:49 +00:00
#infCur = multiply2(referencename, secondaryname, ionname, rngname, fact, overlapBox[jj][4:8], virtual=virtual)
infCur = multiply2 ( referencename , secondaryname , fact , rngname = rngname , ionname = None , infname = None , overlapBox = overlapBox [ jj ] [ 4 : 8 ] , valid = True , virtual = virtual )
2019-01-16 19:40:08 +00:00
( dopCur , Ka ) = computeDopplerOffset ( masBurstCur , overlapBox [ jj ] [ 4 ] , overlapBox [ jj ] [ 5 ] , overlapBox [ jj ] [ 6 ] , overlapBox [ jj ] [ 7 ] , nrlks = nrlks , nalks = nalks )
#rng = multilookIndex(overlapBox[jj][6]-1, overlapBox[jj][7]-1, nrlks) * masBurstCur.rangePixelSize + masBurstCur.startingRange
#Ka = masBurstCur.azimuthFMRate(rng)
frqCur = dopCur * Ka [ None , : ] * ( masBurstCur . azimuthTimeInterval * nalks )
infTop = multilook ( infTop , nalks , nrlks )
infCur = multilook ( infCur , nalks , nrlks )
infDif = infTop * np . conjugate ( infCur )
cor = cal_coherence ( infDif , win = 3 , edge = 4 )
index = np . nonzero ( cor > corThreshold )
totalSamples + = infTop . size
if index [ 0 ] . size :
2020-07-02 19:40:49 +00:00
#misregistration in sec. it should be OK to only use reference frequency to compute ESD
2019-01-16 19:40:08 +00:00
misreg0 = np . angle ( infDif [ index ] ) / ( 2.0 * np . pi * ( frqTop [ index ] - frqCur [ index ] ) )
misreg = np . append ( misreg , misreg0 . flatten ( ) )
print ( " misregistration at burst %02d and burst %02d of swath %d : %10.5f azimuth lines " % ( ii + 1 - 1 , ii + 1 , swath , np . mean ( misreg0 , dtype = np . float64 ) / masBurstCur . azimuthTimeInterval ) )
else :
print ( " no samples available for ESD at burst %02d and burst %02d of swath %d " % ( ii + 1 - 1 , ii + 1 , swath ) )
percentage = 100.0 * len ( misreg ) / totalSamples
#number of samples per overlap: 100/5*23334/150 = 3111.2
print ( " samples available for ESD at swath %d : %d out of %d available, percentage: %5.1f %% " % ( swath , len ( misreg ) , totalSamples , percentage ) )
if len ( misreg ) < 1000 :
print ( " too few samples available for ESD, no ESD correction will be applied \n " )
misreg = 0
continue
else :
misreg = np . mean ( misreg , dtype = np . float64 )
2020-07-02 19:40:49 +00:00
print ( " misregistration from ESD: {} sec, {} azimuth lines \n " . format ( misreg , misreg / reference . bursts [ minBurst ] . azimuthTimeInterval ) )
2019-01-16 19:40:08 +00:00
sdir = os . path . join ( ionParam . ionDirname , esddir , ' IW {0} ' . format ( swath ) )
2020-04-13 19:40:32 +00:00
os . makedirs ( sdir , exist_ok = True )
2019-01-16 19:40:08 +00:00
#use mis-registration estimated from esd to compute phase error
for ii in range ( minBurst , maxBurst ) :
jj = ii - minBurst
####Process the top bursts
2020-07-02 19:40:49 +00:00
masBurst = reference . bursts [ ii ]
slvBurst = secondary . bursts [ jj ]
2019-01-16 19:40:08 +00:00
#ionname = os.path.join(ionParam.ionDirname, ionParam.ionBurstDirname, 'IW{0}'.format(swath), '%s_%02d.ion'%('burst',ii+1))
#ion = np.fromfile(ionname, dtype=np.float32).reshape(masBurst.numberOfLines, masBurst.numberOfSamples)
( dopplerOffset , Ka ) = computeDopplerOffset ( masBurst , 1 , masBurst . numberOfLines , 1 , masBurst . numberOfSamples , nrlks = 1 , nalks = 1 )
centerFrequency = dopplerOffset * Ka [ None , : ] * ( masBurst . azimuthTimeInterval )
ion = 2.0 * np . pi * centerFrequency * misreg
#overwrite
ionname = os . path . join ( ionParam . ionDirname , esddir , ' IW {0} ' . format ( swath ) , ' %s _ %02d .esd ' % ( ' burst ' , ii + 1 ) )
ion . astype ( np . float32 ) . tofile ( ionname )
#create xml and vrt files
burstImg = isceobj . createImage ( )
burstImg . setDataType ( ' FLOAT ' )
burstImg . setFilename ( ionname )
burstImg . extraFilename = ionname + ' .vrt '
burstImg . setWidth ( masBurst . numberOfSamples )
burstImg . setLength ( masBurst . numberOfLines )
burstImg . renderHdr ( )
def rawion ( self , ionParam ) :
'''
a simple wrapper
'''
if ionParam . calIonWithMerged == True :
#merge bursts
merge ( self , ionParam )
#unwrap
unwrap ( self , ionParam )
#compute ionosphere
ionosphere ( self , ionParam )
else :
#an alternative of the above steps: processing swath by swath
ionSwathBySwath ( self , ionParam )
def run_step ( currentStep , ionParam ) :
return ionParam . allSteps . index ( ionParam . startStep ) < = ionParam . allSteps . index ( currentStep ) < = ionParam . allSteps . index ( ionParam . endStep )
def runIon ( self ) :
#get processing parameters
ionParam = setup ( self )
#if do ionospheric correction
if ionParam . doIon == False :
return
#form subband interferograms
if run_step ( ' subband ' , ionParam ) :
subband ( self , ionParam )
#compute ionosphere (raw_no_projection.ion) and coherence (raw_no_projection.cor) without projection
if run_step ( ' rawion ' , ionParam ) :
rawion ( self , ionParam )
#next we move to 'ion_cal' to do the remaining processing
#resample ionosphere from the ground layer to ionospheric layer
if run_step ( ' grd2ion ' , ionParam ) :
grd2ion ( self , ionParam )
#filter ionosphere
if run_step ( ' filt_gaussian ' , ionParam ) :
filt_gaussian ( self , ionParam )
2020-10-20 02:49:28 +00:00
#only do the following steps when considering burst properties
2019-01-16 19:40:08 +00:00
#ionosphere shift
2020-10-20 02:49:28 +00:00
if run_step ( ' ionosphere_shift ' , ionParam ) and ionParam . considerBurstProperties :
2019-01-16 19:40:08 +00:00
ionosphere_shift ( self , ionParam )
#resample from ionospheric layer to ground layer, get ionosphere for each burst
2020-10-20 02:49:28 +00:00
if run_step ( ' ion2grd ' , ionParam ) and ionParam . considerBurstProperties :
2019-01-16 19:40:08 +00:00
ion2grd ( self , ionParam )
#esd
2020-10-20 02:49:28 +00:00
if run_step ( ' esd ' , ionParam ) and ionParam . considerBurstProperties :
2019-01-16 19:40:08 +00:00
esd ( self , ionParam )
#pure esd without applying ionospheric correction
#esd_noion(self, ionParam)
return