Executing EO4Atlantic Services

EO4Atlantic services may be executed locally outside of the platform. This is currently achieved by means of Jupyter notebooks, which leverage eo4a.development module functions provided by the service framework, and is the recommended method for local service development prior to deployment in the platform.

This notebook demonstrates how to execute the example services provided in the EO4Atlantic service development repository, and may be used as a starting point for executing other (new) services.


In [1]:
# Required imports from service development module.
from eo4a.development import create_wps, describe_service, list_services, monitor_execution, reload_services

As described in the user guide, each EO4Atlantic service is hosted as an OGC Web Processing Service (WPS). When creating the development service container, any WPS definitions found in $EO4A_SERVICES_DIR will be made available. The following demonstrates how to list the available services.


In [2]:
wps = create_wps() # This reference is instantiated first, and used in most subsequent calls.
reload_services(wps) # This can be used to reload services when local code changes are made.
list_services(wps)


Processes reloaded successfully:
	merge_shapefiles
	sentinel2-rgb
	gdalinfo
	gdalwarp

Errors:


########## Services: ###########

Merge Shapefiles (id: merge_shapefiles)
----------------------------------------
Merge multiple shapefiles into a single file.


Sentinel-2 RGB (id: sentinel2-rgb)
----------------------------------------
Example service that generates composite RGB rasters from Sentinel-2 products, using bands 4, 3, and 2 respectively by default.
However, alternative bands may also be used, such as the false color (R=8, G=4, B=3).


gdalinfo (id: gdalinfo)
----------------------------------------
Lists information about a raster dataset. See <a href="http://gdal.org/gdalinfo.html" target="_blank">gdalinfo manual</a>.


gdalwarp (id: gdalwarp)
----------------------------------------
Image reprojection and warping utility. See <a href="http://gdal.org/gdalwarp.html" target="_blank">gdalwarp manual</a>.


Full details of individual services, including their WPS input and output parameters, can be achieved as follows (the details are loaded from the corresponding wps.py module), using the id value returned by list_services():


In [3]:
describe_service('sentinel2-rgb', wps)


Sentinel-2 RGB (id: sentinel2-rgb)
----------------------------------------
Example service that generates composite RGB rasters from Sentinel-2 products, using bands 4, 3, and 2 respectively by default.
However, alternative bands may also be used, such as the false color (R=8, G=4, B=3).


---- Inputs ----
 identifier=s2_product_dir, title=Sentinel-2 product directory, abstract=Contains one or more Sentinel-2 products., data type=string
 Any value allowed
 Default Value: None 
 minOccurs=1, maxOccurs=1


 identifier=r_band, title=R band, abstract=R band number (default=4).,, data type=integer
 Any value allowed
 Default Value: 4 
 minOccurs=0, maxOccurs=1


 identifier=g_band, title=G band, abstract=G band number (default=3).,, data type=integer
 Any value allowed
 Default Value: 3 
 minOccurs=0, maxOccurs=1


 identifier=b_band, title=B band, abstract=B band number (default=2).,, data type=integer
 Any value allowed
 Default Value: 2 
 minOccurs=0, maxOccurs=1


 identifier=resolution, title=Sentinel-2 product resolution (default=60), abstract=The default resolution of 60m is used for level 2 products generated by <a href="http://step.esa.int/main/third-party-plugins-2/sen2cor/" target="_blank">Sen2Cor</a>, as this generates raster layers of manageable size for the pathfinder., data type=integer
 Any value allowed
 Default Value: 60 
 minOccurs=0, maxOccurs=1


---- Outputs ----
 identifier=rgb_dir, title=RGB rasters directory, abstract=Directory containing RGB rasters., data type=string
 Default Value: None 
 reference=None, mimeType=None

Synchronous service execution

Services are typically executed as follows:

  1. Prepare a list of WPS inputs (identifier, value) tuples, using the identifiers found in the describe_service() output (taken from the corresponding wps.py definition).
  2. Execute the process with the inputs.
  3. Parse the process WPS outputs.

Example 1

The first example uses the gdalinfo service to retrieve information about a test raster. First, get the list of service inputs:


In [4]:
describe_service('gdalinfo', wps)


gdalinfo (id: gdalinfo)
----------------------------------------
Lists information about a raster dataset. See <a href="http://gdal.org/gdalinfo.html" target="_blank">gdalinfo manual</a>.


---- Inputs ----
 identifier=datasetname, title=Input dataset path, abstract=Full path to input dataset., data type=string
 Any value allowed
 Default Value: None 
 minOccurs=1, maxOccurs=1


 identifier=json, title=Display the output in json format, abstract=Display the output in json format., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=mm, title=Min/max values, abstract=Force computation of the actual min/max values for each band in the dataset., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=stats, title=Image statistics, abstract=Read and display image statistics. Force computation if no statistics are stored in an image., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=approx_stats, title=Image statistics, abstract=Read and display image statistics. 
                Force computation if no statistics are stored in an image. 
                However, they may be computed based on overviews or a subset of all tiles. 
                Useful if you are in a hurry and don't want precise stats., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=hist, title=Histograms, abstract=Report histogram information for all bands., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=nogcp, title=No ground control points, abstract=Suppress ground control points list printing. 
                It may be useful for datasets with huge amount of GCPs, such as L1B AVHRR or HDF4 MODIS which contain thousands of them., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=nomd, title=Suppress metadata printing, abstract=Suppress metadata printing. Some datasets may contain a lot of metadata strings., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=norat, title=Suppress printing of raster attribute table., abstract=Suppress printing of raster attribute table., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=noct, title=Suppress printing of color table, abstract=Suppress printing of color table., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=checksum, title=Band checksums, abstract=Force computation of the checksum for each band in the dataset., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=listmdd, title=List all metadata domains available for the dataset, abstract=List all metadata domains available for the dataset., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=mdd, title=Report metadata for the specified domain, abstract=Report metadata for the specified domain. Starting with GDAL 1.11, "all" can be used to report metadata in all domains., data type=string
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=nofl, title=Only display the first file of the file list, abstract=Only display the first file of the file list., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=sd, title=Subdatasets, abstract=If the input dataset contains several subdatasets read and display a subdataset with specified number (starting from 1). 
                This is an alternative of giving the full subdataset name., data type=string
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=proj4, title=Report a PROJ.4 string corresponding to the file's coordinate system, abstract=Report a PROJ.4 string corresponding to the file's coordinate system., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=oo, title=Dataset open option (format specific), abstract=Dataset open option (format specific)., data type=string
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


---- Outputs ----
 identifier=output, title=gdalinfo output, abstract=Will contain any output generated by gdalinfo., data type=string
 Default Value: None 
 reference=None, mimeType=None

Next, prepare the required inputs, execute the service, and parse the outputs.


In [5]:
inputs = [
    ('datasetname', '/opt/eo4a/services/gdaltools/tests/data/raster_1k_1k.tif'),
    ('json', 'false'),
    ('mm', 'true'),
    ('stats', 'true'),
    ('approx_stats', 'true'),
    ('hist', 'true'),
    ('nogcp', 'true'),
    ('nomd', 'false'),
    ('norat', 'true'),
    ('noct', 'true'),
    ('checksum', 'true'),
    ('listmdd', 'true'),
    ('mdd', 'all'),
    ('nofl', 'true'),
    ('proj4', 'true'),
]
# Synchronous execution
execution = wps.execute('gdalinfo', inputs)

# Check the description for the outputs provided by the service
# Only one output for this service
print('gdalinfo output:')
output = execution.processOutputs[0]
print('%s: %s' % (output.identifier, output.data[0]))


gdalinfo output:
output: Driver: GTiff/GeoTIFF
Files: /opt/eo4a/services/gdaltools/tests/data/raster_1k_1k.tif
Size is 110, 110
Coordinate System is:
PROJCS["WGS 84 / UTM zone 29N",
    GEOGCS["WGS 84",
        DATUM["WGS_1984",
            SPHEROID["WGS 84",6378137,298.257223563,
                AUTHORITY["EPSG","7030"]],
            AUTHORITY["EPSG","6326"]],
        PRIMEM["Greenwich",0,
            AUTHORITY["EPSG","8901"]],
        UNIT["degree",0.0174532925199433,
            AUTHORITY["EPSG","9122"]],
        AUTHORITY["EPSG","4326"]],
    PROJECTION["Transverse_Mercator"],
    PARAMETER["latitude_of_origin",0],
    PARAMETER["central_meridian",-9],
    PARAMETER["scale_factor",0.9996],
    PARAMETER["false_easting",500000],
    PARAMETER["false_northing",0],
    UNIT["metre",1,
        AUTHORITY["EPSG","9001"]],
    AXIS["Easting",EAST],
    AXIS["Northing",NORTH],
    AUTHORITY["EPSG","32629"]]
PROJ.4 string is:
'+proj=utm +zone=29 +datum=WGS84 +units=m +no_defs '
Origin = (600000.000000000000000,6000000.000000000000000)
Pixel Size = (1000.000000000000000,-1000.000000000000000)
Metadata domains:
  IMAGE_STRUCTURE
  (default)
  DERIVED_SUBDATASETS
Metadata:
  AREA_OR_POINT=Area
Metadata (DERIVED_SUBDATASETS):
  DERIVED_SUBDATASET_1_NAME=DERIVED_SUBDATASET:LOGAMPLITUDE:/opt/eo4a/services/gdaltools/tests/data/raster_1k_1k.tif
  DERIVED_SUBDATASET_1_DESC=log10 of amplitude of input bands from /opt/eo4a/services/gdaltools/tests/data/raster_1k_1k.tif
Image Structure Metadata:
  COMPRESSION=LZW
  INTERLEAVE=BAND
Corner Coordinates:
Upper Left  (  600000.000, 6000000.000) (  7d28' 9.48"W, 54d 8'18.14"N)
Lower Left  (  600000.000, 5890000.000) (  7d30'16.86"W, 53d 8'59.96"N)
Upper Right (  710000.000, 6000000.000) (  5d47'15.67"W, 54d 6'18.80"N)
Lower Right (  710000.000, 5890000.000) (  5d51'42.58"W, 53d 7' 4.82"N)
Center      (  655000.000, 5945000.000) (  6d39'21.14"W, 53d37'50.90"N)
Band 1 Block=110x37 Type=UInt16, ColorInterp=Gray
    Computed Min/Max=0.000,10987.000
  Minimum=0.000, Maximum=10987.000, Mean=2418.122, StdDev=1998.462
0...10...20...30...40...50...60...70...80...90...100 - done.
  256 buckets from -21.5431 to 11008.5:
  2512 647 591 109 25 27 14 13 13 19 12 14 14 15 12 12 16 19 15 21 20 23 19 14 15 16 27 33 24 16 31 24 16 32 35 39 43 40 36 58 49 46 46 40 52 56 56 62 66 72 65 61 62 67 53 75 71 70 74 62 54 82 70 78 86 66 79 65 76 93 76 85 60 87 88 88 88 93 88 108 95 99 100 103 83 97 101 122 94 103 103 107 105 107 126 127 126 117 103 110 116 111 110 89 101 102 79 95 86 93 76 60 74 85 80 73 64 71 52 55 54 39 46 45 45 42 27 34 31 32 36 22 15 14 16 13 10 15 11 10 13 11 17 7 6 9 10 5 8 9 4 4 7 4 9 3 2 1 8 5 7 2 2 5 2 5 2 4 0 1 4 2 2 3 3 5 2 3 4 5 3 0 2 0 1 1 2 1 1 7 1 1 1 1 2 0 0 2 0 4 2 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 
  Checksum=50508
  Metadata domains:
    (default)
  Metadata:
    STATISTICS_MAXIMUM=10987
    STATISTICS_MEAN=2418.1220661157
    STATISTICS_MINIMUM=0
    STATISTICS_STDDEV=1998.4623021091

Example 2

The second example uses the gdalwarp service to modify the resolution of a test raster. As before, get the list of service inputs (Note - only a selection of the possible gdalwarp tool parameters are currently available):


In [6]:
describe_service('gdalwarp', wps)


gdalwarp (id: gdalwarp)
----------------------------------------
Image reprojection and warping utility. See <a href="http://gdal.org/gdalwarp.html" target="_blank">gdalwarp manual</a>.


---- Inputs ----
 identifier=srcfile, title=Source file name, abstract=Full path to source file name., data type=string
 Any value allowed
 Default Value: None 
 minOccurs=1, maxOccurs=1


 identifier=dstfile, title=Destination file name, abstract=Full path to destination file name., data type=string
 Any value allowed
 Default Value: None 
 minOccurs=1, maxOccurs=1


 identifier=tr, title=Output file resolution, abstract=Set output file resolution (in target georeferenced units). 
                -tr xres yres, data type=string
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=co, title="NAME=VALUE", abstract=Passes a creation option to the output format driver. 
                Multiple -co options may be listed. 
                See format specific documentation for legal creation options for each format at http://gdal.org/formats_list.html, data type=string
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


 identifier=overwrite, title=Overwrite the target dataset if it already exists, abstract=Overwrite the target dataset if it already exists., data type=boolean
 Any value allowed
 Default Value: None 
 minOccurs=0, maxOccurs=1


---- Outputs ----
 identifier=dstfile, title=Destination file name, abstract=Full path to destination file name, generated by gdalwarp., data type=string
 Default Value: None 
 reference=None, mimeType=None

Again, prepare the required inputs, execute the service, and parse the outputs.


In [7]:
inputs = [
    ('srcfile', '/opt/eo4a/services/gdaltools/tests/data/raster_1k_1k.tif'),
    ('dstfile', '/tmp/raster_2k_2k.tif'),
    ('tr', '2000 2000'),
    ('co', 'COMPRESS=LZW'),    
    ('overwrite', 'true'),
]
# Synchronous execution
execution = wps.execute('gdalwarp', inputs)

# Check the description for the outputs provided by the service
# Only one output for this service
print('gdalwarp output:')
output = execution.processOutputs[0]
output_raster = output.data[0]
print('%s: %s' % (output.identifier, output_raster))


gdalwarp output:
dstfile: /tmp/raster_2k_2k.tif

The resolution of this file can be checked with the gdalinfo service (check the Pixel Size values in the output):


In [8]:
inputs = [
    ('datasetname', output_raster),
    ('json', 'false'),
    ('mm', 'true'),
    ('stats', 'true'),
    ('approx_stats', 'true'),
    ('hist', 'true'),
    ('nogcp', 'true'),
    ('nomd', 'false'),
    ('norat', 'true'),
    ('noct', 'true'),
    ('checksum', 'true'),
    ('listmdd', 'true'),
    ('mdd', 'all'),
    ('nofl', 'true'),
    ('proj4', 'true'),
]
# Synchronous execution
execution = wps.execute('gdalinfo', inputs)

# Check the description for the outputs provided by the service
# Only one output for this service
print('gdalinfo output:')
output = execution.processOutputs[0]
print('%s: %s' % (output.identifier, output.data[0]))


gdalinfo output:
output: Driver: GTiff/GeoTIFF
Files: /tmp/raster_2k_2k.tif
Size is 55, 55
Coordinate System is:
PROJCS["WGS 84 / UTM zone 29N",
    GEOGCS["WGS 84",
        DATUM["WGS_1984",
            SPHEROID["WGS 84",6378137,298.257223563,
                AUTHORITY["EPSG","7030"]],
            AUTHORITY["EPSG","6326"]],
        PRIMEM["Greenwich",0,
            AUTHORITY["EPSG","8901"]],
        UNIT["degree",0.0174532925199433,
            AUTHORITY["EPSG","9122"]],
        AUTHORITY["EPSG","4326"]],
    PROJECTION["Transverse_Mercator"],
    PARAMETER["latitude_of_origin",0],
    PARAMETER["central_meridian",-9],
    PARAMETER["scale_factor",0.9996],
    PARAMETER["false_easting",500000],
    PARAMETER["false_northing",0],
    UNIT["metre",1,
        AUTHORITY["EPSG","9001"]],
    AXIS["Easting",EAST],
    AXIS["Northing",NORTH],
    AUTHORITY["EPSG","32629"]]
PROJ.4 string is:
'+proj=utm +zone=29 +datum=WGS84 +units=m +no_defs '
Origin = (600000.000000000000000,6000000.000000000000000)
Pixel Size = (2000.000000000000000,-2000.000000000000000)
Metadata domains:
  IMAGE_STRUCTURE
  (default)
  DERIVED_SUBDATASETS
Metadata:
  AREA_OR_POINT=Area
Metadata (DERIVED_SUBDATASETS):
  DERIVED_SUBDATASET_1_NAME=DERIVED_SUBDATASET:LOGAMPLITUDE:/tmp/raster_2k_2k.tif
  DERIVED_SUBDATASET_1_DESC=log10 of amplitude of input bands from /tmp/raster_2k_2k.tif
Image Structure Metadata:
  COMPRESSION=LZW
  INTERLEAVE=BAND
Corner Coordinates:
Upper Left  (  600000.000, 6000000.000) (  7d28' 9.48"W, 54d 8'18.14"N)
Lower Left  (  600000.000, 5890000.000) (  7d30'16.86"W, 53d 8'59.96"N)
Upper Right (  710000.000, 6000000.000) (  5d47'15.67"W, 54d 6'18.80"N)
Lower Right (  710000.000, 5890000.000) (  5d51'42.58"W, 53d 7' 4.82"N)
Center      (  655000.000, 5945000.000) (  6d39'21.14"W, 53d37'50.90"N)
Band 1 Block=55x55 Type=UInt16, ColorInterp=Gray
    Computed Min/Max=0.000,10987.000
  Minimum=0.000, Maximum=10987.000, Mean=2454.940, StdDev=2027.746
0...10...20...30...40...50...60...70...80...90...100 - done.
  256 buckets from -21.5431 to 11008.5:
  611 176 146 24 7 10 0 3 2 7 1 5 3 4 4 2 3 3 5 3 5 6 6 4 5 4 10 7 7 1 8 9 6 10 11 10 12 10 8 12 14 10 12 9 9 14 13 14 19 17 14 10 13 21 13 19 17 15 19 19 13 19 16 13 20 14 22 16 13 23 22 21 14 23 19 17 22 24 21 24 33 24 27 22 23 24 23 29 13 26 26 17 35 21 35 26 32 28 22 30 33 27 33 24 35 33 18 33 19 33 17 15 16 22 24 22 15 20 10 13 17 6 14 8 7 13 7 9 10 6 10 4 5 6 4 4 2 7 5 0 6 3 3 2 2 3 0 3 1 2 1 1 2 0 2 0 1 1 0 1 1 0 0 1 0 4 0 2 0 0 1 1 0 2 1 3 0 0 1 1 2 0 1 0 1 0 0 0 0 2 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 
  Checksum=29961
  Metadata domains:
    (default)
  Metadata:
    STATISTICS_MAXIMUM=10987
    STATISTICS_MEAN=2454.9398347107
    STATISTICS_MINIMUM=0
    STATISTICS_STDDEV=2027.7460356614

Asynchronous service execution

It is also possible to execute services asynchronously, where this is recommended for services that may be time-consuming. Note: services are always executed asynchronously when hosted in the EO4Atlantic platform.

The process is similar to synchronous execution:

  1. Prepare a list of WPS inputs (identifier, value) tuples, using the identifiers found in the describe_service() output (taken from the corresponding wps.py definition).
  2. Asynchronously execute the process with the inputs.
    1. This is achieved by specifying an optional identifier specifying that process output is to be returned as a reference rather than in the response from the call to execute().
  3. Monitor the execution progress.
  4. Upon completion, parse the process WPS outputs.

Example 3

The next example uses the sentinel2-rgb service to generate a composite RGB raster for a particular Sentinel-2 product. It is executed asynchronously. It assumes that a test product has been previously copied to the host data volume ($EO4A_DATA_DIR/service/test_s2products). Using directories in $EO4A_DATA_DIR/service is the recommended approach for local execution of services using real products.


In [9]:
inputs = [
    ('s2_product_dir', 'test_s2products'), # Location relative to $EO4A_DATA_DIR/service on the host
    ('r_band', '4'),
    ('g_band', '3'),
    ('b_band', '2'),
    ('resolution', '60'),
]
# Aynchronous execution - note the specification of the 'output' reference
execution = wps.execute('sentinel2-rgb', inputs,  output='output_reference')

monitor_execution(execution, sleep_secs=5) # Check every 3 seconds by default
execution.getOutput()

# Check the description for the outputs provided by the service
# Only one output for this service
print('RGB output is available at (relative to $EO4A_DATA_DIR/service):')
output = execution.processOutputs[0]
print('%s: %s' % (output.identifier, output.data[0]))


Status(0% - ProcessAccepted) PyWPS Process sentinel2-rgb accepted
Status(20% - ProcessStarted) Executing process.
Status(20% - ProcessSucceeded) Finished
Status: ProcessSucceeded
RGB output is available at (relative to $EO4A_DATA_DIR/service):
rgb_dir: sentinel2-rgb/output/rgb

In [ ]: