Skip to content

Add bandmath tool to order_request #876

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions planet/order_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,3 +455,61 @@ def harmonize_tool(target_sensor: str) -> dict:
raise ClientError(e)

return _tool('harmonize', {'target_sensor': target_sensor})


def band_math_tool(b1: str,
b2: Optional[str] = None,
b3: Optional[str] = None,
b4: Optional[str] = None,
b5: Optional[str] = None,
b6: Optional[str] = None,
b7: Optional[str] = None,
b8: Optional[str] = None,
b9: Optional[str] = None,
b10: Optional[str] = None,
b11: Optional[str] = None,
b12: Optional[str] = None,
b13: Optional[str] = None,
b14: Optional[str] = None,
b15: Optional[str] = None,
pixel_type: str = specs.BAND_MATH_PIXEL_TYPE_DEFAULT):
'''Specify an Orders API band math tool.

The parameters of the bandmath tool define how each output band in the
derivative product should be produced, referencing the product inputs’
original bands. Band math expressions may not reference neighboring pixels,
as non-local operations are not supported. The tool can calculate up to 15
bands for an item. Input band parameters may not be skipped. For example,
if the b4 parameter is provided, then b1, b2, and b3 parameters are also
required.

For each band expression, the bandmath tool supports normal arithmetic
operations and simple math operators offered in the Python numpy package.
(For a list of supported mathematical functions, see
[Bandmath supported numpy math routines](https://developers.planet.com/apis/orders/bandmath-numpy-routines/)).

One bandmath imagery output file is produced for each product bundle, with
output bands derived from the band math expressions. nodata pixels are
processed with the band math equation. These files have “_bandmath”
appended to their file names.

The tool passes through UDM, RPC, and XML files, and does not update values
in these files.

Parameters:
b1-b15: An expression defining how the output band should be computed.
pixel_type: A value indicating what the output pixel type should be.

Raises:
planet.exceptions.ClientError: If pixel_type is not valid.
''' # noqa
try:
pixel_type = specs.get_match(pixel_type,
specs.BAND_MATH_PIXEL_TYPE,
'pixel_type')
except specs.SpecificationException as e:
raise ClientError(e)

# e.g. {"b1": "b1", "b2":"arctan(b1)"} if b1 and b2 are specified
parameters = dict((k, v) for k, v in locals().items() if v)
return _tool('bandmath', parameters)
4 changes: 3 additions & 1 deletion planet/specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

PRODUCT_BUNDLE_SPEC_NAME = 'orders_product_bundle_2023-02-24.json'
SUPPORTED_TOOLS = [
'band_math',
'bandmath',
'clip',
'composite',
'coregister',
Expand All @@ -34,6 +34,8 @@
SUPPORTED_ARCHIVE_TYPES = ['zip']
SUPPORTED_FILE_FORMATS = ['COG', 'PL_NITF']
HARMONIZE_TOOL_TARGET_SENSORS = ('Sentinel-2', 'PS2')
BAND_MATH_PIXEL_TYPE = ('Auto', '8U', '16U', '16S', '32R')
BAND_MATH_PIXEL_TYPE_DEFAULT = 'Auto'

LOGGER = logging.getLogger(__name__)

Expand Down
7 changes: 2 additions & 5 deletions planet/subscription_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
from . import geojson, specs
from .exceptions import ClientError

BAND_MATH_PIXEL_TYPE = ('Auto', '8U', '16U', '16S', '32R')
BAND_MATH_PIXEL_TYPE_DEFAULT = 'Auto'

NOTIFICATIONS_TOPICS = ('delivery.success',
'delivery.match',
'delivery.failed',
Expand Down Expand Up @@ -296,7 +293,7 @@ def band_math_tool(b1: str,
b13: Optional[str] = None,
b14: Optional[str] = None,
b15: Optional[str] = None,
pixel_type: str = BAND_MATH_PIXEL_TYPE_DEFAULT):
pixel_type: str = specs.BAND_MATH_PIXEL_TYPE_DEFAULT):
'''Specify a subscriptions API band math tool.

The parameters of the bandmath tool define how each output band in the
Expand Down Expand Up @@ -329,7 +326,7 @@ def band_math_tool(b1: str,
''' # noqa
try:
pixel_type = specs.get_match(pixel_type,
BAND_MATH_PIXEL_TYPE,
specs.BAND_MATH_PIXEL_TYPE,
'pixel_type')
except specs.SpecificationException as e:
raise ClientError(e)
Expand Down
26 changes: 23 additions & 3 deletions tests/unit/test_order_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_build_request():
'webhook_per_order': True
}
order_type = 'partial'
tool = {'band_math': 'jsonstring'}
tool = {'bandmath': 'jsonstring'}
stac_json = {'stac': {}}

request = order_request.build_request('test_name', [product],
Expand Down Expand Up @@ -215,8 +215,8 @@ def test_google_earth_engine():


def test__tool():
test_tool = order_request._tool('band_math', 'jsonstring')
assert test_tool == {'band_math': 'jsonstring'}
test_tool = order_request._tool('bandmath', 'jsonstring')
assert test_tool == {'bandmath': 'jsonstring'}

with pytest.raises(specs.SpecificationException):
_ = order_request._tool('notsupported', 'jsonstring')
Expand Down Expand Up @@ -272,3 +272,23 @@ def test_harmonization_tool_success():
def test_harmonization_tool_invalid_target_sensor():
with pytest.raises(exceptions.ClientError):
order_request.harmonize_tool('invalid')


def test_band_math_tool_success():
res = order_request.band_math_tool(b1='b1', b2='arctan(b1)')

expected = {
"bandmath": {
"b1": "b1",
"b2": "arctan(b1)",
"pixel_type": specs.BAND_MATH_PIXEL_TYPE_DEFAULT
}
}
assert res == expected


def test_band_math_tool_invalid_pixel_type():
with pytest.raises(exceptions.ClientError):
order_request.band_math_tool(b1='b1',
b2='arctan(b1)',
pixel_type="invalid")
4 changes: 2 additions & 2 deletions tests/unit/test_subscription_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import pytest

from planet import exceptions, subscription_request
from planet import exceptions, subscription_request, specs

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -191,7 +191,7 @@ def test_band_math_tool_success():
"parameters": {
"b1": "b1",
"b2": "arctan(b1)",
"pixel_type": subscription_request.BAND_MATH_PIXEL_TYPE_DEFAULT
"pixel_type": specs.BAND_MATH_PIXEL_TYPE_DEFAULT
}
}
assert res == expected
Expand Down