diff --git a/mapchete_eo/search/base.py b/mapchete_eo/search/base.py index 65a93b1..b20fb4c 100644 --- a/mapchete_eo/search/base.py +++ b/mapchete_eo/search/base.py @@ -224,6 +224,7 @@ def filter_items( items: Generator[Item, None, None], cloud_cover_field: str = "eo:cloud_cover", max_cloud_cover: float = 100.0, + **kwargs, ) -> Generator[Item, None, None]: """ Only for cloudcover now, this can and should be adapted for filter field and value diff --git a/mapchete_eo/search/config.py b/mapchete_eo/search/config.py index 3969060..2dcd647 100644 --- a/mapchete_eo/search/config.py +++ b/mapchete_eo/search/config.py @@ -5,20 +5,13 @@ class StacSearchConfig(BaseModel): - max_cloud_cover: float = 100.0 catalog_chunk_threshold: int = 10_000 catalog_chunk_zoom: int = 5 catalog_pagesize: int = 100 footprint_buffer: float = 0 -class StacStaticConfig(BaseModel): - max_cloud_cover: float = 100.0 - - class UTMSearchConfig(BaseModel): - max_cloud_cover: float = 100.0 - sinergise_aws_collections: dict = dict( S2_L2A=dict( id="sentinel-s2-l2a", diff --git a/mapchete_eo/search/platforms/sentinel2/config.py b/mapchete_eo/search/platforms/sentinel2/config.py new file mode 100644 index 0000000..acd68f9 --- /dev/null +++ b/mapchete_eo/search/platforms/sentinel2/config.py @@ -0,0 +1,16 @@ +from pydantic import Field + +from typing import List + +from mapchete_eo.search.config import StacSearchConfig, UTMSearchConfig + + +ALLOWED_SENTINEL2_QUERIES_LIST: List[str] = ["eo:cloud_cover"] + + +class Sentinel2STACSearchQueryablesConfig(StacSearchConfig): + max_cloud_cover: float = Field(100.0, serialization_alias="eo:cloud_cover") + + +class Sentinel2UTMSearchQueryablesConfig(UTMSearchConfig): + max_cloud_cover: float = Field(100.0, serialization_alias="eo:cloud_cover") diff --git a/mapchete_eo/search/stac_search.py b/mapchete_eo/search/stac_search.py index 8b782bf..36e69ee 100644 --- a/mapchete_eo/search/stac_search.py +++ b/mapchete_eo/search/stac_search.py @@ -13,11 +13,17 @@ from shapely.geometry.base import BaseGeometry from mapchete_eo.product import blacklist_products -from mapchete_eo.search.base import CatalogSearcher, StaticCatalogWriterMixin -from mapchete_eo.search.config import StacSearchConfig + from mapchete_eo.settings import mapchete_eo_settings from mapchete_eo.types import TimeRange +from mapchete_eo.search.base import CatalogSearcher, StaticCatalogWriterMixin +from mapchete_eo.search.config import StacSearchConfig +from mapchete_eo.search.platforms.sentinel2.config import ( + ALLOWED_SENTINEL2_QUERIES_LIST, + Sentinel2STACSearchQueryablesConfig, +) + logger = logging.getLogger(__name__) @@ -28,6 +34,7 @@ class STACSearchCatalog(StaticCatalogWriterMixin, CatalogSearcher): if mapchete_eo_settings.blacklist else set() ) + config_cls = StacSearchConfig def __init__( @@ -71,7 +78,11 @@ def search( area: Optional[BaseGeometry] = None, search_kwargs: Optional[Dict[str, Any]] = None, ) -> Generator[Item, None, None]: + if [s for s in self.collections if "sentinel-2" or "sentinel-s2" in s]: + self.config_cls = Sentinel2STACSearchQueryablesConfig + config = self.config_cls(**search_kwargs or {}) + if bounds: bounds = Bounds.from_inp(bounds) if time is None: # pragma: no cover @@ -155,7 +166,8 @@ def _search( time_range: Optional[TimeRange] = None, bounds: Optional[Bounds] = None, area: Optional[BaseGeometry] = None, - config: StacSearchConfig = StacSearchConfig(), + config: Sentinel2STACSearchQueryablesConfig = Sentinel2STACSearchQueryablesConfig(), + stac_query: Union[Sentinel2STACSearchQueryablesConfig, List] = [], **kwargs, ): if time_range is None: # pragma: no cover @@ -180,10 +192,17 @@ def _search( if isinstance(time_range.end, datetime) else time_range.end ) + + for i in ALLOWED_SENTINEL2_QUERIES_LIST: + for k, v in config.model_dump(by_alias=True).items(): + if k == i: + if "cloud_cover" in k: + stac_query.append(f"{k}<={v}") + search_params = dict( self.default_search_params, datetime=f"{start}/{end}", - query=[f"eo:cloud_cover<={config.max_cloud_cover}"], + query=stac_query, **kwargs, ) if ( diff --git a/mapchete_eo/search/stac_static.py b/mapchete_eo/search/stac_static.py index 3fbc6ac..41da5d4 100644 --- a/mapchete_eo/search/stac_static.py +++ b/mapchete_eo/search/stac_static.py @@ -19,10 +19,13 @@ StaticCatalogWriterMixin, filter_items, ) -from mapchete_eo.search.config import StacStaticConfig from mapchete_eo.time import time_ranges_intersect from mapchete_eo.types import TimeRange +from mapchete_eo.search.platforms.sentinel2.config import ( + Sentinel2STACSearchQueryablesConfig, +) + logger = logging.getLogger(__name__) @@ -30,8 +33,6 @@ class STACStaticCatalog(StaticCatalogWriterMixin, CatalogSearcher): - config_cls = StacStaticConfig - def __init__( self, baseurl: MPathLike, @@ -64,13 +65,16 @@ def search( area: Optional[BaseGeometry] = None, search_kwargs: Optional[Dict[str, Any]] = None, ) -> Generator[Item, None, None]: + if [s for s in self.collections if "sentinel-2" or "sentinel-s2" in s]: + self.config_cls = Sentinel2STACSearchQueryablesConfig + config = self.config_cls(**search_kwargs or {}) + if area is None and bounds: bounds = Bounds.from_inp(bounds) area = shape(bounds) for item in filter_items( - self._raw_search(time=time, area=area), - max_cloud_cover=config.max_cloud_cover, + self._raw_search(time=time, area=area), **config.model_dump() ): yield item diff --git a/mapchete_eo/search/utm_search.py b/mapchete_eo/search/utm_search.py index 69796b6..5f963ed 100644 --- a/mapchete_eo/search/utm_search.py +++ b/mapchete_eo/search/utm_search.py @@ -20,6 +20,9 @@ filter_items, ) from mapchete_eo.search.config import UTMSearchConfig +from mapchete_eo.search.platforms.sentinel2.config import ( + Sentinel2UTMSearchQueryablesConfig, +) from mapchete_eo.search.s2_mgrs import S2Tile, s2_tiles_from_bounds from mapchete_eo.settings import mapchete_eo_settings from mapchete_eo.time import day_range, to_datetime @@ -65,6 +68,9 @@ def search( area: Optional[BaseGeometry] = None, search_kwargs: Optional[Dict[str, Any]] = None, ) -> Generator[Item, None, None]: + if [s for s in self.collections if "sentinel-2" or "sentinel-s2" in s]: + self.config_cls = Sentinel2UTMSearchQueryablesConfig + config = self.config_cls(**search_kwargs or {}) if bounds: bounds = Bounds.from_inp(bounds) @@ -80,7 +86,7 @@ def _raw_search( time: Optional[Union[TimeRange, List[TimeRange]]] = None, bounds: Optional[Bounds] = None, area: Optional[BaseGeometry] = None, - config: UTMSearchConfig = UTMSearchConfig(), + config: Sentinel2UTMSearchQueryablesConfig = Sentinel2UTMSearchQueryablesConfig(), ) -> Generator[Item, None, None]: if time is None: raise ValueError("time must be given") @@ -153,9 +159,9 @@ def _raw_search( def _eo_bands(self) -> list: for collection_name in self.collections: - for ( - collection_properties - ) in UTMSearchConfig().sinergise_aws_collections.values(): + for collection_properties in ( + Sentinel2UTMSearchQueryablesConfig().sinergise_aws_collections.values() + ): if collection_properties["id"] == collection_name: collection = Collection.from_dict( collection_properties["path"].read_json() diff --git a/tests/test_known_catalogs.py b/tests/test_known_catalogs.py index 709df55..20490e5 100644 --- a/tests/test_known_catalogs.py +++ b/tests/test_known_catalogs.py @@ -20,6 +20,7 @@ def test_e84_cog_catalog_search_items(e84_cog_catalog): end="2022-06-06", ), bounds=[16, 46, 17, 47], + search_kwargs=dict(max_cloud_cover=80), ) ) ) @@ -44,6 +45,7 @@ def test_utm_search_catalog_search_items(utm_search_catalog): end="2022-06-05", ), bounds=[-180, 65, -179, 65.3], + search_kwargs=dict(max_cloud_cover=80), ) ) ) @@ -71,5 +73,6 @@ def test_known_catalogs(catalog_cls, collection_name): end="2022-06-05", ), bounds=[-180, 65, -179, 65.3], + search_kwargs=dict(max_cloud_cover=80), ) assert items