(for v0.3.0) https://github.com/ASFHyP3/hyp3-isce2/releases/tag/v0.3.0
https://github.com/ASFHyP3/hyp3-isce2/tree/v0.3.0
import geopandas as gpd
import asf_search as asf
import requests
import os
# not sure why DEBUG statements is happening in other libraries if imported after hyp3_isce2...
import logging
import hyp3_isce2.burst as hb # https://github.com/ASFHyP3/hyp3-isce2/issues/53 ?
rootlogs = logging.getLogger()
rootlogs.setLevel('WARNING')
import numpy as np
import xmlschema
import lxml
import re
import hyp3_isce2
hyp3_isce2.__version__ # syntax changing rapidly, so stick with 0.3.0
'0.3.0'
# https://geojson.io/#new&map=15.23/47.654452/-122.303174
gfa = gpd.GeoDataFrame.from_features( {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
-122.29994319751066,
47.657472535245574
],
"type": "Point"
}
}
]
},
crs=4326
)
gfa.explore()
https://sar-mpc.eu/test-data-sets/
Sentinel-1 Burst ID Map, version 20220530, generated by the SAR-MPC service, available on Sentinel-1 MPC Test data sets
# For now consider selecting a burst covering a point
gf = gpd.read_file('S1_burstid_20220530/IW/sqlite/burst_map_IW_000001_375887.sqlite3',
mask=gfa)
gf.head()
burst_id | subswath_name | relative_orbit_number | time_from_anx_sec | orbit_pass | geometry | |
---|---|---|---|---|---|---|
0 | 26566 | IW2 | 13 | 2181.796971 | DESCENDING | MULTIPOLYGON Z (((-122.23228 47.70264 0.00000,... |
1 | 135602 | IW1 | 64 | 778.871202 | ASCENDING | MULTIPOLYGON Z (((-122.33284 47.59533 0.00000,... |
2 | 245655 | IW3 | 115 | 2183.851464 | DESCENDING | MULTIPOLYGON Z (((-121.35897 47.72621 0.00000,... |
3 | 245656 | IW3 | 115 | 2186.609737 | DESCENDING | MULTIPOLYGON Z (((-121.40024 47.56094 0.00000,... |
4 | 292399 | IW2 | 137 | 774.912738 | ASCENDING | MULTIPOLYGON Z (((-123.23149 47.51699 0.00000,... |
#gf.explore()
# Ascending test
burstId = '137_IW2_292399'
relorb = int(burstId.split('_')[0])
subswath = burstId.split('_')[1]
idnum = int(burstId.split('_')[2])
ind = (gf.relative_orbit_number == relorb) & (gf.subswath_name == subswath) & (gf.burst_id == idnum)
myburst = gf[ind]
myburst
burst_id | subswath_name | relative_orbit_number | time_from_anx_sec | orbit_pass | geometry | |
---|---|---|---|---|---|---|
4 | 292399 | IW2 | 137 | 774.912738 | ASCENDING | MULTIPOLYGON Z (((-123.23149 47.51699 0.00000,... |
results = asf.geo_search(platform=[asf.PLATFORM.SENTINEL1],
processingLevel=asf.SLC,
beamMode=asf.BEAMMODE.IW,
relativeOrbit=relorb,
intersectsWith=str(myburst.geometry.values[0]),
)
gf = gpd.GeoDataFrame.from_features(results.geojson(), crs=4326)
len(gf)
312
# Get a summer scene from each year
gf = gf.set_index(gpd.pd.to_datetime(gf.startTime))
gf.head(2)
geometry | beamModeType | browse | bytes | centerLat | centerLon | faradayRotation | fileID | flightDirection | groupID | ... | processingDate | processingLevel | sceneName | sensor | startTime | stopTime | url | pgeVersion | fileName | frameNumber | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
startTime | |||||||||||||||||||||
2023-05-25 02:02:36+00:00 | POLYGON ((-124.70564 48.54142, -124.22576 46.9... | IW | None | 4615857449 | 47.9470 | -122.7622 | None | S1A_IW_SLC__1SDV_20230525T020236_20230525T0203... | ASCENDING | S1A_IWDV_0152_0159_048684_137 | ... | 2023-05-25T02:02:36.000Z | SLC | S1A_IW_SLC__1SDV_20230525T020236_20230525T0203... | C-SAR | 2023-05-25T02:02:36.000Z | 2023-05-25T02:03:02.000Z | https://datapool.asf.alaska.edu/SLC/SA/S1A_IW_... | 003.61 | S1A_IW_SLC__1SDV_20230525T020236_20230525T0203... | 153 |
2023-05-13 02:02:35+00:00 | POLYGON ((-124.70805 48.54140, -124.22818 46.9... | IW | None | 4613670822 | 47.9471 | -122.7646 | None | S1A_IW_SLC__1SDV_20230513T020235_20230513T0203... | ASCENDING | S1A_IWDV_0153_0158_048509_137 | ... | 2023-05-13T02:02:35.000Z | SLC | S1A_IW_SLC__1SDV_20230513T020235_20230513T0203... | C-SAR | 2023-05-13T02:02:35.000Z | 2023-05-13T02:03:02.000Z | https://datapool.asf.alaska.edu/SLC/SA/S1A_IW_... | 003.61 | S1A_IW_SLC__1SDV_20230513T020235_20230513T0203... | 153 |
2 rows × 29 columns
# 1st acquisition of every month
#gf.groupby([gf.index.year, gf.index.month]).first()
# 1st acquisition of given month every year
subset = gf[gf.index.month == 5]
subset = subset.groupby(subset.index.year).first()
subset
geometry | beamModeType | browse | bytes | centerLat | centerLon | faradayRotation | fileID | flightDirection | groupID | ... | processingDate | processingLevel | sceneName | sensor | startTime | stopTime | url | pgeVersion | fileName | frameNumber | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
startTime | |||||||||||||||||||||
2015 | POLYGON ((-124.56292 48.10650, -124.08672 46.4... | IW | None | 2505781543 | 47.5056 | -122.6591 | None | S1A_IW_SLC__1SSV_20150531T020141_20150531T0202... | ASCENDING | S1A_IWSV_0152_0157_006159_137 | ... | 2015-05-31T02:01:41.000Z | SLC | S1A_IW_SLC__1SSV_20150531T020141_20150531T0202... | C-SAR | 2015-05-31T02:01:41.000Z | 2015-05-31T02:02:08.000Z | https://datapool.asf.alaska.edu/SLC/SA/S1A_IW_... | 002.72 | S1A_IW_SLC__1SSV_20150531T020141_20150531T0202... | 151 |
2016 | POLYGON ((-124.82479 48.86943, -124.34055 47.2... | IW | None | 2443054559 | 48.2749 | -122.8768 | None | S1A_IW_SLC__1SSV_20160525T020200_20160525T0202... | ASCENDING | S1A_IWSV_0155_0160_011409_137 | ... | 2016-05-25T02:02:00.000Z | SLC | S1A_IW_SLC__1SSV_20160525T020200_20160525T0202... | C-SAR | 2016-05-25T02:02:00.000Z | 2016-05-25T02:02:27.000Z | https://datapool.asf.alaska.edu/SLC/SA/S1A_IW_... | 002.71 | S1A_IW_SLC__1SSV_20160525T020200_20160525T0202... | 154 |
2017 | POLYGON ((-124.70644 48.54178, -124.22670 46.9... | IW | None | 4653823591 | 47.9476 | -122.7629 | None | S1B_IW_SLC__1SDV_20170526T020118_20170526T0201... | ASCENDING | S1B_IWDV_0153_0158_005763_137 | ... | 2017-05-26T02:01:18.000Z | SLC | S1B_IW_SLC__1SDV_20170526T020118_20170526T0201... | C-SAR | 2017-05-26T02:01:18.000Z | 2017-05-26T02:01:44.000Z | https://datapool.asf.alaska.edu/SLC/SB/S1B_IW_... | 002.82 | S1B_IW_SLC__1SDV_20170526T020118_20170526T0201... | 153 |
2018 | POLYGON ((-124.87379 49.03462, -124.38744 47.4... | IW | None | 4586153379 | 48.4414 | -122.9070 | None | S1B_IW_SLC__1SDV_20180521T020132_20180521T0201... | ASCENDING | S1B_IWDV_0154_0160_011013_137 | ... | 2018-05-21T02:01:32.000Z | SLC | S1B_IW_SLC__1SDV_20180521T020132_20180521T0201... | C-SAR | 2018-05-21T02:01:32.000Z | 2018-05-21T02:01:59.000Z | https://datapool.asf.alaska.edu/SLC/SB/S1B_IW_... | 002.90 | S1B_IW_SLC__1SDV_20180521T020132_20180521T0201... | 154 |
2019 | POLYGON ((-124.87373 49.03450, -124.38760 47.4... | IW | None | 4611044652 | 48.4394 | -122.9256 | None | S1B_IW_SLC__1SDV_20190528T020139_20190528T0202... | ASCENDING | S1B_IWDV_0154_0160_016438_137 | ... | 2019-05-28T02:01:39.000Z | SLC | S1B_IW_SLC__1SDV_20190528T020139_20190528T0202... | C-SAR | 2019-05-28T02:01:39.000Z | 2019-05-28T02:02:06.000Z | https://datapool.asf.alaska.edu/SLC/SB/S1B_IW_... | 002.91 | S1B_IW_SLC__1SDV_20190528T020139_20190528T0202... | 154 |
2020 | POLYGON ((-124.85921 49.03609, -124.37350 47.4... | IW | None | 4599535780 | 48.4404 | -122.9141 | None | S1B_IW_SLC__1SDV_20200522T020145_20200522T0202... | ASCENDING | S1B_IWDV_0155_0160_021688_137 | ... | 2020-05-22T02:01:45.000Z | SLC | S1B_IW_SLC__1SDV_20200522T020145_20200522T0202... | C-SAR | 2020-05-22T02:01:45.000Z | 2020-05-22T02:02:12.000Z | https://datapool.asf.alaska.edu/SLC/SB/S1B_IW_... | 003.20 | S1B_IW_SLC__1SDV_20200522T020145_20200522T0202... | 154 |
2021 | POLYGON ((-124.85926 49.03585, -124.37357 47.4... | IW | None | 4389441623 | 48.4402 | -122.9141 | None | S1B_IW_SLC__1SDV_20210529T020151_20210529T0202... | ASCENDING | S1B_IWDV_0154_0160_027113_137 | ... | 2021-05-29T02:01:51.000Z | SLC | S1B_IW_SLC__1SDV_20210529T020151_20210529T0202... | C-SAR | 2021-05-29T02:01:51.000Z | 2021-05-29T02:02:18.000Z | https://datapool.asf.alaska.edu/SLC/SB/S1B_IW_... | 003.31 | S1B_IW_SLC__1SDV_20210529T020151_20210529T0202... | 154 |
2022 | POLYGON ((-124.70712 48.54180, -124.22723 46.9... | IW | None | 4648906192 | 47.9474 | -122.7636 | None | S1A_IW_SLC__1SDV_20220530T020231_20220530T0202... | ASCENDING | S1A_IWDV_0152_0159_043434_137 | ... | 2022-05-30T02:02:31.000Z | SLC | S1A_IW_SLC__1SDV_20220530T020231_20220530T0202... | C-SAR | 2022-05-30T02:02:31.000Z | 2022-05-30T02:02:58.000Z | https://datapool.asf.alaska.edu/SLC/SA/S1A_IW_... | 003.52 | S1A_IW_SLC__1SDV_20220530T020231_20220530T0202... | 153 |
2023 | POLYGON ((-124.70564 48.54142, -124.22576 46.9... | IW | None | 4615857449 | 47.9470 | -122.7622 | None | S1A_IW_SLC__1SDV_20230525T020236_20230525T0203... | ASCENDING | S1A_IWDV_0152_0159_048684_137 | ... | 2023-05-25T02:02:36.000Z | SLC | S1A_IW_SLC__1SDV_20230525T020236_20230525T0203... | C-SAR | 2023-05-25T02:02:36.000Z | 2023-05-25T02:03:02.000Z | https://datapool.asf.alaska.edu/SLC/SA/S1A_IW_... | 003.61 | S1A_IW_SLC__1SDV_20230525T020236_20230525T0203... | 153 |
9 rows × 29 columns
subset.reset_index(drop=True).set_crs(4326).explore(column='startTime', style_kwds=dict(fillOpacity=.3))
# Get IPF version for each of these
def get_ipf(sceneName):
sat = sceneName[0]+sceneName[2]
url = f'https://datapool.asf.alaska.edu/METADATA_SLC/{sat}/{sceneName}.iso.xml'
#print(url)
r = requests.get(url)
IPF = re.search(r'\(version(.*?)\)',r.text).group(1).strip()
return IPF
subset['IPF'] = subset.sceneName.apply(get_ipf)
subset.IPF
startTime 2015 002.72 2016 002.71 2017 002.82 2018 002.90 2019 002.91 2020 003.20 2021 003.31 2022 003.52 2023 003.61 Name: IPF, dtype: object
# Only IPF>=3.4 has burstnumbers in the metadata, others require reverse-lookup based on TANX
def get_metadata_xml(session, params, outfile=None):
root = hb.download_metadata(session, params, outfile)
return root
def get_ipf(root):
''' for consolidated XML metadata get version '''
ipfnode = root.find('.//safe:software', {'safe':'http://www.esa.int/safe/sentinel-1.0'})
return ipfnode.attrib['version']
def get_burstnumber(session, row, myburst, product_schema='./support/s1-level-1-product.xsd'):
''' given an ASF frame, determine relative burst number corresponding to standard esa burstid
session = asf session from hyp3-isce2
row = geodataframe row of asf_search results
myburst = geoseries for burst of interest
Note: requires support/s1-level-1-product.xsd XML schema from SLC SAFE for parsing metadata
'''
params = hb.BurstParams(row.sceneName, myburst.subswath_name, row.polarization[:2], 1)
# Get All XML metadata for SLC
root = get_metadata_xml(session, params)
IPF = get_ipf(root)
# Extract correct section of xml
for product in root.findall('.//product'):
prod_pol = product.find('polarisation').text
prod_swath = product.find('swath').text
if (prod_pol == params.polarization) and (prod_swath == params.swath):
node = product.find('content')
node.tag = 'product'
string = lxml.etree.tostring(node, encoding='unicode')
# Convert to python dictionary
xs = xmlschema.XMLSchema(product_schema)
parsed = xs.to_dict(string, validation='lax')[0]
if IPF >= '003.4':
burstid = [t.get('burstId').get('$') for t in parsed['swathTiming']['burstList']['burst']]
burstnum = burstid.index(myburst.burst_id)
else:
tanx = np.array([t['azimuthAnxTime'] for t in parsed['swathTiming']['burstList']['burst']])
burstnum = np.argmin(np.abs(tanx - myburst.time_from_anx_sec))
return burstnum
myburst # '137_IW2_292399'
burst_id | subswath_name | relative_orbit_number | time_from_anx_sec | orbit_pass | geometry | |
---|---|---|---|---|---|---|
4 | 292399 | IW2 | 137 | 774.912738 | ASCENDING | MULTIPOLYGON Z (((-123.23149 47.51699 0.00000,... |
asf_session = hb.get_asf_session()
# For small number of granules just iterate over pandas dataframe (slow but works)
Bursts = []
for i,row in subset.iterrows():
num = get_burstnumber(asf_session, row, myburst.iloc[0])
Bursts.append(num)
subset['burst'] = Bursts
subset['date'] = gpd.pd.to_datetime(subset.startTime).dt.strftime('%Y%m%d')
with gpd.pd.option_context('display.max_colwidth', None):
display(subset.loc[:,['date','sceneName','IPF','burst']])
date | sceneName | IPF | burst | |
---|---|---|---|---|
startTime | ||||
2015 | 20150531 | S1A_IW_SLC__1SSV_20150531T020141_20150531T020208_006159_008023_7F5E | 002.72 | 5 |
2016 | 20160525 | S1A_IW_SLC__1SSV_20160525T020200_20160525T020227_011409_01159A_9CE4 | 002.71 | 0 |
2017 | 20170526 | S1B_IW_SLC__1SDV_20170526T020118_20170526T020144_005763_00A197_3444 | 002.82 | 2 |
2018 | 20180521 | S1B_IW_SLC__1SDV_20180521T020132_20180521T020159_011013_0142CF_7C0D | 002.90 | 0 |
2019 | 20190528 | S1B_IW_SLC__1SDV_20190528T020139_20190528T020206_016438_01EF17_B76F | 002.91 | 0 |
2020 | 20200522 | S1B_IW_SLC__1SDV_20200522T020145_20200522T020212_021688_0292AF_50CF | 003.20 | 0 |
2021 | 20210529 | S1B_IW_SLC__1SDV_20210529T020151_20210529T020218_027113_033D24_B0C0 | 003.31 | 0 |
2022 | 20220530 | S1A_IW_SLC__1SDV_20220530T020231_20220530T020258_043434_052FB9_BD0A | 003.52 | 2 |
2023 | 20230525 | S1A_IW_SLC__1SDV_20230525T020236_20230525T020302_048684_05DAF3_C204 | 003.61 | 2 |
os.mkdir('ascending')
for i in range(len(subset)-1):
ref = subset.iloc[i]
sec = subset.iloc[i+1]
os.mkdir(f'ascending/{ref.date}_{sec.date}')
cmd = f'''python -m hyp3_isce2 ++process insar_tops_burst --reference-scene {ref.sceneName} --secondary-scene {sec.sceneName} \
--swath-number 2 --polarization VV --reference-burst-number {ref.burst} --secondary-burst-number {sec.burst} --azimuth-looks 4 --range-looks 20\n'''
with open(f'ascending/{ref.date}_{sec.date}/cmd.txt', 'w') as f:
f.write(cmd)