Test the data transformation application for WFP-01-01-02¶
This Jupyter Notebook to query the catalog for a set of Sentinel-1 SLC products (one slave product and its related master files), creates a Web Processing Service (WPS) request invoking the data transformation application that was deployed in the Deploy step, monitors the WPS request execution and finally retrieves the data transformation execution results
- First do the imports of the Python libraries required
In [1]:
import os
import owslib
from owslib.wps import monitorExecution
from owslib.wps import WebProcessingService
import lxml.etree as etree
import cioppy
import numpy as np
from shapely.wkt import loads
import getpass
ciop = cioppy.Cioppy()
from datetime import datetime, timedelta
import dateutil.parser
import folium
import nbformat as nbf
In [2]:
%store -r
nb_config = os.path.join('../operations', 'configuration.ipynb')
nb = nbf.read(nb_config, 4)
exec(nb['cells'][1]['source']) in globals(), locals()
app = dict([('artifact_id', app_artifact_id),
('version', app_version),
('repository', repository),
('community', community)])
app_process_id = '%s_%s_%s_%s' % (app['community'].replace('-', '_'),
app['artifact_id'].replace('-', '_'),
app['artifact_id'].replace('-', '_'),
app['version'].replace('.', '_'))
In [3]:
app_process_id
Out[3]:
'ec_better_ewf_wfp_01_01_02_ewf_wfp_01_01_02_0_18'
- Define the search parameters: the catalog series OpenSearch endpoint, the time of interest and the area of interest
In [4]:
series = 'https://catalog.terradue.com/sentinel1/search'
start_date = '2018-08-08T04:47:30'
stop_date = '2018-08-08T04:47:32'
geom = 'MULTIPOLYGON (((26.832 9.5136, 28.6843 9.5136, 28.6843 7.8009, 26.832 7.8009, 26.832 9.5136)), ((21.29611111111111 39.58638888888889, 21.29611111111111 41.032, 19.89788888888889 41.032, 19.89788888888889 39.58638888888889, 21.29611111111111 39.58638888888889)), ((-5.5 17.26, -1.08 17.26, -1.08 13.5, -5.5 13.5, -5.5 17.26)), ((67.7116 37.9032, 68.791 37.9032, 68.791 36.9211, 67.7116 36.9211, 67.7116 37.9032)))'
- Search for Sentinel-1 GRD products in one of the polygons of the area of interest
In [5]:
wkt = loads(geom)[1]
AoI=wkt.wkt
In [6]:
AoI
Out[6]:
'POLYGON ((21.29611111111111 39.58638888888889, 21.29611111111111 41.032, 19.89788888888889 41.032, 19.89788888888889 39.58638888888889, 21.29611111111111 39.58638888888889))'
In [7]:
aoi=np.asarray([t[::-1] for t in list(wkt.exterior.coords)]).tolist()
In [8]:
search_params = dict([('geom', AoI),
('start', start_date),
('stop', stop_date),
('pt', 'SLC'),
('psn','S1A')
])
slave = ciop.search(end_point = series,
params = search_params,
output_fields='self,enclosure,identifier,wkt,track,startdate,platform',
model='EOP')
In [9]:
discovery_locations = []
for index, elem in enumerate(slave):
discovery_locations.append([t[::-1] for t in list(loads(elem['wkt']).exterior.coords)])
print(index, elem['identifier'] + ' ' + elem['track'] + ' ' + elem['startdate'])
(0, 'S1A_IW_SLC__1SDV_20180808T044730_20180808T044757_023150_0283C3_27C9 153 2018-08-08T04:47:30.6081240Z')
(1, 'S1A_IW_SLC__1SDV_20180808T044704_20180808T044732_023150_0283C3_4936 153 2018-08-08T04:47:04.9239470Z')
- Plot the result products for the selected AoI
In [10]:
lat = (loads(AoI).bounds[3]+loads(AoI).bounds[1])/2
lon = (loads(AoI).bounds[2]+loads(AoI).bounds[0])/2
zoom_start = 4
m = folium.Map(location=[lat, lon], zoom_start=zoom_start)
radius = 4
folium.CircleMarker(
location=[lat, lon],
radius=radius,
color='#FF0000',
stroke=False,
fill=True,
fill_opacity=0.9,
opacity=1,
popup='{} pixels'.format(radius),
tooltip='I am in pixels, centre of AoI',
).add_to(m)
folium.PolyLine(
locations=aoi,
color='green',
weight=1,
opacity=1,
smooth_factor=0,
).add_to(m)
folium.PolyLine(
locations=discovery_locations,
color='orange',
weight=1,
opacity=1,
smooth_factor=0,
).add_to(m)
m.save(os.path.join('results', 'wfp-01-01-02-search.html'))
m
Out[10]:
- Setting parameters for master search
In [11]:
s1_index = 0
In [12]:
if slave[s1_index]['platform']=='S1B':
master_platform='S1A'
else:
master_platform='S1B'
In [13]:
master_platform
Out[13]:
'S1B'
Master search¶
Hint.In order to get the correct master products from Sentinel-1B occured 6days prior to the slave’s start date, deltaTime should include the whole day-length of the 6-th day
In [14]:
start_date = (dateutil.parser.parse(slave[s1_index]['startdate']) + timedelta(days=-7)).isoformat()
stop_date = (dateutil.parser.parse(slave[s1_index]['startdate']) + timedelta(days=-1)).isoformat()
master_search_params = dict([('geom', slave[s1_index]['wkt']),
('start', start_date),
('stop', stop_date),
('pt', 'SLC'),
('psn', master_platform),
('track', slave[s1_index]['track']),
])
In [15]:
master_search = ciop.search(end_point = series,
params = master_search_params,
output_fields='self,enclosure,identifier,wkt,track,startdate',
model='EOP')
In [16]:
for index, elem in enumerate(master_search):
print(index, elem['identifier'] + ' ' + elem['track'])
(0, 'S1B_IW_SLC__1SDV_20180802T044713_20180802T044740_012079_0163DC_C7E9 153')
(1, 'S1B_IW_SLC__1SDV_20180802T044648_20180802T044715_012079_0163DC_7EFB 153')
(2, 'S1B_IW_SLC__1SDV_20180802T044622_20180802T044650_012079_0163DC_68BB 153')
In [17]:
master_search
Out[17]:
[{'enclosure': 'https://store.terradue.com/download/sentinel1/files/v1/S1B_IW_SLC__1SDV_20180802T044713_20180802T044740_012079_0163DC_C7E9',
'identifier': 'S1B_IW_SLC__1SDV_20180802T044713_20180802T044740_012079_0163DC_C7E9',
'self': 'https://catalog.terradue.com/sentinel1/search?format=atom&uid=S1B_IW_SLC__1SDV_20180802T044713_20180802T044740_012079_0163DC_C7E9',
'startdate': '2018-08-02T04:47:13.3040910Z',
'track': '153',
'wkt': 'POLYGON((20.286062 37.690067,17.40239 38.091949,17.737614 39.720036,20.690239 39.319366,20.286062 37.690067))'},
{'enclosure': 'https://store.terradue.com/download/sentinel1/files/v1/S1B_IW_SLC__1SDV_20180802T044648_20180802T044715_012079_0163DC_7EFB',
'identifier': 'S1B_IW_SLC__1SDV_20180802T044648_20180802T044715_012079_0163DC_7EFB',
'self': 'https://catalog.terradue.com/sentinel1/search?format=atom&uid=S1B_IW_SLC__1SDV_20180802T044648_20180802T044715_012079_0163DC_7EFB',
'startdate': '2018-08-02T04:46:48.4873600Z',
'track': '153',
'wkt': 'POLYGON((20.640738 39.184887,17.700554 39.58445,18.039661 41.21101,21.053816 40.81237,20.640738 39.184887))'},
{'enclosure': 'https://store.terradue.com/download/sentinel1/files/v1/S1B_IW_SLC__1SDV_20180802T044622_20180802T044650_012079_0163DC_68BB',
'identifier': 'S1B_IW_SLC__1SDV_20180802T044622_20180802T044650_012079_0163DC_68BB',
'self': 'https://catalog.terradue.com/sentinel1/search?format=atom&uid=S1B_IW_SLC__1SDV_20180802T044622_20180802T044650_012079_0163DC_68BB',
'startdate': '2018-08-02T04:46:22.8114060Z',
'track': '153',
'wkt': 'POLYGON((21.012932 40.676811,18.007711 41.075058,18.362541 42.752243,21.449932 42.35461,21.012932 40.676811))'}]
In [18]:
result = []
for index, elem in enumerate(master_search):
master_wkt = loads(elem['wkt'])
slave_WKT_coverage=int((master_wkt.intersection(loads(slave[s1_index]['wkt']))).area /loads(slave[s1_index]['wkt']).area * 100)
AoI_WKT_coverage=(master_wkt.intersection(loads(AoI))).area /loads(AoI).area * 100
if (slave_WKT_coverage >= 10)and (AoI_WKT_coverage ):
result.append({'self' : elem['self'],
'identifier' : elem['identifier'],
'enclosure' : elem['enclosure'],
'wkt': elem['wkt'],
'slave_intersect' : slave_WKT_coverage,
'AOI_intersect' :AoI_WKT_coverage,
'days_back': (dateutil.parser.parse(slave[s1_index]['startdate']) -
dateutil.parser.parse(elem['startdate'])).days
})
In [19]:
result
Out[19]:
[{'AOI_intersect': 65.04562640157037,
'days_back': 6,
'enclosure': 'https://store.terradue.com/download/sentinel1/files/v1/S1B_IW_SLC__1SDV_20180802T044648_20180802T044715_012079_0163DC_7EFB',
'identifier': 'S1B_IW_SLC__1SDV_20180802T044648_20180802T044715_012079_0163DC_7EFB',
'self': 'https://catalog.terradue.com/sentinel1/search?format=atom&uid=S1B_IW_SLC__1SDV_20180802T044648_20180802T044715_012079_0163DC_7EFB',
'slave_intersect': 99,
'wkt': 'POLYGON((20.640738 39.184887,17.700554 39.58445,18.039661 41.21101,21.053816 40.81237,20.640738 39.184887))'}]
In [20]:
import geopandas as gp
masters = gp.GeoDataFrame(result)
In [21]:
masters
Out[21]:
AOI_intersect | days_back | enclosure | identifier | self | slave_intersect | wkt | |
---|---|---|---|---|---|---|---|
0 | 65.045626 | 6 | https://store.terradue.com/download/sentinel1/... | S1B_IW_SLC__1SDV_20180802T044648_20180802T0447... | https://catalog.terradue.com/sentinel1/search?... | 99 | POLYGON((20.640738 39.184887,17.700554 39.5844... |
In [22]:
locations_master = []
for index, elem in enumerate(result):
locations_master.append([t[::-1] for t in list(loads(elem['wkt']).exterior.coords)])
locations_slave=[t[::-1] for t in list(loads(slave[s1_index]['wkt']).exterior.coords)]
In [23]:
lat = (loads(AoI).bounds[3]+loads(AoI).bounds[1])/2
lon = (loads(AoI).bounds[2]+loads(AoI).bounds[0])/2
zoom_start = 4
m = folium.Map(location=[lat, lon], zoom_start=zoom_start)
radius = 4
folium.CircleMarker(
location=[lat, lon],
radius=radius,
color='#FF0000',
stroke=False,
fill=True,
fill_opacity=0.9,
opacity=1,
popup='{} pixels'.format(radius),
tooltip='I am in pixels, centre of AoI',
).add_to(m)
folium.PolyLine(
locations=locations_master,
color='orange',
weight=1,
opacity=1,
smooth_factor=0,
).add_to(m)
folium.PolyLine(
locations=locations_slave,
color='blue',
weight=1,
opacity=1,
smooth_factor=0,
).add_to(m)
folium.PolyLine(
locations=aoi,
color='green',
weight=1,
opacity=1,
smooth_factor=0,
).add_to(m)
m.save(os.path.join('results', 'wfp-01-01-02-search.html'))
m
Out[23]:
In [24]:
item_list=[]
for index, elem in enumerate(result):
item_list.append(elem['self'])
item_list.append(slave[s1_index]['self'])
In [25]:
item_list
Out[25]:
['https://catalog.terradue.com/sentinel1/search?format=atom&uid=S1B_IW_SLC__1SDV_20180802T044648_20180802T044715_012079_0163DC_7EFB',
'https://catalog.terradue.com/sentinel1/search?format=atom&uid=S1A_IW_SLC__1SDV_20180808T044730_20180808T044757_023150_0283C3_27C9']
In [26]:
sourceX=','.join(item_list)
- Connect to the WPS server
In [27]:
wps_url = 'https://ec-better-apps-deployer.terradue.com/zoo-bin/zoo_loader.cgi'
wps = WebProcessingService(wps_url,
verbose=False,
skip_caps=True)
- Do a GetCapabilities WPS request and list the process:
In [28]:
wps.getcapabilities()
In [29]:
app_deployed = False
for index, elem in enumerate(wps.processes):
if elem.identifier == app_process_id:
app_deployed = True
if app_deployed:
print 'Process %s deployed' % app_process_id
else:
raise Exception('Process %s not deployed' % app_process_id)
Process ec_better_ewf_wfp_01_01_02_ewf_wfp_01_01_02_0_18 deployed
- Select the process and print the title and abstract after having submited a WPS DescribeProcess request
In [30]:
process = wps.describeprocess(app_process_id)
print process.title
print process.abstract
WFP-01-01-02 Sentinel-1 coherence
WFP-01-01-02 Sentinel-1 coherence
- List the WPS process inputs:
In [31]:
for data_input in process.dataInputs:
print data_input.identifier
source
swaths
cohWinRg
cohWinAz
polarisation
_T2Username
- Create a Python dictionary with the inputs:
In [32]:
inputs = [('source', sourceX),
('swaths','IW1,IW2,IW3'),
('cohWinRg', '20'),
('cohWinAz', '5'),
('polarisation', 'VV'),
('_T2Username', 'better-wfp-00002')]
- Submit the Execute WPS request:
In [33]:
execution = owslib.wps.WPSExecution(url=wps.url)
execution_request = execution.buildRequest(app_process_id,
inputs,
output=[('result_osd', False)])
execution_response = execution.submitRequest(etree.tostring(execution_request))
execution.parseResponse(execution_response)
- Monitor the request:
In [34]:
execution.statusLocation
Out[34]:
'http://ec-better-apps-deployer.terradue.com/zoo-bin/zoo_loader.cgi?request=Execute&service=WPS&version=1.0.0&Identifier=GetStatus&DataInputs=sid=4179a19e-344f-11e9-a37a-0242ac11000f&RawDataOutput=Result'
In [ ]:
monitorExecution(execution)
In [ ]:
execution.isSucceded()
- Check the outcome of the processing request
In [ ]:
execution.isSucceded()
- Search for the results produced
In [ ]:
for output in execution.processOutputs:
print(output.identifier)
In [ ]:
results_osd = execution.processOutputs[0].reference
In [ ]:
results_osd
In [ ]:
recast_process_id = 'dataPublication'
recast_wps_url = 'https://recast.terradue.com/t2api/ows'
wps = WebProcessingService(recast_wps_url,
verbose=False,
skip_caps=False)
recast_inputs = [('items', results_osd),
('index', data_pipeline),
('_T2ApiKey', api_key),
('_T2Username', data_pipeline)]
recast_execution = wps.execute(recast_process_id,
recast_inputs,
output = [('result_osd', True)])
monitorExecution(recast_execution, sleepSecs=60)
etree.fromstring(recast_execution.processOutputs[0].data[0]).xpath('./@href')[0]