2022-02-14 19:13:23 +00:00
#!/usr/bin/env python3
# Author: Cunren Liang
# Copyright 2021
import os
import copy
import shutil
import argparse
import numpy as np
import isce
import isceobj
from isceobj . TopsProc . runMergeBursts import mergeBox
from isceobj . TopsProc . runMergeBursts import adjustValidWithLooks
from isceobj . TopsProc . runIon import cal_cross_ab_ramp
from Stack import ionParam
import s1a_isce_utils as ut
from mergeBurstsIon import updateValid
def createParser ( ) :
parser = argparse . ArgumentParser ( description = ' merge swath ionosphere ' )
parser . add_argument ( ' -c ' , ' --reference ' , type = str , dest = ' reference ' , required = True ,
help = ' directory with the reference image ' )
parser . add_argument ( ' -s ' , ' --stack ' , type = str , dest = ' stack ' , default = None ,
help = ' directory with the stack xml files which includes the common valid region of the stack ' )
parser . add_argument ( ' -i ' , ' --input ' , dest = ' input ' , type = str , required = True ,
help = ' directory with input swath ionosphere containing swath directories ion_cal_IW* ' )
parser . add_argument ( ' -o ' , ' --output ' , dest = ' output ' , type = str , required = True ,
help = ' directory with output merged ionosphere ' )
parser . add_argument ( ' -r ' , ' --nrlks ' , type = int , dest = ' nrlks ' , default = 1 ,
help = ' number of range looks. NOT number of range looks 0 ' )
parser . add_argument ( ' -a ' , ' --nalks ' , type = int , dest = ' nalks ' , default = 1 ,
help = ' number of azimuth looks. NOT number of azimuth looks 0 ' )
parser . add_argument ( ' -m ' , ' --remove_ramp ' , type = int , dest = ' remove_ramp ' , default = 0 ,
help = ' remove an empirical ramp as a result of different platforms. 0: no removal (default), 1: S1A-S1B, -1: S1B-S1A ' )
return parser
def cmdLineParse ( iargs = None ) :
parser = createParser ( )
return parser . parse_args ( args = iargs )
def main ( iargs = None ) :
'''
'''
inps = cmdLineParse ( iargs )
corThresholdSwathAdj = 0.85
numberRangeLooks = inps . nrlks
numberAzimuthLooks = inps . nalks
remove_ramp = inps . remove_ramp
ionParamObj = ionParam ( )
ionParamObj . configure ( )
#####################################################################
framesBox = [ ]
swathList = sorted ( ut . getSwathList ( inps . reference ) )
for swath in swathList :
frame = ut . loadProduct ( os . path . join ( inps . reference , ' IW {0} .xml ' . format ( swath ) ) )
minBurst = frame . bursts [ 0 ] . burstNumber
maxBurst = frame . bursts [ - 1 ] . burstNumber
if minBurst == maxBurst :
print ( ' Skipping processing of swath {0} ' . format ( swath ) )
continue
passDirection = frame . bursts [ 0 ] . passDirection . lower ( )
if inps . stack is not None :
print ( ' Updating the valid region of each burst to the common valid region of the stack ' )
frame_stack = ut . loadProduct ( os . path . join ( inps . stack , ' IW {0} .xml ' . format ( swath ) ) )
updateValid ( frame , frame_stack )
framesBox . append ( frame )
box = mergeBox ( framesBox )
#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 ( framesBox , box , numberAzimuthLooks , numberRangeLooks , edge = 0 , avalid = ' strict ' , rvalid = ' strict ' )
#1. we use adjustValidWithLooks() to compute burstValidBox for extracting burst bounding boxes, use each burst's bounding box to retrive
#the corresponding burst in merged swath image and then put the burst in the final merged image.
#so there is no need to use interferogram IW*.xml, reference IW*.xml is good enough. If there is no corresponding burst in interferogram
#IW*.xml, the burst in merged swath image is just zero, and we can put this zero burst in the final merged image.
#2. we use mergeBox() to compute box[1] to be used in cal_cross_ab_ramp()
#####################################################################
numValidSwaths = len ( swathList )
if numValidSwaths == 1 :
print ( ' there is only one valid swath, simply copy the files ' )
os . makedirs ( inps . output , exist_ok = True )
corName = os . path . join ( inps . input , ' ion_cal_IW {} ' . format ( swathList [ 0 ] ) , ' raw_no_projection.cor ' )
ionName = os . path . join ( inps . input , ' ion_cal_IW {} ' . format ( swathList [ 0 ] ) , ' raw_no_projection.ion ' )
corOutName = os . path . join ( inps . output , ' raw_no_projection.cor ' )
ionOutName = os . path . join ( inps . output , ' raw_no_projection.ion ' )
shutil . copy2 ( corName , corOutName )
shutil . copy2 ( ionName , ionOutName )
#os.symlink(os.path.abspath(corName), os.path.abspath(corOutName))
#os.symlink(os.path.abspath(ionName), os.path.abspath(ionOutName))
img = isceobj . createImage ( )
img . load ( corName + ' .xml ' )
img . setFilename ( corOutName )
img . extraFilename = corOutName + ' .vrt '
img . renderHdr ( )
img = isceobj . createImage ( )
img . load ( ionName + ' .xml ' )
img . setFilename ( ionOutName )
img . extraFilename = ionOutName + ' .vrt '
img . renderHdr ( )
return
print ( ' merging swaths ' )
corList = [ ]
ampList = [ ]
ionosList = [ ]
for swath in swathList :
corName = os . path . join ( inps . input , ' ion_cal_IW {} ' . format ( swath ) , ' raw_no_projection.cor ' )
ionName = os . path . join ( inps . input , ' ion_cal_IW {} ' . format ( swath ) , ' raw_no_projection.ion ' )
img = isceobj . createImage ( )
img . load ( ionName + ' .xml ' )
width = img . width
length = img . length
amp = ( np . fromfile ( corName , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 0 : length * 2 : 2 , : ]
cor = ( np . fromfile ( corName , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
ion = ( np . fromfile ( ionName , dtype = np . float32 ) . reshape ( length * 2 , width ) ) [ 1 : length * 2 : 2 , : ]
corList . append ( cor )
ampList . append ( amp )
ionosList . append ( ion )
#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
2023-02-16 00:29:25 +00:00
first_line = int ( np . around ( ( burstValidBox [ i ] [ j ] [ 0 ] - 1 ) / numberAzimuthLooks + 1 ) )
last_line = int ( np . around ( burstValidBox [ i ] [ j ] [ 1 ] / numberAzimuthLooks ) )
first_sample = int ( np . around ( ( burstValidBox [ i ] [ j ] [ 2 ] - 1 ) / numberRangeLooks + 1 ) )
last_sample = int ( np . around ( burstValidBox [ i ] [ j ] [ 3 ] / numberRangeLooks ) )
2022-02-14 19:13:23 +00:00
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 remove_ramp != 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 , passDirection )
if remove_ramp == - 1 :
abramp * = - 1.0
#currently do not apply this
#ionosMerged -= abramp[None, :]
#dump ionosphere
os . makedirs ( inps . output , exist_ok = True )
outFilename = os . path . join ( inps . output , ionParamObj . 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 ( inps . output , ionParamObj . ionCorNoProj )
ion [ 1 : length * 2 : 2 , : ] = corMerged
ion . astype ( np . float32 ) . tofile ( outFilename )
img . filename = outFilename
img . extraFilename = outFilename + ' .vrt '
img . renderHdr ( )
if __name__ == ' __main__ ' :
'''
Main driver .
'''
# Main Driver
main ( )