Skip to content
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

Add basic tasking request creation #48

Merged
merged 15 commits into from
Dec 22, 2023
98 changes: 97 additions & 1 deletion capella_console_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
_filter_items_by_product_types,
)
from capella_console_client.search import StacSearch, SearchResult
from capella_console_client.tasking import get_tasking_requests, _task_contains_status
from capella_console_client.tasking import get_tasking_requests, _task_contains_status, create_tasking_request
from capella_console_client.repeat_requests import create_repeat_request
from capella_console_client.validate import (
_validate_uuid,
_validate_stac_id_or_stac_items,
Expand Down Expand Up @@ -100,6 +101,51 @@ def whoami(self) -> Dict[str, Any]:
return resp.json()

# TASKING
def create_tasking_request(self, **kwargs):
"""
Create a new tasking request

Find more information at https://docs.capellaspace.com/constellation-tasking/tasking-requests

Args:
geometry: A GeoJSON representation of the area/point of interest. Must be either a polygon or point
name: Can be used along with description to help characterize and describe the tasking request. Default: ""
description: Can be used along with name to help characterize and describe the tasking request. Default: ""
window_open: Earliest time (in UTC) that you would like data to be collected. Default: Now
window_close: Latest time (in UTC) that you would like data to be collected. Default: Seven days after window_open
collection_tier: Preference for data to be collected within a certain time after window_open. Can be one of "high", "medium", "low", or "background"; these correspond respectively to one day, three days, seven days, and background. Default: "low"
product_category: Category used to define image collection. "Extended" has broader look angles and "Custom" allows specifying advanced image acquisition parameters. More information on the specifics of each can be found at https://support.capellaspace.com/hc/en-us/articles/360049110852-SAR-Imagery-Product-Tasking-Categories. One of "standard", "extended", and "custom". Default: "standard"
product_types: List of analytics to add to the order along with the imagery. Currently available analytics are Amplitude Change Detection and Vessel Detection. One of "ACD", "VS". Default: None
archive_holdback: If defined will specify a time period during which the resulting imagery will be kept from the publicly accessible archive. One of "none", "one_year", "thirty_day", "permanent". Default: "none"
custom_attribute_1: Can be used along with custom_attribute_2 to help you track a Capella task with your own metadata or internal systems. Default: None
custom_attribute_2: Can be used along with custom_attribute_1 to help you track a Capella task with your own metadata or internal systems. Default: None
collect_mode: Collect mode to be used by the satellite when making the collect. One of "spotlight", "stripmap", "sliding_spotlight". Default: "spotlight"
look_direction: Constraint on view angle. One of "right", "left", "either". Default: "either"
asc_dsc: Constraint on ascending/descending pass. One of "ascending", "descending", "either". Default: "either"
orbital_planes: List of orbital planes allowed to service request. If empty any spacecraft in any plane can service request. One of 45, 53, 97. Default: None
local_time: Times, in the timezone of the area where the image will be collected, during which the collect can be taken. Represented by a list of time ranges as seconds in the day. For example, [[21600, 64800]] would allow collects between 6 AM and 6 PM; [[0, 21600], [64800, 86400]] would allow collects between 6 PM and 12 AM as well as from 12 AM to 6 AM. Default: None
off_nadir_min: Minimum off-nadir angle permitted. Must be less than off_nadir_max. Default: None
off_nadir_max: Maximum off-nadir angle permitted. Must be greater than off_nadir_min. Default: None
elevation_min: Minimum elevation angle permitted. Default: None
elevation_max: Maximum elevation angle permitted. Default: None
image_length: Image length. Default: None
image_width: Image width. Default: None
azimuth: Azimuth angle at collect mid-time. Clockwise angle from North to the spacecraft in the target frame of reference. Default: None
grr_min: Minimum ground-range resolution. Minimum is in ordinal sense. Default: None
grr_max: Maximum ground-range resolution. Maximum is in ordinal sense. Default: None
srr_min: Minimum slant-range resolution. Minimum is in ordinal sense. Default: None
srr_max: Maximum slant-range resolution. Maximum is in ordinal sense. Default: None
azr_min: Minimum azimuth resolution. Minimum is in ordinal sense. Default: None
azr_max: Maximum azimuth resolution. Maximum is in ordinal sense. Default: None
nesz_max: Maximum allowable NESZ of resulting collect. Default: None
num_looks: Number of looks to use in processing collect. Default: None
polarization: Image polarization. One of "HH", "VV". Default: None

Returns:
Dict[str, Any]: created tasking request metadata
"""
return create_tasking_request(session=self._sesh, **kwargs)

def list_tasking_requests(
self, *tasking_request_ids: Optional[str], for_org: Optional[bool] = False, **kwargs: Optional[Dict[str, Any]]
) -> List[Dict[str, Any]]:
Expand Down Expand Up @@ -161,6 +207,56 @@ def get_collects_for_task(self, tasking_request_id: str) -> List[Dict[str, Any]]

return collects_list_resp.json()

# REPEAT REQUESTS
def create_repeat_request(self, **kwargs):
"""
Create a new repeat request

Find more information at https://docs.capellaspace.com/constellation-tasking/tasking-requests

Args:
geometry: A GeoJSON representation of the area/point of interest. Must be either a polygon or point
name: Can be used along with description to help characterize and describe the tasking request. Default: ""
description: Can be used along with name to help characterize and describe the tasking request. Default: ""
collection_tier: Preference for data to be collected within a certain time after window_open. Can be one of "high", "medium", "low", or "background"; these correspond respectively to one day, three days, seven days, and background. Default: "low"
product_category: Category used to define image collection. "Extended" has broader look angles and "Custom" allows specifying advanced image acquisition parameters. More information on the specifics of each can be found at https://support.capellaspace.com/hc/en-us/articles/360049110852-SAR-Imagery-Product-Tasking-Categories. One of "standard", "extended", and "custom". Default: "standard"
archive_holdback: If defined will specify a time period during which the resulting imagery will be kept from the publicly accessible archive. One of "none", "one_year", "thirty_day", "permanent". Default: "none"
custom_attribute_1: Can be used along with custom_attribute_2 to help you track a Capella task with your own metadata or internal systems. Default: None
custom_attribute_2: Can be used along with custom_attribute_1 to help you track a Capella task with your own metadata or internal systems. Default: None
product_types: List of analytics to add to the order along with the imagery. Currently available analytics are Amplitude Change Detection and Vessel Detection. One of "ACD", "VS". Default: None
repeat_start: Starting date (in UTC) when you would like data to begin being collected. Default: Now
repeat_end: Starting date (in UTC) when you would like data to stop being collected. This and repetition_count are mutually exclusive; only one of them can be defined per request. Default: None
repetition_interval: Number of days between the start of each derived request. Default: 7
repetition_count: Total number of acquisitions in the repeat series. This and repeat_end are mutually exclusive; only one of them can be defined per request. Default: None
maintain_scene_framing: Whether to maintain consistent framing (look-direction, ascending/descending, orbital-plane) across all acquisitions. Default: False
look_angle_tolerance: Tolerance to look-angle deviations across all acquisitions. Default: None
collect_mode: Collect mode to be used by the satellite when making the collect. One of "spotlight", "stripmap", "sliding_spotlight". Default: "spotlight"
look_direction: Constraint on view angle. One of "right", "left", "either". Default: "either"
asc_dsc: Constraint on ascending/descending pass. One of "ascending", "descending", "either". Default: "either"
orbital_planes: List of orbital planes allowed to service request. If empty any spacecraft in any plane can service request. One of 45, 53, 97. Default: None
local_time: Times, in the timezone of the area where the image will be collected, during which the collect can be taken. Represented by a list of time ranges as seconds in the day. For example, [[21600, 64800]] would allow collects between 6 AM and 6 PM; [[0, 21600], [64800, 86400]] would allow collects between 6 PM and 12 AM as well as from 12 AM to 6 AM. Default: None
off_nadir_min: Minimum off-nadir angle permitted. Must be less than off_nadir_max. Default: None
off_nadir_max: Maximum off-nadir angle permitted. Must be greater than off_nadir_min. Default: None
elevation_min: Minimum elevation angle permitted. Default: None
elevation_max: Maximum elevation angle permitted. Default: None
image_length: Image length. Default: None
image_width: Image width. Default: None
azimuth: Azimuth angle at collect mid-time. Clockwise angle from North to the spacecraft in the target frame of reference. Default: None
grr_min: Minimum ground-range resolution. Minimum is in ordinal sense. Default: None
grr_max: Maximum ground-range resolution. Maximum is in ordinal sense. Default: None
srr_min: Minimum slant-range resolution. Minimum is in ordinal sense. Default: None
srr_max: Maximum slant-range resolution. Maximum is in ordinal sense. Default: None
azr_min: Minimum azimuth resolution. Minimum is in ordinal sense. Default: None
azr_max: Maximum azimuth resolution. Maximum is in ordinal sense. Default: None
nesz_max: Maximum allowable NESZ of resulting collect. Default: None
num_looks: Number of looks to use in processing collect. Default: None
polarization: Image polarization. One of "HH", "VV". Default: None

Returns:
Dict[str, Any]: created repeat request metadata
"""
return create_repeat_request(session=self._sesh, **kwargs)

# ORDER
def list_orders(self, *order_ids: Optional[str], is_active: Optional[bool] = False) -> List[Dict[str, Any]]:
"""
Expand Down
30 changes: 29 additions & 1 deletion capella_console_client/enumerations.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,16 @@ class ProductClass(str, BaseEnum):
class OrbitState(str, BaseEnum):
ascending = "ascending"
descending = "descending"
either = "either"


class ObservationDirection(str, BaseEnum):
left = "left"
right = "right"
either = "either"


class OrbitalPlane(str, BaseEnum):
class OrbitalPlane(int, BaseEnum):
fortyfive = 45
fiftythree = 53
ninetyseven = 97
Expand All @@ -89,3 +91,29 @@ class TaskingRequestStatus(str, BaseEnum):
canceled = "canceled"
error = "error"
failed = "failed"


class CollectionTier(str, BaseEnum):
high = "1_day"
medium = "3_day"
low = "7_day"
background = "background"
internal = "internal"


class RepeatCollectionTier(str, BaseEnum):
background = "background"
routine = "routine"
internal = "internal"


class ArchiveHoldback(str, BaseEnum):
none = "none"
one_year = "1 year"
thirty_day = "30 day"
permanent = "permanent"


class Polarization(str, BaseEnum):
HH = "HH"
VV = "VV"
145 changes: 145 additions & 0 deletions capella_console_client/repeat_requests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
from typing import Optional, Dict, Any, List, Union
from datetime import datetime, timedelta

import geojson
from dateutil.parser import parse, ParserError

from capella_console_client.session import CapellaConsoleSession
from capella_console_client.validate import _snake_to_camel
from capella_console_client.enumerations import (
ObservationDirection,
OrbitState,
ProductType,
ProductClass,
OrbitalPlane,
RepeatCollectionTier,
InstrumentMode,
Polarization,
ArchiveHoldback,
)

COLLECT_CONSTRAINTS_KEYS = set(
[
"collect_mode",
"look_direction",
"asc_dsc",
"orbital_planes",
"local_time",
"off_nadir_min",
"off_nadir_max",
"elevation_min",
"elevation_max",
"image_length",
"image_width",
"azimuth",
"grr_min",
"grr_max",
"srr_min",
"srr_max",
"azr_min",
"azr_max",
"nesz_max",
"num_looks",
"polarization",
]
)

REPETITION_PROPERTIES_KEYS = set(
[
"repeat_start",
"repeat_end",
"repetition_interval",
"repetition_count",
"maintain_scene_framing",
"look_angle_tolerance",
]
)


def create_repeat_request(
session: CapellaConsoleSession,
geometry: geojson.geometry.Geometry,
name: Optional[str] = "",
description: Optional[str] = "",
collection_tier: Optional[Union[str, RepeatCollectionTier]] = RepeatCollectionTier.routine,
product_category: Optional[Union[str, ProductClass]] = ProductClass.standard,
archive_holdback: Optional[Union[str, ArchiveHoldback]] = ArchiveHoldback.none,
custom_attribute_1: Optional[str] = None,
custom_attribute_2: Optional[str] = None,
product_types: Optional[List[Union[str, ProductType]]] = None,
# Repetition properties
repeat_start: Optional[Union[datetime, str]] = None,
repeat_end: Optional[Union[datetime, str]] = None,
repetition_interval: Optional[int] = 7,
repetition_count: Optional[int] = None,
maintain_scene_framing: Optional[bool] = False,
look_angle_tolerance: Optional[int] = None,
# Collect constraints
collect_mode: Optional[Union[str, InstrumentMode]] = InstrumentMode.spotlight,
look_direction: Optional[Union[str, ObservationDirection]] = ObservationDirection.either,
asc_dsc: Optional[Union[str, OrbitState]] = OrbitState.either,
orbital_planes: Optional[List[Union[int, OrbitalPlane]]] = None,
local_time: Optional[List[int]] = None,
off_nadir_min: Optional[int] = None,
off_nadir_max: Optional[int] = None,
elevation_min: Optional[int] = None,
elevation_max: Optional[int] = None,
image_length: Optional[int] = None,
image_width: Optional[int] = None,
azimuth: Optional[int] = None,
grr_min: Optional[int] = None,
grr_max: Optional[int] = None,
srr_min: Optional[int] = None,
srr_max: Optional[int] = None,
azr_min: Optional[int] = None,
azr_max: Optional[int] = None,
nesz_max: Optional[int] = None,
num_looks: Optional[int] = None,
polarization: Optional[Union[str, Polarization]] = None,
) -> Dict[str, Any]:

if isinstance(repeat_start, str):
try:
repeat_start = parse(repeat_start)
except ParserError:
raise ValueError("Could not parse repeat_start string into a useable datetime")
if isinstance(repeat_end, str):
try:
repeat_end = parse(repeat_end)
except ParserError:
raise ValueError("Could not parse repeat_end string into a useable datetime")

if not repeat_start:
repeat_start = datetime.utcnow()

repeat_start = repeat_start.isoformat(timespec="milliseconds") + "Z"
if repeat_end is not None:
repeat_end = repeat_end.isoformat(timespec="milliseconds") + "Z"

loc = locals()
collect_constraints = {_snake_to_camel(k): loc[k] for k in COLLECT_CONSTRAINTS_KEYS if k in loc and loc[k]}
repetition_properties = {_snake_to_camel(k): loc[k] for k in REPETITION_PROPERTIES_KEYS if k in loc and loc[k]}

payload = {
"type": "Feature",
"geometry": geometry,
"properties": {
"repeatrequestName": name,
"repeatrequestDescription": description,
"windowOpen": repeat_start,
"windowClose": repeat_end,
"collectionTier": collection_tier,
"productCategory": product_category,
"archiveHoldback": archive_holdback,
"customAttribute1": custom_attribute_1,
"customAttribute2": custom_attribute_2,
"collectConstraints": collect_constraints,
"repetitionProperties": repetition_properties,
},
}

print(payload)
if product_types is not None:
payload["properties"]["processingConfig"] = {"productTypes": product_types}

return session.post("/repeat-requests", json=payload).json()
Loading