  GEOS 639 Geodetic Imaging

  Lab 1: DEM Generation with InSAR using ISCE  -- [20 Points]

Assignment Due Date:  February 10, 2022

  Heresh Fattahi with modifications by Franz J Meyer

 Date:  Jan 25, 2022

  THIS NOTEBOOK INCLUDES TWO HOMEWORK ASSIGNMENTS.

 The homework assignments in this lab are indicated by markdown fields with red background. Please complete these assignments to achieve full score.

 To submit your homework, please download your completed Jupyter Notebook from the server both as PDF (*.pdf) and Notebook file (*.ipynb) and submit them as a ZIP bundle via the GEOS 639 Canvas page. To download, please select the following options in the main menu of the notebook interface:

  Save your notebook with all of its content by selecting  File / Save and Checkpoint

 To export in Notebook format, click the radio button next to the notebook file in the main Jupyter Hub browser tab. Once clicked, a download field will appear near the top of the page.

 To export in PDF format, right-click on your browser window and print the browser content to PDF

Contact me at fjmeyer@alaska.edu should you run into any problems.

# Set Conda Environment

```javascript
%%javascript
var kernel = Jupyter.notebook.kernel;
var command = ["notebookUrl = ",
               "'", window.location, "'" ].join('')
kernel.execute(command)
```

```python
from IPython.display import Markdown
from IPython.display import display

user = !echo $JUPYTERHUB_USER
env = !echo $CONDA_PREFIX
if env[0] == '':
    env[0] = 'Python 3 (base)'
if env[0] != '/home/jovyan/.local/envs/unavco':
    display(Markdown(f'<text style=color:red><strong>WARNING:</strong></text>'))
    display(Markdown(f'<text style=color:red>This notebook should be run using the "unavco" conda environment.</text>'))
    display(Markdown(f'<text style=color:red>It is currently using the "{env[0].split("/")[-1]}" environment.</text>'))
    display(Markdown(f'<text style=color:red>Select the "unavco" from the "Change Kernel" submenu of the "Kernel" menu.</text>'))
    display(Markdown(f'<text style=color:red>If the "unavco" environment is not present, use <a href="{notebookUrl.split("/user")[0]}/user/{user[0]}/notebooks/conda_environments/Create_OSL_Conda_Environments.ipynb"> Create_OSL_Conda_Environments.ipynb </a> to create it.</text>'))
    display(Markdown(f'<text style=color:red>Note that you must restart your server after creating a new environment before it is usable by notebooks.</text>'))
```

# Intro 1: DEM Generation using InSAR

InSAR is a great apporach to generage digital elevation models (DEMs), especially in areas where frequent cloud cover limits the applicability of stereo-photogrammetry, which is using optical sensors.

In InSAR, we analyze the phase difference $\phi$ between two images acquired from slightly different vantage points. The phase differencing is needed as the phase in a single SAR image is randomized by speckle. Once the phase difference (interferometric phase) was calculated, topographic information can be extracted.

InSAR Workflow: To generate DEMs using InSAR, we will follow the InSAR processing steps we discussed in lecture #3:

Image co-registration (this needs to be done very precisely to make sure that the phase noise patterns (see image) in the two InSAR parners are perfectly aligned)

Interferogram formation (i.e., phase difference calculation)

Removal of all known phase patterns $\rightarrow$ this will make phase unwrapping simpler (we will subtract the flat earth phase and an already known DEM).

Phase filtering - this is a spatial smoothing process to reduce phase noise $\rightarrow$ improves phase unwrapping performance.

Phase unwrapping (using a Minimum-Cost-Flow Algorithm).

Geocoding and phase-to-height conversion.

InSAR Performance Considerations: As was discussed in the lectures, DEM generation from InSAR data provides highest quality information if the following conditions are met:

The InSAR pair has a sufficiently large spatial baseline.

The temporal separation of image partners is small enough to warrant sufficient coherence.

The temporal baseline is small enough to reduce potential impacts from surface deformation on the interferometric phase.

Outside of the TanDEM-X sensor constellation discussed in the lecture, not many satellite platforms meet these conditions well. Here we process a pair of ALOS PALSAR images acquired over Okmok volcano with the goal of DEM mapping.

 The ALOS PALSAR mission is another good option as it created InSAR pairs with long spatial baselines. The L-band wavelength also ensures that the InSAR coherence is comparatively high.

That being said, a downside of ALOS PALSAR is that the temporal baselines of available InSAR pairs is often rather long. So there may be deformation information hiding in the InSAR phase.

# Intro 2: About Stripmap Data

In conventional stripmap Synthetic Aperture Radar(SAR) imaging mode, the radar antenna is fixed to a specific direction, illuminating a single swath of the scene with a fixed squint angle (i.e., the angle between the radar beam and the cross-track direction). The imaging swath width can be increased using the scanning SAR (ScanSAR) or Terrain Observation by Progressive Scan(TOPS). In this notebook we focus on interferometric processing of stripmap data using stripmapApp.py.

The stripmap mode has been used by sevreal SAR missions, such as Envisat, ERS, RadarSAT-1, Radarsat-2, ALOS-1, Cosmo Sky-Med and TerraSAR-X. Although Sentinel-1 A/B and ALOS-2 are capable of acuqiring SAR data with stripmap mode, their operational imaging modes are TOPS and ScanSAR respectively. Both missions have been acquiring stripmap data over certain regions.

For processing TOPS data using topsApp, please see the topsApp notebook. However, we recommend that new InSAR users may start with the stripmapApp notebook first, and then try the topsApp notebook.

The detailed algorithms for stripmap processing and TOPS processing implemented in ISCE software can be found in the following literatures:

### stripmapApp:

H. Fattahi, M. Simons, and P. Agram,  "InSAR Time-Series Estimation of the Ionospheric Phase Delay: An Extension of the Split Range-Spectrum Technique", IEEE Trans. Geosci. Remote Sens., vol. 55, no. 10, 5984-5996, 2017.
(https://ieeexplore.ieee.org/abstract/document/7987747/)

### topsApp:

H. Fattahi, P. Agram, and M. Simons, “A network-based enhanced spectral diversity approach for TOPS time-series analysis,” IEEE Trans. Geosci. Remote Sens., vol. 55, no. 2, pp. 777–786, Feb. 2017. (https://ieeexplore.ieee.org/abstract/document/7637021/)

### ISCE framework:
Rosen et al, IGARSS 2018 [Complete reference here]

(Figure from Fattahi et. al., 2017)

# stripmapApp, a General Overview

stripmapApp.py is an ISCE application, designed for interferometric processing of SAR data acquired with stripmap mode onboard platforms with precise orbits. The main features of stripmapApp includes the following:

#### a) Focusing RAW data:

If processing starts from RAW data, JPL's ROI software is used for focusing the raw data to SLC(Single Look Complex) SAR images. If data are provided in an already focused SLC format, this step will be skipped.

#### b) Interferometric processing of SLCs
Interferograms will be formed from the focused SLCs using the following steps

#### c) Coregistration using SAR acquisition geometry (Orbit + DEM)
The geometry module of ISCE is used for coregistration of SAR images, i.e., range and azimuth offsets are computed for each pixel using SAR acquisition geometry, orbit information and an existing Digital Elevation Model(DEM). The geometrical offsets are refined with a small constant shift in range and azimuth directions. The constant shifts are estimated using incoherent cross-correlation of the two SAR images already coregistered using pure geometrical information.

#### d) More optional precise coregistration step
An optional step called "rubbersheeting" is available for more precise coregistration. If "rubbersheeting" is requested, a dense azimuth offsets is computed using incoherent cross-correlation between the two SAR images, and is added to the geometrical offsets for more precise coregistration. Rubbersheeting may be required if SAR images are affected by ionospheric scintillation.

#### e) Ionospheric phase estimation
Split Range-Spectrum technique and ionospheric phase estimation are available as optional processing steps.

# Prepare directories, download raw data

## Importing Python Libraries and Setting up Environment Variables

```python
# If you want to use the staged data on S3 bucket, change this flag to True.
# when the falg is False, the notebook downloads the ALOS raw data from ASF and
# ISCE automatically downloads an SRTM DEM for processing
Use_Staged_Data = True
import os
import numpy as np
import matplotlib.pyplot as plt
from osgeo import gdal
import shutil
from tqdm import tqdm
import urllib.request

import isce
import isceobj.StripmapProc.StripmapProc as St
from isceobj.Planet.Planet import Planet

#
ASF_USER = " "
ASF_PASS = " "

# the working directory:
home_dir = os.path.join(os.getenv("HOME"), "work")
PROCESS_DIR = os.path.join(home_dir, "Okmok")
DATA_DIR =  os.path.join(PROCESS_DIR, "data")

# if the ASF user/pass is not provided above, try to read it from ~/.netrc file
if (len(ASF_PASS)==0 | len(ASF_USER)==0) & (os.path.exists(os.path.join(os.getenv("HOME"), ".netrc"))):
    netrc_path = os.path.join(os.getenv("HOME"), ".netrc")
    print('Hello')
    count = len(open(netrc_path).readlines(  ))
    if count == 1:
        file = open(os.path.join(os.getenv("HOME"), ".netrc"), "r")
        contents = file.read().split(" ")
        ASF_USER = contents[3]
        ASF_PASS = contents[5]
        file.close()
    else:
        ASF_USER = np.loadtxt(os.path.join(os.getenv("HOME"), ".netrc"), skiprows=1, usecols=1, dtype=str)[0]
        ASF_PASS = np.loadtxt(os.path.join(os.getenv("HOME"), ".netrc"), skiprows=1, usecols=1, dtype=str)[1]

if (len(ASF_PASS)==0 | len(ASF_USER)==0) | (not os.path.exists(os.path.join(os.getenv("HOME"), ".netrc"))) :
    print("WARNING: The ASF USER pass needs to be included in ~/.netrc file.")
    print(" The ~/.netrc file does not exixt or is not setup properly.")
    print("Follow this link for instructions on setting up your ~/.netrc file")
    print("""If you wish to download the data from ASF please make sure:
             1) you have valid earthdata login and password stored in your ~/.netrc file
             2) make sure that you have logged into ASF vertex page and have accepted the EULA agreement.""")
    print("Without further actions you will still be able to run this notebook using already available data on S3 bucket.")
    print("Using data on S3 bucket ...")
    Use_Staged_Data = True

if Use_Staged_Data:
    print("Using the staged data for this notebook has been turned on.")
```

```python
def configure_inputs(outDir, Use_Staged_Data):

    """Wraite Configuration files for ISCE2 stripmapApp to process NISAR sample products"""
    cmd_reference_config = '''<component>
    <property name="IMAGEFILE">
       <value>[data/20080822/ALPSRP137311060-L1.0/IMG-HH-ALPSRP137311060-H1.0__A]</value>
    </property>
    <property name="LEADERFILE">
        <value>[data/20080822/ALPSRP137311060-L1.0/LED-ALPSRP137311060-H1.0__A]</value>
    </property>
    <property name="OUTPUT">
        <value>20080822</value>
    </property>
</component>'''

    print("writing reference.xml")
    with open(os.path.join(outDir,"reference.xml"), "w") as fid:
        fid.write(cmd_reference_config)

    cmd_secondary_config = '''<component>
    <property name="IMAGEFILE">
        <value>[data/20081007/ALPSRP144021060-L1.0/IMG-HH-ALPSRP144021060-H1.0__A]</value>
    </property>
    <property name="LEADERFILE">
        <value>[data/20081007/ALPSRP144021060-L1.0/LED-ALPSRP144021060-H1.0__A]</value>
    </property>
    <property name="OUTPUT">
        <value>20081007</value>
    </property>

</component>'''

    print("writing secondary.xml")
    with open(os.path.join(outDir,"secondary.xml"), "w") as fid:
        fid.write(cmd_secondary_config)

    if Use_Staged_Data:
        cmd_stripmap_config = '''<?xml version="1.0" encoding="UTF-8"?>
<stripmapApp>
  <component name="insar">
    <property name="sensor name">ALOS</property>
    <component name="reference">
        <catalog>reference.xml</catalog>
    </component>
    <component name="secondary">
        <catalog>secondary.xml</catalog>
    </component>

    <property name="demFilename">
        <value>demLat_N52_N55_Lon_W169_W167.dem.wgs84</value>
    </property>

    <property name="unwrapper name">icu</property>

    <property name="do split spectrum">False</property>

    <property name="do dispersive">False</property>

</component>
</stripmapApp>'''
    else:

        cmd_stripmap_config = '''<?xml version="1.0" encoding="UTF-8"?>
<stripmapApp>
  <component name="insar">
    <property name="sensor name">ALOS</property>
    <component name="reference">
        <catalog>reference.xml</catalog>
    </component>
    <component name="secondary">
        <catalog>secondary.xml</catalog>
    </component>

    <!--
    <property name="demFilename">
        <value>demLat_N52_N55_Lon_W169_W167.dem.wgs84</value>
    </property>
    -->

    <property name="unwrapper name">icu</property>

    <property name="do split spectrum">False</property>

    <property name="do dispersive">False</property>

</component>
</stripmapApp>'''

    print("writing stripmapApp.xml")
    with open(os.path.join(outDir,"stripmapApp.xml"), "w") as fid:
        fid.write(cmd_stripmap_config)
```

Check if the PROCESS_DIR and DATA_DIR already exist. If they don't exist, we create them:

```python
if not os.path.exists(PROCESS_DIR):
    print("create ", PROCESS_DIR)
    os.makedirs(PROCESS_DIR)
else:
    print(PROCESS_DIR, " already exists!")

if not os.path.exists(DATA_DIR):
    print("create ", DATA_DIR)
    os.makedirs(DATA_DIR)
else:
    print(DATA_DIR, " already exists!")

os.chdir(DATA_DIR)
```

## Area of Interest for this Lab

In this tutorial we will process two ALOS1 PALSAR acquistions over Umnak Island in the Aleutians, Alaska. The two acquisitions cover Okmok Volcano right after its eruption in June 2008.

## Downloading and Unzipping of SAR RAW Data

Download two ALOS-1 acquistions from ASF using the following command:

```python
if Use_Staged_Data:
    # Check if a stage file from S3 already exist, if not try and download it
    if not os.path.isfile('ALPSRP137311060-L1.0.zip'):
        !aws --region=us-east-1 --no-sign-request s3 cp s3://asf-jupyter-data/ALPSRP137311060-L1.0.zip ALPSRP137311060-L1.0.zip

    if not os.path.isfile('ALPSRP144021060-L1.0.zip'):
        !aws --region=us-east-1 --no-sign-request s3 cp s3://asf-jupyter-data/ALPSRP144021060-L1.0.zip ALPSRP144021060-L1.0.zip

else:
    print("Will not be using S3 pre-staged data, Data will be downloaded from ASF")
    cmd = "wget  https://datapool.asf.alaska.edu/L1.0/A3/ALPSRP137311060-L1.0.zip --user={0} --password={1}".format(ASF_USER, ASF_PASS)
    if not os.path.exists(os.path.join(DATA_DIR, "ALPSRP137311060-L1.0.zip")):
        os.system(cmd)
    else:
        print("ALPSRP137311060-L1.0.zip already exists")

    cmd = "wget  https://datapool.asf.alaska.edu/L1.0/A3/ALPSRP144021060-L1.0.zip --user={0} --password={1}".format(ASF_USER, ASF_PASS)
    if not os.path.exists(os.path.join(DATA_DIR, "ALPSRP144021060-L1.0.zip")):
        os.system(cmd)
    else:
        print("ALPSRP144021060-L1.0.zip already exists")
```

unzip the downloaded files

```python
if not os.path.exists(os.path.join(DATA_DIR, "ALPSRP137311060-L1.0")):
    !unzip ALPSRP137311060-L1.0.zip

if not os.path.exists(os.path.join(DATA_DIR, "ALPSRP144021060-L1.0")):
    !unzip ALPSRP144021060-L1.0.zip
```

 looking at the unzipped directories there are multiple files:

```python
ls ALPSRP137311060-L1.0
```

When you download PALSAR data from a data provider, each frame comprises an image data file and an image leader file, as well as possibly some other ancillary files that are not used by ISCE.

Files with IMG as prefix are images.
Files with LED as prefix are leaders.

The leader file contains parameters of the sensor that are relevant to the imaging mode, all the information necessary to process the data.  The data file contains the raw data samples if Level 1.0 raw data (this is just a different name from what other satellites call Level 0) and processed imagery if Level 1.1 or 1.5 image data.  The naming convention for these files is standardized across data archives, and has the following taxonomy:

To see the acquisition date of this PALSAR acquisition we can look at the following file:

```python
!cat ALPSRP137311060-L1.0/ALPSRP137311060.l0.workreport
```

```python
!grep Img_SceneCenterDateTime ALPSRP137311060-L1.0/ALPSRP137311060.l0.workreport
!grep Img_SceneCenterDateTime ALPSRP144021060-L1.0/ALPSRP144021060.l0.workreport
```

for clarity let's create two directories for the two acquisition dates and move the unziped folders there:

```python
if not os.path.exists('/home/jovyan/work/Okmok/data/20080822'):
    os.mkdir('/home/jovyan/work/Okmok/data/20080822')
if not os.path.exists('/home/jovyan/work/Okmok/data/20081007'):
    os.mkdir('/home/jovyan/work/Okmok/data/20081007')

if not os.path.exists('/home/jovyan/work/Okmok/data/20080822/ALPSRP137311060-L1.0'):
    shutil.move('/home/jovyan/work/Okmok/data/ALPSRP137311060-L1.0',
               '/home/jovyan/work/Okmok/data/20080822')
if not os.path.exists('/home/jovyan/work/Okmok/data/20081007/ALPSRP144021060-L1.0'):
    shutil.move('/home/jovyan/work/Okmok/data/ALPSRP144021060-L1.0',
               '/home/jovyan/work/Okmok/data/20081007')
```

Now that we have the data ready let's cd to the main PROCESS directroy

```python
os.chdir(PROCESS_DIR)
```

To make sure where we are, run pwd:

```python
!pwd
```

# Setting up Input xml Files for Processing with stripmapApp

Create the input configuration files (refernce.xml, secondary.xml, stripmapApp.xml) to configure the inputs and the processing parameters.
The configurations files can be created using your favorit editor or by calling the "configure" funstion which is defined at the top of this notebook:

```python
if Use_Staged_Data:
    # Check if a stage file from S3 already exist, if not try and download it
    if not os.path.isfile('demLat_N52_N55_Lon_W169_W167.dem.wgs84'):
        !aws --region=us-east-1 --no-sign-request s3 cp s3://asf-jupyter-data/demLat_N52_N55_Lon_W169_W167.dem.wgs84 demLat_N52_N55_Lon_W169_W167.dem.wgs84
        !aws --region=us-east-1 --no-sign-request s3 cp s3://asf-jupyter-data/demLat_N52_N55_Lon_W169_W167.dem.wgs84.vrt demLat_N52_N55_Lon_W169_W167.dem.wgs84.vrt
        !aws --region=us-east-1 --no-sign-request s3 cp s3://asf-jupyter-data/demLat_N52_N55_Lon_W169_W167.dem.wgs84.xml demLat_N52_N55_Lon_W169_W167.dem.wgs84.xml
    else:
        print("The DEM already exists")
else:
    print("Will not be using S3 pre-staged data, The DEM will be automatically downloaded by ISCE")

```

```python
configure_inputs(PROCESS_DIR, Use_Staged_Data)
```

Here is an example refernce.xml file for this tutorial:

### reference.xml

```xml
<component>
    <property name="IMAGEFILE">
       <value>[data/20080822/ALPSRP137311060-L1.0/IMG-HH-ALPSRP137311060-H1.0__D]</value>
    </property>
    <property name="LEADERFILE">
        <value>[data/20080822/ALPSRP137311060-L1.0/LED-ALPSRP137311060-H1.0__D]</value>
    </property>
    <property name="OUTPUT">
        <value>20080822</value>
    </property>
</component>
```

### secondary.xml

```xml
<component>
    <property name="IMAGEFILE">
        <value>[data/20110306/ALPSRP144021060-L1.0/IMG-HH-ALPSRP144021060-H1.0__D]</value>
    </property>
    <property name="LEADERFILE">
        <value>[data/20110306/ALPSRP144021060-L1.0/LED-ALPSRP144021060-H1.0__D]</value>
    </property>
    <property name="OUTPUT">
        <value>20110306</value>
    </property>

</component>
```

### stripmapApp.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<stripmapApp>
  <component name="insar">
    <property name="sensor name">ALOS</property>
    <component name="reference">
        <catalog>refernce.xml</catalog>
    </component>
    <component name="secondary">
        <catalog>secondary.xml</catalog>
    </component>

    <!--
    <property name="demFilename">
        <value>demLat_N52_N55_Lon_W169_W167.dem.wgs84.wgs84</value>
    </property>
    -->

    <property name="unwrapper name">icu</property>

</component>
</stripmapApp>
```

Note :

In this example, demFilename is commented out in the stripmapApp.xml. This means that user has not specified the DEM. Therefore, isce looks online and download the SRTM dem.

After downloading the data to process, and setting up the input xml files, we are ready to start processing with stripmapApp. To see a full list of the processing steps run the following command:

```python
!stripmapApp.py --help --steps
```

# Creating an Interferogram with stripmapApp

By default, stripmapApp includes the following processing steps to generate a geocoded interferogram from raw data or SLC images:

Data Preparation [Steps: startup, preprocess, cropraw]

SLC Formation [Steps: formslc]

DEM Assisted Co-Registration [Steps: verifyDEM, topo, geo2rdr, coarse_resample, misregistration, refined_resample]

Interferogram Formation [Steps: interferogram]

Phase Filtering and Phase Unwrapping [Steps: filter, unwrap]

Geocoding and Phase2Height Conversion [Steps: geocode]

In this tutorial we will process the interferogram step-by-step.

At the end of each step, you will see a mesage showing the remaining steps:

The remaining steps are (in order):  [.....]

Note that you can process the interferogram with one command:

```stripmapApp.py stripmapApp.xml --start=startup --end=endup```

## Data Preparation:

### Step: preprocess

```python
!stripmapApp.py stripmapApp.xml --start=startup --end=preprocess
```

By the end of "preprocess", the following folders are created:

20080822_raw

20081007_raw

If you look into one of these folders:

```python
ls 20080822_raw
```

20080822.raw contains the raw data (I/Q real and imaginary parts of each pulse, sampled along track (azimuth direction) with Pulse Repitition Frequency (PRF) and across track(range direction) with Range Sampling Frequency. stripmapApp currently only handles data acquired (or resampled) to a constant PRF.

### Step: cropraw

The "cropraw" step would crop the raw data based on the region of interest if it was requested in the stripmapApp.xml. The region of interest can be added to stripmapApp.xml as:
```xml
<property name="regionOfInterest">[19.0, 19.9, -155.4, -154.7]</property>
```

Since we have not specified the region of interest, then "cropraw" will be ignored and the whole frame will be processed.

```python
!stripmapApp.py stripmapApp.xml --start=cropraw --end=cropraw
```

## SLC Formation

### Step: formslc

Step "formslc", focuses SLC images from the raw data for both the reference and secondary scenes.

```python
!stripmapApp.py stripmapApp.xml --start=formslc --end=formslc
```

```python
ls 20080822_slc
```

20080822.slc: Single Look Comlex image for 20080822 acquisition.

20080822.slc.vrt: A gdal VRT file which contains the size, data type, etc.

20080822.slc.xml: ISCE xml metadat file

In order to see the number of lines and pixels for an SLC image (or any data readable by GDAL):

```python
!gdalinfo 20080822_slc/20080822.slc
```

Display a subset of SLC's amplitude and phase

```python
ds = gdal.Open("20080822_slc/20080822.slc", gdal.GA_ReadOnly)
# extract a part of the SLC to display
x0 = 0
y0 = 10000
x_offset = 4000
y_offset = 10000
slc = ds.GetRasterBand(1).ReadAsArray(x0, y0, x_offset, y_offset)
ds = None

plt.rcParams['font.size'] = '14'
fig = plt.figure(figsize=(14, 12))

# display amplitude of the slc
ax = fig.add_subplot(1,2,1)
ax.imshow(np.abs(slc), vmin = -2, vmax=2, cmap='gray')
ax.set_title("amplitude")

#display phase of the slc
ax = fig.add_subplot(1,2,2)
ax.imshow(np.angle(slc))
ax.set_title("phase")

plt.show()

slc = None
```

### Step: crop SLC

```python
!stripmapApp.py stripmapApp.xml  --start=cropslc --end=cropslc
```

Similar to crop raw data but for SLC. Since region of interest has not been specified, the whole frame is processed.

## DEM-Assisted Co-Registration

### Step: verifyDEM

This step checks if the DEM was provided in the input xml file. If a DEM is not provided, then the app downloads SRTM DEM.

```python
!stripmapApp.py stripmapApp.xml  --start=verifyDEM --end=verifyDEM
```

### Step: topo (mapping radar coordinates to geo coordinates)

```python
!stripmapApp.py stripmapApp.xml  --start=topo --end=topo
```

At this step, based on the SAR acquisition geometry of the reference Image (including Doppler information), platforms trajectory and an existing DEM, each pixel of the reference image is geolocated. The geolocated coordinates will be at the same coordinate system of the platforms state vectors, which are usually given in WGS84 coordinate system. Moreover the incidence angle and heading angles will be computed for each pixel.

Outputs of the step "topo" are written to "geometry" directory:

```python
!ls geometry
```

lat.rdr.full: latitude of each pixel on the ground. "full" stands for full SAR image resolution grid (before multi-looking)

lon.rdr.full: longitude

z.rdr.full: height

los.rdr.full: incidence angle and heading angle

```python
# Read a bounding box of latitude
ds = gdal.Open('geometry/lat.rdr.full', gdal.GA_ReadOnly)
lat = ds.GetRasterBand(1).ReadAsArray(0,10000,3000, 10000)
ds = None

# Read a bounding box of longitude
ds = gdal.Open('geometry/lon.rdr.full', gdal.GA_ReadOnly)
lon = ds.GetRasterBand(1).ReadAsArray(0,10000,3000, 10000)
ds = None

# Read a bounding box of height
ds = gdal.Open('geometry/z.rdr.full', gdal.GA_ReadOnly)
hgt = ds.GetRasterBand(1).ReadAsArray(0,10000,3000, 10000)
ds = None

plt.rcParams['font.size'] = '14'
fig = plt.figure(figsize=(18, 16))

ax = fig.add_subplot(1,3,1)
cax=ax.imshow(lat)
ax.set_title("latitude")
ax.set_axis_off()
cbar = fig.colorbar(cax, orientation='horizontal')

ax = fig.add_subplot(1,3,2)
cax=ax.imshow(lon)
ax.set_title("longitude")
ax.set_axis_off()
cbar = fig.colorbar(cax, orientation='horizontal')

ax = fig.add_subplot(1,3,3)
cax=ax.imshow(hgt, vmin = -100, vmax=1000)
ax.set_title("height")
ax.set_axis_off()
cbar = fig.colorbar(cax, orientation='horizontal')

plt.show()

lat = None
lon = None
hgt = None
```

### Step: geo2rdr (mapping from geo coordinates to radar coordinates)

```python
!stripmapApp.py stripmapApp.xml --start=geo2rdr --end=geo2rdr
```

In this step, given the geo-ccordinates of each pixel in the reference image (outputs of topo), the range and azimuth time (radar coordinates) is computed given the acquisition geometry and orbit information of the secondary image.

The computed range and azimuth time for the secondary image, gives the pure geometrical offset, required for resampling the secondary image to the reference image in the next step.

After running this step, the geometrical offsets are available in "offsets" folder:

```python
!ls offsets
```

azimuth.off: contains the offsets betwen reference ans secondary images in azimuth direction

range.off:   contains the offsets betwen reference ans secondary images in range direction

```python
ds = gdal.Open('offsets/azimuth.off', gdal.GA_ReadOnly)
# extract only part of the data to display
az_offsets = ds.GetRasterBand(1).ReadAsArray(100,100,2000,5000)
ds = None

ds = gdal.Open('offsets/range.off', gdal.GA_ReadOnly)
# extract only part of the data to display
rng_offsets = ds.GetRasterBand(1).ReadAsArray(100,100,2000,5000)
ds = None
plt.rcParams['font.size'] = '14'
fig = plt.figure(figsize=(14, 12))

ax = fig.add_subplot(1,2,1)
cax=ax.imshow(az_offsets)
ax.set_title("azimuth offsets")
ax.set_axis_off()
cbar = fig.colorbar(cax, orientation='horizontal')

ax = fig.add_subplot(1,2,2)
cax = ax.imshow(rng_offsets)
ax.set_title("range offsets")
ax.set_axis_off()
cbar = fig.colorbar(cax, orientation='horizontal')

plt.show()

az_offsets = None
rng_offsets = None
```

### Step: resampling (using only geometrical offsets)

```python
!stripmapApp.py stripmapApp.xml --start=coarse_resample --end=coarse_resample
```

At this step, the gemetrical offsets are used to resample the secondary image to the same grid as the reference image, i.e., the secondary image is co-registered to the reference image. The output of this step is written to "coregisteredSlc" folder.

```python
!ls coregisteredSlc/
```

coarse_coreg.slc: is the secondary SLC coregistered to the reference image

```python
ds = gdal.Open("coregisteredSlc/coarse_coreg.slc", gdal.GA_ReadOnly)
slc = ds.GetRasterBand(1).ReadAsArray(0, 5000, 4000, 15000)
ds = None
plt.rcParams['font.size'] = '14'
fig = plt.figure(figsize=(18, 16))
ax = fig.add_subplot(1,2,1)
ax.imshow(np.abs(slc), vmin = -2, vmax=2, cmap='gray')
ax.set_title("amplitude")

slc = None
```

### Step: misregistration (estimating residual constant offsets in range and azimuth directions)

```python
!stripmapApp.py stripmapApp.xml --start=misregistration --end=misregistration
```

The range and azimuth offsets derived from pure geometry can be potentially affected by inaccuracy of orbit information or inaccurate DEMs, or inaccurate SAR metadata. The current available DEMs (e.g., SRTM DEMs) are accurate enough to estimate offsets with accuracies of 1/100 of a pixel. The Orbit information of most modern SAR sensors are also precise enough to obtain the same order of accuracy. However, inaccurate metadata (such as timing error, constant range bias), or range bulk delay may affect the estimated offsets. To account for such sources of errors the misregistration step is performed to estimate possible constant offsets between coarse coregistered SLC and reference SLC. For this purpose an incoherent cross correlation is performed.

The results of the "misregistration" step is written to the "misreg" folder.

```python
!ls misreg/
```

In order to extract the estimated misregistration offsets:

```python
stObj=St()
stObj.configure()

az = stObj.loadProduct("misreg/misreg_az.xml")
rng = stObj.loadProduct("misreg/misreg_rg.xml")

print("azimuth misregistration: ", az._coeffs)
print("range misregistration: ", rng._coeffs)
```

### Step: refine_resample (resampling using geometrical offsets + misregistration)

```python
!stripmapApp.py stripmapApp.xml --start=refined_resample --end=refined_resample
```

At this step resampling is re-run to account for the misregistration estimated at the previous step. The new coregisterd SLC (named refined_coreg.slc) is written to the "coregisteredSlc" folder.

```python
!ls coregisteredSlc/
```

### optional steps ('dense_offsets', 'rubber_sheet', 'fine_resample', 'split_range_spectrum' , 'sub_band_resample')

```python
!stripmapApp.py stripmapApp.xml --start=dense_offsets --end=sub_band_resample
```

These steps are optional and will be skipped if user does not request them in the input xml file. We will get back to these steps in a different session where we estimate ionospheric phase.

## Interferogram Formation

### Step: interferogram

At this step the reference image and refined_coreg.slc is used to generate the interferogram. The generated interferogram is multi-looked based on the user inputs in the input xml file. If user does not specify the number of looks in range and azimuth directions, then they will be estimated based on posting. The default posting is 30 m which can be also specified in the input xml file.

The results of the interferogram step is written to the "interferogram" folder:

```python
!stripmapApp.py stripmapApp.xml --start=interferogram --end=interferogram
```

```python
!ls interferogram/
```

topophase.flat: flattened (geometrical phase removed) and multi-looked interferogram.(one band complex64 data).

topophase.cor: coherence and magnitude for the flattened multi-looked interferogram. (two bands float32 data).

topophase.cor.full: similar to topophase.cor but at full SAR resolution.

topophase.amp: amplitudes of reference amd secondary images. (two bands float32)

### Optional Step: sub-band interferogram

```python
!stripmapApp.py stripmapApp.xml --start=sub_band_interferogram --end=sub_band_interferogram
```

This step will be skipped as we have not asked for ionospheric phase estimation. We will get back to this step in the ionospheric phase estimation notebook.

## Phase Filtering and Phase Unwrapping

### Step: filter

A power spectral filter is applied to the multi-looked interferogram to reduce noise.

```python
!stripmapApp.py stripmapApp.xml --start=filter --end=filter
```

Next we visualize the interferogram before and after filtering.

```python
# reading the multi-looked wrapped interferogram
ds = gdal.Open("interferogram/topophase.flat", gdal.GA_ReadOnly)
igram = ds.GetRasterBand(1).ReadAsArray()
ds = None

# reading the multi-looked un-wrapped interferogram
ds = gdal.Open("interferogram/filt_topophase.flat", gdal.GA_ReadOnly)
filt_igram = ds.GetRasterBand(1).ReadAsArray()
ds = None
plt.rcParams['font.size'] = '14'
fig = plt.figure(figsize=(18, 16))

ax = fig.add_subplot(1,3,1)
ax.imshow(np.abs(igram), vmin = 0 , vmax = 60.0, cmap = 'gray')
ax.set_title("magnitude")
#ax.set_axis_off()

ax = fig.add_subplot(1,3,2)
ax.imshow(np.angle(igram), cmap='jet')
ax.plot([10,1500,1500,10,10],[2500,2500,1000,1000,2500],'-k')
ax.set_title("multi-looked interferometric phase")
ax.set_axis_off()

ax = fig.add_subplot(1,3,3)
ax.imshow(np.angle(filt_igram), cmap='jet')
ax.plot([10,1500,1500,10,10],[2500,2500,1000,1000,2500],'-k')
ax.set_title("multi-looked & filtered phase")
#ax.set_axis_off()

fig = plt.figure(figsize=(18, 16))

ax = fig.add_subplot(1,3,1)
ax.imshow(np.abs(igram[1000:2500, 10:1500]), vmin = 0 , vmax = 60.0, cmap = 'gray')
ax.set_title("magnitude")
#ax.set_axis_off()

ax = fig.add_subplot(1,3,2)
ax.imshow(np.angle(igram[1000:2500, 10:1500]), cmap='jet')
ax.plot([600,1400,1400,600,600],[1400,1400,800,800,1400],'--k')
ax.set_title("multi-looked interferometric phase")
ax.set_axis_off()

ax = fig.add_subplot(1,3,3)
ax.imshow(np.angle(filt_igram[1000:2500, 10:1500]), cmap='jet')
ax.plot([600,1400,1400,600,600],[1400,1400,800,800,1400],'--k')
ax.set_title("multi-looked & filtered phase")
ax.set_axis_off()

fig = plt.figure(figsize=(18, 16))

ax = fig.add_subplot(1,3,1)
ax.imshow(np.abs(igram[1800:2400, 610:1410]), vmin = 0 , vmax = 60.0, cmap = 'gray')
ax.set_title("magnitude")
ax.set_axis_off()

ax = fig.add_subplot(1,3,2)
ax.imshow(np.angle(igram[1800:2400, 610:1410]), cmap='jet')
ax.set_title("multi-looked interferometric phase")
ax.set_axis_off()

ax = fig.add_subplot(1,3,3)
ax.imshow(np.angle(filt_igram[1800:2400, 610:1410]), cmap='jet')
ax.set_title("multi-looked & filtered phase")
ax.set_axis_off()

filt_igram = None
igram = None

```

###  Homework Assignment #1

   ASSIGNMENT #1:   Flat Earth Phase Correction   -- [5 Points]

During Lecture 3 (InSAR), we saw that before flat earth correction, the interferogram contains many fringes. Here a couple of short questions related to that:

Question 1.1: In addition to improve the visualization of InSAR data, one important reason why we remove the flat earth phase from interferograms is to make phase unwrapping easier. Explain in a few sentences why you think removing the flat earth phase makes phase unwrapping less complicated. To answer this question, please edit the markdown cell below. -- [3 Points]

Question 1.2: It turns out, ISCE tries to reduce the unwrapping complexity even more. Instead of "just" removing the flat earth phase, it subtracts any already know topography from the interferogram by using an existing DEM. Once this is done, what does the residual phase information in the interferogram shown above represent?  -- [2 Points]

 Question 1.1 [3 Points]:

ADD DISCUSSION HERE:

 Question 1.2 [3 Points]:

ADD DISCUSSION HERE:

### Optional Steps ('filter_low_band', 'filter_high_band')

```python
!stripmapApp.py stripmapApp.xml --start=filter_low_band  --end=filter_high_band
```

These steps will be skipped since we have not asked for ionospheric phase estimation in the input xml file.

### Step: unwrap

```python
!stripmapApp.py stripmapApp.xml --start=unwrap  --end=unwrap
```

At this step the wrapped phase of the filtered and multi-looked interferogram is unwrapped. The unwrapped interferogram is a two band data with magnitude and phase components.

```python
# reading the multi-looked wrapped interferogram
ds = gdal.Open("interferogram/filt_topophase.flat", gdal.GA_ReadOnly)
igram = ds.GetRasterBand(1).ReadAsArray()
ds = None

# reading the multi-looked unwrapped interferogram
ds = gdal.Open("interferogram/filt_topophase.unw", gdal.GA_ReadOnly)
igram_unw = ds.GetRasterBand(2).ReadAsArray()
ds = None

# reading the connected component file
ds = gdal.Open("interferogram/filt_topophase.conncomp", gdal.GA_ReadOnly)
connected_components = ds.GetRasterBand(1).ReadAsArray()
ds = None

plt.rcParams['font.size'] = '14'
fig = plt.figure(figsize=(18, 6))

ax = fig.add_subplot(1,3,1)
cax=ax.imshow(np.angle(igram[1000:2600, 10:1800]), cmap='jet')
ax.set_title("wrapped")
#ax.set_axis_off()
cbar = fig.colorbar(cax, ticks=[-3.14,0,3.14],orientation='horizontal')
cbar.ax.set_xticklabels(["$-\pi$",0,"$\pi$"])

ax = fig.add_subplot(1,3,2)
cax = ax.imshow(igram_unw[1000:2600, 10:1800], vmin = -5 , vmax = 2.0, cmap = 'jet')
ax.set_title("unwrapped")
ax.set_axis_off()
cbar = fig.colorbar(cax, ticks=[-5,0, 2
                               ], orientation='horizontal')

ax = fig.add_subplot(1,3,3)
cax = ax.imshow(connected_components[1000:2600, 10:1800], cmap = 'jet')
ax.set_title("components")
ax.set_axis_off()
cbar = fig.colorbar(cax, ticks=[0, 1] , orientation='horizontal')
cbar.ax.set_xticklabels([0,1])

connected_components = None
```

Note (wrapped vs unwrapped) :
Note the colorscale for the wrapped and unwrapped interferograms. The wrapped interferometric phase varies from $-\pi$ to $\pi$, while the unwrapped interferogram varies from -15 to 15 radians.

Note :
The connected components file is a product of the phase unwrapping. Each interferogram may have several connected compoenets. The unwrapped phase within each component is expected to be correctly unwrapped. However, there might be $2\pi$ phase jumps between the components. Advanced ISCE users may use the 2-stage unwrapping to adjust ambiguities among different components. stripmapApp currently does not support 2-stage unwrapping. Look for this option in future releases.

```python
profile_wrapped_1 = np.angle(igram[2000,1000:1500])
profile_unwrapped_1 = igram_unw[2000,1000:1500]
profile_wrapped_2 = np.angle(igram[1400,400:600])
profile_unwrapped_2 = igram_unw[1400,400:600]
plt.rcParams['font.size'] = '14'
fig = plt.figure(figsize=(20,8))

ax = fig.add_subplot(2,3,1)
cax=ax.plot(profile_wrapped_1)
ax.set_title("wrapped")

ax = fig.add_subplot(2,3,2)
cax=ax.plot(profile_unwrapped_1)
ax.set_title("unwrapped")

ax = fig.add_subplot(2,3,3)
cax=ax.plot(np.round((profile_unwrapped_1-profile_wrapped_1)/2.0/np.pi))
ax.set_title("(unwrapped - wrapped)/(2$\pi$)")

ax = fig.add_subplot(2,3,4)
cax=ax.plot(profile_wrapped_2)
ax.set_title("wrapped")

ax = fig.add_subplot(2,3,5)
cax=ax.plot(profile_unwrapped_2)
ax.set_title("unwrapped")

ax = fig.add_subplot(2,3,6)
cax=ax.plot((profile_unwrapped_2-profile_wrapped_2)/2.0/np.pi)
ax.set_title("(unwrapped - wrapped)/(2$\pi$)")

igram = None
igram_unw = None
```

### Optional Steps ('unwrap_low_band', 'unwrap_high_band', 'ionosphere')

```python
!stripmapApp.py stripmapApp.xml --start=unwrap_low_band  --end=ionosphere
```

Since we have not asked for ionospheric phase estimation, all these steps will be skipped.

## Geocoding and Phase2Height Conversion

### Step: geocoding

```python
!stripmapApp.py stripmapApp.xml --start=geocode  --end=geocode
```

```python
# reading the multi-looked wrapped interferogram
ds = gdal.Open("interferogram/filt_topophase.unw.geo", gdal.GA_ReadOnly)
unw_geocoded = ds.GetRasterBand(2).ReadAsArray()
ds = None

plt.rcParams['font.size'] = '14'
fig = plt.figure(figsize=(12,10))

ax = fig.add_subplot(1,1,1)
cax = ax.imshow(unw_geocoded, vmin = -5 , vmax = 2.0, cmap = 'jet')
ax.set_title("geocoded unwrapped")
ax.set_axis_off()
cbar = fig.colorbar(cax, ticks=[-5,0, 2], orientation='horizontal')

plt.show()
unw_geocoded = None
```

###  Homework Assignment #2

   ASSIGNMENT #2:   Succeed with the Geocoding of your Interferogram   -- [15 Points]

Run the notebook all the way to this point and compare your geocoded interferogram to the interferogram shown below. If your product looks very similar then you succeeded with this notebook. All you need to do is download the notebook as described above and you completed this assignment.

### Step: Phase-to-Height Conversion

Once the phase is geocoded, the phase $\phi$ information has to be scaled into height $h$ using equation

\begin{equation}
h = \frac{\lambda}{4\pi} \cdot \frac{R \cdot sin(\theta)}{B_{\perp}} \cdot \phi
\end{equation}

We will use the ISCE function ```imageMath.py``` for this step.

The following code cell uses ```imageMath.py``` to do the phase-to-height conversion. The parameters are as follows:

-e: This argument encodes the equation we are trying to execute. We are using a interferometric baseline of $B_{\perp} = 900m$ here.

-o: This argument specifies the output file we create.

-t: Sets the format of the output file. We are setting this format to float

--a: specifies the input file use in our equation.

```python
!imageMath.py -e='a_0 ; 0.0566/(4.0 * 3.14) * 850000 * 0.5 / (900) * a_1' -o DEMupdate.geo -t float --a=interferogram/filt_topophase.unw.geo
```

Now we can plot the DEM update height map we generated:

```python
# reading the multi-looked wrapped interferogram
ds = gdal.Open("DEMupdate.geo", gdal.GA_ReadOnly)
DEMupdate = ds.GetRasterBand(2).ReadAsArray()
ds = None
DEMupdate_m = np.ma.masked_where(DEMupdate==0, DEMupdate)
plt.rcParams['font.size'] = '14'
fig = plt.figure(figsize=(12,10))

ax = fig.add_subplot(1,1,1)
cax = ax.imshow(DEMupdate - np.mean(DEMupdate_m), vmin = -5 , vmax = 5, cmap = 'jet')
ax.set_title("geocoded unwrapped")
ax.set_axis_off()
cbar = fig.colorbar(cax, ticks=[-5,0, 5], orientation='horizontal')

plt.show()
unw_geocoded = None
```

# Supplementary Information

### understanding xml files

The format of this type of file may seem unfamiliar or strange to you, but with the following description of the basics of the format, it will hopefully become more familiar.   The first thing to point out is that the indentations and line breaks seen above are not required and are simply used to make the structure more clear and the file more readable to humans.  The xml file provides structure to data for consumption by a computer.  As far as the computer is concerned the data structure is equally readable if all of the information were contained on a single very long line, but human readers would have a hard time reading it in that format.

The next thing to point out is the method by which the data are structured through the use of tags and attributes.  An item enclosed in the < (less-than) and > (greater-than) symbols is referred to as a tag.  The name enclosed in the < and > symbols is the name of the tag.  Every tag in an xml file must have an associated closing tag that contains the same name but starts with the symbol </ and ends with the symbol >.  This is the basic unit of structure given to the data.  Data are enclosed inside of opening and closing tags that have names identifying the enclosed data.  This structure is nested to any order of nesting necessary to represent the data.  The Python language (in which the ISCE user interface is written) provides powerful tools to parse the xml structure into a data structure object and to very easily “walk” through the structure of that object.

In the above xml file the first and last tags in the file are a tag pair: <stripmapApp> and </stripmapApp> (note again, tags must come in pairs like this).  The first of these two tags, or the opening tag,  marks the beginning of the contents of the tag and the second of these two tags, or the closing tag, marks the end of the contents of the tag.  ISCE expects a “file tag” of this nature to bracket all inputs contained in the file.  The actual name of the file tag, as far as ISCE is concerned, is user selectable.  In this example it is used, as a convenience to the user, to document the ISCE application, named insarApp.py, for which it is meant to provide inputs; it could have been named <foo> and insarApp.py would have been equally happy provided that the closing tag were </foo>.

The next tag  is <component name="insar">.  Its closing tag </component> is located at the penultimate line of the file (one line above the </insar> tag). The name of this tag is component and it has an attribute called name with value “insarApp”. The component tags bound a collection of information that is used by a computational element within ISCE that has the name specified by the name attribute.   The name “insarApp”  in the first component tag tells ISCE that the enclosed information correspond to a functional component in ISCE named “insarApp”, which in this case is actually the application that is run at the command line.

In general, component tags contain information in the form of other component tags or property tags, all of which can be nested to any required level. In this example the  insarApp component contains a property tag and two other component tags.

The first tag we see in the insarApp component tag is the property tag with attribute name=“sensor name”. The property tag contains a value tag that contains the name of the sensor, ALOS in this case.  The next tag is a component tag with attribute name=”reference”. This tag contains a catalog tag containing  refernce.xml.  The catalog tag in general informs ISCE to look in the named file (reference.xml in this case) for the contents of the current tag.  The next component tag has the same structure with the catalog  tag containing a different file named secondary.xml.

### Extra configuration parameters

The input configuration file in this tutorial only included mandatory parameters including the reference and secondary images, which are enough to run the application. This means that the application is configured with default parameters hardwired in the code or computed during processing.
For custom processing, user may want to set parameters in the input configuration file. In the following a few more parameters are shown that can be added to stripmapApp.xml.

### regionOfInterest

To specify a region of interest to process:

```xml
<property name="regionOfInterest">[South, North, West, East]</property>
```

Example:

```xml
<property name="regionOfInterest">[19.0, 19.9, -155.4, -154.7]</property>
```

Default: Full frame is processed.

### range looks
number of looks in range direction

```xml
<property name="range looks">USER_INPUT</property>
```

Deafult: is computed based on the posting parameter.

### azimuth looks
number of looks in azimuth direction

Deafult: is computed based on the posting parameter.

### posting
Interferogram posting in meters.

```xml
<property name="posting">USER_INPUT</property>
```

Default: 30

Note :
If "range looks" and "azimuth looks" have not been specified, then posting is used to compute them such that the interferogram is generated with a roughly square pixels size with each dimension close to the "posting" parameter.

### filter strength

strength of the adaptive filter used for filtering the wrapped interferogram

```xml
<property name="filter strength">USER_INPUT</property>
```

Default: 0.5

### useHighResolutionDemOnly
```xml
<property name="useHighResolutionDemOnly">True</property>
```

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)

Default: False

### do unwrap

To turn phase unwrapping off
```xml
<property name="do unwrap">False</property>
```

Default: True

### unwrapper name
To choose the name of the phase unwrapping method. e.g., to choose "snaphu" for phase unwrapping
```xml
<property name="unwrapper name">snaphu</property>
```

Default: "icu".

### do rubbersheeting

To turn on rubbersheeting (estimating azimuth offsets caused by strong ionospheric scentilation)

```xml
<property name="do rubbersheeting">True</property>
```
Default : False

### rubber sheet SNR Threshold

```xml
<property name="rubber sheet SNR Threshold">USER_INPUT</property>
```
If "do rubbersheeting" is turned on, then this values is used to mask out azimuth offsets with SNR less that the input threshold.

Default: 5

### rubber sheet filter size
the size of the median filter used for filtering the azimuth offsets

```xml
<property name="rubber sheet filter size">USER_INPUT</property>
```

Default: 8

### do denseoffsets
turn on the dense offsets computation from cross correlation

```xml
<property name="do denseoffsets">True</property>
```

Default: False

Note :

If "do rubbersheeting" is turned on, then dense offsets computation is turned on regardless of the user input for "do denseoffsets"

### setting the dense offsets parameters

```xml
<property name="dense window width">USER_INPUT</property>
<property name="dense window height">USER_INPUT</property>
<property name="dense search width">USER_INPUT</property>
<property name="dense search height">USER_INPUT</property>
<property name="dense skip width">USER_INPUT</property>
<property name="dense skip height">USER_INPUT</property>
```

Default values:

    dense window width  = 64

    dense window height = 64

    dense search width  = 20

    dense search height = 20

    dense skip width    = 32

    dense skip height   = 32

### geocode list

List of products to be geocoded.
```xml
<property name="geocode list">"a list of files to geocode">
```
Default: multilooked, filtered wrapped and unwrapped interferograms, coherence, ionospehric phase

### offset geocode list
List of offset-specific files to geocode
```xml
<property name="offset geocode list">"a list of offset files to geocode">
```

### do split spectrum

turn on split spectrum

```xml
<property name="do split spectrum">True</property>
```

Default: False

### do dispersive
turn on disperive phase estimation

```xml
<property name="do dispersive">True</property>
```

Default: False

Note :

By turning on "do dispersive", the user input for "do split spectrum" is ignored and the split spectrum will be turned on as it is needed for dispersive phase estimation.

### control the filter kernel for filtering the dispersive phase
```xml
<property name="dispersive filter kernel x-size">800</property>
<property name="dispersive filter kernel y-size">800</property>
<property name="dispersive filter kernel sigma_x">100</property>
<property name="dispersive filter kernel sigma_y">100</property>
<property name="dispersive filter kernel rotation">0</property>
<property name="dispersive filter number of iterations">5</property>
<property name="dispersive filter mask type">coherence</property>
<property name="dispersive filter coherence threshold">0.6</property>

```

### processing data from other stripmap sensors

stripmapApp.py is able to process the stripmap data from the following sensors. So far it has been sucessfully tested on the following sensors:

    ALOS1 (Raw and SLC)
    ALOS2 (SLC, one frame)
    COSMO_SkyMed (Raw and SLC)
    ERS
    ENVISAT ()
    Radarsat-1
    Radarsat-2
    TerraSARX
    TanDEMX
    Sentinel1

    envisat_slc

### Sample input data xml for different sensors:

#### Envisat:
```xml

<component name="reference">
    <property name="IMAGEFILE">data/ASA_IMS_1PNESA20050519_140259_000000172037_00239_16826_0000.N1</property>
    <property name="INSTRUMENT_DIRECTORY">/u/k-data/agram/sat_metadata/ENV/INS_DIR</property>
    <property name="ORBIT_DIRECTORY">/u/k-data/agram/sat_metadata/ENV/Doris/VOR</property>
    <property name="OUTPUT">
        20050519
    </property>
</component>

```

Note :
Note that for processing the ENVISAT data a directory that contains the orbits is required.

### Sentinel-1 stripmap:
```xml
    <component name="reference">
      <property name="orbit directory">/u/data/sat_metadata/S1/aux_poeorb/</property>
      <property name="output">20151024</property>
      <property name="safe">/u/data/S1A_S1_SLC__1SSV_20151024T234201_20151024T234230_008301_00BB43_068C.zip</property>
    </component>
    <component name="secondary">
      <property name="orbit directory">/u/k-raw/sat_metadata/S1/aux_poeorb/</property>
      <property name="output">20150930</property>
      <property name="safe">/u/data/S1A_S1_SLC__1SSV_20150930T234200_20150930T234230_007951_00B1CC_121C.zip</property>
    </component>
```

Note :
Note that for processing the Sentinel-1 data a directory that contains the orbits is required.

### ALOS2 SLC
```xml
<component>
    <property name="IMAGEFILE">
        <value>data/20141114/ALOS2025732920-141114/IMG-HH-ALOS2025732920-141114-UBSL1.1__D</value>
    </property>
    <property name="LEADERFILE">
        <value>data/20141114/ALOS2025732920-141114/LED-ALOS2025732920-141114-UBSL1.1__D</value>
    </property>
    <property name="OUTPUT">
        <value>20141114</value>
    </property>
</component>
```

### ALOS1 raw data
``` xml
<component>
    <property name="IMAGEFILE">
       <value>[data/20080822/ALPSRP137311060-L1.0/IMG-HH-ALPSRP137311060-H1.0__D]</value>
    </property>
    <property name="LEADERFILE">
        <value>[data/20080822/ALPSRP137311060-L1.0/LED-ALPSRP137311060-H1.0__D]</value>
    </property>
    <property name="OUTPUT">
        <value>20080822</value>
    </property>
</component>
```

### CosmoSkyMed raw or SLC data

```xml
<component name="reference">
    <property name="HDF5">data/CSKS3_RAW_B_HI_03_HH_RD_SF_20111007021527_20111007021534.h5</property>
    <property name="OUTPUT">
        20111007
    </property>
</component>

```

### TerraSAR-X and TanDEM-X

```xml
<component name="reference">
    <property name="xml">PATH_TO_TSX_DATA_XML</property>
    <property name="OUTPUT">OUTPUT_NAME</property>
</component>
```

### Using ISCE as a python library

ISCE can be used a python library. Users can develop their own workflows within ISCE framework. Here are few simple examples where we try to call isce modules:

#### Example 1: (extract metadata, range and azimuth pixel size)

```python
stObj = St()
stObj.configure()
frame = stObj.loadProduct("20080822_slc.xml")
print("Wavelength = {0} m".format(frame.radarWavelegth))
print("Slant Range Pixel Size = {0} m".format(frame.instrument.rangePixelSize))

#For azimuth pixel size we need to multiply azimuth time interval by the platform velocity along the track

# the acquisition time at the middle of the scene
t_mid = frame.sensingMid

#get the orbit for t_mid
st_mid=frame.orbit.interpolateOrbit(t_mid)

# platform velocity
Vs = st_mid.getScalarVelocity()

# pulse repitition frequency
prf = frame.instrument.PRF

#Azimuth time interval
ATI = 1.0/prf

#Azimuth Pixel size
az_pixel_size = ATI*Vs
print("Azimuth Pixel Size = {0} m".format(az_pixel_size))

```

#### Example 2: compute ground range pixels size

```python
r0 = frame.startingRange
rmax = frame.getFarRange()
rng =(r0+rmax)/2

elp = Planet(pname='Earth').ellipsoid
tmid = frame.sensingMid

sv = frame.orbit.interpolateOrbit( tmid, method='hermite') #.getPosition()
llh = elp.xyz_to_llh(sv.getPosition())

hdg = frame.orbit.getENUHeading(tmid)
elp.setSCH(llh[0], llh[1], hdg)
sch, vsch = elp.xyzdot_to_schdot(sv.getPosition(), sv.getVelocity())

Re = elp.pegRadCur
H = sch[2]
cos_beta_e = (Re**2 + (Re + H)**2 -rng**2)/(2*Re*(Re+H))
sin_bet_e = np.sqrt(1 - cos_beta_e**2)
sin_theta_i = sin_bet_e*(Re + H)/rng
print("incidence angle at the middle of the swath: ", np.arcsin(sin_theta_i)*180.0/np.pi)
groundRangeRes = frame.instrument.rangePixelSize/sin_theta_i
print("Ground range pixel size: {0} m ".format(groundRangeRes))

```

Note :
One can easily get the incidence angle from the los.rdr file inside geometry folder. Even without opening the file, here is a way to get the statistics and the average value of the incidence angle:  gdalinfo geometry/los.rdr -stats

```python

```