1209 lines
38 KiB
Python
1209 lines
38 KiB
Python
#!/usr/bin/env python3
|
|
|
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# Copyright 2012 California Institute of Technology. ALL RIGHTS RESERVED.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
# United States Government Sponsorship acknowledged. This software is subject to
|
|
# U.S. export control laws and regulations and has been classified as 'EAR99 NLR'
|
|
# (No [Export] License Required except when exporting to an embargoed country,
|
|
# end user, or in support of a prohibited end use). By downloading this software,
|
|
# the user agrees to comply with all applicable U.S. export laws and regulations.
|
|
# The user has the responsibility to obtain export licenses, or other export
|
|
# authority as may be required before exporting this software to any 'EAR99'
|
|
# embargoed foreign country or citizen of those countries.
|
|
#
|
|
# Authors: Giangi Sacco, Eric Gurrola
|
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
from __future__ import print_function
|
|
import time
|
|
import os
|
|
import sys
|
|
from isce import logging
|
|
|
|
import isce
|
|
import isceobj
|
|
import iscesys
|
|
from iscesys.Component.Application import Application
|
|
from iscesys.Compatibility import Compatibility
|
|
from iscesys.Component.Configurable import SELF
|
|
import isceobj.InsarProc as InsarProc
|
|
from isceobj.Scene.Frame import FrameMixin
|
|
|
|
logger = logging.getLogger('isce.insar')
|
|
|
|
|
|
SENSOR_NAME = Application.Parameter(
|
|
'sensorName',
|
|
public_name='sensor name',
|
|
default=None,
|
|
type=str,
|
|
mandatory=True,
|
|
doc="Sensor name"
|
|
)
|
|
|
|
OFFSET_METHOD = Application.Parameter(
|
|
'offsetMethod',
|
|
public_name='slc offset method',
|
|
default="offsetprf",
|
|
type=str,
|
|
mandatory=False,
|
|
doc=("SLC offset estimation method name. "+
|
|
"Use value=ampcor to run ampcor")
|
|
)
|
|
|
|
OFFSET_SEARCH_WINDOW_SIZE = Application.Parameter(
|
|
'offsetSearchWindowSize',
|
|
public_name='offset search window size',
|
|
default=None,
|
|
type=int,
|
|
mandatory=False,
|
|
doc=("Search window size used in offsetprf "+
|
|
"and rgoffset.")
|
|
)
|
|
|
|
PEG_SELECT = Application.Parameter(
|
|
'pegSelect',
|
|
public_name='peg select',
|
|
default='average',
|
|
mandatory=False,
|
|
doc='Peg selection method. Can be reference, secondary or average'
|
|
)
|
|
|
|
PEG_LAT = Application.Parameter(
|
|
'pegLat',
|
|
public_name='peg latitude (deg)',
|
|
default=None,
|
|
type=float,
|
|
mandatory=False,
|
|
doc='Peg Latitude in degrees'
|
|
)
|
|
|
|
PEG_LON = Application.Parameter(
|
|
'pegLon',
|
|
public_name='peg longitude (deg)',
|
|
default=None,
|
|
type=float,
|
|
mandatory=False,
|
|
doc='Peg Longitude in degrees'
|
|
)
|
|
|
|
PEG_HDG = Application.Parameter(
|
|
'pegHdg',
|
|
public_name='peg heading (deg)',
|
|
default=None,
|
|
type=float,
|
|
mandatory=False,
|
|
doc='Peg Heading in degrees'
|
|
)
|
|
|
|
PEG_RAD = Application.Parameter(
|
|
'pegRad',
|
|
public_name='peg radius (m)',
|
|
default=None,
|
|
type=float,
|
|
mandatory=False,
|
|
doc='Peg Radius of Curvature in meters'
|
|
)
|
|
|
|
FILTER_STRENGTH = Application.Parameter(
|
|
'filterStrength',
|
|
public_name='filter strength',
|
|
default = None,
|
|
type=float,
|
|
mandatory=False,
|
|
doc='Goldstein Werner Filter strength'
|
|
)
|
|
|
|
CORRELATION_METHOD = Application.Parameter(
|
|
'correlation_method',
|
|
public_name='correlation_method',
|
|
default='cchz_wave',
|
|
type=str,
|
|
mandatory=False,
|
|
doc=(
|
|
"""Select coherence estimation method:
|
|
cchz=cchz_wave
|
|
phase_gradient=phase gradient"""
|
|
)
|
|
)
|
|
DOPPLER_METHOD = Application.Parameter(
|
|
'dopplerMethod',
|
|
public_name='doppler method',
|
|
default='useDOPIQ',
|
|
type=str, mandatory=False,
|
|
doc= "Doppler calculation method.Choices: 'useDOPIQ', 'useCalcDop', 'useDoppler'."
|
|
)
|
|
|
|
USE_DOP = Application.Parameter(
|
|
'use_dop',
|
|
public_name='use_dop',
|
|
default="average",
|
|
type=float,
|
|
mandatory=False,
|
|
doc="Choose whether to use reference, secondary, or average Doppler for processing."
|
|
)
|
|
|
|
UNWRAPPER_NAME = Application.Parameter(
|
|
'unwrapper_name',
|
|
public_name='unwrapper name',
|
|
default='grass',
|
|
type=str,
|
|
mandatory=False,
|
|
doc="Unwrapping method to use. To be used in combination with UNWRAP."
|
|
)
|
|
|
|
# to be replaced by DO_UNWRAP;
|
|
UNWRAP = Application.Parameter(
|
|
'unwrap',
|
|
public_name='unwrap',
|
|
default=False,
|
|
type=bool,
|
|
mandatory=False,
|
|
doc="True if unwrapping is desired. To be used in combination with UNWRAPPER_NAME."
|
|
)
|
|
|
|
# not fully supported yet; use UNWRAP instead
|
|
DO_UNWRAP = Application.Parameter(
|
|
'do_unwrap',
|
|
public_name='do unwrap',
|
|
default=False,
|
|
type=bool,
|
|
mandatory=False,
|
|
doc="True if unwrapping is desired. To be unsed in combination with UNWRAPPER_NAME."
|
|
)
|
|
|
|
DO_UNWRAP_2STAGE = Application.Parameter(
|
|
'do_unwrap_2stage',
|
|
public_name='do unwrap 2 stage',
|
|
default=False,
|
|
type=bool,
|
|
mandatory=False,
|
|
doc="True if unwrapping is desired. To be unsed in combination with UNWRAPPER_NAME."
|
|
)
|
|
|
|
UNWRAPPER_2STAGE_NAME = Application.Parameter(
|
|
'unwrapper_2stage_name',
|
|
public_name='unwrapper 2stage name',
|
|
default='REDARC0',
|
|
type=str,
|
|
mandatory=False,
|
|
doc="2 Stage Unwrapping method to use. Available: MCF, REDARC0, REDARC1, REDARC2"
|
|
)
|
|
|
|
SOLVER_2STAGE = Application.Parameter(
|
|
'solver_2stage',
|
|
public_name='SOLVER_2STAGE',
|
|
default='pulp',
|
|
type=str,
|
|
mandatory=False,
|
|
doc='Linear Programming Solver for 2Stage; Options: pulp, gurobi, glpk; Used only for Redundant Arcs'
|
|
)
|
|
|
|
DO_OFFSETPRF = Application.Parameter(
|
|
'do_offsetprf',
|
|
public_name='do offsetprf',
|
|
default=True,
|
|
type=bool,
|
|
mandatory=False,
|
|
doc="Set to False if offsetprf is not required."
|
|
)
|
|
|
|
DO_RGOFFSET = Application.Parameter(
|
|
'do_rgoffset',
|
|
public_name='do rgoffset',
|
|
default=True,
|
|
type=bool,
|
|
mandatory=False,
|
|
doc="Set to False if offsetprf is not required."
|
|
)
|
|
|
|
USE_HIGH_RESOLUTION_DEM_ONLY = Application.Parameter(
|
|
'useHighResolutionDemOnly',
|
|
public_name='useHighResolutionDemOnly',
|
|
default=False,
|
|
type=int,
|
|
mandatory=False,
|
|
doc=(
|
|
"""If True and a dem is not specified in input, it will only
|
|
download the SRTM highest resolution dem if it is available
|
|
and fill the missing portion with null values (typically -32767)."""
|
|
)
|
|
)
|
|
DEM_FILENAME = Application.Parameter(
|
|
'demFilename',
|
|
public_name='demFilename',
|
|
default='',
|
|
type=str,
|
|
mandatory=False,
|
|
doc="Filename of the DEM init file"
|
|
)
|
|
|
|
GEO_POSTING = Application.Parameter(
|
|
'geoPosting',
|
|
public_name='geoPosting',
|
|
default=None,
|
|
type=float,
|
|
mandatory=False,
|
|
doc=(
|
|
"Output posting for geocoded images in degrees (latitude = longitude)"
|
|
)
|
|
)
|
|
POSTING = Application.Parameter(
|
|
'posting',
|
|
public_name='posting',
|
|
default=15,
|
|
type=int,
|
|
mandatory=False,
|
|
doc="posting for interferogram"
|
|
)
|
|
RANGE_LOOKS = Application.Parameter(
|
|
'rangeLooks',
|
|
public_name='range looks',
|
|
default=None,
|
|
type=int,
|
|
mandatory=False,
|
|
doc='Number of range looks to use in resamp'
|
|
)
|
|
AZ_LOOKS = Application.Parameter(
|
|
'azLooks',
|
|
public_name='azimuth looks',
|
|
default=None,
|
|
type=int,
|
|
mandatory=False,
|
|
doc='Number of azimuth looks to use in resamp'
|
|
)
|
|
PATCH_SIZE = Application.Parameter(
|
|
'patchSize',
|
|
public_name='azimuth patch size',
|
|
default=None,
|
|
type=int,
|
|
mandatory=False,
|
|
doc=(
|
|
"Size of overlap/save patch size for formslc"
|
|
)
|
|
)
|
|
|
|
GOOD_LINES = Application.Parameter(
|
|
'goodLines',
|
|
public_name='patch valid pulses',
|
|
default=None,
|
|
type=int,
|
|
mandatory=False,
|
|
doc=(
|
|
"Size of overlap/save save region for formslc"
|
|
)
|
|
)
|
|
|
|
NUM_PATCHES = Application.Parameter(
|
|
'numPatches',
|
|
public_name='number of patches',
|
|
default=None,
|
|
type=int,
|
|
mandatory=False,
|
|
doc=(
|
|
"How many patches to process of all available patches"
|
|
)
|
|
)
|
|
|
|
GROSS_AZ = Application.Parameter(
|
|
'grossAz',
|
|
public_name='gross azimuth offset',
|
|
default=None,
|
|
type=int,
|
|
mandatory=False,
|
|
doc=(
|
|
"Override the value of the gross azimuth offset for offset " +
|
|
"estimation prior to interferogram formation"
|
|
)
|
|
)
|
|
|
|
GROSS_RG = Application.Parameter(
|
|
'grossRg',
|
|
public_name='gross range offset',
|
|
default=None,
|
|
type=int,
|
|
mandatory=False,
|
|
doc=(
|
|
"Override the value of the gross range offset for offset" +
|
|
"estimation prior to interferogram formation"
|
|
)
|
|
)
|
|
|
|
CULLING_SEQUENCE = Application.Parameter(
|
|
'culling_sequence',
|
|
public_name='Culling Sequence',
|
|
default= (10,5,3),
|
|
container=tuple,
|
|
type=int,
|
|
doc="TBD"
|
|
)
|
|
|
|
CULLING_ERROR_LIMIT = Application.Parameter(
|
|
'culling_error_limit',
|
|
public_name='Culling error limit',
|
|
default=100,
|
|
type = int,
|
|
mandatory = False,
|
|
doc = 'Minimum number of culled offsets to be used for offset field polynomial estimation'
|
|
)
|
|
|
|
GEOCODE_LIST = Application.Parameter(
|
|
'geocode_list',
|
|
public_name='geocode list',
|
|
default = None,
|
|
container=list,
|
|
type=str,
|
|
doc = "List of products to geocode."
|
|
)
|
|
|
|
GEOCODE_BOX = Application.Parameter(
|
|
'geocode_bbox',
|
|
public_name='geocode bounding box',
|
|
default = None,
|
|
container=list,
|
|
type=float,
|
|
doc='Bounding box for geocoding - South, North, West, East in degrees'
|
|
)
|
|
|
|
PICKLE_DUMPER_DIR = Application.Parameter(
|
|
'pickleDumpDir',
|
|
public_name='pickle dump directory',
|
|
default='PICKLE',
|
|
type=str,
|
|
mandatory=False,
|
|
doc=(
|
|
"If steps is used, the directory in which to store pickle objects."
|
|
)
|
|
)
|
|
PICKLE_LOAD_DIR = Application.Parameter(
|
|
'pickleLoadDir',
|
|
public_name='pickle load directory',
|
|
default='PICKLE',
|
|
type=str,
|
|
mandatory=False,
|
|
doc=(
|
|
"If steps is used, the directory from which to retrieve pickle objects."
|
|
)
|
|
)
|
|
|
|
RENDERER = Application.Parameter(
|
|
'renderer',
|
|
public_name='renderer',
|
|
default='pickle',
|
|
type=str,
|
|
mandatory=False,
|
|
doc=(
|
|
"Format in which the data is serialized when using steps. Options are xml (default) or pickle."
|
|
)
|
|
)
|
|
|
|
#Facility declarations
|
|
REFERENCE = Application.Facility(
|
|
'reference',
|
|
public_name='Reference',
|
|
module='isceobj.Sensor',
|
|
factory='createSensor',
|
|
args=(SENSOR_NAME, 'reference'),
|
|
mandatory=True,
|
|
doc="Reference raw data component"
|
|
)
|
|
|
|
SECONDARY = Application.Facility(
|
|
'secondary',
|
|
public_name='Secondary',
|
|
module='isceobj.Sensor',
|
|
factory='createSensor',
|
|
args=(SENSOR_NAME,'secondary'),
|
|
mandatory=True,
|
|
doc="Secondary raw data component"
|
|
)
|
|
|
|
REFERENCEDOP = Application.Facility(
|
|
'referencedop',
|
|
public_name='Reference Doppler',
|
|
module='isceobj.Doppler',
|
|
factory='createDoppler',
|
|
args=(DOPPLER_METHOD,),
|
|
mandatory=False,
|
|
doc="Reference Doppler calculation method"
|
|
)
|
|
|
|
SECONDARYDOP = Application.Facility(
|
|
'secondarydop',
|
|
public_name='Secondary Doppler',
|
|
module='isceobj.Doppler',
|
|
factory='createDoppler',
|
|
args=(DOPPLER_METHOD,),
|
|
mandatory=False,
|
|
doc="Reference Doppler calculation method"
|
|
)
|
|
|
|
DEM = Application.Facility(
|
|
'dem',
|
|
public_name='Dem',
|
|
module='isceobj.Image',
|
|
factory='createDemImage',
|
|
mandatory=False,
|
|
doc=(
|
|
"Dem Image configurable component. Do not include this in the "+
|
|
"input file and an SRTM Dem will be downloaded for you."
|
|
)
|
|
)
|
|
|
|
DEM_STITCHER = Application.Facility(
|
|
'demStitcher',
|
|
public_name='demStitcher',
|
|
module='iscesys.DataManager',
|
|
factory='createManager',
|
|
args=('dem1','iscestitcher',),
|
|
mandatory=False,
|
|
doc="Object that based on the frame bounding boxes creates a DEM"
|
|
)
|
|
|
|
RUN_ESTIMATE_HEIGHTS = Application.Facility(
|
|
'runEstimateHeights',
|
|
public_name='Estimate Heights',
|
|
module='isceobj.InsarProc',
|
|
factory='createEstimateHeights',
|
|
args=(SELF(), SENSOR_NAME),
|
|
mandatory=False,
|
|
doc="mocomp height estimation module"
|
|
)
|
|
|
|
RUN_FORM_SLC = Application.Facility(
|
|
'runFormSLC',
|
|
public_name='Form SLC',
|
|
module='isceobj.InsarProc',
|
|
factory='createFormSLC',
|
|
args=(SELF(), SENSOR_NAME),
|
|
mandatory=False,
|
|
doc="SLC formation module"
|
|
)
|
|
|
|
RUN_OFFSETPRF = Application.Facility(
|
|
'runOffsetprf',
|
|
public_name='slc offsetter',
|
|
module='isceobj.InsarProc',
|
|
factory='createOffsetprf',
|
|
args=(SELF(), OFFSET_METHOD, DO_OFFSETPRF),
|
|
mandatory=False,
|
|
doc="Offset a pair of SLC images."
|
|
)
|
|
|
|
RUN_RGOFFSET = Application.Facility(
|
|
'runRgoffset',
|
|
public_name='dem offseter',
|
|
module = 'isceobj.InsarProc',
|
|
factory= 'createRgoffset',
|
|
args=(SELF(), OFFSET_METHOD, DO_RGOFFSET),
|
|
mandatory=False,
|
|
doc="Dem offset estimator."
|
|
)
|
|
|
|
RUN_UNWRAPPER = Application.Facility(
|
|
'runUnwrapper',
|
|
public_name='Run unwrapper',
|
|
module='isceobj.InsarProc',
|
|
factory='createUnwrapper',
|
|
args=(SELF(), DO_UNWRAP, UNWRAPPER_NAME, UNWRAP),
|
|
mandatory=False,
|
|
doc="Unwrapping module"
|
|
)
|
|
|
|
RUN_UNWRAP_2STAGE = Application.Facility(
|
|
'runUnwrap2Stage',
|
|
public_name='Run unwrapper 2 Stage',
|
|
module='isceobj.InsarProc',
|
|
factory='createUnwrap2Stage',
|
|
args=(SELF(), DO_UNWRAP_2STAGE, UNWRAPPER_NAME),
|
|
mandatory=False,
|
|
doc="Unwrapping module"
|
|
)
|
|
|
|
_INSAR = Application.Facility(
|
|
'_insar',
|
|
public_name='insarproc',
|
|
module='isceobj.InsarProc',
|
|
factory='createInsarProc',
|
|
args = ('insarAppContext',isceobj.createCatalog('insarProc')),
|
|
mandatory=False,
|
|
doc="InsarProc object"
|
|
)
|
|
|
|
|
|
## Common interface for all insar applications.
|
|
class _InsarBase(Application, FrameMixin):
|
|
|
|
family = 'insar'
|
|
## Define Class parameters in this list
|
|
parameter_list = (SENSOR_NAME,
|
|
OFFSET_METHOD,
|
|
OFFSET_SEARCH_WINDOW_SIZE,
|
|
PEG_SELECT,
|
|
PEG_LAT,
|
|
PEG_LON,
|
|
PEG_HDG,
|
|
PEG_RAD,
|
|
FILTER_STRENGTH,
|
|
CORRELATION_METHOD,
|
|
DOPPLER_METHOD,
|
|
USE_DOP,
|
|
UNWRAP,
|
|
UNWRAPPER_NAME,
|
|
DO_UNWRAP,
|
|
DO_OFFSETPRF,
|
|
DO_RGOFFSET,
|
|
USE_HIGH_RESOLUTION_DEM_ONLY,
|
|
DEM_FILENAME,
|
|
GEO_POSTING,
|
|
POSTING,
|
|
RANGE_LOOKS,
|
|
AZ_LOOKS,
|
|
PATCH_SIZE,
|
|
GOOD_LINES,
|
|
NUM_PATCHES,
|
|
GROSS_AZ,
|
|
GROSS_RG,
|
|
CULLING_SEQUENCE,
|
|
CULLING_ERROR_LIMIT,
|
|
GEOCODE_LIST,
|
|
GEOCODE_BOX,
|
|
PICKLE_DUMPER_DIR,
|
|
PICKLE_LOAD_DIR,
|
|
RENDERER,
|
|
DO_UNWRAP_2STAGE,
|
|
UNWRAPPER_2STAGE_NAME,
|
|
SOLVER_2STAGE)
|
|
|
|
facility_list = (REFERENCE,
|
|
SECONDARY,
|
|
REFERENCEDOP,
|
|
SECONDARYDOP,
|
|
DEM,
|
|
DEM_STITCHER,
|
|
RUN_ESTIMATE_HEIGHTS,
|
|
RUN_FORM_SLC,
|
|
RUN_UNWRAPPER,
|
|
RUN_UNWRAP_2STAGE,
|
|
RUN_OFFSETPRF,
|
|
RUN_RGOFFSET,
|
|
_INSAR)
|
|
|
|
_pickleObj = "_insar"
|
|
|
|
def __init__(self, family='', name='',cmdline=None):
|
|
import isceobj
|
|
super().__init__(family=family, name=name,
|
|
cmdline=cmdline)
|
|
|
|
from isceobj.InsarProc import InsarProc
|
|
from iscesys.StdOEL.StdOELPy import create_writer
|
|
self._stdWriter = create_writer("log", "", True, filename="insar.log")
|
|
self._add_methods()
|
|
self._insarProcFact = InsarProc
|
|
'''
|
|
procDoc = isceobj.createCatalog('insarProc')
|
|
#self._insar = InsarProc.InsarProc(name='insarApp_conf',
|
|
# procDoc=procDoc
|
|
# )
|
|
self.insar.procDoc._addItem("ISCE_VERSION",
|
|
"Release: %s, svn-%s, %s. Current svn-%s" %
|
|
(isce.release_version, isce.release_svn_revision,
|
|
isce.release_date, isce.svn_revision
|
|
),
|
|
["insarProc"]
|
|
)
|
|
'''
|
|
return None
|
|
|
|
def _init(self):
|
|
|
|
message = (
|
|
("ISCE VERSION = %s, RELEASE_SVN_REVISION = %s,"+
|
|
"RELEASE_DATE = %s, CURRENT_SVN_REVISION = %s") %
|
|
(isce.__version__,
|
|
isce.release_svn_revision,
|
|
isce.release_date,
|
|
isce.svn_revision)
|
|
)
|
|
logger.info(message)
|
|
|
|
print(message)
|
|
# print("self.sensorName = ", self.sensorName)
|
|
# print("self.correlation_method = ", self.correlation_method)
|
|
# print("self.use_dop = ", self.use_dop)
|
|
# print("self.geoPosting = ", self.geoPosting)
|
|
# print("self.posting = ", self.posting)
|
|
# print("self.rangeLooks = ", self.rangeLooks)
|
|
# print("self.azLooks = ", self.azLooks)
|
|
# print("self.offsetMethod = ", self.offsetMethod)
|
|
# print("self.grossRg, self.grossAz = ", self.grossRg, self.grossAz )
|
|
if ( self.pegLat is not None and
|
|
self.pegLon is not None and
|
|
self.pegHdg is not None and
|
|
self.pegRad is not None ):
|
|
from isceobj.Location.Peg import Peg
|
|
self.peg = Peg(latitude=self.pegLat,
|
|
longitude=self.pegLon,
|
|
heading=self.pegHdg,
|
|
radiusOfCurvature=self.pegRad)
|
|
# print("self.peg = ", self.peg)
|
|
else:
|
|
self.peg = None
|
|
return None
|
|
|
|
## You need this to use the FrameMixin
|
|
@property
|
|
def frame(self):
|
|
return self.insar.frame
|
|
|
|
|
|
def _configure(self):
|
|
|
|
self.insar.procDoc._addItem("ISCE_VERSION",
|
|
"Release: %s, svn-%s, %s. Current svn-%s" %
|
|
(isce.release_version, isce.release_svn_revision,
|
|
isce.release_date, isce.svn_revision
|
|
),
|
|
["insarProc"]
|
|
)
|
|
#This is a temporary fix to get the user interface back to the dem
|
|
#facility interface while changes are being made in the DemImage class
|
|
#to include within it the capabilities urrently in extractInfo and
|
|
#createDem.
|
|
#jng ask Eric No longer needed
|
|
if self.demFilename:
|
|
import sys
|
|
print(
|
|
"The demFilename property is no longer supported as an " +
|
|
"input parameter."
|
|
)
|
|
print(
|
|
"The original method using a configurable facility for the " +
|
|
"Dem is now restored."
|
|
)
|
|
print(
|
|
"The automatic download feature is still supported in the " +
|
|
" same way as before:"
|
|
)
|
|
print(
|
|
"If you want automatic download of a Dem, then simply omit "+
|
|
"any configuration\ninformation in your input file regarding "+
|
|
"the Dem."
|
|
)
|
|
print()
|
|
print(
|
|
"Please replace the following information in your input file:"
|
|
)
|
|
print()
|
|
print(
|
|
"<property name='demFilename'><value>%s</value></property>" %
|
|
self.demFilename
|
|
)
|
|
print()
|
|
print("with the following information and try again:")
|
|
print()
|
|
print(
|
|
"<component name=\'Dem\'><catalog>%s</catalog></component>" %
|
|
self.demFilename
|
|
)
|
|
print()
|
|
else:
|
|
try:
|
|
self.dem.checkInitialization()
|
|
#jng ask Eric. self.demFilename no longer needed
|
|
# Give self.demFilename a value so that the SRTM Dem will not
|
|
# be downloaded
|
|
# Temporary fix that will be removed when the download option
|
|
# is handled within demImage
|
|
self.demFilename = "demFilename"
|
|
self.insar.demImage = self.dem
|
|
except Exception as err:
|
|
pass
|
|
#The following print statement is sometimes misleading when
|
|
#checkInitialization fails for a reason other than the dem
|
|
#not being found. The checkInitialization error should be
|
|
#handled more appropriately.
|
|
#print(
|
|
# "The Dem specified was not properly initialized. An SRTM" +
|
|
# " Dem will be downloaded."
|
|
# )
|
|
#self.dem was not properly initialized
|
|
#and self.demFilename is undefined.
|
|
#There is a check on self.demFilename
|
|
#below to download if necessary
|
|
else:
|
|
dem_snwe = self.dem.getsnwe()
|
|
|
|
if self.geocode_bbox:
|
|
####Adjust bbox according to dem
|
|
if self.geocode_bbox[0] < dem_snwe[0]:
|
|
logger.warning('Geocoding southern extent changed to match DEM')
|
|
self.geocode_bbox[0] = dem_snwe[0]
|
|
|
|
if self.geocode_bbox[1] > dem_snwe[1]:
|
|
logger.warning('Geocoding northern extent changed to match DEM')
|
|
self.geocode_bbox[1] = dem_snwe[1]
|
|
|
|
if self.geocode_bbox[2] < dem_snwe[2]:
|
|
logger.warning('Geocoding western extent changed to match DEM')
|
|
self.geocode_bbox[2] = dem_snwe[2]
|
|
|
|
if self.geocode_bbox[3] > dem_snwe[3]:
|
|
logger.warning('Geocoding eastern extent changed to match DEM')
|
|
self.geocode_bbox[3] = dem_snwe[3]
|
|
|
|
#Ensure consistency in geocode_list maintained by insarApp and
|
|
#InsarProc. If it is configured in both places, the one in insarApp
|
|
#will be used. It is complicated to try to merge the two lists
|
|
#because InsarProc permits the user to change the name of the files
|
|
#and the linkage between filename and filetype is lost by the time
|
|
#geocode_list is fully configured. In order to safely change file
|
|
#names and also specify the geocode_list, then insarApp should not
|
|
#be given a geocode_list from the user.
|
|
if(self.geocode_list is None):
|
|
#if not provided by the user use the list from InsarProc
|
|
self.geocode_list = self.insar.geocode_list
|
|
else:
|
|
#if geocode_list defined here, then give it to InsarProc
|
|
#for consistency between insarApp and InsarProc and warn the user
|
|
|
|
#check if the two geocode_lists differ in content
|
|
g_count = 0
|
|
for g in self.geocode_list:
|
|
if g not in self.insar.geocode_list:
|
|
g_count += 1
|
|
#warn if there are any differences in content
|
|
if g_count > 0:
|
|
print()
|
|
logger.warn((
|
|
"Some filenames in insarApp.geocode_list configuration "+
|
|
"are different from those in InsarProc. Using names given"+
|
|
" to insarApp."))
|
|
print("insarApp.geocode_list = {}".format(self.geocode_list))
|
|
print(("InsarProc.geocode_list = {}".format(
|
|
self.insar.geocode_list)))
|
|
|
|
self.insar.geocode_list = self.geocode_list
|
|
|
|
return None
|
|
|
|
@property
|
|
def insar(self):
|
|
return self._insar
|
|
@insar.setter
|
|
def insar(self, value):
|
|
self._insar = value
|
|
return None
|
|
|
|
@property
|
|
def procDoc(self):
|
|
return self.insar.procDoc
|
|
@procDoc.setter
|
|
def procDoc(self):
|
|
raise AttributeError(
|
|
"Can not assign to .insar.procDoc-- but you hit all its other stuff"
|
|
)
|
|
|
|
def _finalize(self):
|
|
pass
|
|
|
|
def help(self):
|
|
from isceobj.Sensor import SENSORS
|
|
print(self.__doc__)
|
|
lsensors = list(SENSORS.keys())
|
|
lsensors.sort()
|
|
print("The currently supported sensors are: ", lsensors)
|
|
return None
|
|
|
|
def help_steps(self):
|
|
print(self.__doc__)
|
|
print("A description of the individual steps can be found in the README file")
|
|
print("and also in the ISCE.pdf document")
|
|
return
|
|
|
|
## Method return True iff it changes the demFilename.
|
|
from isceobj.Util.decorators import use_api
|
|
@use_api
|
|
def verifyDEM(self):
|
|
referenceF = self._insar.referenceFrame
|
|
secondaryF = self._insar.secondaryFrame
|
|
info = self.extractInfo(referenceF, secondaryF)
|
|
#if an image has been specified, then no need to create one
|
|
if not self.dem.filename:
|
|
self.createDem(info)
|
|
else:
|
|
self.insar.demImage = self.dem
|
|
|
|
#ensure that the dem vrt file exists by creating (or recreating) it
|
|
self.insar.demImage.renderVRT()
|
|
|
|
#at this point a dem image has been set into self.insar, whether it
|
|
#was stitched together or read in input
|
|
demImage = self.insar.demImage
|
|
#if the demImage is already in wgs84 (because was provided in input) then skip and proceed
|
|
if demImage.reference.upper() != 'WGS84':
|
|
wgs84demFilename = self.insar.demImage.filename+'.wgs84'
|
|
wgs84demxmlFilename = wgs84demFilename+'.xml'
|
|
#if the dem reference is EGM96 and the WGS84 corrected
|
|
#dem files are not found, then create the WGS84 files
|
|
#using the demStitcher's correct method
|
|
if( demImage.reference.upper() == 'EGM96' and
|
|
not (os.path.isfile(wgs84demFilename) and
|
|
os.path.isfile(wgs84demxmlFilename))
|
|
):
|
|
self.insar.demImage = self.demStitcher.correct(demImage)
|
|
#make sure to load the wgs84 if present
|
|
elif(os.path.isfile(wgs84demFilename) and
|
|
os.path.isfile(wgs84demxmlFilename)):
|
|
from isceobj import createDemImage
|
|
self.insar.demImage = createDemImage()
|
|
self.insar.demImage.load(wgs84demxmlFilename)
|
|
if(self.insar.demImage.reference.upper() != 'WGS84'):
|
|
print('The dem',wgs84demFilename,'is not wgs84')
|
|
raise Exception
|
|
|
|
#ensure that the wgs84 dem vrt file exists
|
|
self.insar.demImage.renderVRT()
|
|
|
|
#get water mask
|
|
self.runCreateWbdMask(info)
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
def renderProcDoc(self):
|
|
self.procDoc.renderXml()
|
|
|
|
## Run runOffoutliers() repeatedly with arguments from "iterator" keyword
|
|
def iterate_runOffoutliers(self, iterator=None):
|
|
"""iterate_runOffoutliers(iterator)
|
|
|
|
runs runOffoutliers multiple times with values (integers) from iterator.
|
|
|
|
iterator defaults to Insar._default_culling_sequence
|
|
"""
|
|
if iterator is None: iterator = self.culling_sequence
|
|
erriterator = [self.culling_error_limit]*len(iterator)
|
|
list(map(self.runOffoutliers, iterator, erriterator))
|
|
return None
|
|
|
|
def set_topoint1(self):
|
|
self._insar.topoIntImage = self._insar.resampIntImage
|
|
return None
|
|
|
|
def set_topoint2(self):
|
|
self._insar.topoIntImage = self._insar.resampOnlyImage
|
|
return None
|
|
|
|
def startup(self):
|
|
self.help()
|
|
self._insar.timeStart = time.time()
|
|
|
|
def endup(self):
|
|
self.renderProcDoc()
|
|
self._insar.timeEnd = time.time()
|
|
logger.info("Total Time: %i seconds" %
|
|
(self._insar.timeEnd-self._insar.timeStart))
|
|
return None
|
|
|
|
|
|
## Add instance attribute RunWrapper functions, which emulate methods.
|
|
def _add_methods(self):
|
|
self.runPreprocessor = InsarProc.createPreprocessor(self)
|
|
self.extractInfo = InsarProc.createExtractInfo(self)
|
|
self.createDem = InsarProc.createCreateDem(self)
|
|
self.runCreateWbdMask = InsarProc.createCreateWbdMask(self)
|
|
self.runMaskImages = InsarProc.createMaskImages(self)
|
|
self.runPulseTiming = InsarProc.createPulseTiming(self)
|
|
self.runSetmocomppath = InsarProc.createSetmocomppath(self)
|
|
self.runOrbit2sch = InsarProc.createOrbit2sch(self)
|
|
self.updatePreprocInfo = InsarProc.createUpdatePreprocInfo(self)
|
|
self.runOffoutliers = InsarProc.createOffoutliers(self)
|
|
self.prepareResamps = InsarProc.createPrepareResamps(self)
|
|
self.runResamp = InsarProc.createResamp(self)
|
|
self.runResamp_image = InsarProc.createResamp_image(self)
|
|
self.runMocompbaseline = InsarProc.createMocompbaseline(self)
|
|
self.runTopo = InsarProc.createTopo(self)
|
|
self.runCorrect = InsarProc.createCorrect(self)
|
|
self.runShadecpx2rg = InsarProc.createShadecpx2rg(self)
|
|
self.runResamp_only = InsarProc.createResamp_only(self)
|
|
self.runCoherence = InsarProc.createCoherence(self)
|
|
self.runFilter = InsarProc.createFilter(self)
|
|
self.runGrass = InsarProc.createGrass(self)
|
|
self.runGeocode = InsarProc.createGeocode(self)
|
|
return None
|
|
|
|
def _steps(self):
|
|
|
|
self.step('startup', func=self.startup,
|
|
doc=("Print a helpful message and "+
|
|
"set the startTime of processing")
|
|
)
|
|
# Run a preprocessor for the two sets of frames
|
|
self.step('preprocess',
|
|
func=self.runPreprocessor,
|
|
doc=(
|
|
"""Preprocess the reference and secondary sensor data to raw images"""
|
|
)
|
|
)
|
|
|
|
# Verify whether the DEM was initialized properly. If not, download
|
|
# a DEM
|
|
self.step('verifyDEM', func=self.verifyDEM)
|
|
|
|
# Run pulsetiming for each set of frames
|
|
self.step('pulsetiming', func=self.runPulseTiming)
|
|
|
|
self.step('estimateHeights', func=self.runEstimateHeights)
|
|
|
|
# Run setmocomppath
|
|
self.step('mocompath', func=self.runSetmocomppath, args=(self.peg,))
|
|
|
|
#init and run orbit2sch
|
|
self.step('orbit2sch', func=self.runOrbit2sch)
|
|
|
|
#update quantities in objPreProc obtained from previous steps
|
|
self.step('updatepreprocinfo',
|
|
func=self.updatePreprocInfo,
|
|
args=(self.use_dop,))
|
|
|
|
self.step('formslc', func=self.runFormSLC)
|
|
|
|
self.step('offsetprf', func=self.runOffsetprf)
|
|
|
|
# Cull offoutliers
|
|
self.step('outliers1', func=self.iterate_runOffoutliers)
|
|
|
|
self.step('prepareresamps',
|
|
func=self.prepareResamps,
|
|
args=(self.rangeLooks,self.azLooks))
|
|
|
|
self.step('resamp', func=self.runResamp)
|
|
|
|
self.step('resamp_image', func=self.runResamp_image)
|
|
|
|
# Mocompbaseline
|
|
self.step('mocompbaseline', func=self.runMocompbaseline)
|
|
|
|
# Topocorrect
|
|
#self.step('settopoint1',
|
|
# func=self.insar.delayed_attrcopy_from_to('resampIntImage',
|
|
# 'topoIntImage')
|
|
# )
|
|
self.step('settopoint1', func=self.set_topoint1)
|
|
|
|
self.step('topo', func=self.runTopo)
|
|
|
|
self.step('shadecpx2rg', func=self.runShadecpx2rg)
|
|
|
|
# Compute offsets and cull offoutliers
|
|
self.step('rgoffset', func=self.runRgoffset)
|
|
self.step('rg_outliers2', func=self.iterate_runOffoutliers)
|
|
|
|
self.step('resamp_only', func=self.runResamp_only)
|
|
|
|
#Topocorrect
|
|
#self.step('settopoint2',
|
|
# func=self.insar.delayed_attrcopy_from_to('resampOnlyImage',
|
|
# 'topoIntImage')
|
|
# )
|
|
self.step('settopoint2', func=self.set_topoint2)
|
|
|
|
self.step('correct', func=self.runCorrect)
|
|
|
|
# Coherence ?
|
|
self.step('coherence',
|
|
func=self.runCoherence,
|
|
args=(self.correlation_method,))
|
|
|
|
# Filter ?
|
|
self.step('filter', func=self.runFilter,
|
|
args=(self.filterStrength,))
|
|
|
|
#add water mask to coherence and interferogram
|
|
self.step('mask', func=self.runMaskImages)
|
|
|
|
# Unwrap ?
|
|
self.step('unwrap', func=self.runUnwrapper)
|
|
|
|
# Conditional 2 stage unwrapping
|
|
self.step('unwrap2stage', func=self.runUnwrap2Stage,
|
|
args=(self.unwrapper_2stage_name, self.solver_2stage))
|
|
|
|
return None
|
|
|
|
## Main has the common start to both insarApp and dpmApp.
|
|
def main(self):
|
|
self.help()
|
|
|
|
# Run a preprocessor for the two sets of frames
|
|
self.runPreprocessor()
|
|
#Verify whether user defined a dem component. If not, then download
|
|
# SRTM DEM.
|
|
self.verifyDEM()
|
|
|
|
# Run pulsetiming for each set of frames
|
|
self.runPulseTiming()
|
|
self.runEstimateHeights()
|
|
|
|
# Run setmocomppath
|
|
self.runSetmocomppath(peg=self.peg)
|
|
|
|
#init and run orbit2sch
|
|
self.runOrbit2sch()
|
|
|
|
#update quantities in objPreProc obtained from previous steps
|
|
self.updatePreprocInfo(use_dop=self.use_dop)
|
|
|
|
self.runFormSLC()
|
|
|
|
self.runOffsetprf()
|
|
|
|
# Cull offoutliers
|
|
self.iterate_runOffoutliers()
|
|
|
|
self.prepareResamps(self.rangeLooks, self.azLooks)
|
|
self.runResamp()
|
|
self.runResamp_image()
|
|
|
|
# Mocompbaseline
|
|
self.runMocompbaseline()
|
|
|
|
# Topocorrect
|
|
self.insar.topoIntImage = self.insar.resampIntImage
|
|
self.runTopo()
|
|
return None
|
|
|
|
@property
|
|
def resampAmpImage(self):
|
|
return self.insar.resampAmpImage
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
class Insar(_InsarBase):
|
|
"""
|
|
Insar Application:
|
|
Implements InSAR processing flow for a pair of scenes from
|
|
sensor raw data to geocoded, flattened interferograms.
|
|
"""
|
|
|
|
family = "insar"
|
|
|
|
def __init__(self, family='',name='',cmdline=None):
|
|
#to allow inheritance with different family name use the locally
|
|
#defined only if the subclass (if any) does not specify one
|
|
|
|
super().__init__(
|
|
family=family if family else self.__class__.family, name=name,
|
|
cmdline=cmdline)
|
|
|
|
def Usage(self):
|
|
print("Usages: ")
|
|
print("insarApp.py <input-file.xml>")
|
|
print("insarApp.py --steps")
|
|
print("insarApp.py --help")
|
|
print("insarApp.py --help --steps")
|
|
|
|
|
|
## extends _InsarBase_steps, but not in the same was as main
|
|
def _steps(self):
|
|
super()._steps()
|
|
|
|
# Geocode
|
|
self.step('geocode', func=self.runGeocode,
|
|
args=(self.geocode_list, self.unwrap, self.geocode_bbox))
|
|
|
|
# self.step('endup', func=self.endup)
|
|
|
|
return None
|
|
|
|
## main() extends _InsarBase.main()
|
|
def main(self):
|
|
import time
|
|
timeStart = time.time()
|
|
|
|
super().main()
|
|
|
|
# self.runCorrect()
|
|
|
|
self.runShadecpx2rg()
|
|
|
|
self.runRgoffset()
|
|
|
|
# Cull offoutliers
|
|
self.iterate_runOffoutliers()
|
|
|
|
self.runResamp_only()
|
|
|
|
self.insar.topoIntImage=self.insar.resampOnlyImage
|
|
#self.runTopo()
|
|
self.runCorrect()
|
|
|
|
# Coherence ?
|
|
self.runCoherence(method=self.correlation_method)
|
|
|
|
|
|
# Filter ?
|
|
self.runFilter(self.filterStrength)
|
|
|
|
#add water mask to coherence and interferogram
|
|
self.runMaskImages()
|
|
# Unwrap ?
|
|
self.runUnwrapper()
|
|
|
|
# 2Stage Unwrapping
|
|
self.runUnwrap2Stage(self.unwrapper_2stage_name, self.solver_2stage)
|
|
|
|
# Geocode
|
|
self.runGeocode(self.geocode_list, self.unwrap, self.geocode_bbox)
|
|
|
|
timeEnd = time.time()
|
|
logger.info("Total Time: %i seconds" %(timeEnd - timeStart))
|
|
|
|
self.renderProcDoc()
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if not isce.stanford_license:
|
|
print("This workflow requires the Stanford licensed code elemnts.")
|
|
print("Unable to find the license information in the isce.stanford_license file.")
|
|
print("Please either obtain a stanford license and follow the instructions to")
|
|
print("install the stanford code elements or else choose a different workflow.")
|
|
raise SystemExit(0)
|
|
else:
|
|
#make an instance of Insar class named 'insarApp'
|
|
insar = Insar(name="insarApp")
|
|
#configure the insar application
|
|
insar.configure()
|
|
#invoke the base class run method, which returns status
|
|
status = insar.run()
|
|
#inform Python of the status of the run to return to the shell
|
|
raise SystemExit(status)
|