#!/usr/bin/env python3 ######################## #Author: Heresh Fattahi ####################### import os, glob, sys import datetime noMCF = 'False' defoMax = '2' maxNodes = 72 class config(object): """ A class representing the config file """ def __init__(self, outname): self.f= open(outname,'w') self.f.write('[Common]'+'\n') self.f.write('') self.f.write('##########################'+'\n') def configure(self,inps): for k in inps.__dict__.keys(): setattr(self, k, inps.__dict__[k]) self.plot = 'False' self.misreg_az = None self.misreg_rng = None self.multilook_tool = None self.no_data_value = None def Sentinel1_TOPS(self,function): self.f.write('##########################'+'\n') self.f.write(function+'\n') self.f.write('Sentinel1_TOPS : ' + '\n') self.f.write('dirname : ' + self.dirName+'\n') self.f.write('swaths : ' + self.swaths+'\n') if self.orbit_type == 'precise': self.f.write('orbitdir : '+self.orbit_dirname+'\n') else: self.f.write('orbit : '+self.orbit_file+'\n') self.f.write('outdir : ' + self.outDir + '\n') self.f.write('auxdir : ' + self.aux_dirname + '\n') if self.bbox is not None: self.f.write('bbox : ' + self.bbox + '\n') self.f.write('pol : ' + self.polarization + '\n') self.f.write('##########################' + '\n') def computeAverageBaseline(self, function): self.f.write('##########################'+'\n') self.f.write(function + '\n') self.f.write('computeBaseline : '+'\n') self.f.write('reference : ' + self.reference + '\n') self.f.write('secondary : ' + self.secondary + '\n') self.f.write('baseline_file : ' + self.baselineFile + '\n') def computeGridBaseline(self, function): self.f.write('##########################'+'\n') self.f.write(function + '\n') self.f.write('baselineGrid : '+'\n') self.f.write('reference : ' + self.reference + '\n') self.f.write('secondary : ' + self.secondary + '\n') self.f.write('baseline_file : ' + self.baselineFile + '\n') def topo(self,function): self.f.write('##########################'+'\n') self.f.write('#Call topo to produce reference geometry files'+'\n') self.f.write(function + '\n') self.f.write('topo : ' + '\n') self.f.write('reference : ' + self.outDir + '\n') self.f.write('dem : ' + self.dem + '\n') self.f.write('geom_referenceDir : ' + self.geom_referenceDir + '\n') self.f.write('numProcess : ' + str(self.numProcess4topo) + '\n') self.f.write('##########################' + '\n') def geo2rdr(self,function): self.f.write('##########################' + '\n') self.f.write(function + '\n') self.f.write('geo2rdr :' + '\n') self.f.write('secondary : ' + self.secondaryDir + '\n') self.f.write('reference : ' + self.referenceDir + '\n') self.f.write('geom_referenceDir : ' + self.geom_reference + '\n') self.f.write('coregSLCdir : ' + self.coregSecondaryDir + '\n') self.f.write('overlap : ' + self.overlapTrueOrFalse + '\n') if self.useGPU: self.f.write('useGPU : True \n') else: self.f.write('useGPU : False\n') if self.misreg_az is not None: self.f.write('azimuth_misreg : ' + self.misreg_az + '\n') if self.misreg_rng is not None: self.f.write('range_misreg : ' + self.misreg_rng + '\n') def resamp_withCarrier(self,function): self.f.write('##########################' + '\n') self.f.write(function + '\n') self.f.write('resamp_withCarrier : ' + '\n') self.f.write('secondary : ' + self.secondaryDir + '\n') self.f.write('reference : ' + self.referenceDir + '\n') #self.f.write('interferogram_prefix :' + self.interferogram_prefix + '\n') self.f.write('coregdir : ' + self.coregSecondaryDir + '\n') self.f.write('overlap : ' + self.overlapTrueOrFalse + '\n') if self.misreg_az is not None: self.f.write('azimuth_misreg : ' + self.misreg_az + '\n') if self.misreg_rng is not None: self.f.write('range_misreg : ' + self.misreg_rng + '\n') def generateIgram(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('generateIgram : ' + '\n') self.f.write('reference : ' + self.referenceDir + '\n') self.f.write('secondary : ' + self.secondaryDir + '\n') self.f.write('interferogram : ' + self.interferogramDir + '\n') self.f.write('flatten : ' + self.flatten + '\n') self.f.write('interferogram_prefix : ' + self.interferogram_prefix +'\n') self.f.write('overlap : ' + self.overlapTrueOrFalse + '\n') if self.misreg_az is not None: self.f.write('azimuth_misreg : ' + self.misreg_az + '\n') if self.misreg_rng is not None: self.f.write('range_misreg : ' + self.misreg_rng + '\n') self.f.write('###################################' + '\n') def overlap_withDEM(self,function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('overlap_withDEM : '+'\n') self.f.write('interferogram : ' + self.interferogramDir +'\n') self.f.write('reference_dir : ' + self.referenceDir+'\n') self.f.write('secondary_dir : ' + self.secondaryDir+'\n') self.f.write('overlap_dir : ' + self.overlapDir+'\n') def azimuthMisreg(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('estimateAzimuthMisreg : ' + '\n') self.f.write('overlap_dir : ' + self.overlapDir + '\n') self.f.write('out_azimuth : ' + self.misregFile + '\n') self.f.write('coh_threshold : ' + self.esdCoherenceThreshold + '\n') self.f.write('plot : ' + self.plot + '\n') def rangeMisreg(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('estimateRangeMisreg : ' + '\n') self.f.write('reference : ' + self.referenceDir + '\n') self.f.write('secondary : ' + self.secondaryDir + '\n') self.f.write('out_range : ' + self.misregFile + '\n') self.f.write('snr_threshold : ' + self.snrThreshold + '\n') def mergeBurst(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('mergeBursts : ' + '\n') try: self.f.write('stack : ' + self.stack +'\n') except: pass self.f.write('inp_reference : ' + self.reference +'\n') self.f.write('dirname : ' + self.dirName + '\n') self.f.write('name_pattern : ' + self.namePattern + '\n') self.f.write('outfile : ' + self.mergedFile + '\n') self.f.write('method : ' + self.mergeBurstsMethod + '\n') self.f.write('aligned : ' + self.aligned + '\n') self.f.write('valid_only : ' + self.validOnly + '\n') self.f.write('use_virtual_files : ' + self.useVirtualFiles + '\n') self.f.write('multilook : ' + self.multiLook + '\n') self.f.write('range_looks : ' + self.rangeLooks + '\n') self.f.write('azimuth_looks : ' + self.azimuthLooks + '\n') if self.multilook_tool: self.f.write('multilook_tool : ' + self.multilook_tool + '\n') if self.no_data_value is not None: self.f.write('no_data_value : ' + self.no_data_value + '\n') def mergeSwaths(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('mergeSwaths : ' + '\n') self.f.write('input : ' + self.inputDirs + '\n') self.f.write('file : ' + self.fileName + '\n') self.f.write('metadata : ' + self.metadata + '\n') self.f.write('output : ' + self.outDir +'\n') def multiLook(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('looks_withDEM : ' + '\n') self.f.write('input : ' + self.input + '\n') self.f.write('output : ' + self.output + '\n') self.f.write('range : ' + self.rangeLooks + '\n') self.f.write('azimuth : ' + self.azimuthLooks + '\n') def FilterAndCoherence(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('FilterAndCoherence : ' + '\n') self.f.write('input : ' + self.input + '\n') self.f.write('filt : ' + self.filtName + '\n') self.f.write('coh : ' + self.cohName + '\n') self.f.write('strength : ' + self.filtStrength + '\n') self.f.write('slc1 : ' + self.slc1 + '\n') self.f.write('slc2 : ' + self.slc2 + '\n') self.f.write('complex_coh : '+ self.cpxCohName + '\n') self.f.write('range_looks : ' + self.rangeLooks + '\n') self.f.write('azimuth_looks : ' + self.azimuthLooks + '\n') def unwrap(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('unwrap : ' + '\n') self.f.write('ifg : ' + self.ifgName + '\n') self.f.write('unw : ' + self.unwName + '\n') self.f.write('coh : ' + self.cohName + '\n') self.f.write('nomcf : ' + self.noMCF + '\n') self.f.write('reference : ' + self.reference + '\n') self.f.write('defomax : ' + self.defoMax + '\n') self.f.write('rlks : ' + self.rangeLooks + '\n') self.f.write('alks : ' + self.azimuthLooks + '\n') if self.rmFilter: self.f.write('rmfilter : True \n') else: self.f.write('rmfilter : False\n') self.f.write('method : ' + self.unwMethod + '\n') def unwrapSnaphu(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('unwrapSnaphu : ' + '\n') self.f.write('ifg : ' + self.ifgName + '\n') self.f.write('unw : ' + self.unwName + '\n') self.f.write('coh : ' + self.cohName + '\n') self.f.write('nomcf : ' + self.noMCF + '\n') self.f.write('reference : ' + self.reference + '\n') self.f.write('defomax : ' + self.defoMax + '\n') self.f.write('rlks : ' + self.rangeLooks + '\n') self.f.write('alks : ' + self.azimuthLooks + '\n') self.f.write('numProcess : ' + self.numProcess + '\n') def denseOffset(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') # CPU or GPU self.f.write('denseOffsets : ' + '\n') #self.f.write('DenseOffsets : ' + '\n') #self.f.write('cuDenseOffsets : ' + '\n') self.f.write('reference : ' + self.reference + '\n') self.f.write('secondary : ' + self.secondary + '\n') self.f.write('outprefix : ' + self.output + '\n') #self.f.write('ww : 256\n') #self.f.write('wh : 128\n') def subband_and_resamp(self, function): self.f.write('##########################' + '\n') self.f.write(function + '\n') self.f.write('subband_and_resamp : ' + '\n') self.f.write('reference : ' + self.reference + '\n') self.f.write('secondary : ' + self.secondary + '\n') self.f.write('coregdir : ' + self.coregdir + '\n') self.f.write('azimuth_misreg : ' + self.azimuth_misreg + '\n') self.f.write('range_misreg : ' + self.range_misreg + '\n') def subband(self, function): self.f.write('##########################' + '\n') self.f.write(function + '\n') self.f.write('subband : ' + '\n') self.f.write('directory : ' + self.reference + '\n') def generateIgram_ion(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('generateIgram : ' + '\n') self.f.write('reference : ' + self.reference + '\n') self.f.write('reference_suffix : ' + self.reference_suffix + '\n') self.f.write('secondary : ' + self.secondary + '\n') self.f.write('secondary_suffix : ' + self.secondary_suffix + '\n') self.f.write('interferogram : ' + self.interferogram + '\n') self.f.write('flatten : ' + self.flatten + '\n') self.f.write('interferogram_prefix : ' + self.interferogram_prefix +'\n') self.f.write('overlap : ' + self.overlap + '\n') def mergeBurstsIon(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('mergeBurstsIon : ' + '\n') self.f.write('reference : ' + self.reference + '\n') self.f.write('stack : ' + self.stack + '\n') self.f.write('dirname : ' + self.dirname + '\n') self.f.write('name_pattern : ' + self.name_pattern + '\n') self.f.write('outfile : ' + self.outfile + '\n') self.f.write('nrlks : ' + '{}'.format(self.nrlks) + '\n') self.f.write('nalks : ' + '{}'.format(self.nalks) + '\n') self.f.write('nrlks0 : ' + '{}'.format(self.nrlks0) +'\n') self.f.write('nalks0 : ' + '{}'.format(self.nalks0) + '\n') if self.rvalid is not None: self.f.write('rvalid : ' + '{}'.format(self.rvalid) + '\n') if self.swath is not None: self.f.write('swath : ' + self.swath + '\n') def coherenceIon(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('coherenceIon : ' + '\n') self.f.write('lower : ' + self.lower + '\n') self.f.write('upper : ' + self.upper + '\n') self.f.write('coherence : ' + self.coherence + '\n') if self.nrlks is not None: self.f.write('nrlks : ' + '{}'.format(self.nrlks) + '\n') if self.nalks is not None: self.f.write('nalks : ' + '{}'.format(self.nalks) + '\n') def lookUnwIon(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('lookUnwIon : ' + '\n') self.f.write('unw : ' + self.unw + '\n') self.f.write('cor : ' + self.cor + '\n') self.f.write('output : ' + self.output + '\n') self.f.write('nrlks : ' + '{}'.format(self.nrlks) + '\n') self.f.write('nalks : ' + '{}'.format(self.nalks) + '\n') def filtIon(self, function): self.f.write('###################################'+'\n') self.f.write(function + '\n') self.f.write('filtIon : ' + '\n') self.f.write('input : ' + self.input + '\n') self.f.write('coherence : ' + self.coherence + '\n') self.f.write('output : ' + self.output + '\n') self.f.write('win_min : ' + '{}'.format(self.win_min) + '\n') self.f.write('win_max : ' + '{}'.format(self.win_max) + '\n') def write_wrapper_config2run_file(self, configName, line_cnt, numProcess = 1): # dispassionate list of commands for single process if numProcess == 1: self.runf.write(self.text_cmd + 'SentinelWrapper.py -c ' + configName + '\n') # aggregate background commands between wait blocks for speed gains elif numProcess > 1: self.runf.write(self.text_cmd + 'SentinelWrapper.py -c ' + configName + ' &\n') if line_cnt == numProcess: self.runf.write('wait\n\n') line_cnt = 0 return line_cnt def finalize(self): self.f.close() class ionParamUsr(object): '''A class containing parameters for ionosphere estimation specified by user while considerBurstProperties is not availavle for stack processing, ionParam still has parameters associated with considerBurstProperties for bookkeeping. ''' def __init__(self, usrInput): # usrInput: usrInput txt file self.usrInput = usrInput def configure(self): #default values same as topsApp.py #only ION_applyIon is removed, compared with topsApp.py self.ION_doIon = False self.ION_considerBurstProperties = False self.ION_ionHeight = 200.0 self.ION_ionFit = True self.ION_ionFilteringWinsizeMax = 200 self.ION_ionFilteringWinsizeMin = 100 self.ION_ionshiftFilteringWinsizeMax = 150 self.ION_ionshiftFilteringWinsizeMin = 75 self.ION_azshiftFlag = 1 self.ION_maskedAreas = None self.ION_numberAzimuthLooks = 50 self.ION_numberRangeLooks = 200 self.ION_numberAzimuthLooks0 = 10 self.ION_numberRangeLooks0 = 40 #get above parameters from usr input with open(self.usrInput, 'r') as f: lines = f.readlines() for x in lines: x = x.strip() if x == '' or x.strip().startswith('#'): continue else: x2 = x.split(':') if 'do ionosphere correction' == x2[0].strip(): self.ION_doIon = eval(x2[1].strip().capitalize()) if 'consider burst properties in ionosphere computation' == x2[0].strip(): self.ION_considerBurstProperties = eval(x2[1].strip().capitalize()) if 'height of ionosphere layer in km' == x2[0].strip(): self.ION_ionHeight = float(x2[1].strip()) if 'apply polynomial fit before filtering ionosphere phase' == x2[0].strip(): self.ION_ionFit = eval(x2[1].strip().capitalize()) if 'maximum window size for filtering ionosphere phase' == x2[0].strip(): self.ION_ionFilteringWinsizeMax = int(x2[1].strip()) if 'minimum window size for filtering ionosphere phase' == x2[0].strip(): self.ION_ionFilteringWinsizeMin = int(x2[1].strip()) if 'maximum window size for filtering ionosphere azimuth shift' == x2[0].strip(): self.ION_ionshiftFilteringWinsizeMax = int(x2[1].strip()) if 'minimum window size for filtering ionosphere azimuth shift' == x2[0].strip(): self.ION_ionshiftFilteringWinsizeMin = int(x2[1].strip()) if 'correct phase error caused by ionosphere azimuth shift' == x2[0].strip(): self.ION_azshiftFlag = int(x2[1].strip()) if 'areas masked out in ionospheric phase estimation' == x2[0].strip(): if x2[1].strip().capitalize() == 'None': self.ION_maskedAreas = None else: self.ION_maskedAreas = [] x3 = x2[1].replace('[', '').replace(']', '').split(',') if len(x3)%4 != 0: raise Exception('there must be four elements for each area.') else: narea = int(len(x3)/4) for i in range(narea): self.ION_maskedAreas.append([int(x3[i*4+0].strip()), int(x3[i*4+1].strip()), int(x3[i*4+2].strip()), int(x3[i*4+3].strip())]) if 'total number of azimuth looks in the ionosphere processing' == x2[0].strip(): self.ION_numberAzimuthLooks = int(x2[1].strip()) if 'total number of range looks in the ionosphere processing' == x2[0].strip(): self.ION_numberRangeLooks = int(x2[1].strip()) if 'number of azimuth looks at first stage for ionosphere phase unwrapping' == x2[0].strip(): self.ION_numberAzimuthLooks0 = int(x2[1].strip()) if 'number of range looks at first stage for ionosphere phase unwrapping' == x2[0].strip(): self.ION_numberRangeLooks0 = int(x2[1].strip()) def print(self): '''print parameters''' print() print('ionosphere estimation parameters:') print('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++') print("do ionosphere correction (ION_doIon): {}".format(self.ION_doIon)) print("consider burst properties in ionosphere computation (ION_considerBurstProperties): {}".format(self.ION_considerBurstProperties)) print("height of ionosphere layer in km (ION_ionHeight): {}".format(self.ION_ionHeight)) print("apply polynomial fit before filtering ionosphere phase (ION_ionFit): {}".format(self.ION_ionFit)) print("maximum window size for filtering ionosphere phase (ION_ionFilteringWinsizeMax): {}".format(self.ION_ionFilteringWinsizeMax)) print("minimum window size for filtering ionosphere phase (ION_ionFilteringWinsizeMin): {}".format(self.ION_ionFilteringWinsizeMin)) print("maximum window size for filtering ionosphere azimuth shift (ION_ionshiftFilteringWinsizeMax): {}".format(self.ION_ionshiftFilteringWinsizeMax)) print("minimum window size for filtering ionosphere azimuth shift (ION_ionshiftFilteringWinsizeMin): {}".format(self.ION_ionshiftFilteringWinsizeMin)) print("correct phase error caused by ionosphere azimuth shift (ION_azshiftFlag): {}".format(self.ION_azshiftFlag)) print("areas masked out in ionospheric phase estimation (ION_maskedAreas): {}".format(self.ION_maskedAreas)) print("total number of azimuth looks in the ionosphere processing (ION_numberAzimuthLooks): {}".format(self.ION_numberAzimuthLooks)) print("total number of range looks in the ionosphere processing (ION_numberRangeLooks): {}".format(self.ION_numberRangeLooks)) print("number of azimuth looks at first stage for ionosphere phase unwrapping (ION_numberAzimuthLooks0): {}".format(self.ION_numberAzimuthLooks0)) print("number of range looks at first stage for ionosphere phase unwrapping (ION_numberRangeLooks0): {}".format(self.ION_numberRangeLooks0)) print() class ionParam(object): '''A class containing parameters for ionosphere estimation while considerBurstProperties is not availavle for stack processing, ionParam still has parameters associated with considerBurstProperties for bookkeeping. ''' def __init__(self, usrInput=None, safeObjFirst=None, safeObjSecondary=None): # usrInput: usrInput parameter object # safeObjFirst: sentinelSLC object defined in Stack.py of first date # safeObjSecond: sentinelSLC object defined in Stack.py of second date self.usrInput = usrInput self.safeObjFirst = safeObjFirst self.safeObjSecondary = safeObjSecondary def configure(self): #all paramters have default values, update the relevant parameters using #self.usrInput, self.safeObjFirst, self.safeObjSecondary #when they are not None ################################################################### #users are supposed to change parameters of this section ONLY #SECTION 1. PROCESSING CONTROL PARAMETERS #1. suggested default values of the parameters self.doIon = False self.considerBurstProperties = False #ionospheric layer height (m) self.ionHeight = 200.0 * 1000.0 #before filtering ionosphere, if applying polynomial fitting #False: no fitting #True: with fitting self.ionFit = True #window size for filtering ionosphere self.ionFilteringWinsizeMax = 200 self.ionFilteringWinsizeMin = 100 #window size for filtering azimuth shift caused by ionosphere self.ionshiftFilteringWinsizeMax = 150 self.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 self.azshiftFlag = 1 self.maskedAreas = None #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 self.numberAzimuthLooks = 50 #number of range looks in the processing of ionosphere estimation self.numberRangeLooks = 200 #number of azimuth looks of the interferogram to be unwrapped self.numberAzimuthLooks0 = 5*2 #number of range looks of the interferogram to be unwrapped self.numberRangeLooks0 = 20*2 #2. accept the above parameters from topsApp.py if self.usrInput is not None: self.doIon = self.usrInput.ION_doIon self.considerBurstProperties = self.usrInput.ION_considerBurstProperties self.ionHeight = self.usrInput.ION_ionHeight * 1000.0 self.ionFit = self.usrInput.ION_ionFit self.ionFilteringWinsizeMax = self.usrInput.ION_ionFilteringWinsizeMax self.ionFilteringWinsizeMin = self.usrInput.ION_ionFilteringWinsizeMin self.ionshiftFilteringWinsizeMax = self.usrInput.ION_ionshiftFilteringWinsizeMax self.ionshiftFilteringWinsizeMin = self.usrInput.ION_ionshiftFilteringWinsizeMin self.azshiftFlag = self.usrInput.ION_azshiftFlag self.maskedAreas = self.usrInput.ION_maskedAreas self.numberAzimuthLooks = self.usrInput.ION_numberAzimuthLooks self.numberRangeLooks = self.usrInput.ION_numberRangeLooks self.numberAzimuthLooks0 = self.usrInput.ION_numberAzimuthLooks0 self.numberRangeLooks0 = self.usrInput.ION_numberRangeLooks0 #3. check parameters #check number of looks if not ((self.numberAzimuthLooks % self.numberAzimuthLooks0 == 0) and \ (1 <= self.numberAzimuthLooks0 <= self.numberAzimuthLooks)): raise Exception('numberAzimuthLooks must be integer multiples of numberAzimuthLooks0') if not ((self.numberRangeLooks % self.numberRangeLooks0 == 0) and \ (1 <= self.numberRangeLooks0 <= self.numberRangeLooks)): raise Exception('numberRangeLooks must be integer multiples of numberRangeLooks0') ################################################################### #SECTION 2. DIRECTORIES AND FILENAMES #directories self.ionDirname = 'ion' self.lowerDirname = 'lower' self.upperDirname = 'upper' self.ioncalDirname = 'ion_cal' self.ionBurstDirname = 'ion_burst' #these are same directory names as topsApp.py/TopsProc.py #self.referenceSlcProduct = 'reference' #self.secondarySlcProduct = 'secondary' #self.fineCoregDirname = 'fine_coreg' self.fineIfgDirname = 'fine_interferogram' self.mergedDirname = 'merged' #filenames self.ionRawNoProj = 'raw_no_projection.ion' self.ionCorNoProj = 'raw_no_projection.cor' self.ionRaw = 'raw.ion' self.ionCor = 'raw.cor' self.ionFilt = 'filt.ion' self.ionShift = 'azshift.ion' self.warning = 'warning.txt' #SECTION 3. DATA PARAMETERS #earth's radius (m) self.earthRadius = 6371 * 1000.0 #reference range (m) for moving range center frequency to zero, center of center swath self.rgRef = 875714.0 #range bandwidth (Hz) for splitting, range processingBandwidth: [5.650000000000000e+07, 4.830000000000000e+07, 4.278991840322842e+07] self.rgBandwidthForSplit = 40.0 * 10**6 self.rgBandwidthSub = self.rgBandwidthForSplit / 3.0 #SECTION 4. DEFINE WAVELENGTHS AND DETERMINE IF CALCULATE IONOSPHERE WITH MERGED INTERFEROGRAM #Sentinel-1A/B radar wavelengths are the same. self.radarWavelength = 0.05546576 self.passDirection = None #self.safeObjFirst, self.safeObjSecondary should have already get these parameters #use the 1/3, 1/3, 1/3 scheme for splitting from isceobj.Constants import SPEED_OF_LIGHT if self.safeObjFirst is not None: #use this to determine which polynomial to use to calculate a ramp when calculating ionosphere for cross A/B interferogram self.passDirection = self.safeObjFirst.passDirection.lower() self.radarWavelength = self.safeObjFirst.radarWavelength self.radarWavelengthLower = SPEED_OF_LIGHT / (SPEED_OF_LIGHT / self.radarWavelength - self.rgBandwidthForSplit / 3.0) self.radarWavelengthUpper = SPEED_OF_LIGHT / (SPEED_OF_LIGHT / self.radarWavelength + self.rgBandwidthForSplit / 3.0) self.calIonWithMerged = False self.rampRemovel = 0 #update the above two parameters depending on self.safeObjFirst and self.safeObjSecondary if (self.safeObjFirst is not None) and (self.safeObjSecondary is not None): #determine if calculate ionosphere using merged interferogram #check if already got parameters needed if hasattr(self.safeObjFirst, 'startingRanges') == False: self.safeObjFirst.get_starting_ranges() if hasattr(self.safeObjSecondary, 'startingRanges') == False: self.safeObjSecondary.get_starting_ranges() if self.safeObjFirst.startingRanges == self.safeObjSecondary.startingRanges: self.calIonWithMerged = False else: self.calIonWithMerged = True #for cross Sentinel-1A/B interferogram, always not using merged interferogram if self.safeObjFirst.platform != self.safeObjSecondary.platform: self.calIonWithMerged = False #there is no need to process swath by swath when there is only one swath #ionSwathBySwath only works when number of swaths >=2 #CONSIDER THIS LATTER!!! #if len(swathList) == 1: # self.calIonWithMerged = True #determine if remove an empirical ramp if self.safeObjFirst.platform == self.safeObjSecondary.platform: self.rampRemovel = 0 else: #estimating ionospheric phase for cross Sentinel-1A/B interferogram #an empirical ramp will be removed from the estimated ionospheric phase if self.safeObjFirst.platform == 'S1A' and self.safeObjSecondary.platform == 'S1B': self.rampRemovel = 1 else: self.rampRemovel = -1 class run(object): """ A class representing a run which may contain several functions """ #def __init__(self): def configure(self,inps, runName): for k in inps.__dict__.keys(): setattr(self, k, inps.__dict__[k]) self.runDir = os.path.join(self.work_dir, 'run_files') os.makedirs(self.runDir, exist_ok=True) self.run_outname = os.path.join(self.runDir, runName) print ('writing ', self.run_outname) self.config_path = os.path.join(self.work_dir,'configs') os.makedirs(self.config_path, exist_ok=True) self.runf= open(self.run_outname,'w') def unpackSLC(self, acquisitionDates, safe_dict): swath_path = self.work_dir os.makedirs(self.config_path, exist_ok=True) line_cnt = 0 for slcdate in acquisitionDates: configName = os.path.join(self.config_path,'config_unpack_'+slcdate) configObj = config(configName) configObj.configure(self) configObj.dirName = safe_dict[slcdate].safe_file configObj.orbit_file = safe_dict[slcdate].orbit configObj.orbit_type = safe_dict[slcdate].orbitType configObj.swaths = self.swath_num configObj.outDir = os.path.join(self.work_dir, 'slc/' + slcdate) configObj.geom_referenceDir = os.path.join(self.work_dir, 'geom_slc/' + slcdate) configObj.dem = os.path.join(self.work_dir, configObj.dem) configObj.Sentinel1_TOPS('[Function-1]') configObj.topo('[Function-2]') configObj.finalize() line_cnt += 1 line_cnt = configObj.write_wrapper_config2run_file(configName, line_cnt) del configObj def unpackStackReferenceSLC(self, safe_dict): swath_path = self.work_dir os.makedirs(self.config_path, exist_ok=True) configName = os.path.join(self.config_path,'config_reference') configObj = config(configName) configObj.configure(self) configObj.dirName = safe_dict[self.reference_date].safe_file configObj.orbit_file = safe_dict[self.reference_date].orbit configObj.orbit_type = safe_dict[self.reference_date].orbitType configObj.swaths = self.swath_num configObj.outDir = os.path.join(self.work_dir, 'reference') configObj.geom_referenceDir = os.path.join(self.work_dir, 'geom_reference') configObj.dem = os.path.join(self.work_dir, configObj.dem) configObj.Sentinel1_TOPS('[Function-1]') configObj.topo('[Function-2]') configObj.finalize() line_cnt = 1 line_cnt = configObj.write_wrapper_config2run_file(configName, line_cnt) del configObj def unpackSecondarysSLC(self, stackReferenceDate, secondaryList, safe_dict): line_cnt = 0 for secondary in secondaryList: configName = os.path.join(self.config_path,'config_secondary_'+secondary) outdir = os.path.join(self.work_dir,'secondarys/'+secondary) configObj = config(configName) configObj.configure(self) configObj.dirName = safe_dict[secondary].safe_file configObj.orbit_file = safe_dict[secondary].orbit configObj.orbit_type = safe_dict[secondary].orbitType configObj.swaths = self.swath_num configObj.outDir = outdir configObj.Sentinel1_TOPS('[Function-1]') configObj.finalize() line_cnt += 1 line_cnt = configObj.write_wrapper_config2run_file(configName, line_cnt, self.numProcess) del configObj def averageBaseline(self, stackReferenceDate, secondaryList): line_cnt = 0 for secondary in secondaryList: configName = os.path.join(self.config_path,'config_baseline_'+secondary) configObj = config(configName) configObj.configure(self) configObj.reference = os.path.join(self.work_dir,'reference/') configObj.secondary = os.path.join(self.work_dir,'secondarys/'+secondary) configObj.baselineFile = os.path.join(self.work_dir,'baselines/' + stackReferenceDate +'_' + secondary + '/' + stackReferenceDate +'_'+ secondary + '.txt') configObj.computeAverageBaseline('[Function-1]') configObj.finalize() line_cnt += 1 line_cnt = configObj.write_wrapper_config2run_file(configName, line_cnt, self.numProcess) del configObj def gridBaseline(self, stackReferenceDate, secondaryList): line_cnt = 0 for secondary in secondaryList: configName = os.path.join(self.config_path,'config_baselinegrid_'+secondary) configObj = config(configName) configObj.configure(self) configObj.reference = os.path.join(self.work_dir,'reference/') configObj.secondary = os.path.join(self.work_dir,'secondarys/'+secondary) configObj.baselineFile = os.path.join(self.work_dir, 'merged/baselines/' + secondary + '/' + secondary ) configObj.computeGridBaseline('[Function-1]') configObj.finalize() line_cnt += 1 line_cnt = configObj.write_wrapper_config2run_file(configName, line_cnt) del configObj # also add the reference in itself to be consistent with the SLC dir configName = os.path.join(self.config_path,'config_baselinegrid_reference') configObj = config(configName) configObj.configure(self) configObj.reference = os.path.join(self.work_dir,'reference/') configObj.secondary = os.path.join(self.work_dir,'reference/') configObj.baselineFile = os.path.join(self.work_dir, 'merged/baselines/' + stackReferenceDate + '/' + stackReferenceDate) configObj.computeGridBaseline('[Function-1]') configObj.finalize() line_cnt = 1 line_cnt = configObj.write_wrapper_config2run_file(configName, line_cnt) del configObj def extractOverlaps(self): self.runf.write(self.text_cmd + 'subsetReference.py -m ' + os.path.join(self.work_dir, 'reference') + ' -g ' + os.path.join(self.work_dir, 'geom_reference') + '\n') def geo2rdr_offset(self, secondaryList, fullBurst='False'): line_cnt = 0 for secondary in secondaryList: reference = self.reference_date if fullBurst == 'True': configName = os.path.join(self.config_path, 'config_fullBurst_geo2rdr_' + secondary) else: configName = os.path.join(self.config_path, 'config_overlap_geo2rdr_'+secondary) ########### configObj = config(configName) configObj.configure(self) configObj.secondaryDir = os.path.join(self.work_dir, 'secondarys/'+secondary) configObj.referenceDir = os.path.join(self.work_dir, 'reference') configObj.geom_reference = os.path.join(self.work_dir, 'geom_reference') configObj.coregSecondaryDir = os.path.join(self.work_dir, 'coreg_secondarys/'+secondary) if fullBurst == 'True': configObj.misreg_az = os.path.join(self.work_dir, 'misreg/azimuth/dates/' + secondary + '.txt') configObj.misreg_rng = os.path.join(self.work_dir, 'misreg/range/dates/' + secondary + '.txt') configObj.overlapTrueOrFalse = 'False' else: configObj.overlapTrueOrFalse = 'True' configObj.geo2rdr('[Function-1]') configObj.finalize() line_cnt += 1 line_cnt = configObj.write_wrapper_config2run_file(configName, line_cnt, self.numProcess) del configObj def resample_with_carrier(self, secondaryList, fullBurst='False'): line_cnt = 0 for secondary in secondaryList: reference = self.reference_date if fullBurst == 'True': configName = os.path.join(self.config_path, 'config_fullBurst_resample_' + secondary) else: configName = os.path.join(self.config_path, 'config_overlap_resample_' + secondary) ########### configObj = config(configName) configObj.configure(self) configObj.secondaryDir = os.path.join(self.work_dir, 'secondarys/' + secondary) configObj.referenceDir = os.path.join(self.work_dir, 'reference') configObj.coregSecondaryDir = os.path.join(self.work_dir, 'coreg_secondarys/' + secondary) configObj.interferogram_prefix = 'coarse' configObj.referenceDir = os.path.join(self.work_dir, 'reference') if fullBurst == 'True': configObj.misreg_az = os.path.join(self.work_dir, 'misreg/azimuth/dates/' + secondary + '.txt') configObj.misreg_rng = os.path.join(self.work_dir, 'misreg/range/dates/' + secondary + '.txt') configObj.overlapTrueOrFalse = 'False' else: configObj.overlapTrueOrFalse = 'True' configObj.resamp_withCarrier('[Function-1]') configObj.finalize() line_cnt += 1 line_cnt = configObj.write_wrapper_config2run_file(configName, line_cnt, self.numProcess) del configObj def pairs_misregistration(self, dateList, safe_dict): # generating overlap interferograms, estimate azimuth misregistration for each pair: pairs = [] num_overlap_connections = int(self.num_overlap_connections) + 1 for i in range(len(dateList)-1): for j in range(i+1,i+num_overlap_connections): if j= orbit_start_date_time and self.stop_date_time < orbit_stop_date_time: self.orbit = os.path.join(orbitDir,orbit) self.orbitType = 'precise' match = True break if not match: print ("*****************************************") print (self.date) print ("orbit was not found in the "+orbitDir) # It should go and look online print ("downloading precise or restituted orbits ...") restitutedOrbitDir = os.path.join(workDir ,'orbits/' + self.date) orbitFiles = glob.glob(os.path.join(restitutedOrbitDir,'*.EOF')) if len(orbitFiles) > 0: orbitFile = orbitFiles[0] #fields = orbitFile.split('_') fields = os.path.basename(orbitFile).split('_') orbit_start_date_time = datetime.datetime.strptime(fields[6].replace('V',''), datefmt) orbit_stop_date_time = datetime.datetime.strptime(fields[7].replace('.EOF',''), datefmt) if self.start_date_time >= orbit_start_date_time and self.stop_date_time < orbit_stop_date_time: print ("restituted or precise orbit already exists.") self.orbit = orbitFile self.orbitType = 'restituted' #if not os.path.exists(restitutedOrbitDir): else: os.makedirs(restitutedOrbitDir, exist_ok=True) cmd = 'fetchOrbit.py -i ' + self.safe_file + ' -o ' + restitutedOrbitDir print(cmd) os.system(cmd) orbitFile = glob.glob(os.path.join(restitutedOrbitDir,'*.EOF')) self.orbit = orbitFile[0] self.orbitType = 'restituted' # an example for writing job files when using clusters """ def writeJobFile(runFile): jobName = runFile + '.job' dirName = os.path.dirname(runFile) with open(runFile) as ff: nodes = len(ff.readlines()) if nodes >maxNodes: nodes = maxNodes f = open (jobName,'w') f.write('#!/bin/bash '+ '\n') f.write('#PBS -N Parallel_GNU'+ '\n') f.write('#PBS -l nodes=' + str(nodes) + '\n') jobTxt='''#PBS -V #PBS -l walltime=05:00:00 #PBS -q default #PBS -m bae -M hfattahi@gps.caltech.edu echo Working directory is $PBS_O_WORKDIR cd $PBS_O_WORKDIR echo Running on host `hostname` echo Time is `date` ### Define number of processors NPROCS=`wc -l < $PBS_NODEFILE` echo This job has allocated $NPROCS cpus # Tell me which nodes it is run on echo " " echo This jobs runs on the following processors: echo `cat $PBS_NODEFILE` echo " " # # Run the parallel with the nodelist and command file # ''' f.write(jobTxt+ '\n') f.write('parallel --sshloginfile $PBS_NODEFILE -a ' + os.path.basename(runFile) + '\n') f.write('') f.close() """