Skip to content

Commit 150c4e3

Browse files
committed
feat: cop_ghsl - add GHS_UCDB product types
1 parent 0bba545 commit 150c4e3

File tree

3 files changed

+131
-49
lines changed

3 files changed

+131
-49
lines changed

eodag/plugins/search/cop_ghsl.py

Lines changed: 86 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,15 @@ def _check_input_parameters_valid(self, product_type: str, params: Any):
163163
Check if all required parameters are given and if the values are valid
164164
raises a ValidationError if this is not the case
165165
"""
166-
constraints_values = self._fetch_constraints(product_type)["constraints"]
166+
constraints_data = self._fetch_constraints(product_type)
167+
constraints_values = constraints_data["constraints"]
167168
# get available values - will raise error if wrong parameters or wrong parameter values in request
169+
grouped_by = params.pop("grouped_by", None)
168170
available_values = _get_available_values_from_constraints(
169171
constraints_values, params, product_type
170172
)
173+
if grouped_by and grouped_by not in params:
174+
params[grouped_by] = available_values[grouped_by]
171175
missing_params = set(available_values.keys()) - set(params.keys())
172176
if missing_params:
173177
raise ValidationError(
@@ -182,6 +186,50 @@ def _check_input_parameters_valid(self, product_type: str, params: Any):
182186
set(available_values["month"])
183187
)
184188

189+
def _get_start_and_end_from_properties(
190+
self, properties: dict[str, Any]
191+
) -> dict[str, str]:
192+
"""get the start and end time from year/month in the properties or missionStart/EndDate"""
193+
if "month" in properties:
194+
start_date = datetime.datetime(
195+
year=int(properties["year"]),
196+
month=int(properties["month"]),
197+
day=1,
198+
hour=0,
199+
minute=0,
200+
second=0,
201+
)
202+
end_day = monthrange(int(properties["year"]), int(properties["month"]))[1]
203+
end_date = datetime.datetime(
204+
year=int(properties["year"]),
205+
month=int(properties["month"]),
206+
day=end_day,
207+
hour=23,
208+
minute=59,
209+
second=59,
210+
)
211+
elif "year" in properties:
212+
start_date = datetime.datetime(
213+
year=int(properties["year"]), month=1, day=1, hour=0, minute=0, second=0
214+
)
215+
end_date = datetime.datetime(
216+
year=int(properties["year"]),
217+
month=12,
218+
day=31,
219+
hour=23,
220+
minute=59,
221+
second=59,
222+
)
223+
else:
224+
start_date = self.get_product_type_cfg_value("missionStartDate")
225+
end_date = self.get_product_type_cfg_value("missionEndDate")
226+
return {"start_date": start_date, "end_date": end_date}
227+
228+
result = {}
229+
result["start_date"] = start_date.strftime("%Y-%m-%dT%H:%M:%SZ")
230+
result["end_date"] = end_date.strftime("%Y-%m-%dT%H:%M:%SZ")
231+
return result
232+
185233
def _create_products_from_tiles(
186234
self,
187235
tiles: dict[str, list[dict[str, Any]]],
@@ -287,77 +335,63 @@ def _create_products_without_tiles(
287335
default_geometry = getattr(self.config, "metadata_mapping")["defaultGeometry"]
288336
properties = {}
289337
properties["geometry"] = default_geometry[1]
290-
download_link = (
291-
self.config.products.get(product_type, {})
292-
.get("metadata_mapping", {})
293-
.get("downloadLink", None)
338+
product_type_config = self.config.products.get(product_type, {})
339+
download_link = product_type_config.get("metadata_mapping", {}).get(
340+
"downloadLink", None
294341
)
295342
if not download_link:
296343
raise MisconfiguredError(
297344
f"Download link configuration missing for product type {product_type}"
298345
)
299-
properties["downloadLink"] = download_link
346+
300347
# product type with assets mapping
301348
assets_mapping = filters.pop("assets_mapping", None)
302349
products = []
303350
start_index = prep.items_per_page * (prep.page - 1)
304351
end_index = start_index + prep.items_per_page - 1
305-
if assets_mapping:
352+
grouped_by = filters.pop("grouped_by", None)
353+
if grouped_by: # dataset with several files differentiated by one parameter
306354
format_params = {k: str(v) for k, v in filters.items() if v}
307355
format_params.pop("metadata_mapping", None)
308-
months = filters.get("month", "12")
309-
num_products = len(months)
310-
if isinstance(months, str) or isinstance(months, int):
311-
months = [months]
312-
for i, month in enumerate(months):
356+
grouped_by_values = filters[grouped_by]
357+
if isinstance(grouped_by_values, str) or isinstance(grouped_by_values, int):
358+
grouped_by_values = [grouped_by_values]
359+
num_products = len(grouped_by_values)
360+
for i, value in enumerate(grouped_by_values):
313361
if i < start_index:
314362
continue
315-
filters["month"] = format_params["month"] = str(month)
363+
filters[grouped_by] = format_params[grouped_by] = str(value)
316364
product_id = product_type + "__" + "_".join(format_params.values())
317365
properties["id"] = properties["title"] = product_id
318-
end_day = monthrange(int(filters["year"]), int(month))[1]
319-
start_time = datetime.datetime(
320-
year=int(filters["year"]),
321-
month=int(month),
322-
day=1,
323-
hour=0,
324-
minute=0,
325-
second=0,
326-
)
327-
end_time = datetime.datetime(
328-
year=int(filters["year"]),
329-
month=int(month),
330-
day=end_day,
331-
hour=23,
332-
minute=59,
333-
second=59,
334-
)
335-
properties["startTimeFromAscendingNode"] = start_time.strftime(
336-
"%Y-%m-%dT%H:%M:%SZ"
337-
)
338-
properties["completionTimeFromAscendingNode"] = end_time.strftime(
339-
"%Y-%m-%dT%H:%M:%SZ"
340-
)
366+
properties["downloadLink"] = download_link.format(**format_params)
367+
datetimes = self._get_start_and_end_from_properties(format_params)
368+
properties["startTimeFromAscendingNode"] = datetimes["start_date"]
369+
properties["completionTimeFromAscendingNode"] = datetimes["end_date"]
341370
product = EOProduct(
342371
provider="cop_ghsl", properties=properties, productType=product_type
343372
)
344-
assets = AssetsDict(product=product)
345-
for key, mapping in assets_mapping.items():
346-
download_link = mapping["href"].format(**filters)
347-
assets[key] = Asset(
348-
product=product,
349-
key=key,
350-
href=download_link,
351-
title=mapping["title"],
352-
type=mapping["type"],
353-
)
354-
product.assets = assets
373+
if assets_mapping: # item with several assets
374+
assets = AssetsDict(product=product)
375+
for key, mapping in assets_mapping.items():
376+
download_link = mapping["href"].format(**filters)
377+
assets[key] = Asset(
378+
product=product,
379+
key=key,
380+
href=download_link,
381+
title=mapping["title"],
382+
type=mapping["type"],
383+
)
384+
product.assets = assets
355385
products.append(product)
356386
if i == end_index:
357387
break
358388
else: # product type with only one file to download
359389
product_id = f"{product_type}_ALL"
360390
properties["id"] = properties["title"] = product_id
391+
datetimes = self._get_start_and_end_from_properties(properties)
392+
properties["startTimeFromAscendingNode"] = datetimes["start_date"]
393+
properties["completionTimeFromAscendingNode"] = datetimes["end_date"]
394+
properties["downloadLink"] = download_link
361395
product = EOProduct(
362396
provider="cop_ghsl", properties=properties, productType=product_type
363397
)
@@ -423,10 +457,13 @@ def _get_tiles_for_filters(
423457
filter_params.pop("assets_mapping", None)
424458

425459
self._check_input_parameters_valid(product_type, filter_params)
426-
if "year" in filter_params:
427-
params["year"] = filter_params["year"]
460+
# update parameters based on changes during validation
461+
params.update(filter_params)
428462

429463
# fetch available tiles based on filters
464+
if "year" not in filter_params:
465+
logger.warning(f"no tiles available for {product_type}")
466+
return None
430467
if isinstance(filter_params["year"], int) or isinstance(
431468
filter_params["year"], str
432469
):

eodag/resources/product_types.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6713,6 +6713,40 @@ GHS_ENACT_POP:
67136713
missionStartDate: "2011-01-01T00:00:00Z"
67146714
missionEndDate: "2011-12-31T00:00:00Z"
67156715

6716+
GHS_UCDB_DOMAIN:
6717+
abstract: |
6718+
The GHS Urban Centre Database (GHS-UCDB) describes spatial entities called “Urban Centres” described through a set of multi-temporal thematic
6719+
attributes from the GHSL data combined with other free and open data sets. The Urban Centres are defined by specific cut-off values on
6720+
resident population and built-up surface share in a 1x1 km uniform global grid. The input data is generated by the GHSL, and the
6721+
operating parameters are set in the frame of the “Degree of Urbanisation” (DEGURBA) methodology. The data is grouped by thematic domain.
6722+
instrument:
6723+
platform:
6724+
platformSerialIdentifier:
6725+
processingLevel:
6726+
keywords: GHS,Settlement,UCDB,Urbanisation,thematic,domain,DEGURBA
6727+
sensorType: multi
6728+
license: other
6729+
title: Stats in the City - the GHS Urban Centre Database UCDB R2024A by Thematic Domain
6730+
missionStartDate: "1975-01-01T00:00:00Z"
6731+
missionEndDate: "2030-12-31T00:00:00Z"
6732+
6733+
GHS_UCDB_REGION:
6734+
abstract: |
6735+
The GHS Urban Centre Database (GHS-UCDB) describes spatial entities called “Urban Centres” described through a set of multi-temporal thematic
6736+
attributes from the GHSL data combined with other free and open data sets. The Urban Centres are defined by specific cut-off values on
6737+
resident population and built-up surface share in a 1x1 km uniform global grid. The input data is generated by the GHSL, and the
6738+
operating parameters are set in the frame of the “Degree of Urbanisation” (DEGURBA) methodology. The data is grouped by region.
6739+
instrument:
6740+
platform:
6741+
platformSerialIdentifier:
6742+
processingLevel:
6743+
keywords: GHS,Settlement,UCDB,Urbanisation,region,DEGURBA
6744+
sensorType: multi
6745+
license: other
6746+
title: Stats in the City - the GHS Urban Centre Database UCDB R2024A by Region
6747+
missionStartDate: "1975-01-01T00:00:00Z"
6748+
missionEndDate: "2030-12-31T00:00:00Z"
6749+
67166750
# MARK: GENERIC ------------------------------------------------------------------------
67176751
GENERIC_PRODUCT_TYPE:
67186752
abstract:

eodag/resources/providers.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6064,6 +6064,7 @@
60646064
# products with several files
60656065
GHS_ENACT_POP:
60666066
productType: ENACT_POP
6067+
grouped_by: month
60676068
year: 2011
60686069
metadata_mapping:
60696070
downloadLink: https://jeodpp.jrc.ec.europa.eu
@@ -6076,6 +6077,16 @@
60766077
href: 'https://jeodpp.jrc.ec.europa.eu/ftp/jrc-opendata/ENACT/ENACT_POP_2011_EU28_R2020A/ENACT_POP_N{month}2011_EU28_R2020A_{coord_system}_{tile_size}/V1-0/ENACT_POP_N{month}2011_EU28_R2020A_{coord_system}_{tile_size}_V1_0.zip'
60776078
type: "application/zip"
60786079
title: Nightime grid
6080+
GHS_UCDB_DOMAIN:
6081+
productType: UCDB
6082+
grouped_by: thematic_domain
6083+
metadata_mapping:
6084+
downloadLink: https://jeodpp.jrc.ec.europa.eu/ftp/jrc-opendata/GHSL/GHS_UCDB_GLOBE_R2024A/GHS_UCDB_THEME_GLOBE_R2024A/GHS_UCDB_THEME_{thematic_domain}_GLOBE_R2024A/V1-1/GHS_UCDB_THEME_{thematic_domain}_GLOBE_R2024A_V1_1.zip
6085+
GHS_UCDB_REGION:
6086+
productType: UCDB
6087+
grouped_by: region
6088+
metadata_mapping:
6089+
downloadLink: https://jeodpp.jrc.ec.europa.eu/ftp/jrc-opendata/GHSL/GHS_UCDB_GLOBE_R2024A/GHS_UCDB_REGION_GLOBE_R2024A/GHS_UCDB_REGION_{region}_R2024A/V1-1/GHS_UCDB_REGION_{region}_R2024A_V1_1.zip
60796090
download: !plugin
60806091
type: HTTPDownload
60816092
ssl_verify: true

0 commit comments

Comments
 (0)