diff --git a/algorithm_catalog/vito/fusets_mogpr/benchmark_scenarios/fusets_mogpr.json b/algorithm_catalog/vito/fusets_mogpr/benchmark_scenarios/fusets_mogpr.json deleted file mode 100644 index a78ef22d..00000000 --- a/algorithm_catalog/vito/fusets_mogpr/benchmark_scenarios/fusets_mogpr.json +++ /dev/null @@ -1,63 +0,0 @@ -[ - { - "id": "fusets_mogpr", - "type": "openeo", - "description": "Multi output gaussian process regression example on NDVI timeseries", - "backend": "openeofed.dataspace.copernicus.eu", - "process_graph": { - "fusetsmogpr": { - "process_id": "fusets_mogpr", - "namespace": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/6a70b010e7af41a19ce6d728972f1561295dd8c5/algorithm_catalog/vito/fusets_mogpr/openeo_udp/fusets_mogpr.json", - "arguments": { - "s1_collection": "RVI", - "s2_collection": "NDVI", - "spatial_extent": { - "coordinates": [ - [ - [ - 5.178303838475193, - 51.252856237848164 - ], - [ - 5.178003609252369, - 51.25109194151486 - ], - [ - 5.179280940922463, - 51.25103833409551 - ], - [ - 5.179565949577788, - 51.25278555186941 - ], - [ - 5.178303838475193, - 51.252856237848164 - ] - ] - ], - "type": "Polygon" - }, - "temporal_extent": [ - "2021-05-01", - "2021-08-15" - ] - } - }, - "save1": { - "process_id": "save_result", - "arguments": { - "data": { - "from_node": "fusetsmogpr" - }, - "format": "NETCDF" - }, - "result": true - } - }, - "reference_data": { - "openEO.nc": "https://s3.waw3-1.cloudferro.com/apex-benchmarks/gh-16156495398!tests_test_benchmarks.py__test_run_benchmark_fusets_mogpr_!actual/openEO.nc", - "job-results.json": "https://s3.waw3-1.cloudferro.com/apex-benchmarks/gh-16156495398!tests_test_benchmarks.py__test_run_benchmark_fusets_mogpr_!actual/job-results.json" - } - } -] diff --git a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/README.md b/algorithm_catalog/vito/fusets_mogpr/openeo_udp/README.md deleted file mode 100644 index 4ffb7a6d..00000000 --- a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Sentinel-1 and Sentinel-2 data fusion through Multi-output Gaussian process regression (MOGPR) - -This service is designed to enable multi-output regression analysis using Gaussian Process Regression (GPR) on geospatial data. It provides a powerful tool for understanding and predicting spatiotemporal phenomena by filling gaps based on other correlated indicators. This service focuses on fusing Sentinel-1 and Sentinel-2 data, allowing the user to select one of the predefined data sources. - -## Parameters - -The `fusets_mogpr_s1s2` service requires the following parameters: - - -| Name | Description | Type | Default | -| --------------- | -------------------------------------------------------------- | ------- | ------- | -| spatial_extent | Polygon representing the AOI on which to apply the data fusion | GeoJSON | | -| temporal_extent | Date range for which to apply the data fusion | Array | | -| s1_collection | S1 data collection to use for the fusion | Text | RVI | -| s2_collection | S2 data collection to use for fusing the data | Text | NDVI | - -## Supported collections - -#### Sentinel-1 - -* RVI -* GRD - -#### Sentinel-2 - -* NDVI -* FAPAR -* LAI -* FCOVER -* EVI -* CCC -* CWC - -## Limitations - -The spatial extent is limited to a maximum size equal to a Sentinel-2 MGRS tile (100 km x 100 km). - -## Dependencies - -In addition to various Python libraries, the workflow utilizes the following libraries included in the User-Defined Function (UDF): - -* Biopar: The `biopar` package retrieves biophysical parameters like FAPAR, FCOVER, and more, that were passed as the S2_collection. The biopar package is a Python package that calculates biophysical parameters from Sentinel-2 satellite images as described [here](https://step.esa.int/docs/extra/ATBD_S2ToolBox_L2B_V1.1.pdf). The `fusets_mogpr` udp directly uses the biopar udp shared in the APEX Algorithms repository. - -* FuseTS: The `fusets` library was developed to facilitate data fusion and time-series analytics using AI/ML to extract insights about land environments. It functions as a Time Series & Data Fusion toolbox integrated with openEO. For additional information, please refer to the [FuseTS documentation](https://open-eo.github.io/FuseTS/installation.html). - - - -## Output - -This User-Defined-Process (UDP) produces a datacube that contains a gap-filled time series for all pixels within the specified temporal and spatial range. This datacube can be seamlessly integrated with other openEO processes. \ No newline at end of file diff --git a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/fusets_mogpr.json b/algorithm_catalog/vito/fusets_mogpr/openeo_udp/fusets_mogpr.json deleted file mode 100644 index e976f437..00000000 --- a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/fusets_mogpr.json +++ /dev/null @@ -1,901 +0,0 @@ -{ - "process_graph": { - "biopar1": { - "process_id": "biopar", - "arguments": { - "biopar_type": "CWC", - "date": { - "from_parameter": "temporal_extent" - }, - "polygon": { - "from_parameter": "spatial_extent" - } - }, - "namespace": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/504895642a7b3a408a2156a2c81bc1e19a27f76d/openeo_udp/biopar/biopar.json" - }, - "biopar2": { - "process_id": "biopar", - "arguments": { - "biopar_type": "CCC", - "date": { - "from_parameter": "temporal_extent" - }, - "polygon": { - "from_parameter": "spatial_extent" - } - }, - "namespace": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/504895642a7b3a408a2156a2c81bc1e19a27f76d/openeo_udp/biopar/biopar.json" - }, - "loadcollection1": { - "process_id": "load_collection", - "arguments": { - "bands": [ - "B02", - "B04", - "B08" - ], - "id": "SENTINEL2_L2A", - "spatial_extent": { - "from_parameter": "spatial_extent" - }, - "temporal_extent": { - "from_parameter": "temporal_extent" - } - } - }, - "loadcollection2": { - "process_id": "load_collection", - "arguments": { - "bands": [ - "SCL" - ], - "id": "SENTINEL2_L2A", - "spatial_extent": { - "from_parameter": "spatial_extent" - }, - "temporal_extent": { - "from_parameter": "temporal_extent" - } - } - }, - "toscldilationmask1": { - "process_id": "to_scl_dilation_mask", - "arguments": { - "data": { - "from_node": "loadcollection2" - } - } - }, - "mask1": { - "process_id": "mask", - "arguments": { - "data": { - "from_node": "loadcollection1" - }, - "mask": { - "from_node": "toscldilationmask1" - } - } - }, - "reducedimension1": { - "process_id": "reduce_dimension", - "arguments": { - "data": { - "from_node": "mask1" - }, - "dimension": "bands", - "reducer": { - "process_graph": { - "arrayelement1": { - "process_id": "array_element", - "arguments": { - "data": { - "from_parameter": "data" - }, - "index": 2 - } - }, - "arrayelement2": { - "process_id": "array_element", - "arguments": { - "data": { - "from_parameter": "data" - }, - "index": 1 - } - }, - "subtract1": { - "process_id": "subtract", - "arguments": { - "x": { - "from_node": "arrayelement1" - }, - "y": { - "from_node": "arrayelement2" - } - } - }, - "multiply1": { - "process_id": "multiply", - "arguments": { - "x": 2.5, - "y": { - "from_node": "subtract1" - } - } - }, - "multiply2": { - "process_id": "multiply", - "arguments": { - "x": 6, - "y": { - "from_node": "arrayelement2" - } - } - }, - "add1": { - "process_id": "add", - "arguments": { - "x": { - "from_node": "arrayelement1" - }, - "y": { - "from_node": "multiply2" - } - } - }, - "arrayelement3": { - "process_id": "array_element", - "arguments": { - "data": { - "from_parameter": "data" - }, - "index": 1 - } - }, - "multiply3": { - "process_id": "multiply", - "arguments": { - "x": 7.5, - "y": { - "from_node": "arrayelement3" - } - } - }, - "subtract2": { - "process_id": "subtract", - "arguments": { - "x": { - "from_node": "add1" - }, - "y": { - "from_node": "multiply3" - } - } - }, - "add2": { - "process_id": "add", - "arguments": { - "x": { - "from_node": "subtract2" - }, - "y": 1 - } - }, - "divide1": { - "process_id": "divide", - "arguments": { - "x": { - "from_node": "multiply1" - }, - "y": { - "from_node": "add2" - } - }, - "result": true - } - } - } - } - }, - "adddimension1": { - "process_id": "add_dimension", - "arguments": { - "data": { - "from_node": "reducedimension1" - }, - "label": "EVI", - "name": "bands", - "type": "bands" - } - }, - "biopar3": { - "process_id": "biopar", - "arguments": { - "biopar_type": "FCOVER", - "date": { - "from_parameter": "temporal_extent" - }, - "polygon": { - "from_parameter": "spatial_extent" - } - }, - "namespace": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/504895642a7b3a408a2156a2c81bc1e19a27f76d/openeo_udp/biopar/biopar.json" - }, - "biopar4": { - "process_id": "biopar", - "arguments": { - "biopar_type": "LAI", - "date": { - "from_parameter": "temporal_extent" - }, - "polygon": { - "from_parameter": "spatial_extent" - } - }, - "namespace": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/504895642a7b3a408a2156a2c81bc1e19a27f76d/openeo_udp/biopar/biopar.json" - }, - "biopar5": { - "process_id": "biopar", - "arguments": { - "biopar_type": "FAPAR", - "date": { - "from_parameter": "temporal_extent" - }, - "polygon": { - "from_parameter": "spatial_extent" - } - }, - "namespace": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/504895642a7b3a408a2156a2c81bc1e19a27f76d/openeo_udp/biopar/biopar.json" - }, - "loadcollection3": { - "process_id": "load_collection", - "arguments": { - "bands": [ - "B04", - "B08" - ], - "id": "SENTINEL2_L2A", - "spatial_extent": { - "from_parameter": "spatial_extent" - }, - "temporal_extent": { - "from_parameter": "temporal_extent" - } - } - }, - "loadcollection4": { - "process_id": "load_collection", - "arguments": { - "bands": [ - "SCL" - ], - "id": "SENTINEL2_L2A", - "spatial_extent": { - "from_parameter": "spatial_extent" - }, - "temporal_extent": { - "from_parameter": "temporal_extent" - } - } - }, - "toscldilationmask2": { - "process_id": "to_scl_dilation_mask", - "arguments": { - "data": { - "from_node": "loadcollection4" - } - } - }, - "mask2": { - "process_id": "mask", - "arguments": { - "data": { - "from_node": "loadcollection3" - }, - "mask": { - "from_node": "toscldilationmask2" - } - } - }, - "ndvi1": { - "process_id": "ndvi", - "arguments": { - "data": { - "from_node": "mask2" - }, - "nir": "B08", - "red": "B04", - "target_band": "NDVI" - } - }, - "filterbands1": { - "process_id": "filter_bands", - "arguments": { - "bands": [ - "NDVI" - ], - "data": { - "from_node": "ndvi1" - } - } - }, - "eq1": { - "process_id": "eq", - "arguments": { - "case_sensitive": false, - "x": { - "from_parameter": "s2_collection" - }, - "y": "ndvi" - } - }, - "if1": { - "process_id": "if", - "arguments": { - "accept": { - "from_node": "filterbands1" - }, - "reject": null, - "value": { - "from_node": "eq1" - } - } - }, - "eq2": { - "process_id": "eq", - "arguments": { - "case_sensitive": false, - "x": { - "from_parameter": "s2_collection" - }, - "y": "fapar" - } - }, - "if2": { - "process_id": "if", - "arguments": { - "accept": { - "from_node": "biopar5" - }, - "reject": { - "from_node": "if1" - }, - "value": { - "from_node": "eq2" - } - } - }, - "eq3": { - "process_id": "eq", - "arguments": { - "case_sensitive": false, - "x": { - "from_parameter": "s2_collection" - }, - "y": "lai" - } - }, - "if3": { - "process_id": "if", - "arguments": { - "accept": { - "from_node": "biopar4" - }, - "reject": { - "from_node": "if2" - }, - "value": { - "from_node": "eq3" - } - } - }, - "eq4": { - "process_id": "eq", - "arguments": { - "case_sensitive": false, - "x": { - "from_parameter": "s2_collection" - }, - "y": "fcover" - } - }, - "if4": { - "process_id": "if", - "arguments": { - "accept": { - "from_node": "biopar3" - }, - "reject": { - "from_node": "if3" - }, - "value": { - "from_node": "eq4" - } - } - }, - "eq5": { - "process_id": "eq", - "arguments": { - "case_sensitive": false, - "x": { - "from_parameter": "s2_collection" - }, - "y": "evi" - } - }, - "if5": { - "process_id": "if", - "arguments": { - "accept": { - "from_node": "adddimension1" - }, - "reject": { - "from_node": "if4" - }, - "value": { - "from_node": "eq5" - } - } - }, - "eq6": { - "process_id": "eq", - "arguments": { - "case_sensitive": false, - "x": { - "from_parameter": "s2_collection" - }, - "y": "ccc" - } - }, - "if6": { - "process_id": "if", - "arguments": { - "accept": { - "from_node": "biopar2" - }, - "reject": { - "from_node": "if5" - }, - "value": { - "from_node": "eq6" - } - } - }, - "eq7": { - "process_id": "eq", - "arguments": { - "case_sensitive": false, - "x": { - "from_parameter": "s2_collection" - }, - "y": "cwc" - } - }, - "if7": { - "process_id": "if", - "arguments": { - "accept": { - "from_node": "biopar1" - }, - "reject": { - "from_node": "if6" - }, - "value": { - "from_node": "eq7" - } - } - }, - "loadcollection5": { - "process_id": "load_collection", - "arguments": { - "bands": [ - "VV", - "VH" - ], - "id": "SENTINEL1_GRD", - "spatial_extent": { - "from_parameter": "spatial_extent" - }, - "temporal_extent": { - "from_parameter": "temporal_extent" - } - } - }, - "sarbackscatter1": { - "process_id": "sar_backscatter", - "arguments": { - "coefficient": "sigma0-ellipsoid", - "contributing_area": false, - "data": { - "from_node": "loadcollection5" - }, - "elevation_model": null, - "ellipsoid_incidence_angle": false, - "local_incidence_angle": false, - "mask": false, - "noise_removal": true - } - }, - "renamelabels1": { - "process_id": "rename_labels", - "arguments": { - "data": { - "from_node": "sarbackscatter1" - }, - "dimension": "bands", - "target": [ - "VV", - "VH" - ] - } - }, - "reducedimension2": { - "process_id": "reduce_dimension", - "arguments": { - "data": { - "from_node": "renamelabels1" - }, - "dimension": "bands", - "reducer": { - "process_graph": { - "arrayelement4": { - "process_id": "array_element", - "arguments": { - "data": { - "from_parameter": "data" - }, - "index": 1 - } - }, - "add3": { - "process_id": "add", - "arguments": { - "x": { - "from_node": "arrayelement4" - }, - "y": { - "from_node": "arrayelement4" - } - } - }, - "arrayelement5": { - "process_id": "array_element", - "arguments": { - "data": { - "from_parameter": "data" - }, - "index": 0 - } - }, - "add4": { - "process_id": "add", - "arguments": { - "x": { - "from_node": "arrayelement5" - }, - "y": { - "from_node": "arrayelement4" - } - } - }, - "divide2": { - "process_id": "divide", - "arguments": { - "x": { - "from_node": "add3" - }, - "y": { - "from_node": "add4" - } - }, - "result": true - } - } - } - } - }, - "adddimension2": { - "process_id": "add_dimension", - "arguments": { - "data": { - "from_node": "reducedimension2" - }, - "label": "RVI", - "name": "bands", - "type": "bands" - } - }, - "loadcollection6": { - "process_id": "load_collection", - "arguments": { - "bands": [ - "VV", - "VH" - ], - "id": "SENTINEL1_GRD", - "spatial_extent": { - "from_parameter": "spatial_extent" - }, - "temporal_extent": { - "from_parameter": "temporal_extent" - } - } - }, - "sarbackscatter2": { - "process_id": "sar_backscatter", - "arguments": { - "coefficient": "sigma0-ellipsoid", - "contributing_area": false, - "data": { - "from_node": "loadcollection6" - }, - "elevation_model": null, - "ellipsoid_incidence_angle": false, - "local_incidence_angle": false, - "mask": false, - "noise_removal": true - } - }, - "renamelabels2": { - "process_id": "rename_labels", - "arguments": { - "data": { - "from_node": "sarbackscatter2" - }, - "dimension": "bands", - "target": [ - "VV", - "VH" - ] - } - }, - "eq8": { - "process_id": "eq", - "arguments": { - "case_sensitive": false, - "x": { - "from_parameter": "s1_collection" - }, - "y": "grd" - } - }, - "if8": { - "process_id": "if", - "arguments": { - "accept": { - "from_node": "renamelabels2" - }, - "reject": null, - "value": { - "from_node": "eq8" - } - } - }, - "eq9": { - "process_id": "eq", - "arguments": { - "case_sensitive": false, - "x": { - "from_parameter": "s1_collection" - }, - "y": "rvi" - } - }, - "if9": { - "process_id": "if", - "arguments": { - "accept": { - "from_node": "adddimension2" - }, - "reject": { - "from_node": "if8" - }, - "value": { - "from_node": "eq9" - } - } - }, - "mergecubes1": { - "process_id": "merge_cubes", - "arguments": { - "cube1": { - "from_node": "if7" - }, - "cube2": { - "from_node": "if9" - } - } - }, - "applyneighborhood1": { - "process_id": "apply_neighborhood", - "arguments": { - "data": { - "from_node": "mergecubes1" - }, - "overlap": [], - "process": { - "process_graph": { - "runudf1": { - "process_id": "run_udf", - "arguments": { - "context": {}, - "data": { - "from_parameter": "data" - }, - "runtime": "Python", - "version": "3.8", - "udf": "#%%\n\nimport os\nimport sys\nimport zipfile\nimport requests\nimport tempfile\nimport shutil\nimport functools\n\nfrom openeo.udf import inspect\n\ndef download_file(url, path):\n \"\"\"\n Downloads a file from the given URL to the specified path.\n \"\"\"\n response = requests.get(url, stream=True)\n with open(path, \"wb\") as file:\n file.write(response.content)\n\ndef extract_zip_to_temp(zip_path, temp_dir):\n \"\"\"\n Extracts a zip file into the given temporary directory.\n \"\"\"\n with zipfile.ZipFile(zip_path, \"r\") as zip_ref:\n zip_ref.extractall(temp_dir) # Use the existing temp_dir\n return temp_dir\n\ndef move_top_level_folder_to_destination(temp_dir, destination_dir):\n \"\"\"\n Moves each top-level folder from the temporary directory to the destination directory.\n Throws an error if the folder already exists at the destination.\n \"\"\"\n # Find the top-level folders inside the extracted zip\n for item in os.listdir(temp_dir):\n item_path = os.path.join(temp_dir, item)\n \n if os.path.isdir(item_path):\n # Check if the folder already exists at destination\n dest_path = os.path.join(destination_dir, item)\n\n if os.path.exists(dest_path):\n # Throw an error if the folder already exists\n raise FileExistsError(f\"Error: The folder '{item}' already exists in the destination directory: {dest_path}\")\n\n # Move the folder out of temp and into the destination directory\n shutil.move(item_path, dest_path)\n\n\ndef add_to_sys_path(folder_path):\n \"\"\"\n Adds the folder path to sys.path.\n \"\"\"\n if folder_path not in sys.path:\n sys.path.append(folder_path)\n\n\n@functools.lru_cache(maxsize=5)\ndef setup_dependencies(dependencies_url):\n \"\"\"\n Main function to download, unzip, move the top-level folder, and add it to sys.path.\n \"\"\"\n with tempfile.TemporaryDirectory() as temp_dir:\n # Step 1: Download the zip file\n zip_path = os.path.join(temp_dir, \"temp.zip\")\n download_file(dependencies_url, zip_path)\n\n inspect(message=\"Extract dependencies to temp\")\n # Step 2: Extract the zip file to the temporary directory\n extracted_dir = extract_zip_to_temp(zip_path, temp_dir) \n\n # Step 3: Move the first top-level folder (dynamically) to the destination\n destination_dir = os.getcwd() # Current working directory\n inspect(message=\"Move top-level folder to destination\")\n moved_folder = move_top_level_folder_to_destination(extracted_dir, destination_dir)\n\n # Step 4: Add the folder to sys.path\n add_to_sys_path(moved_folder)\n inspect(message=\"Added to the sys path\") \n\n\nsetup_dependencies(\"https://artifactory.vgt.vito.be:443/artifactory/auxdata-public/ai4food/fusets_venv.zip\")\nimport os\nimport sys\nfrom configparser import ConfigParser\nfrom pathlib import Path\nfrom typing import Dict\n\nfrom openeo.udf import XarrayDataCube\n\n\ndef load_venv():\n \"\"\"\n Add the virtual environment to the system path if the folder `/tmp/venv_static` exists\n :return:\n \"\"\"\n for venv_path in ['tmp/venv_static', 'tmp/venv']:\n if Path(venv_path).exists():\n sys.path.insert(0, venv_path)\n\n\ndef set_home(home):\n os.environ['HOME'] = home\n\n\ndef create_gpy_cfg():\n home = os.getenv('HOME')\n set_home('/tmp')\n user_file = Path.home() / '.config' / 'GPy' / 'user.cfg'\n if not user_file.exists():\n user_file.parent.mkdir(parents=True, exist_ok=True)\n return user_file, home\n\n\ndef write_gpy_cfg():\n user_file, home = create_gpy_cfg()\n config = ConfigParser()\n config['plotting'] = {\n 'library': 'none'\n }\n with open(user_file, 'w') as cfg:\n config.write(cfg)\n cfg.close()\n return home\n\n\ndef apply_datacube(cube: XarrayDataCube, context: Dict) -> XarrayDataCube:\n \"\"\"\n Apply mogpr integration to a datacube.\n MOGPR requires a full timeseries for multiple bands, so it needs to be invoked in the context of an apply_neighborhood process.\n @param cube:\n @param context:\n @return:\n \"\"\"\n load_venv()\n home = write_gpy_cfg()\n\n from fusets.mogpr import mogpr\n dims = cube.get_array().dims\n result = mogpr(cube.get_array().to_dataset(dim=\"bands\"))\n result_dc = XarrayDataCube(result.to_array(dim=\"bands\").transpose(*dims))\n set_home(home)\n return result_dc\n\n\ndef load_mogpr_udf() -> str:\n \"\"\"\n Loads an openEO udf that applies mogpr.\n @return:\n \"\"\"\n import os\n return Path(os.path.realpath(__file__)).read_text()\n" - }, - "result": true - } - } - }, - "size": [ - { - "dimension": "x", - "value": 32, - "unit": "px" - }, - { - "dimension": "y", - "value": 32, - "unit": "px" - } - ] - }, - "result": true - } - }, - "id": "fusets_mogpr", - "summary": "Integrate S1 and S2 timeseries using multi-output gaussian process regression", - "description": "# Sentinel-1 and Sentinel-2 data fusion through Multi-output Gaussian process regression (MOGPR)\n\nThis service is designed to enable multi-output regression analysis using Gaussian Process Regression (GPR) on geospatial data. It provides a powerful tool for understanding and predicting spatiotemporal phenomena by filling gaps based on other correlated indicators. This service focuses on fusing Sentinel-1 and Sentinel-2 data, allowing the user to select one of the predefined data sources.\n\n## Parameters\n\nThe `fusets_mogpr_s1s2` service requires the following parameters:\n\n\n| Name | Description | Type | Default |\n| --------------- | -------------------------------------------------------------- | ------- | ------- |\n| spatial_extent | Polygon representing the AOI on which to apply the data fusion | GeoJSON | |\n| temporal_extent | Date range for which to apply the data fusion | Array | |\n| s1_collection | S1 data collection to use for the fusion | Text | RVI |\n| s2_collection | S2 data collection to use for fusing the data | Text | NDVI |\n\n## Supported collections\n\n#### Sentinel-1\n\n* RVI\n* GRD\n\n#### Sentinel-2\n\n* NDVI\n* FAPAR\n* LAI\n* FCOVER\n* EVI\n* CCC\n* CWC\n\n## Limitations\n\nThe spatial extent is limited to a maximum size equal to a Sentinel-2 MGRS tile (100 km x 100 km).\n\n## Dependencies\n\nIn addition to various Python libraries, the workflow utilizes the following libraries included in the User-Defined Function (UDF):\n\n* Biopar: The `biopar` package retrieves biophysical parameters like FAPAR, FCOVER, and more, that were passed as the S2_collection. The biopar package is a Python package that calculates biophysical parameters from Sentinel-2 satellite images as described [here](https://step.esa.int/docs/extra/ATBD_S2ToolBox_L2B_V1.1.pdf). The `fusets_mogpr` udp directly uses the biopar udp shared in the APEX Algorithms repository. \n\n* FuseTS: The `fusets` library was developed to facilitate data fusion and time-series analytics using AI/ML to extract insights about land environments. It functions as a Time Series & Data Fusion toolbox integrated with openEO. For additional information, please refer to the [FuseTS documentation](https://open-eo.github.io/FuseTS/installation.html).\n\n\n\n## Output\n\nThis User-Defined-Process (UDP) produces a datacube that contains a gap-filled time series for all pixels within the specified temporal and spatial range. This datacube can be seamlessly integrated with other openEO processes.", - "parameters": [ - { - "name": "spatial_extent", - "description": "Limits the data to process to the specified bounding box or polygons.\\n\\nFor raster data, the process loads the pixel into the data cube if the point at the pixel center intersects with the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC).\\nFor vector data, the process loads the geometry into the data cube if the geometry is fully within the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). Empty geometries may only be in the data cube if no spatial extent has been provided.\\n\\nEmpty geometries are ignored.\\nSet this parameter to null to set no limit for the spatial extent.", - "schema": [ - { - "title": "Bounding Box", - "type": "object", - "subtype": "bounding-box", - "required": [ - "west", - "south", - "east", - "north" - ], - "properties": { - "west": { - "description": "West (lower left corner, coordinate axis 1).", - "type": "number" - }, - "south": { - "description": "South (lower left corner, coordinate axis 2).", - "type": "number" - }, - "east": { - "description": "East (upper right corner, coordinate axis 1).", - "type": "number" - }, - "north": { - "description": "North (upper right corner, coordinate axis 2).", - "type": "number" - }, - "base": { - "description": "Base (optional, lower left corner, coordinate axis 3).", - "type": [ - "number", - "null" - ], - "default": null - }, - "height": { - "description": "Height (optional, upper right corner, coordinate axis 3).", - "type": [ - "number", - "null" - ], - "default": null - }, - "crs": { - "description": "Coordinate reference system of the extent, specified as as [EPSG code](http://www.epsg-registry.org/) or [WKT2 CRS string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html). Defaults to `4326` (EPSG code 4326) unless the client explicitly requests a different coordinate reference system.", - "anyOf": [ - { - "title": "EPSG Code", - "type": "integer", - "subtype": "epsg-code", - "minimum": 1000, - "examples": [ - 3857 - ] - }, - { - "title": "WKT2", - "type": "string", - "subtype": "wkt2-definition" - } - ], - "default": 4326 - } - } - }, - { - "title": "Vector data cube", - "description": "Limits the data cube to the bounding box of the given geometries in the vector data cube. For raster data, all pixels inside the bounding box that do not intersect with any of the polygons will be set to no data (`null`). Empty geometries are ignored.", - "type": "object", - "subtype": "datacube", - "dimensions": [ - { - "type": "geometry" - } - ] - }, - { - "title": "No filter", - "description": "Don't filter spatially. All data is included in the data cube.", - "type": "null" - } - ] - }, - { - "name": "temporal_extent", - "description": "Temporal extent specified as two-element array with start and end date/date-time. \nThis is date range for which to apply the data fusion", - "schema": { - "type": "array", - "subtype": "temporal-interval", - "uniqueItems": true, - "minItems": 2, - "maxItems": 2, - "items": { - "anyOf": [ - { - "type": "string", - "subtype": "date-time", - "format": "date-time" - }, - { - "type": "string", - "subtype": "date", - "format": "date" - }, - { - "type": "null" - } - ] - } - } - }, - { - "name": "s1_collection", - "description": "S1 data collection to use for fusing the data", - "schema": { - "type": "string", - "enum": [ - "RVI", - "GRD" - ] - }, - "default": "RVI", - "optional": true - }, - { - "name": "s2_collection", - "description": "S2 data collection to use for fusing the data", - "schema": { - "type": "string", - "enum": [ - "NDVI", - "FAPAR", - "LAI", - "FCOVER", - "EVI", - "CCC", - "CWC" - ] - }, - "default": "NDVI", - "optional": true - } - ] -} \ No newline at end of file diff --git a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/generate.py b/algorithm_catalog/vito/fusets_mogpr/openeo_udp/generate.py deleted file mode 100644 index 62020b6f..00000000 --- a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/generate.py +++ /dev/null @@ -1,86 +0,0 @@ -import json -from pathlib import Path -from typing import Union, Sequence - -import openeo -from openeo.api.process import Parameter -from openeo.processes import ProcessBuilder, apply_neighborhood -from openeo.rest.udp import build_process_dict - -from fusets.openeo import load_mogpr_udf - -from helpers import load_s1_collection, load_s2_collection - - -connection = openeo.connect("openeofed.dataspace.copernicus.eu") - -def get_mogpr_s1_s2( - polygon: Union[Parameter, dict] = None, - date: Union[Sequence[str], Parameter] = None, - s1_collection: Union[str, Parameter] = None, - s2_collection: Union[str, Parameter] = None, -) -> ProcessBuilder: - s1_input_cube = load_s1_collection(connection, s1_collection, polygon, date) - s2_input_cube = load_s2_collection(connection, s2_collection, polygon, date) - - # Merge the inputs to a single datacube - merged_cube = s2_input_cube.merge_cubes(s1_input_cube) - - return apply_neighborhood(merged_cube, - lambda data: data.run_udf(udf=Path("set_path.py").read_text()+"\n"+load_mogpr_udf(), runtime='Python', version="3.8", context=dict()), - size=[ - {'dimension': 'x', 'value': 32, 'unit': 'px'}, - {'dimension': 'y', 'value': 32, 'unit': 'px'} - ], overlap=[]) - - -def generate() -> dict: - - # define parameters - polygon = Parameter.spatial_extent( - name="spatial_extent", - description="Limits the data to process to the specified bounding box or polygons.\\n\\nFor raster data, the process loads the pixel into the data cube if the point at the pixel center intersects with the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC).\\nFor vector data, the process loads the geometry into the data cube if the geometry is fully within the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). Empty geometries may only be in the data cube if no spatial extent has been provided.\\n\\nEmpty geometries are ignored.\\nSet this parameter to null to set no limit for the spatial extent." - ) - date = Parameter.temporal_interval( - name="temporal_extent", - description="Temporal extent specified as two-element array with start and end date/date-time. \nThis is date range for which to apply the data fusion" - ) - s1_collection = Parameter.string( - name="s1_collection", - description="S1 data collection to use for fusing the data.", - default='RVI', - values=['RVI', 'GRD'] - ) - s2_collection = Parameter.string( - name="s2_collection", - description="S2 data collection to use for fusing the data.", - default='NDVI', - values=['NDVI', 'FAPAR', 'LAI', 'FCOVER', 'EVI', 'CCC', 'CWC'] - ) - - - mogpr = get_mogpr_s1_s2( - polygon=polygon, - date=date, - s1_collection=s1_collection, - s2_collection=s2_collection - ) - - return build_process_dict( - process_graph=mogpr, - process_id="fusets_mogpr", - summary="Integrate S1 and S2 timeseries using multi-output gaussian process regression", - description=(Path(__file__).parent / "README.md").read_text(), - parameters=[ - polygon, - date, - s1_collection, - s2_collection - ], - ) - - -if __name__ == "__main__": - # save the generated process to a file - with open(Path(__file__).parent / "fusets_mogpr.json", "w") as f: - json.dump(generate(), f, indent=2) diff --git a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/requirements.txt b/algorithm_catalog/vito/fusets_mogpr/openeo_udp/requirements.txt deleted file mode 100644 index fddacbd7..00000000 --- a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -fusets>=2.0.1 \ No newline at end of file diff --git a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/set_path.py b/algorithm_catalog/vito/fusets_mogpr/openeo_udp/set_path.py deleted file mode 100644 index 7b06dc3a..00000000 --- a/algorithm_catalog/vito/fusets_mogpr/openeo_udp/set_path.py +++ /dev/null @@ -1,82 +0,0 @@ -#%% - -import os -import sys -import zipfile -import requests -import tempfile -import shutil -import functools - -from openeo.udf import inspect - -def download_file(url, path): - """ - Downloads a file from the given URL to the specified path. - """ - response = requests.get(url, stream=True) - with open(path, "wb") as file: - file.write(response.content) - -def extract_zip_to_temp(zip_path, temp_dir): - """ - Extracts a zip file into the given temporary directory. - """ - with zipfile.ZipFile(zip_path, "r") as zip_ref: - zip_ref.extractall(temp_dir) # Use the existing temp_dir - return temp_dir - -def move_top_level_folder_to_destination(temp_dir, destination_dir): - """ - Moves each top-level folder from the temporary directory to the destination directory. - Throws an error if the folder already exists at the destination. - """ - # Find the top-level folders inside the extracted zip - for item in os.listdir(temp_dir): - item_path = os.path.join(temp_dir, item) - - if os.path.isdir(item_path): - # Check if the folder already exists at destination - dest_path = os.path.join(destination_dir, item) - - if os.path.exists(dest_path): - # Throw an error if the folder already exists - raise FileExistsError(f"Error: The folder '{item}' already exists in the destination directory: {dest_path}") - - # Move the folder out of temp and into the destination directory - shutil.move(item_path, dest_path) - - -def add_to_sys_path(folder_path): - """ - Adds the folder path to sys.path. - """ - if folder_path not in sys.path: - sys.path.append(folder_path) - - -@functools.lru_cache(maxsize=5) -def setup_dependencies(dependencies_url): - """ - Main function to download, unzip, move the top-level folder, and add it to sys.path. - """ - with tempfile.TemporaryDirectory() as temp_dir: - # Step 1: Download the zip file - zip_path = os.path.join(temp_dir, "temp.zip") - download_file(dependencies_url, zip_path) - - inspect(message="Extract dependencies to temp") - # Step 2: Extract the zip file to the temporary directory - extracted_dir = extract_zip_to_temp(zip_path, temp_dir) - - # Step 3: Move the first top-level folder (dynamically) to the destination - destination_dir = os.getcwd() # Current working directory - inspect(message="Move top-level folder to destination") - moved_folder = move_top_level_folder_to_destination(extracted_dir, destination_dir) - - # Step 4: Add the folder to sys.path - add_to_sys_path(moved_folder) - inspect(message="Added to the sys path") - - -setup_dependencies("https://artifactory.vgt.vito.be:443/artifactory/auxdata-public/ai4food/fusets_venv.zip") \ No newline at end of file diff --git a/algorithm_catalog/vito/mogpr_s1s2/benchmark_scenarios/mogpr_s1s2.json b/algorithm_catalog/vito/mogpr_s1s2/benchmark_scenarios/mogpr_s1s2.json new file mode 100644 index 00000000..3eb8e847 --- /dev/null +++ b/algorithm_catalog/vito/mogpr_s1s2/benchmark_scenarios/mogpr_s1s2.json @@ -0,0 +1,63 @@ +[ + { + "id": "mogpr_s1s2", + "type": "openeo", + "description": "Multi output gaussian process regression example on NDVI timeseries", + "backend": "openeofed.dataspace.copernicus.eu", + "process_graph": { + "mogprs1s21": { + "arguments": { + "s1_collection": "RVI", + "s2_collection": "NDVI", + "spatial_extent": { + "coordinates": [ + [ + [ + 5.170012098271149, + 51.25062964728295 + ], + [ + 5.17085904378298, + 51.24882567194015 + ], + [ + 5.17857421368097, + 51.2468515482926 + ], + [ + 5.178972704726344, + 51.24982704376254 + ], + [ + 5.170012098271149, + 51.25062964728295 + ] + ] + ], + "type": "Polygon" + }, + "temporal_extent": [ + "2021-05-01", + "2021-08-01" + ] + }, + "namespace": "https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/mogpr_s1s2/openeo_udp/mogpr_s1s2.json", + "process_id": "mogpr_s1s2" + }, + "saveresult1": { + "arguments": { + "data": { + "from_node": "mogprs1s21" + }, + "format": "NetCDF", + "options": {} + }, + "process_id": "save_result", + "result": true + } + }, + "reference_data": { + "openEO.nc": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/mogpr_s1s2/openEO.nc" + } + } +] \ No newline at end of file diff --git a/algorithm_catalog/vito/fusets_mogpr/records/fusets_mogpr.json b/algorithm_catalog/vito/mogpr_s1s2/records/mogpr_s1s2.json similarity index 89% rename from algorithm_catalog/vito/fusets_mogpr/records/fusets_mogpr.json rename to algorithm_catalog/vito/mogpr_s1s2/records/mogpr_s1s2.json index b14fbc74..d7ac4c93 100644 --- a/algorithm_catalog/vito/fusets_mogpr/records/fusets_mogpr.json +++ b/algorithm_catalog/vito/mogpr_s1s2/records/mogpr_s1s2.json @@ -1,5 +1,5 @@ { - "id": "fusets_mogpr", + "id": "mogpr_s1s2", "type": "Feature", "conformsTo": [ "http://www.opengis.net/spec/ogcapi-records-1/1.0/req/record-core", @@ -8,7 +8,7 @@ "geometry": null, "properties": { "created": "2025-01-09T00:00:00Z", - "updated": "2025-01-29T00:00:00Z", + "updated": "2025-12-07T00:00:00Z", "type": "service", "title": "Multi output gaussian process regression", "description": "Integrates timeseries in data cube using multi-output gaussian process regression. The service is designed to enable multi-output regression analysis using Gaussian Process Regression (GPR) on geospatial data. It provides a powerful tool for understanding and predicting spatiotemporal phenomena by filling gaps based on other indicators that are correlated with each other.", @@ -121,7 +121,7 @@ "rel": "application", "type": "application/vnd.openeo+json;type=process", "title": "openEO Process Definition", - "href": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/09413be3c27e0e695d426c9ffe5a0fe90beefe65/openeo_udp/fusets_mogpr/fusets_mogpr.json" + "href": "https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/mogpr_s1s2/openeo_udp/mogpr_s1s2.json" }, { "rel": "service", @@ -151,19 +151,19 @@ "rel": "code", "type": "text/html", "title": "Git source repository", - "href": "https://github.com/Open-EO/FuseTS" + "href": "https://github.com/VITObelgium/openeo_algorithm_catalog" }, { "rel": "example-output", "type": "application/netcdf", "title": "Example output", - "href": "https://s3.waw3-1.cloudferro.com/apex-benchmarks/gh-16156495398!tests_test_benchmarks.py__test_run_benchmark_fusets_mogpr_!actual/openEO.nc" + "href": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/mogpr_s1s2/openEO.nc" }, { "rel": "webapp", "type": "text/html", "title": "OpenEO Web Editor", - "href": "https://editor.openeo.org/?wizard=UDP&wizard~process=fusets_mogpr&wizard~processUrl=https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/refs/heads/main/algorithm_catalog/vito/fusets_mogpr/openeo_udp/fusets_mogpr.json&server=https://openeofed.dataspace.copernicus.eu" + "href": "https://editor.openeo.org/?wizard=UDP&wizard~process=mogpr_s1s2&wizard~processUrl=https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/mogpr_s1s2/openeo_udp/mogpr_s1s2.json&server=https://openeofed.dataspace.copernicus.eu" }, { "rel": "thumbnail", diff --git a/algorithm_catalog/vito/fusets_mogpr/records/thumbnail.jpg b/algorithm_catalog/vito/mogpr_s1s2/records/thumbnail.jpg similarity index 100% rename from algorithm_catalog/vito/fusets_mogpr/records/thumbnail.jpg rename to algorithm_catalog/vito/mogpr_s1s2/records/thumbnail.jpg diff --git a/algorithm_catalog/vito/peakvalley/benchmark_scenarios/peakvalley.json b/algorithm_catalog/vito/peakvalley/benchmark_scenarios/peakvalley.json new file mode 100644 index 00000000..03b87371 --- /dev/null +++ b/algorithm_catalog/vito/peakvalley/benchmark_scenarios/peakvalley.json @@ -0,0 +1,44 @@ +[ + { + "id": "peakvalley", + "type": "openeo", + "description": "Detects peaks and valleys in a time series by analysing amplitude changes and slope patterns", + "backend": "openeofed.dataspace.copernicus.eu", + "process_graph": { + "peakvalley1": { + "arguments": { + "drop_threshold": 0.15, + "recovery_ratio": 1, + "slope_threshold": 0.007, + "spatial_extent": { + "crs": 4326, + "east": 15.185336903822831, + "north": 45.81302555710934, + "south": 45.80924633589998, + "west": 15.179421073198585 + }, + "temporal_extent": [ + "2021-01-01", + "2021-12-31" + ] + }, + "namespace": "https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/peakvalley/openeo_udp/peakvalley.json", + "process_id": "peakvalley" + }, + "saveresult1": { + "arguments": { + "data": { + "from_node": "peakvalley1" + }, + "format": "NetCDF", + "options": {} + }, + "process_id": "save_result", + "result": true + } + }, + "reference_data": { + "openEO.nc": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/peakvalley/openEO.nc" + } + } +] \ No newline at end of file diff --git a/algorithm_catalog/vito/peakvalley/records/peakvalley.json b/algorithm_catalog/vito/peakvalley/records/peakvalley.json new file mode 100644 index 00000000..59e05e57 --- /dev/null +++ b/algorithm_catalog/vito/peakvalley/records/peakvalley.json @@ -0,0 +1,174 @@ +{ + "id": "peakvalley", + "type": "Feature", + "conformsTo": [ + "http://www.opengis.net/spec/ogcapi-records-1/1.0/req/record-core", + "https://apex.esa.int/core/openeo-udp" + ], + "geometry": null, + "properties": { + "created": "2025-01-09T00:00:00Z", + "updated": "2025-01-29T00:00:00Z", + "type": "service", + "title": "Detect peaks and valleys in a time series", + "description": "This process provides automated detection of peaks and valleys in time-series data by analysing amplitude changes and slope patterns. It identifies significant drops, recoveries, and inflexion points to classify each time step as a peak, a valley, or a neutral state.", + "cost_estimate": 10, + "cost_unit": "platform credits per km²", + "keywords": [ + "Data Analysis and Visualization", + "Sentinel-2" + ], + "language": { + "code": "en-US", + "name": "English (United States)" + }, + "languages": [ + { + "code": "en-US", + "name": "English (United States)" + } + ], + "contacts": [ + { + "name": "Bram Janssen", + "position": "Researcher", + "organization": "VITO", + "links": [ + { + "href": "https://www.vito.be/", + "title": "VITO Website", + "rel": "about", + "type": "text/html" + }, + { + "href": "https://github.com/JanssenBrm", + "title": "GitHub", + "rel": "about", + "type": "text/html" + } + ], + "contactInstructions": "Contact via VITO", + "roles": [ + "principal investigator" + ] + }, + { + "name": "Pratichhya Sharma", + "position": "Researcher", + "organization": "VITO", + "links": [ + { + "href": "https://www.vito.be/", + "title": "VITO Website", + "rel": "about", + "type": "text/html" + }, + { + "href": "https://github.com/Pratichhya", + "title": "GitHub", + "rel": "about", + "type": "text/html" + } + ], + "contactInstructions": "Contact via VITO", + "roles": [ + "service provider" + ] + }, + { + "name": "VITO", + "links": [ + { + "href": "https://www.vito.be/", + "title": "VITO Website", + "rel": "about", + "type": "text/html" + } + ], + "contactInstructions": "SEE WEBSITE", + "roles": [ + "processor" + ] + } + ], + "themes": [ + { + "concepts": [ + { + "id": "Normalised vegetation difference index (NDVI)" + }, + { + "id": "Radar Vegetation Index (RVI)" + }, + { + "id": "peakvalley" + } + ], + "scheme": "https://gcmd.earthdata.nasa.gov/kms/concepts/concept_scheme/sciencekeywords" + } + ], + "formats": [ + { + "name": "JSON" + } + ], + "license": "other" + }, + "linkTemplates": [], + "links": [ + { + "rel": "application", + "type": "application/vnd.openeo+json;type=process", + "title": "openEO Process Definition", + "href": "https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/peakvalley/openeo_udp/peakvalley.json" + }, + { + "rel": "service", + "type": "application/json", + "title": "CDSE openEO federation", + "href": "https://openeofed.dataspace.copernicus.eu" + }, + { + "rel": "platform", + "type": "application/json", + "title": "CDSE openEO federation", + "href": "../../../../platform_catalog/cdse_openeo_federation.json" + }, + { + "rel": "provider", + "type": "application/json", + "title": "VITO", + "href": "../../record.json" + }, + { + "rel": "about", + "type": "text/html", + "title": "Documentation", + "href": "https://open-eo.github.io/FuseTS/" + }, + { + "rel": "code", + "type": "text/html", + "title": "Git source repository", + "href": "https://github.com/VITObelgium/openeo_algorithm_catalog" + }, + { + "rel": "webapp", + "type": "text/html", + "title": "OpenEO Web Editor", + "href": "https://editor.openeo.org/?wizard=UDP&wizard~process=peakvalley&wizard~processUrl=https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/peakvalley/openeo_udp/peakvalley.json&server=https://openeofed.dataspace.copernicus.eu" + }, + { + "rel": "example-output", + "type": "application/netcdf", + "title": "Example output", + "href": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/peakvalley/openEO.nc" + }, + { + "rel": "thumbnail", + "type": "image/png", + "title": "Thumbnail image", + "href": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/refs/heads/main/algorithm_catalog/vito/peakvalley/records/thumbnail.png" + } + ] +} \ No newline at end of file diff --git a/algorithm_catalog/vito/peakvalley/records/thumbnail.png b/algorithm_catalog/vito/peakvalley/records/thumbnail.png new file mode 100644 index 00000000..fa4b1886 Binary files /dev/null and b/algorithm_catalog/vito/peakvalley/records/thumbnail.png differ diff --git a/algorithm_catalog/vito/phenology/benchmark_scenarios/phenology.json b/algorithm_catalog/vito/phenology/benchmark_scenarios/phenology.json new file mode 100644 index 00000000..55a2b918 --- /dev/null +++ b/algorithm_catalog/vito/phenology/benchmark_scenarios/phenology.json @@ -0,0 +1,62 @@ +[ + { + "id": "phenology", + "type": "openeo", + "description": "Computes phenology metrics based on the Phenolopy implementation on NDVI", + "backend": "openeofed.dataspace.copernicus.eu", + "process_graph": { + "phenology1": { + "arguments": { + "spatial_extent": { + "coordinates": [ + [ + [ + 5.179169745059369, + 51.24984286550534 + ], + [ + 5.170016107999743, + 51.25052999567865 + ], + [ + 5.171081610725707, + 51.24861004739975 + ], + [ + 5.178604705735125, + 51.246720335821465 + ], + [ + 5.179169745059369, + 51.24984286550534 + ] + ] + ], + "type": "Polygon" + }, + "temporal_extent": [ + "2022-05-01", + "2022-09-30" + ] + }, + "namespace": "https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/phenology/openeo_udp/phenology.json", + "process_id": "phenology" + }, + "saveresult1": { + "arguments": { + "data": { + "from_node": "phenology1" + }, + "format": "GTiff", + "options": {} + }, + "process_id": "save_result", + "result": true + } + }, + "reference_data": { + "timeseries.json": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/phenology/openEO.tif", + "job-results.json": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/phenology/job-results.json" + } + } +] \ No newline at end of file diff --git a/algorithm_catalog/vito/phenology/records/phenology.json b/algorithm_catalog/vito/phenology/records/phenology.json new file mode 100644 index 00000000..8ae72369 --- /dev/null +++ b/algorithm_catalog/vito/phenology/records/phenology.json @@ -0,0 +1,175 @@ +{ + "id": "phenology", + "type": "Feature", + "conformsTo": [ + "http://www.opengis.net/spec/ogcapi-records-1/1.0/req/record-core", + "https://apex.esa.int/core/openeo-udp" + ], + "geometry": null, + "properties": { + "created": "2025-01-09T00:00:00Z", + "updated": "2025-01-29T00:00:00Z", + "type": "service", + "title": "Phenology metrics from Sentinel-2 NDVI", + "description": "Computes phenology metrics that is designed to investigate the seasonality of satellite timeseries data and their relationship with dynamic vegetation properties such as phenology and temporal growth patterns.", + "cost_estimate": 10, + "cost_unit": "platform credits per km²", + "keywords": [ + "Data Analysis and Visualization", + "Sentinel-1", + "Sentinel-2" + ], + "language": { + "code": "en-US", + "name": "English (United States)" + }, + "languages": [ + { + "code": "en-US", + "name": "English (United States)" + } + ], + "contacts": [ + { + "name": "Bram Janssen", + "position": "Researcher", + "organization": "VITO", + "links": [ + { + "href": "https://www.vito.be/", + "title": "VITO Website", + "rel": "about", + "type": "text/html" + }, + { + "href": "https://github.com/JanssenBrm", + "title": "GitHub", + "rel": "about", + "type": "text/html" + } + ], + "contactInstructions": "Contact via VITO", + "roles": [ + "principal investigator" + ] + }, + { + "name": "Pratichhya Sharma", + "position": "Researcher", + "organization": "VITO", + "links": [ + { + "href": "https://www.vito.be/", + "title": "VITO Website", + "rel": "about", + "type": "text/html" + }, + { + "href": "https://github.com/Pratichhya", + "title": "GitHub", + "rel": "about", + "type": "text/html" + } + ], + "contactInstructions": "Contact via VITO", + "roles": [ + "service provider" + ] + }, + { + "name": "VITO", + "links": [ + { + "href": "https://www.vito.be/", + "title": "VITO Website", + "rel": "about", + "type": "text/html" + } + ], + "contactInstructions": "SEE WEBSITE", + "roles": [ + "processor" + ] + } + ], + "themes": [ + { + "concepts": [ + { + "id": "Normalised vegetation difference index (NDVI)" + }, + { + "id": "Radar Vegetation Index (RVI)" + }, + { + "id": "Phenology" + } + ], + "scheme": "https://gcmd.earthdata.nasa.gov/kms/concepts/concept_scheme/sciencekeywords" + } + ], + "formats": [ + { + "name": "JSON" + } + ], + "license": "other" + }, + "linkTemplates": [], + "links": [ + { + "rel": "application", + "type": "application/vnd.openeo+json;type=process", + "title": "openEO Process Definition", + "href": "https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/phenology/openeo_udp/phenology.json" + }, + { + "rel": "service", + "type": "application/json", + "title": "CDSE openEO federation", + "href": "https://openeofed.dataspace.copernicus.eu" + }, + { + "rel": "platform", + "type": "application/json", + "title": "CDSE openEO federation", + "href": "../../../../platform_catalog/cdse_openeo_federation.json" + }, + { + "rel": "provider", + "type": "application/json", + "title": "VITO", + "href": "../../record.json" + }, + { + "rel": "about", + "type": "text/html", + "title": "Documentation", + "href": "https://open-eo.github.io/FuseTS/" + }, + { + "rel": "code", + "type": "text/html", + "title": "Git source repository", + "href": "https://github.com/VITObelgium/openeo_algorithm_catalog" + }, + { + "rel": "webapp", + "type": "text/html", + "title": "OpenEO Web Editor", + "href": "https://editor.openeo.org/?wizard=UDP&wizard~process=phenology&wizard~processUrl=https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/phenology/openeo_udp/phenology.json&server=https://openeofed.dataspace.copernicus.eu" + }, + { + "rel": "example-output", + "type": "application/netcdf", + "title": "Example output", + "href": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/phenology/openEO.tif" + }, + { + "rel": "thumbnail", + "type": "image/png", + "title": "Thumbnail image", + "href": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/refs/heads/main/algorithm_catalog/vito/phenology/records/thumbnail.png" + } + ] +} \ No newline at end of file diff --git a/algorithm_catalog/vito/phenology/records/thumbnail.png b/algorithm_catalog/vito/phenology/records/thumbnail.png new file mode 100644 index 00000000..a318d0a2 Binary files /dev/null and b/algorithm_catalog/vito/phenology/records/thumbnail.png differ diff --git a/algorithm_catalog/vito/whittaker/benchmark_scenarios/whittaker.json b/algorithm_catalog/vito/whittaker/benchmark_scenarios/whittaker.json new file mode 100644 index 00000000..3c232d4c --- /dev/null +++ b/algorithm_catalog/vito/whittaker/benchmark_scenarios/whittaker.json @@ -0,0 +1,63 @@ +[ + { + "id": "whittaker", + "type": "openeo", + "description": "Whittaker smoothing on Sentinel-2 NDVI time series", + "backend": "openeofed.dataspace.copernicus.eu", + "process_graph": { + "saveresult1": { + "arguments": { + "data": { + "from_node": "whittaker1" + }, + "format": "JSON", + "options": {} + }, + "process_id": "save_result", + "result": true + }, + "whittaker1": { + "arguments": { + "smoothing_lambda": 10000, + "spatial_extent": { + "coordinates": [ + [ + [ + 5.170012098271149, + 51.25062964728295 + ], + [ + 5.17085904378298, + 51.24882567194015 + ], + [ + 5.17857421368097, + 51.2468515482926 + ], + [ + 5.178972704726344, + 51.24982704376254 + ], + [ + 5.170012098271149, + 51.25062964728295 + ] + ] + ], + "type": "Polygon" + }, + "temporal_extent": [ + "2022-01-01", + "2022-12-31" + ] + }, + "namespace": "https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/whittaker/openeo_udp/whittaker.json", + "process_id": "whittaker" + } + }, + "reference_data": { + "timeseries.json": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/whittaker/timeseries.json", + "job-results.json": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/whittaker/job-results.json" + } + } +] \ No newline at end of file diff --git a/algorithm_catalog/vito/whittaker/records/thumbnail.png b/algorithm_catalog/vito/whittaker/records/thumbnail.png new file mode 100644 index 00000000..f461e9cf Binary files /dev/null and b/algorithm_catalog/vito/whittaker/records/thumbnail.png differ diff --git a/algorithm_catalog/vito/whittaker/records/whittaker.json b/algorithm_catalog/vito/whittaker/records/whittaker.json new file mode 100644 index 00000000..554402fa --- /dev/null +++ b/algorithm_catalog/vito/whittaker/records/whittaker.json @@ -0,0 +1,174 @@ +{ + "id": "whittaker", + "type": "Feature", + "conformsTo": [ + "http://www.opengis.net/spec/ogcapi-records-1/1.0/req/record-core", + "https://apex.esa.int/core/openeo-udp" + ], + "geometry": null, + "properties": { + "created": "2025-01-09T00:00:00Z", + "updated": "2025-01-29T00:00:00Z", + "type": "service", + "title": "Whittaker smoothing on Sentinel-2 NDVI time series", + "description": "Applies Whittaker smoothing to Sentinel-2 NDVI time series to reduce noise and enhance the signal for better analysis of vegetation dynamics.", + "cost_estimate": 10, + "cost_unit": "platform credits per km²", + "keywords": [ + "Data Analysis and Visualization", + "Sentinel-2" + ], + "language": { + "code": "en-US", + "name": "English (United States)" + }, + "languages": [ + { + "code": "en-US", + "name": "English (United States)" + } + ], + "contacts": [ + { + "name": "Bram Janssen", + "position": "Researcher", + "organization": "VITO", + "links": [ + { + "href": "https://www.vito.be/", + "title": "VITO Website", + "rel": "about", + "type": "text/html" + }, + { + "href": "https://github.com/JanssenBrm", + "title": "GitHub", + "rel": "about", + "type": "text/html" + } + ], + "contactInstructions": "Contact via VITO", + "roles": [ + "principal investigator" + ] + }, + { + "name": "Pratichhya Sharma", + "position": "Researcher", + "organization": "VITO", + "links": [ + { + "href": "https://www.vito.be/", + "title": "VITO Website", + "rel": "about", + "type": "text/html" + }, + { + "href": "https://github.com/Pratichhya", + "title": "GitHub", + "rel": "about", + "type": "text/html" + } + ], + "contactInstructions": "Contact via VITO", + "roles": [ + "service provider" + ] + }, + { + "name": "VITO", + "links": [ + { + "href": "https://www.vito.be/", + "title": "VITO Website", + "rel": "about", + "type": "text/html" + } + ], + "contactInstructions": "SEE WEBSITE", + "roles": [ + "processor" + ] + } + ], + "themes": [ + { + "concepts": [ + { + "id": "Normalised vegetation difference index (NDVI)" + }, + { + "id": "Radar Vegetation Index (RVI)" + }, + { + "id": "whittaker" + } + ], + "scheme": "https://gcmd.earthdata.nasa.gov/kms/concepts/concept_scheme/sciencekeywords" + } + ], + "formats": [ + { + "name": "JSON" + } + ], + "license": "other" + }, + "linkTemplates": [], + "links": [ + { + "rel": "application", + "type": "application/vnd.openeo+json;type=process", + "title": "openEO Process Definition", + "href": "https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/whittaker/openeo_udp/whittaker.json" + }, + { + "rel": "service", + "type": "application/json", + "title": "CDSE openEO federation", + "href": "https://openeofed.dataspace.copernicus.eu" + }, + { + "rel": "platform", + "type": "application/json", + "title": "CDSE openEO federation", + "href": "../../../../platform_catalog/cdse_openeo_federation.json" + }, + { + "rel": "provider", + "type": "application/json", + "title": "VITO", + "href": "../../record.json" + }, + { + "rel": "about", + "type": "text/html", + "title": "Documentation", + "href": "https://open-eo.github.io/FuseTS/" + }, + { + "rel": "code", + "type": "text/html", + "title": "Git source repository", + "href": "https://github.com/Open-EO/FuseTS" + }, + { + "rel": "webapp", + "type": "text/html", + "title": "OpenEO Web Editor", + "href": "https://editor.openeo.org/?wizard=UDP&wizard~process=whittaker&wizard~processUrl=https://raw.githubusercontent.com/VITObelgium/openeo_algorithm_catalog/refs/heads/main/whittaker/openeo_udp/whittaker.json&server=https://openeofed.dataspace.copernicus.eu" + }, + { + "rel": "example-output", + "type": "application/netcdf", + "title": "Example output", + "href": "https://s3.waw3-1.cloudferro.com/swift/v1/apex-examples/whittaker/timeseries.json" + }, + { + "rel": "thumbnail", + "type": "image/png", + "title": "Thumbnail image", + "href": "https://raw.githubusercontent.com/ESA-APEx/apex_algorithms/refs/heads/main/algorithm_catalog/vito/whittaker/records/thumbnail.png" + } + ] +} \ No newline at end of file