diff --git a/SUPPORT.md b/SUPPORT.md index 613bc15b..63e4baa8 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -2,8 +2,8 @@ ## How to file issues and get help -This project uses GitHub Issues to track bugs and feature requests. Please search the existing -issues before filing new issues to avoid duplicates. For new issues, file your bug or +This project uses GitHub Issues to track bugs and feature requests. Please search the existing +issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new Issue. For help and questions about using this project, please reach out to the team at farmvibes at microsoft.com. @@ -11,6 +11,7 @@ For help and questions about using this project, please reach out to the team at ## Troubleshooting A list of common issues and their resolution can be found in the [troubleshooting documentation](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/TROUBLESHOOTING.html). +We also provide a current list of [known issues on our GitHub](https://github.com/microsoft/farmvibes-ai/labels/known%20issues) that are actively being worked on. ## Microsoft Support Policy diff --git a/docs/source/conf.py b/docs/source/conf.py index cd777be6..2fe34b1c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -22,6 +22,7 @@ "sphinxcontrib.mermaid", "myst_parser", "sphinx_autodoc_typehints", + "sphinxcontrib.openapi", ] autosummary_generate = True diff --git a/docs/source/docfiles/code/vibe_core_client/client.md b/docs/source/docfiles/code/vibe_core_client/client.md index 90a26a8e..b2286cf1 100644 --- a/docs/source/docfiles/code/vibe_core_client/client.md +++ b/docs/source/docfiles/code/vibe_core_client/client.md @@ -4,6 +4,7 @@ .. automodule:: vibe_core.client :members: :show-inheritance: + :private-members: _form_payload .. autosummary:: :toctree: _autosummary diff --git a/docs/source/docfiles/markdown/NOTEBOOK_LIST.md b/docs/source/docfiles/markdown/NOTEBOOK_LIST.md index 3e4ad74a..caa6879d 100644 --- a/docs/source/docfiles/markdown/NOTEBOOK_LIST.md +++ b/docs/source/docfiles/markdown/NOTEBOOK_LIST.md @@ -61,6 +61,19 @@ We organize available notebooks in the following topics: - [`Crop land segmentation (4/4) - inference` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/crop_segmentation/04_inference.ipynb) + +
+ Deforestation + +- [`Detecting Forest Changes` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/forest_change_detection.ipynb) + +- [`Download ALOS forest extent maps` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_alos_forest_map.ipynb) + +- [`Download Glad Forest Map` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_glad_forest_map.ipynb) + +- [`Download Global Forest Change (Hansen) maps.` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_hansen_forest_map.ipynb) + +
Index Computation @@ -151,6 +164,14 @@ We organize available notebooks in the following topics: - [`Crop land segmentation (4/4) - inference` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/crop_segmentation/04_inference.ipynb) +- [`Detecting Forest Changes` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/forest_change_detection.ipynb) + +- [`Download ALOS forest extent maps` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_alos_forest_map.ipynb) + +- [`Download Glad Forest Map` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_glad_forest_map.ipynb) + +- [`Download Global Forest Change (Hansen) maps.` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_hansen_forest_map.ipynb) + - [`Field boundary segmentation (SAM exploration)` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/segment_anything/sam_exploration.ipynb) - [`Field-level Irrigation Classification` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/irrigation/field_level_irrigation_classification.ipynb) @@ -239,6 +260,14 @@ We organize available notebooks in the following topics: - [`Carbon sequestration evaluation with Microsoft Azure Data Manager for Agriculture (ADMAg) and COMET-Farm API` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/admag/azure_data_manager_for_agriculture_and_comet_farm_api_example.ipynb) +- [`Detecting Forest Changes` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/forest_change_detection.ipynb) + +- [`Download ALOS forest extent maps` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_alos_forest_map.ipynb) + +- [`Download Glad Forest Map` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_glad_forest_map.ipynb) + +- [`Download Global Forest Change (Hansen) maps.` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_hansen_forest_map.ipynb) + - [`Green House Gas fluxes` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/ghg_fluxes/ghg_fluxes.ipynb) - [`Nutrient Heatmap Estimation - Classification` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/heatmaps/nutrients_using_classification.ipynb) @@ -341,6 +370,14 @@ We organize available notebooks in the following topics: - [`Crop land segmentation (4/4) - inference` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/crop_segmentation/04_inference.ipynb) : Infer crop land segmentation for new regions with a trained model. +- [`Detecting Forest Changes` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/forest_change_detection.ipynb) : Helps users to detect forest changes + +- [`Download ALOS forest extent maps` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_alos_forest_map.ipynb) : This notebook downloads the ALOS (Advanced Land Observing Satellite) forest extent maps + +- [`Download Glad Forest Map` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_glad_forest_map.ipynb) : This notebook downloads the Global Land Analysis (GLAD) forest extent maps. + +- [`Download Global Forest Change (Hansen) maps.` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/forest/download_hansen_forest_map.ipynb) : This notebook contains functions to download and process the Global Forest Change (Hansen) maps. + - [`Field boundary segmentation (SAM exploration)` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/segment_anything/sam_exploration.ipynb) : Segment Anything Model exploration over FarmVibes.AI data to segment crop field boundaries. - [`Field-level Irrigation Classification` 📓](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/irrigation/field_level_irrigation_classification.ipynb) : Estimate an irrigation probability map over crop fields segmented with Segment Anything Model. diff --git a/docs/source/docfiles/markdown/QUICKSTART.md b/docs/source/docfiles/markdown/QUICKSTART.md index 0747f31f..6963a861 100644 --- a/docs/source/docfiles/markdown/QUICKSTART.md +++ b/docs/source/docfiles/markdown/QUICKSTART.md @@ -111,3 +111,6 @@ that FarmVibes.AI and the python client are working properly. For more information on how to execute workflows, please take a look at our [client guide](./CLIENT.md). For information on any issues running the cluster, including on how to re-start it after a machine reboot, take a look at our [troubleshoot guide](./TROUBLESHOOTING.md). +If you do not find the information you are looking for, please reach out to the team by opening +an issue on our [GitHub repository](https://github.com/microsoft/farmvibes-ai/issues) or browsing +through our [known issues](https://github.com/microsoft/farmvibes-ai/labels/known%20issues). diff --git a/docs/source/docfiles/markdown/REST_API.md b/docs/source/docfiles/markdown/REST_API.md new file mode 100644 index 00000000..a0e9ccad --- /dev/null +++ b/docs/source/docfiles/markdown/REST_API.md @@ -0,0 +1,232 @@ +# REST API + +Once the FarmVibes.AI cluster is up and running, you can interact with it using the REST API, which provides a set of endpoints that allow you to list and describe workflows, as well as manage workflow runs. +The REST API is available at the URL and port specified during cluster creation, and its address is printed in the terminal once the setup is complete. You can also check the address by running the following command in the terminal: + +```bash +$ farmvibes-ai status +2024-01-01 00:00:00,000 - INFO - Cluster farmvibes-ai-username is running with 1 servers and 0 agents. +2024-01-01 00:00:00,001 - INFO - Service url is http://ip.address:port +``` + +## Interacting with the API + +The API is accessible from the [FarmVibes.AI Python client](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/CLIENT.html), which provides an interface to interact with the cluster, list workflows, and manage workflow runs. +Alternativelly, interacting with the API can be done using any tool that can send HTTP requests, such as `curl` or [Bruno](https://www.usebruno.com/). + +For example, to list the available workflows, you can use the following command: + +```bash +$ curl -X GET http://localhost:31108/v0/workflows +``` + +Which will return the following list: + +``` +["helloworld","farm_ai/land_degradation/landsat_ndvi_trend","farm_ai/land_degradation/ndvi_linear_trend", ...] +``` + +For submiting a run of a specific workflow, we need to pass a JSON with the run configuration +(i.e., workflow name, input geometry and time range, workflow parameters, etc) as the body of the +request. For example, we can use the following command to create a `helloworld` workflow run: + +```bash +$ curl -X POST -H "Content-Type: application/json" -d +``` + +Replacing the body of the request `` with the following: + +```json +{ + "name": "Hello!", + "workflow": "helloworld", + "parameters": null, + "user_input": { + "start_date": "2020-05-01T00:00:00", + "end_date": "2020-05-05T00:00:00", + "geojson": { + "features": [ + { + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -119.14896203939314, + 46.51578909859286 + ], + [ + -119.14896203939314, + 46.37578909859286 + ], + [ + -119.28896203939313, + 46.37578909859286 + ], + [ + -119.28896203939313, + 46.51578909859286 + ], + [ + -119.14896203939314, + 46.51578909859286 + ] + ] + ] + }, + "type": "Feature" + } + ], + "type": "FeatureCollection" + } + } +} +``` + +To help in understanding the expected format and structure of the json in our requests, we provide in +our Python client the `_form_payload` method ([`vibe_core.client.FarmvibesAiClient._form_payload`](https://microsoft.github.io/farmvibes-ai/docfiles/code/vibe_core_client/client.html#vibe_core.client.FarmvibesAiClient._form_payload)) that can be used to +generate the request payload for a given run configuration. For example, the following code could +be used to obtain the json above for the helloworld workflow: + +```python +from vibe_core.client import get_default_vibe_client +import shapely.geometry as shpg +from datetime import datetime + +client = get_default_vibe_client() + +geom = shpg.Point(-119.21896203939313, 46.44578909859286).buffer(.07, cap_style=3) +time_range = (datetime(2020, 5, 1), datetime(2020, 5, 5)) + +payload = client._form_payload("helloworld", None, geom, time_range, None,"Hello!") +``` + +Another example, considering the `farm_ai/segmentation/segment_s2` workflow run submited in the +[Sentinel-2 Segmentation notebook](https://github.com/microsoft/farmvibes-ai/blob/main/notebooks/segment_anything/sentinel2_segmentation.ipynb), would be: + +```python +payload = client._form_payload("farm_ai/segmentation/segment_s2", None, None, None, {"user_input": roi_time_range, "prompts": geom_collection},"SAM segmentation") +``` + +Which would generate the following json: + +```json +{ + "name": "SAM segmentation", + "workflow": "farm_ai/segmentation/segment_s2", + "parameters": null, + "user_input": { + "user_input": { + "type": "Feature", + "stac_version": "1.0.0", + "id": "f6465ad0-5e01-4792-ad99-a0bd240c1e7d", + "properties": { + "start_datetime": "2020-05-01T00:00:00+00:00", + "end_datetime": "2020-05-05T00:00:00+00:00", + "datetime": "2020-05-01T00:00:00Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -119.14896203939314, + 46.51578909859286 + ], + [ + -119.14896203939314, + 46.37578909859286 + ], + [ + -119.28896203939313, + 46.37578909859286 + ], + [ + -119.28896203939313, + 46.51578909859286 + ], + [ + -119.14896203939314, + 46.51578909859286 + ] + ] + ] + }, + "links": [], + "assets": {}, + "bbox": [ + -119.28896203939313, + 46.37578909859286, + -119.14896203939314, + 46.51578909859286 + ], + "stac_extensions": [], + "terravibes_data_type": "DataVibe" + }, + "prompts": { + "type": "Feature", + "stac_version": "1.0.0", + "id": "geo_734c6441-cb25-4c40-8204-6b7286f24bb9", + "properties": { + "urls": [ + "/mnt/734c6441-cb25-4c40-8204-6b7286f24bb9_geometry_collection.geojson" + ], + "start_datetime": "2020-05-01T00:00:00+00:00", + "end_datetime": "2020-05-05T00:00:00+00:00", + "datetime": "2020-05-01T00:00:00Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -119.14896203939314, + 46.51578909859286 + ], + [ + -119.14896203939314, + 46.37578909859286 + ], + [ + -119.28896203939313, + 46.37578909859286 + ], + [ + -119.28896203939313, + 46.51578909859286 + ], + [ + -119.14896203939314, + 46.51578909859286 + ] + ] + ] + }, + "links": [], + "assets": {}, + "bbox": [ + -119.28896203939313, + 46.37578909859286, + -119.14896203939314, + 46.51578909859286 + ], + "stac_extensions": [], + "terravibes_data_type": "ExternalReferenceList" + } + } +} +``` + +For more information about the `_form_payload` method, please refer to the [FarmVibes.AI Python client documentation](https://microsoft.github.io/farmvibes-ai/docfiles/code/vibe_core_client/client.html#vibe_core.client.FarmvibesAiClient._form_payload). + +## Endpoints + +We provide below a list of the available endpoints and their descriptions. + +----------------------------- + +```{eval-rst} +.. openapi:: ../openapi.json + :examples: + :format: markdown +``` diff --git a/docs/source/docfiles/markdown/TROUBLESHOOTING.md b/docs/source/docfiles/markdown/TROUBLESHOOTING.md index 1e2d056d..d3e54963 100644 --- a/docs/source/docfiles/markdown/TROUBLESHOOTING.md +++ b/docs/source/docfiles/markdown/TROUBLESHOOTING.md @@ -1,6 +1,8 @@ # Troubleshooting This document compiles the most common issues encountered when installing and running FarmVibes.AI platform, grouped into broad categories. +Besides the issues listed here, we also collect a list of [known issues on our GitHub repository](https://github.com/microsoft/farmvibes-ai/labels/known%20issues) +that are currently being addressed by the development team. - **Package installation:** @@ -224,6 +226,13 @@ This document compiles the most common issues encountered when installing and ru
+
+ Workflow run monitor table not rendering inside notebook + + Make sure to have the `ipywidgets` [package](https://pypi.org/project/ipywidgets/) installed in your environment. + +
+
- **Segment Anything Model (SAM):** diff --git a/docs/source/docfiles/markdown/WORKFLOWS.md b/docs/source/docfiles/markdown/WORKFLOWS.md index ed585ef0..02ed1383 100644 --- a/docs/source/docfiles/markdown/WORKFLOWS.md +++ b/docs/source/docfiles/markdown/WORKFLOWS.md @@ -7,6 +7,7 @@ We group FarmVibes.AI workflows in the following categories: This includes raw data sources (e.g., Sentinel 1 and 2, LandSat, CropDataLayer) as well as the SpaceEye cloud-removal model; - **Data Processing**: workflows that transform data into different data types (e.g., computing NDVI/MSAVI/Methane indexes, aggregating mean/max/min statistics of rasters, timeseries aggregation); - **FarmAI**: composed workflows (data ingestion + processing) whose outputs enable FarmAI scenarios (e.g., predicting conservation practices, estimating soil carbon sequestration, identifying methane leakage); +- **ForestAI**: composed workflows (data ingestion + processing) whose outputs enable ForestAI scenarios (e.g., detecting forest change, estimating forest extent); - **ML**: machine learning-related workflows to train, evaluate, and infer models within the FarmVibes.AI platform (e.g., dataset creation, inference); For a list of all available workflows within the FarmVibes.AI platform, please diff --git a/docs/source/docfiles/markdown/WORKFLOW_LIST.md b/docs/source/docfiles/markdown/WORKFLOW_LIST.md index eca05337..473d9a7e 100644 --- a/docs/source/docfiles/markdown/WORKFLOW_LIST.md +++ b/docs/source/docfiles/markdown/WORKFLOW_LIST.md @@ -6,6 +6,7 @@ We group FarmVibes.AI workflows in the following categories: This includes raw data sources (e.g., Sentinel 1 and 2, LandSat, CropDataLayer) as well as the SpaceEye cloud-removal model; - **Data Processing**: workflows that transform data into different data types (e.g., computing NDVI/MSAVI/Methane indexes, aggregating mean/max/min statistics of rasters, timeseries aggregation); - **FarmAI**: composed workflows (data ingestion + processing) whose outputs enable FarmAI scenarios (e.g., predicting conservation practices, estimating soil carbon sequestration, identifying methane leakage); +- **ForestAI**: composed workflows (data ingestion + processing) whose outputs enable ForestAI scenarios (e.g., detecting forest change, estimating forest extent); - **ML**: machine learning-related workflows to train, evaluate, and infer models within the FarmVibes.AI platform (e.g., dataset creation, inference); Below is a list of all available workflows within the FarmVibes.AI platform. For each of them, we provide a brief description and a link to the corresponding documentation page. @@ -44,6 +45,8 @@ Below is a list of all available workflows within the FarmVibes.AI platform. For - [`gnatsgo/download_gnatsgo` 📄](workflow_yaml/data_ingestion/gnatsgo/download_gnatsgo.md): Downloads gNATSGO raster data that intersect with the input geometry and time range. +- [`hansen/hansen_forest_change_download` 📄](workflow_yaml/data_ingestion/hansen/hansen_forest_change_download.md): Downloads and merges Global Forest Change (Hansen) rasters that intersect the user-provided geometry/time range. + - [`landsat/preprocess_landsat` 📄](workflow_yaml/data_ingestion/landsat/preprocess_landsat.md): Downloads and preprocesses LANDSAT tiles that intersect with the input geometry and time range. - [`modis/download_modis_surface_reflectance` 📄](workflow_yaml/data_ingestion/modis/download_modis_surface_reflectance.md): Downloads MODIS 8-day surface reflectance rasters that intersect with the input geometry and time range. @@ -56,8 +59,6 @@ Below is a list of all available workflows within the FarmVibes.AI platform. For - [`sentinel1/preprocess_s1` 📄](workflow_yaml/data_ingestion/sentinel1/preprocess_s1.md): Downloads and preprocesses tiles of Sentinel-1 imagery that intersect with the input Sentinel-2 products in the input time range. -- [`sentinel1/preprocess_s1_rtc` 📄](workflow_yaml/data_ingestion/sentinel1/preprocess_s1_rtc.md): Downloads and preprocesses tiles of Sentinel-1 imagery that intersect with the input Sentinel-2 products in the input time range. - - [`sentinel2/cloud_ensemble` 📄](workflow_yaml/data_ingestion/sentinel2/cloud_ensemble.md): Computes the cloud probability of a Sentinel-2 L2A raster using an ensemble of five cloud segmentation models. - [`sentinel2/improve_cloud_mask` 📄](workflow_yaml/data_ingestion/sentinel2/improve_cloud_mask.md): Improves cloud masks by merging the product cloud mask with cloud and shadow masks computed by machine learning segmentation models. @@ -180,6 +181,13 @@ Below is a list of all available workflows within the FarmVibes.AI platform. For - [`water/irrigation_classification` 📄](workflow_yaml/farm_ai/water/irrigation_classification.md): Develops 30m pixel-wise irrigation probability map. +## forest_ai + +- [`deforestation/alos_trend_detection` 📄](workflow_yaml/forest_ai/deforestation/alos_trend_detection.md): Detects increase/decrease trends in forest pixel levels over the user-input geometry and time range for the ALOS forest map. + +- [`deforestation/ordinal_trend_detection` 📄](workflow_yaml/forest_ai/deforestation/ordinal_trend_detection.md): Detects increase/decrease trends in the pixel levels over the user-input geometry and time range. + + ## ml - [`crop_segmentation` 📄](workflow_yaml/ml/crop_segmentation.md): Runs a crop segmentation model based on NDVI from SpaceEye imagery along the year. @@ -188,4 +196,8 @@ Below is a list of all available workflows within the FarmVibes.AI platform. For - [`driveway_detection` 📄](workflow_yaml/ml/driveway_detection.md): Detects driveways in front of houses. +- [`segment_anything/basemap_prompt_segmentation` 📄](workflow_yaml/ml/segment_anything/basemap_prompt_segmentation.md): Runs Segment Anything Model (SAM) over BingMaps basemap rasters with points and/or bounding boxes as prompts. + +- [`segment_anything/s2_prompt_segmentation` 📄](workflow_yaml/ml/segment_anything/s2_prompt_segmentation.md): Runs Segment Anything Model (SAM) over Sentinel-2 rasters with points and/or bounding boxes as prompts. + diff --git a/docs/source/docfiles/markdown/data_types_diagram/core_types_hierarchy.md b/docs/source/docfiles/markdown/data_types_diagram/core_types_hierarchy.md index c9fb1b1b..45f7fbfd 100644 --- a/docs/source/docfiles/markdown/data_types_diagram/core_types_hierarchy.md +++ b/docs/source/docfiles/markdown/data_types_diagram/core_types_hierarchy.md @@ -28,10 +28,14 @@ classDiagram } class GeometryCollection { } + class OrdinalTrendTest { + } class ProteinSequence { } class PydanticAssetVibe { } + class RasterPixelCount { + } class TimeSeries { } class Tmp { @@ -54,7 +58,9 @@ classDiagram GHGFlux --|> DataVibe GHGProtocolVibe --|> DataVibe GeometryCollection --|> DataVibe + OrdinalTrendTest --|> DataVibe ProteinSequence --|> DataVibe + RasterPixelCount --|> DataVibe TimeSeries --|> DataVibe UnresolvedDataVibe --|> BaseVibe diff --git a/docs/source/docfiles/markdown/data_types_diagram/farm_hierarchy.md b/docs/source/docfiles/markdown/data_types_diagram/farm_hierarchy.md index 9b058cec..2deb78fb 100644 --- a/docs/source/docfiles/markdown/data_types_diagram/farm_hierarchy.md +++ b/docs/source/docfiles/markdown/data_types_diagram/farm_hierarchy.md @@ -6,6 +6,12 @@ classDiagram } class DataVibe { } + class ADMAgPrescription { + } + class ADMAgPrescriptionInput { + } + class ADMAgPrescriptionMapInput { + } class ADMAgSeasonalFieldInput { } class FertilizerInformation { @@ -19,6 +25,9 @@ classDiagram class TillageInformation { } DataVibe --|> BaseVibe + ADMAgPrescription --|> BaseVibe + ADMAgPrescriptionInput --|> BaseVibe + ADMAgPrescriptionMapInput --|> BaseVibe ADMAgSeasonalFieldInput --|> BaseVibe SeasonalFieldInformation --|> DataVibe diff --git a/docs/source/docfiles/markdown/data_types_diagram/products_hierarchy.md b/docs/source/docfiles/markdown/data_types_diagram/products_hierarchy.md index 12db2fde..e90cd707 100644 --- a/docs/source/docfiles/markdown/data_types_diagram/products_hierarchy.md +++ b/docs/source/docfiles/markdown/data_types_diagram/products_hierarchy.md @@ -28,6 +28,8 @@ classDiagram } class GNATSGOProduct { } + class HansenProduct { + } class HerbieProduct { } class LandsatProduct { @@ -48,6 +50,7 @@ classDiagram GEDIProduct --|> DataVibe GLADProduct --|> DataVibe GNATSGOProduct --|> DataVibe + HansenProduct --|> DataVibe HerbieProduct --|> DataVibe LandsatProduct --|> DataVibe ModisProduct --|> DataVibe diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/admag/admag_seasonal_field.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/admag/admag_seasonal_field.md index 02e04341..d9f5206f 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/admag/admag_seasonal_field.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/admag/admag_seasonal_field.md @@ -1,5 +1,42 @@ # data_ingestion/admag/admag_seasonal_field +Generates SeasonalFieldInformation using ADMAg (Microsoft Azure Data Manager for Agriculture). The workflow creates a DataVibe subclass SeasonalFieldInformation that contains farm-related operations (e.g., fertilization, harvest, tillage, planting, crop name). + +```{mermaid} + graph TD + inp1>admag_input] + out1>seasonal_field] + tsk1{{admag_seasonal_field}} + inp1>admag_input] -- admag_input --> tsk1{{admag_seasonal_field}} + tsk1{{admag_seasonal_field}} -- seasonal_field --> out1>seasonal_field] +``` + +## Sources + +- **admag_input**: Unique identifiers for ADMAg seasonal field, and party. + +## Sinks + +- **seasonal_field**: Crop SeasonalFieldInformation which contains SeasonalFieldInformation that contains farm-related operations (e.g., fertilization, harvest, tillage, planting, crop name). + +## Parameters + +- **base_url**: Azure Data Manager for Agriculture host. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +- **client_id**: Azure Data Manager for Agriculture client id. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +- **client_secret**: Azure Data Manager for Agriculture client secret. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +- **authority**: Azure Data Manager for Agriculture authority. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +- **default_scope**: Azure Data Manager for Agriculture default scope. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +## Tasks + +- **admag_seasonal_field**: Establishes the connection with ADMAg and fetches seasonal field information. + +## Workflow Yaml + ```yaml name: admag_seasonal_field @@ -31,7 +68,7 @@ description: that contains farm-related operations (e.g., fertilization, harvest, tillage, planting, crop name). sources: - admag_input: Unique identifiers for ADMAg seasonal field, boundary, and farmer. + admag_input: Unique identifiers for ADMAg seasonal field, and party. sinks: seasonal_field: Crop SeasonalFieldInformation which contains SeasonalFieldInformation that contains farm-related operations (e.g., fertilization, harvest, tillage, @@ -49,13 +86,4 @@ description: https://aka.ms/farmvibesDMA to check how to get these credentials. -``` - -```{mermaid} - graph TD - inp1>admag_input] - out1>seasonal_field] - tsk1{{admag_seasonal_field}} - inp1>admag_input] -- admag_input --> tsk1{{admag_seasonal_field}} - tsk1{{admag_seasonal_field}} -- seasonal_field --> out1>seasonal_field] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/admag/prescriptions.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/admag/prescriptions.md index d4ebeecf..bf21c61c 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/admag/prescriptions.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/admag/prescriptions.md @@ -1,10 +1,57 @@ # data_ingestion/admag/prescriptions +Fetches prescriptions using ADMAg (Microsoft Azure Data Manager for Agriculture). The workflow fetch prescriptions (sensor samples) linked to prescription_map_id. Each sensor sample have the information of nutrient (Nitrogen, Carbon, Phosphorus, pH, Latitude, Longitude etc., ). The Latitude & Longitude used to create a point geometry. Geometry and nutrient information transformed to GeoJSON. The GeoJSON stored as asset in farmvibes-ai. + +```{mermaid} + graph TD + inp1>admag_input] + out1>response] + tsk1{{list_prescriptions}} + tsk2{{get_prescription}} + tsk3{{admag_prescriptions}} + tsk1{{list_prescriptions}} -- prescriptions/prescription_without_geom_input --> tsk2{{get_prescription}} + tsk2{{get_prescription}} -- prescription_with_geom/prescriptions_with_geom_input --> tsk3{{admag_prescriptions}} + inp1>admag_input] -- admag_input --> tsk1{{list_prescriptions}} + inp1>admag_input] -- admag_input --> tsk3{{admag_prescriptions}} + tsk3{{admag_prescriptions}} -- response --> out1>response] +``` + +## Sources + +- **admag_input**: Required inputs to access ADMAg resources, party_id and prescription_map_id that helps fetching prescriptions. + +## Sinks + +- **response**: Prescriptions received from ADMAg. + +## Parameters + +- **base_url**: URL to access the registered app. Refer this url to create required resources for admag. https://learn.microsoft.com/en-us/azure/data-manager-for-agri/quickstart-install-data-manager-for-agriculture + +- **client_id**: Value uniquely identifies registered application in the Microsoft identity platform. Visit url https://learn.microsoft.com/en-us/azure/data-manager-for-agri/quickstart-install-data-manager-for-agriculture to register the app. + +- **client_secret**: Sometimes called an application password, a client secret is a string value your app can use in place of a certificate to identity itself. + +- **authority**: The endpoint URIs for your app are generated automatically when you register or configure your app. It is used by client to obtain authorization from the resource owner + +- **default_scope**: URL for default azure OAuth2 permissions + +## Tasks + +- **list_prescriptions**: List available prescriptions using prescription map. + +- **get_prescription**: Get prescription using ADMAg API. + +- **admag_prescriptions**: Downloads boundary and prescriptions linked to seasonal field from ADMAg data source. + +## Workflow Yaml + ```yaml name: admag_prescritpions sources: admag_input: + - list_prescriptions.admag_input - admag_prescriptions.admag_input sinks: response: admag_prescriptions.response @@ -15,6 +62,24 @@ parameters: authority: null default_scope: null tasks: + list_prescriptions: + op: list_prescriptions + op_dir: admag + parameters: + base_url: '@from(base_url)' + client_id: '@from(client_id)' + client_secret: '@from(client_secret)' + authority: '@from(authority)' + default_scope: '@from(default_scope)' + get_prescription: + op: get_prescription + op_dir: admag + parameters: + base_url: '@from(base_url)' + client_id: '@from(client_id)' + client_secret: '@from(client_secret)' + authority: '@from(authority)' + default_scope: '@from(default_scope)' admag_prescriptions: op: prescriptions op_dir: admag @@ -24,6 +89,13 @@ tasks: client_secret: '@from(client_secret)' authority: '@from(authority)' default_scope: '@from(default_scope)' +edges: +- origin: list_prescriptions.prescriptions + destination: + - get_prescription.prescription_without_geom_input +- origin: get_prescription.prescription_with_geom + destination: + - admag_prescriptions.prescriptions_with_geom_input description: short_description: Fetches prescriptions using ADMAg (Microsoft Azure Data Manager for Agriculture). @@ -33,7 +105,7 @@ description: geometry. Geometry and nutrient information transformed to GeoJSON. The GeoJSON stored as asset in farmvibes-ai. sources: - admag_input: Required inputs to access ADMAg resources, farmer_id and prescription_map_id + admag_input: Required inputs to access ADMAg resources, party_id and prescription_map_id that helps fetching prescriptions. sinks: response: Prescriptions received from ADMAg. @@ -51,13 +123,4 @@ description: default_scope: URL for default azure OAuth2 permissions -``` - -```{mermaid} - graph TD - inp1>admag_input] - out1>response] - tsk1{{admag_prescriptions}} - inp1>admag_input] -- admag_input --> tsk1{{admag_prescriptions}} - tsk1{{admag_prescriptions}} -- response --> out1>response] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/airbus/airbus_download.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/airbus/airbus_download.md index 81d7c27a..f3338809 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/airbus/airbus_download.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/airbus/airbus_download.md @@ -1,5 +1,38 @@ # data_ingestion/airbus/airbus_download +Downloads available AirBus imagery for the input geometry and time range. The workflow will check available imagery, using the AirBus API, that contains the input geometry and inside the input time range. Matching images will be purchased (if they are not already in the user's library) and downloaded. This workflow requires an AirBus API key. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- airbus_products --> tsk2{{download}} + inp1>user_input] -- input_item --> tsk1{{list}} + tsk2{{download}} -- downloaded_products --> out1>raster] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: AirBus raster. + +## Parameters + +- **api_key**: AirBus API key. Required to run the workflow. + +## Tasks + +- **list**: Lists available AirBus products for the input geometry and time range. + +- **download**: Downloads the AirBus imagery from the listed product. + +## Workflow Yaml + ```yaml name: airbus_download @@ -38,15 +71,4 @@ description: api_key: AirBus API key. Required to run the workflow. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- airbus_products --> tsk2{{download}} - inp1>user_input] -- input_item --> tsk1{{list}} - tsk2{{download}} -- downloaded_products --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/airbus/airbus_price.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/airbus/airbus_price.md index fe025d19..ac6ac4f8 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/airbus/airbus_price.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/airbus/airbus_price.md @@ -1,5 +1,38 @@ # data_ingestion/airbus/airbus_price +Prices available AirBus imagery for the input geometry and time range. The workflow will check available imagery, using the AirBus API, that contains the input geometry inside the input time range. The aggregate price (in kB) for matching images will be computed, discounting images already in the user's library. This workflow requires an AirBus API key. + +```{mermaid} + graph TD + inp1>user_input] + out1>price] + tsk1{{list}} + tsk2{{price}} + tsk1{{list}} -- airbus_products --> tsk2{{price}} + inp1>user_input] -- input_item --> tsk1{{list}} + tsk2{{price}} -- products_price --> out1>price] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **price**: Price for all matching imagery. + +## Parameters + +- **api_key**: AirBus API key. Required to run the workflow. + +## Tasks + +- **list**: Lists available AirBus products for the input geometry and time range. + +- **price**: Calculates the aggregate price (in kB) for selected AirBus images, discounting images already in the user's library. + +## Workflow Yaml + ```yaml name: airbus_price @@ -38,15 +71,4 @@ description: api_key: AirBus API key. Required to run the workflow. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>price] - tsk1{{list}} - tsk2{{price}} - tsk1{{list}} -- airbus_products --> tsk2{{price}} - inp1>user_input] -- input_item --> tsk1{{list}} - tsk2{{price}} -- products_price --> out1>price] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/alos/alos_forest_extent_download.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/alos/alos_forest_extent_download.md index 0094a816..9e544b44 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/alos/alos_forest_extent_download.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/alos/alos_forest_extent_download.md @@ -1,5 +1,38 @@ # data_ingestion/alos/alos_forest_extent_download +Downloads Advanced Land Observing Satellite (ALOS) forest/non-forest classification map. The workflow lists all ALOS forest/non-forest classification products that intersect with the input geometry and time range (available range 2015-2020), then downloads the data for each of them. The data will be returned in the form of rasters. + +```{mermaid} + graph TD + inp1>user_input] + out1>downloaded_product] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- alos_products/product --> tsk2{{download}} + inp1>user_input] -- input_data --> tsk1{{list}} + tsk2{{download}} -- raster --> out1>downloaded_product] +``` + +## Sources + +- **user_input**: Geometry of interest for which to download the ALOS forest/non-forest classification map. + +## Sinks + +- **downloaded_product**: Downloaded ALOS forest/non-forest classification map. + +## Parameters + +- **pc_key**: Planetary computer API key. + +## Tasks + +- **list**: Lists ALOS forest products for input geometry and time range. + +- **download**: Downloads Advanced Land Observing Satellite (ALOS) forest/non-forest classification map. + +## Workflow Yaml + ```yaml name: alos_forest_extent_download @@ -35,15 +68,4 @@ description: downloaded_product: Downloaded ALOS forest/non-forest classification map. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>downloaded_product] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- alos_products/product --> tsk2{{download}} - inp1>user_input] -- input_data --> tsk1{{list}} - tsk2{{download}} -- raster --> out1>downloaded_product] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/alos/alos_forest_extent_download_merge.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/alos/alos_forest_extent_download_merge.md index 427c31ad..046e46b5 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/alos/alos_forest_extent_download_merge.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/alos/alos_forest_extent_download_merge.md @@ -1,5 +1,46 @@ # data_ingestion/alos/alos_forest_extent_download_merge +Downloads Advanced Land Observing Satellite (ALOS) forest/non-forest classification map and merges it into a single raster. The workflow lists the ALOS forest/non-forest classification products that intersect with the input geometry and time range (available range 2015-2020), and downloads the filtered products. The workflow processes the downloaded products and merge them into a single raster. + +```{mermaid} + graph TD + inp1>user_input] + out1>merged_raster] + out2>categorical_raster] + tsk1{{alos_forest_extent_download}} + tsk2{{group_rasters_by_time}} + tsk3{{merge}} + tsk1{{alos_forest_extent_download}} -- downloaded_product/rasters --> tsk2{{group_rasters_by_time}} + tsk2{{group_rasters_by_time}} -- raster_groups/raster_sequence --> tsk3{{merge}} + inp1>user_input] -- user_input --> tsk1{{alos_forest_extent_download}} + tsk3{{merge}} -- raster --> out1>merged_raster] + tsk1{{alos_forest_extent_download}} -- downloaded_product --> out2>categorical_raster] +``` + +## Sources + +- **user_input**: Geometry of interest for which to download the ALOS forest/non-forest classification map. + +## Sinks + +- **merged_raster**: ALOS forest/non-forest classification products converted to raster and merged. + +- **categorical_raster**: ALOS forest/non-forest classification products that intersect with the input geometry & time range. + +## Parameters + +- **pc_key**: Planetary computer API key. + +## Tasks + +- **alos_forest_extent_download**: Downloads Advanced Land Observing Satellite (ALOS) forest/non-forest classification map. + +- **group_rasters_by_time**: This op groups rasters in time according to 'criterion'. + +- **merge**: Merges rasters in a sequence to a single raster. + +## Workflow Yaml + ```yaml name: alos_forest_extent_download_merge @@ -48,19 +89,4 @@ description: pc_key: Planetary computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>merged_raster] - out2>categorical_raster] - tsk1{{alos_forest_extent_download}} - tsk2{{group_rasters_by_time}} - tsk3{{merge}} - tsk1{{alos_forest_extent_download}} -- downloaded_product/rasters --> tsk2{{group_rasters_by_time}} - tsk2{{group_rasters_by_time}} -- raster_groups/raster_sequence --> tsk3{{merge}} - inp1>user_input] -- user_input --> tsk1{{alos_forest_extent_download}} - tsk3{{merge}} -- raster --> out1>merged_raster] - tsk1{{alos_forest_extent_download}} -- downloaded_product --> out2>categorical_raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/bing/basemap_download.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/bing/basemap_download.md index 881d3632..9f30f0db 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/bing/basemap_download.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/bing/basemap_download.md @@ -1,5 +1,40 @@ # data_ingestion/bing/basemap_download +Downloads Bing Maps basemaps. The workflow will list all tiles intersecting with the input geometry for a given zoom level and download a basemap for each of them using Bing Maps API. The basemap tiles will be returned as individual rasters. + +```{mermaid} + graph TD + inp1>input_geometry] + out1>basemaps] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- products/input_product --> tsk2{{download}} + inp1>input_geometry] -- user_input --> tsk1{{list}} + tsk2{{download}} -- basemap --> out1>basemaps] +``` + +## Sources + +- **input_geometry**: Geometry of interest for which to download the basemap tiles. + +## Sinks + +- **basemaps**: Downloaded basemaps. + +## Parameters + +- **api_key**: Required BingMaps API key. + +- **zoom_level**: Zoom level of interest, ranging from 0 to 20. For instance, a zoom level of 1 corresponds to a resolution of 78271.52 m/pixel, a zoom level of 10 corresponds to 152.9 m/pixel, and a zoom level of 19 corresponds to 0.3 m/pixel. For more information on zoom levels and their corresponding scale and resolution, please refer to the BingMaps API documentation at https://learn.microsoft.com/en-us/bingmaps/articles/understanding-scale-and-resolution + +## Tasks + +- **list**: Lists BingMaps basemap tile products intersecting the input geometry for a given `zoom_level`. + +- **download**: Downloads a basemap tile represented by a BingMapsProduct using BingMapsAPI. + +## Workflow Yaml + ```yaml name: basemap_download @@ -36,15 +71,4 @@ description: basemaps: Downloaded basemaps. -``` - -```{mermaid} - graph TD - inp1>input_geometry] - out1>basemaps] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- products/input_product --> tsk2{{download}} - inp1>input_geometry] -- user_input --> tsk1{{list}} - tsk2{{download}} -- basemap --> out1>basemaps] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/bing/basemap_download_merge.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/bing/basemap_download_merge.md index 1ad37192..121723af 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/bing/basemap_download_merge.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/bing/basemap_download_merge.md @@ -1,5 +1,46 @@ # data_ingestion/bing/basemap_download_merge +Downloads Bing Maps basemap tiles and merges them into a single raster. The workflow will list all tiles intersecting with the input geometry for a given zoom level, and download a basemap for each of them using Bing Maps API. The basemaps will be merged into a single raster with the union of the geometries of all tiles. + +```{mermaid} + graph TD + inp1>input_geometry] + out1>merged_basemap] + tsk1{{basemap_download}} + tsk2{{to_sequence}} + tsk3{{merge}} + tsk1{{basemap_download}} -- basemaps/list_rasters --> tsk2{{to_sequence}} + tsk2{{to_sequence}} -- rasters_seq/raster_sequence --> tsk3{{merge}} + inp1>input_geometry] -- input_geometry --> tsk1{{basemap_download}} + tsk3{{merge}} -- raster --> out1>merged_basemap] +``` + +## Sources + +- **input_geometry**: Geometry of interest for which to download the basemap tiles. + +## Sinks + +- **merged_basemap**: Merged basemap raster. + +## Parameters + +- **api_key**: Required BingMaps API key. + +- **zoom_level**: Zoom level of interest, ranging from 0 to 20. For instance, a zoom level of 1 corresponds to a resolution of 78271.52 m/pixel, a zoom level of 10 corresponds to 152.9 m/pixel, and a zoom level of 19 corresponds to 0.3 m/pixel. For more information on zoom levels and their corresponding scale and resolution, please refer to the BingMaps API documentation at https://learn.microsoft.com/en-us/bingmaps/articles/understanding-scale-and-resolution + +- **merge_resolution**: Determines how the resolution of the output raster is defined. One of 'equal' (breaks if the resolution of the sequence rasters are not the same), 'lowest' (uses the lowest resolution among rasters), 'highest' (uses the highest resolution among rasters), or 'average' (averages the resolution of all rasters in the sequence). + +## Tasks + +- **basemap_download**: Downloads Bing Maps basemaps. + +- **to_sequence**: Combines a list of Rasters into a RasterSequence. + +- **merge**: Merges rasters in a sequence to a single raster. + +## Workflow Yaml + ```yaml name: basemap_download_merge @@ -44,17 +85,4 @@ description: merged_basemap: Merged basemap raster. -``` - -```{mermaid} - graph TD - inp1>input_geometry] - out1>merged_basemap] - tsk1{{basemap_download}} - tsk2{{to_sequence}} - tsk3{{merge}} - tsk1{{basemap_download}} -- basemaps/list_rasters --> tsk2{{to_sequence}} - tsk2{{to_sequence}} -- rasters_seq/raster_sequence --> tsk3{{merge}} - inp1>input_geometry] -- input_geometry --> tsk1{{basemap_download}} - tsk3{{merge}} -- raster --> out1>merged_basemap] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/cdl/download_cdl.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/cdl/download_cdl.md index aa4d0424..1f844998 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/cdl/download_cdl.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/cdl/download_cdl.md @@ -1,5 +1,34 @@ # data_ingestion/cdl/download_cdl +Downloads crop classes maps in the continental USA for the input time range. The workflow will download crop-specific land cover maps from the USDA Cropland Data Layer, available for the continental United States. The input geometry must intersect with the coverage area. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{list_cdl}} + tsk2{{download_cdl}} + tsk1{{list_cdl}} -- cdl_products/input_product --> tsk2{{download_cdl}} + inp1>user_input] -- input_item --> tsk1{{list_cdl}} + tsk2{{download_cdl}} -- cdl_raster --> out1>raster] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: CDL land cover raster. + +## Tasks + +- **list_cdl**: Lists all years for the input time range and creates a product for each of them to be downloaded. + +- **download_cdl**: Downloads a CategoricalRaster from a CDLProduct. + +## Workflow Yaml + ```yaml name: download_cdl @@ -30,15 +59,4 @@ description: raster: CDL land cover raster. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{list_cdl}} - tsk2{{download_cdl}} - tsk1{{list_cdl}} -- cdl_products/input_product --> tsk2{{download_cdl}} - inp1>user_input] -- input_item --> tsk1{{list_cdl}} - tsk2{{download_cdl}} -- cdl_raster --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/dem/download_dem.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/dem/download_dem.md index 2ab1eca9..57419d31 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/dem/download_dem.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/dem/download_dem.md @@ -1,5 +1,42 @@ # data_ingestion/dem/download_dem +Downloads digital elevation map tiles that intersect with the input geometry and time range. The workflow will download digital elevation maps from the USGS 3DEP datasets (available for the United States at 10 and 30 meters) or Copernicus DEM GLO-30 (globally at 30 meters) through the Planetary Computer. For more information, see https://planetarycomputer.microsoft.com/dataset/3dep-seamless and https://planetarycomputer.microsoft.com/dataset/cop-dem-glo-30 . + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- dem_products/input_product --> tsk2{{download}} + inp1>user_input] -- input_items --> tsk1{{list}} + tsk2{{download}} -- downloaded_product --> out1>raster] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: DEM raster. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +- **resolution**: Spatial resolution of the DEM. 10m and 30m are available. + +- **provider**: Provider of the DEM. "USGS3DEP" and "CopernicusDEM30" are available. + +## Tasks + +- **list**: Lists digital elevation map tiles that intersect with the input geometry and time range. + +- **download**: Downloads digital elevation map raster given a DemProduct. + +## Workflow Yaml + ```yaml name: download_dem @@ -44,15 +81,4 @@ description: provider: Provider of the DEM. "USGS3DEP" and "CopernicusDEM30" are available. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- dem_products/input_product --> tsk2{{download}} - inp1>user_input] -- input_items --> tsk1{{list}} - tsk2{{download}} -- downloaded_product --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gedi/download_gedi.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gedi/download_gedi.md index dbd2eb0c..17cc5147 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gedi/download_gedi.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gedi/download_gedi.md @@ -1,5 +1,40 @@ # data_ingestion/gedi/download_gedi +Downloads GEDI products for the input region and time range. The workflow downloads Global Ecosystem Dynamics Investigation (GEDI) products at the desired processing level using NASA's EarthData API. This workflow requires an EarthData API token. + +```{mermaid} + graph TD + inp1>user_input] + out1>product] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- gedi_products/gedi_product --> tsk2{{download}} + inp1>user_input] -- input_data --> tsk1{{list}} + tsk2{{download}} -- downloaded_product --> out1>product] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **product**: GEDI products. + +## Parameters + +- **earthdata_token**: API token for the EarthData platform. Required to run the workflow. + +- **processing_level**: GEDI product processing level. One of 'GEDI01_B.002', 'GEDI02_A.002', 'GEDI02_B.002'. + +## Tasks + +- **list**: Lists GEDI Products from NASA's EarthData API. + +- **download**: Downloads GEDI products. + +## Workflow Yaml + ```yaml name: download_gedi @@ -39,15 +74,4 @@ description: 'GEDI02_B.002'. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>product] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- gedi_products/gedi_product --> tsk2{{download}} - inp1>user_input] -- input_data --> tsk1{{list}} - tsk2{{download}} -- downloaded_product --> out1>product] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gedi/download_gedi_rh100.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gedi/download_gedi_rh100.md index 15563e8d..a77db935 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gedi/download_gedi_rh100.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gedi/download_gedi_rh100.md @@ -1,5 +1,41 @@ # data_ingestion/gedi/download_gedi_rh100 +Downloads L2B GEDI products and extracts RH100 variables. The workflow will download the products for the input region and time range, and then extract RH100 variables for each of the beam shots. Each value is geolocated according to the lowest mode latitude and longitude values. + +```{mermaid} + graph TD + inp1>user_input] + out1>rh100] + tsk1{{download}} + tsk2{{extract}} + tsk1{{download}} -- product/gedi_product --> tsk2{{extract}} + inp1>user_input] -- user_input --> tsk1{{download}} + inp1>user_input] -- roi --> tsk2{{extract}} + tsk2{{extract}} -- rh100 --> out1>rh100] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **rh100**: Points in EPSG:4326 with their associated RH100 values. + +## Parameters + +- **earthdata_token**: API token for the EarthData platform. Required to run the workflow. + +- **check_quality**: Whether to filter points according to the quality flag. + +## Tasks + +- **download**: Downloads GEDI products for the input region and time range. + +- **extract**: Extracts RH100 variables within the region of interest of a GEDIProduct. + +## Workflow Yaml + ```yaml name: download_gedi_rh100 @@ -38,16 +74,4 @@ description: check_quality: Whether to filter points according to the quality flag. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>rh100] - tsk1{{download}} - tsk2{{extract}} - tsk1{{download}} -- product/gedi_product --> tsk2{{extract}} - inp1>user_input] -- user_input --> tsk1{{download}} - inp1>user_input] -- roi --> tsk2{{extract}} - tsk2{{extract}} -- rh100 --> out1>rh100] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/glad/glad_forest_extent_download.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/glad/glad_forest_extent_download.md index 6c3d7e41..cc0bf726 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/glad/glad_forest_extent_download.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/glad/glad_forest_extent_download.md @@ -1,5 +1,34 @@ # data_ingestion/glad/glad_forest_extent_download +Downloads Global Land Analysis (GLAD) forest extent data. The workflow will list all GLAD forest extent products that intersect with the input geometry and download the data for each of them. The data will be returned as rasters. + +```{mermaid} + graph TD + inp1>input_item] + out1>downloaded_product] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- glad_products/glad_product --> tsk2{{download}} + inp1>input_item] -- input_item --> tsk1{{list}} + tsk2{{download}} -- downloaded_product --> out1>downloaded_product] +``` + +## Sources + +- **input_item**: Geometry of interest for which to download the GLAD forest extent data. + +## Sinks + +- **downloaded_product**: Downloaded GLAD forest extent product. + +## Tasks + +- **list**: Lists Global Land Analysis (GLAD) forest products that intersect the user-provided geometry/time range. + +- **download**: Downloads a GLADProduct + +## Workflow Yaml + ```yaml name: glad_forest_extent_download @@ -31,15 +60,4 @@ description: downloaded_product: Downloaded GLAD forest extent product. -``` - -```{mermaid} - graph TD - inp1>input_item] - out1>downloaded_product] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- glad_products/glad_product --> tsk2{{download}} - inp1>input_item] -- input_item --> tsk1{{list}} - tsk2{{download}} -- downloaded_product --> out1>downloaded_product] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/glad/glad_forest_extent_download_merge.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/glad/glad_forest_extent_download_merge.md index 4f3a5dfd..ccb0fc8b 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/glad/glad_forest_extent_download_merge.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/glad/glad_forest_extent_download_merge.md @@ -1,5 +1,42 @@ # data_ingestion/glad/glad_forest_extent_download_merge +Downloads the tiles from Global Land Analysis (GLAD) forest data that intersect with the user input geometry and time range, and merges them into a single raster. The workflow lists the GLAD forest products that intersect with the input geometry and time range, and downloads the filtered products. The downloaded products are merged into a single raster and classified. The result tiles have pixel values categorized into two classes - 0 (non-forest) and 1 (forest). This workflow uses the same forest definition as the Food and Agriculture Organization of the United Nations (FAO). + +```{mermaid} + graph TD + inp1>input_item] + out1>merged_product] + out2>categorical_raster] + tsk1{{glad_forest_extent_download}} + tsk2{{group_rasters_by_time}} + tsk3{{merge}} + tsk1{{glad_forest_extent_download}} -- downloaded_product/rasters --> tsk2{{group_rasters_by_time}} + tsk2{{group_rasters_by_time}} -- raster_groups/raster_sequence --> tsk3{{merge}} + inp1>input_item] -- input_item --> tsk1{{glad_forest_extent_download}} + tsk3{{merge}} -- raster --> out1>merged_product] + tsk1{{glad_forest_extent_download}} -- downloaded_product --> out2>categorical_raster] +``` + +## Sources + +- **input_item**: Geometry of interest for which to download the GLAD forest extent data. + +## Sinks + +- **merged_product**: Merged GLAD forest extent product to geometry of interest. + +- **categorical_raster**: Raster with the GLAD forest extent data. + +## Tasks + +- **glad_forest_extent_download**: Downloads Global Land Analysis (GLAD) forest extent data. + +- **group_rasters_by_time**: This op groups rasters in time according to 'criterion'. + +- **merge**: Merges rasters in a sequence to a single raster. + +## Workflow Yaml + ```yaml name: glad_forest_extent_download_merge @@ -44,19 +81,4 @@ description: categorical_raster: Raster with the GLAD forest extent data. -``` - -```{mermaid} - graph TD - inp1>input_item] - out1>merged_product] - out2>categorical_raster] - tsk1{{glad_forest_extent_download}} - tsk2{{group_rasters_by_time}} - tsk3{{merge}} - tsk1{{glad_forest_extent_download}} -- downloaded_product/rasters --> tsk2{{group_rasters_by_time}} - tsk2{{group_rasters_by_time}} -- raster_groups/raster_sequence --> tsk3{{merge}} - inp1>input_item] -- input_item --> tsk1{{glad_forest_extent_download}} - tsk3{{merge}} -- raster --> out1>merged_product] - tsk1{{glad_forest_extent_download}} -- downloaded_product --> out2>categorical_raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gnatsgo/download_gnatsgo.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gnatsgo/download_gnatsgo.md index c54c541b..b0dd9828 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gnatsgo/download_gnatsgo.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/gnatsgo/download_gnatsgo.md @@ -1,5 +1,79 @@ # data_ingestion/gnatsgo/download_gnatsgo +Downloads gNATSGO raster data that intersect with the input geometry and time range. This workflow lists and downloads raster products of gNATSGO dataset from Planetary Computer. Input geometry must fall within Continel USA, whereas input time range can be arbitrary (all gNATSGO assets are from 2020-07-01). For more information on the available properties, see https://planetarycomputer.microsoft.com/dataset/gnatsgo-rasters. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- gnatsgo_products/gnatsgo_product --> tsk2{{download}} + inp1>user_input] -- input_item --> tsk1{{list}} + tsk2{{download}} -- downloaded_raster --> out1>raster] +``` + +## Sources + +- **user_input**: Geometry of interest (arbitrary time range). + +## Sinks + +- **raster**: Raster with desired property. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +- **variable**: Options are: + aws{DEPTH} - Available water storage estimate (AWS) for the DEPTH zone. + soc{DEPTH} - Soil organic carbon stock estimate (SOC) for the DEPTH zone. + tk{DEPTH}a - Thickness of soil components used in the DEPTH zone for the AWS calculation. + tk{DEPTH}s - Thickness of soil components used in the DEPTH zone for the SOC calculation. + mukey - Map unit key, a unique identifier of a record for matching with gNATSGO tables. + droughty - Drought vulnerability estimate. + nccpi3all - National Commodity Crop Productivity Index that has the highest value among Corn +and Soybeans, Small Grains, or Cotton for major earthy components. + nccpi3corn - National Commodity Crop Productivity Index for Corn for major earthy +components. + nccpi3cot - National Commodity Crop Productivity Index for Cotton for major earthy +components. + nccpi3sg - National Commodity Crop Productivity Index for Small Grains for major earthy +components. + nccpi3soy - National Commodity Crop Productivity Index for Soy for major earthy components. + pctearthmc - National Commodity Crop Productivity Index map unit percent earthy is the map +unit summed comppct_r for major earthy components. + pwsl1pomu - Potential Wetland Soil Landscapes (PWSL). + rootznaws - Root zone (commodity crop) available water storage estimate (RZAWS). + rootznemc - Root zone depth is the depth within the soil profile that commodity crop (cc) +roots can effectively extract water and nutrients for growth. + musumcpct - Sum of the comppct_r (SSURGO component table) values for all listed components +in the map unit. + musumcpcta - Sum of the comppct_r (SSURGO component table) values used in the available +water storage calculation for the map unit. + musumcpcts - Sum of the comppct_r (SSURGO component table) values used in the soil organic +carbon calculation for the map unit. +gNATSGO has properties available for multiple soil depths. You may exchange DEPTH in the variable names above for any of the following (all measured in cm): + 0_5 + 0_20 + 0_30 + 5_20 + 0_100 + 0_150 + 0_999 + 20_50 + 50_100 + 100_150 + 150_999 + +## Tasks + +- **list**: Lists gNATSGO products from Planetary Computer that intersect with input geometry. + +- **download**: Downloads the raster asset for 'variable' given a GNATSGO product. + +## Workflow Yaml + ```yaml name: download_gnatsgo @@ -66,15 +140,4 @@ description: \ 0_999\n 20_50\n 50_100\n 100_150\n 150_999" -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- gnatsgo_products/gnatsgo_product --> tsk2{{download}} - inp1>user_input] -- input_item --> tsk1{{list}} - tsk2{{download}} -- downloaded_raster --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/hansen/hansen_forest_change_download.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/hansen/hansen_forest_change_download.md new file mode 100644 index 00000000..1a36c647 --- /dev/null +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/hansen/hansen_forest_change_download.md @@ -0,0 +1,110 @@ +# data_ingestion/hansen/hansen_forest_change_download + +Downloads and merges Global Forest Change (Hansen) rasters that intersect the user-provided geometry/time range. The workflow lists Global Forest Change (Hansen) products that intersect the user-provided geometry/time range, downloads the data for each of them, and merges the rasters. The dataset is available at 30m resolution and is updated annually. The data contains information on forest cover, loss, and gain. The default dataset version is GFC-2022-v1.10 and is passed to the workflow as the parameter tiles_folder_url. For the default version, the dataset is available from 2000 to 2022. Dataset details can be found at https://storage.googleapis.com/earthenginepartners-hansen/GFC-2022-v1.10/download.html. + +```{mermaid} + graph TD + inp1>input_item] + out1>merged_raster] + out2>downloaded_raster] + tsk1{{list}} + tsk2{{download}} + tsk3{{group}} + tsk4{{merge}} + tsk1{{list}} -- hansen_products/hansen_product --> tsk2{{download}} + tsk2{{download}} -- raster/rasters --> tsk3{{group}} + tsk3{{group}} -- raster_groups/raster_sequence --> tsk4{{merge}} + inp1>input_item] -- input_item --> tsk1{{list}} + tsk4{{merge}} -- raster --> out1>merged_raster] + tsk2{{download}} -- raster --> out2>downloaded_raster] +``` + +## Sources + +- **input_item**: User-provided geometry and time range. + +## Sinks + +- **merged_raster**: Merged Global Forest Change (Hansen) data as a raster. + +- **downloaded_raster**: Individual Global Forest Change (Hansen) rasters prior to the merge operation. + +## Parameters + +- **layer_name**: Name of the Global Forest Change (Hansen) layer. Can be any of the following names 'treecover2000', 'loss', 'gain', 'lossyear', 'datamask', 'first', 'last'. + +- **tiles_folder_url**: URL to the Global Forest Change (Hansen) dataset. It specifies the dataset version and is used to download the data. + +## Tasks + +- **list**: Lists Global Forest Change (Hansen) products that intersect the user-provided geometry/time range. + +- **download**: Downloads Global Forest Change (Hansen) data. + +- **group**: This op groups rasters in time according to 'criterion'. + +- **merge**: Merges rasters in a sequence to a single raster. + +## Workflow Yaml + +```yaml + +name: glad_forest_change_download +sources: + input_item: + - list.input_item +sinks: + merged_raster: merge.raster + downloaded_raster: download.raster +parameters: + layer_name: null + tiles_folder_url: https://storage.googleapis.com/earthenginepartners-hansen/GFC-2022-v1.10/ +tasks: + list: + op: list_hansen_products + parameters: + tiles_folder_url: '@from(tiles_folder_url)' + layer_name: '@from(layer_name)' + download: + op: download_hansen + group: + op: group_rasters_by_time + parameters: + criterion: year + merge: + op: merge_rasters +edges: +- origin: list.hansen_products + destination: + - download.hansen_product +- origin: download.raster + destination: + - group.rasters +- origin: group.raster_groups + destination: + - merge.raster_sequence +description: + short_description: Downloads and merges Global Forest Change (Hansen) rasters that + intersect the user-provided geometry/time range. + long_description: The workflow lists Global Forest Change (Hansen) products that + intersect the user-provided geometry/time range, downloads the data for each of + them, and merges the rasters. The dataset is available at 30m resolution and is + updated annually. The data contains information on forest cover, loss, and gain. + The default dataset version is GFC-2022-v1.10 and is passed to the workflow as + the parameter tiles_folder_url. For the default version, the dataset is available + from 2000 to 2022. Dataset details can be found at https://storage.googleapis.com/earthenginepartners-hansen/GFC-2022-v1.10/download.html. + sources: + input_item: User-provided geometry and time range. + sinks: + merged_raster: Merged Global Forest Change (Hansen) data as a raster. + downloaded_raster: Individual Global Forest Change (Hansen) rasters prior to the + merge operation. + parameters: + tiles_folder_url: URL to the Global Forest Change (Hansen) dataset. It specifies + the dataset version and is used to download the data. + layer_name: Name of the Global Forest Change (Hansen) layer. Can be any of the + following names 'treecover2000', 'loss', 'gain', 'lossyear', 'datamask', 'first', + 'last'. + + +``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/landsat/preprocess_landsat.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/landsat/preprocess_landsat.md index ae984f20..0e167384 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/landsat/preprocess_landsat.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/landsat/preprocess_landsat.md @@ -1,5 +1,44 @@ # data_ingestion/landsat/preprocess_landsat +Downloads and preprocesses LANDSAT tiles that intersect with the input geometry and time range. The workflow will download the tile bands from the Planetary Computer and stack them into a single raster at 30m resolution. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{list}} + tsk2{{download}} + tsk3{{stack}} + tsk1{{list}} -- landsat_products/landsat_product --> tsk2{{download}} + tsk2{{download}} -- downloaded_product/landsat_product --> tsk3{{stack}} + inp1>user_input] -- input_item --> tsk1{{list}} + tsk3{{stack}} -- landsat_raster --> out1>raster] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: LANDSAT rasters at 30m resolution. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +- **qa_mask_value**: Bitmap for which pixel to be included. See documentation for each bit in https://www.usgs.gov/media/images/landsat-collection-2-pixel-quality-assessment-bit-index For example, the default value 64 (i.e. 1<<6 ) corresponds to "Clear" pixels + +## Tasks + +- **list**: Lists LANDSAT tiles that intersect with the input geometry and time range. + +- **download**: Downloads LANDSAT tile bands from product. + +- **stack**: Stacks downloaded bands into a single raster. + +## Workflow Yaml + ```yaml name: preprocess_landsat @@ -45,17 +84,4 @@ description: For example, the default value 64 (i.e. 1<<6 ) corresponds to "Clear" pixels -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{list}} - tsk2{{download}} - tsk3{{stack}} - tsk1{{list}} -- landsat_products/landsat_product --> tsk2{{download}} - tsk2{{download}} -- downloaded_product/landsat_product --> tsk3{{stack}} - inp1>user_input] -- input_item --> tsk1{{list}} - tsk3{{stack}} -- landsat_raster --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/modis/download_modis_surface_reflectance.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/modis/download_modis_surface_reflectance.md index 7c8dbd06..8024938d 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/modis/download_modis_surface_reflectance.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/modis/download_modis_surface_reflectance.md @@ -1,5 +1,40 @@ # data_ingestion/modis/download_modis_surface_reflectance +Downloads MODIS 8-day surface reflectance rasters that intersect with the input geometry and time range. The workflow will download MODIS raster images either at 250m or 500m resolution. The products are available at a 8-day interval and pixel values are selected based on low clouds, low view angle, and highest index value. Notice that only bands 1, 2 and quality control are available on 250m. For more information, see https://planetarycomputer.microsoft.com/dataset/modis-09Q1-061 https://planetarycomputer.microsoft.com/dataset/modis-09A1-061 + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- modis_products/product --> tsk2{{download}} + inp1>user_input] -- input_data --> tsk1{{list}} + tsk2{{download}} -- raster --> out1>raster] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: Products containing MODIS reflectance bands and data. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +- **resolution_m**: Product resolution, in meters. Either 250 or 500. + +## Tasks + +- **list**: Lists MODIS 8-day surface reflectance rasters intersecting with the input geometry and time range for desired resolution. + +- **download**: Downloads MODIS surface reflectance rasters. + +## Workflow Yaml + ```yaml name: download_modis_surface_reflectance @@ -41,15 +76,4 @@ description: resolution_m: Product resolution, in meters. Either 250 or 500. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- modis_products/product --> tsk2{{download}} - inp1>user_input] -- input_data --> tsk1{{list}} - tsk2{{download}} -- raster --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/modis/download_modis_vegetation_index.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/modis/download_modis_vegetation_index.md index ca221ee7..1ca2651d 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/modis/download_modis_vegetation_index.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/modis/download_modis_vegetation_index.md @@ -1,5 +1,42 @@ # data_ingestion/modis/download_modis_vegetation_index +Downloads MODIS 16-day vegetation index products that intersect with the input geometry and time range. The workflow will download products at the chosen index and resolution. The products are available at a 16-day interval and pixel values are selected based on low clouds, low view angle, and highest index value. Vegetation index values range from (-2000 to 10000). For more information, see https://planetarycomputer.microsoft.com/dataset/modis-13Q1-061 and https://lpdaac.usgs.gov/products/mod13a1v061/ . + +```{mermaid} + graph TD + inp1>user_input] + out1>index] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- modis_products/product --> tsk2{{download}} + inp1>user_input] -- input_data --> tsk1{{list}} + tsk2{{download}} -- index --> out1>index] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **index**: Products containing the chosen index at the chosen resolution. + +## Parameters + +- **index**: Vegetation index that should be downloaded. Either 'evi' or 'ndvi'. + +- **pc_key**: Optional Planetary Computer API key. + +- **resolution_m**: Product resolution, in meters. Either 250 or 500. + +## Tasks + +- **list**: Lists MODIS vegetation products for input geometry, time range and resolution. + +- **download**: Downloads selected index raster from Modis product. + +## Workflow Yaml + ```yaml name: download_modis_vegetation_index @@ -44,15 +81,4 @@ description: resolution_m: Product resolution, in meters. Either 250 or 500. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>index] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- modis_products/product --> tsk2{{download}} - inp1>user_input] -- input_data --> tsk1{{list}} - tsk2{{download}} -- index --> out1>index] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/naip/download_naip.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/naip/download_naip.md index 915ea69e..ce471e87 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/naip/download_naip.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/naip/download_naip.md @@ -1,5 +1,38 @@ # data_ingestion/naip/download_naip +Downloads NAIP tiles that intersect with the input geometry and time range. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- naip_products/input_product --> tsk2{{download}} + inp1>user_input] -- input_item --> tsk1{{list}} + tsk2{{download}} -- downloaded_product --> out1>raster] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: NAIP tiles. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **list**: Lists Naip tiles that intersect with input geometry and time range. + +- **download**: Downloads Naip raster from Naip product. + +## Workflow Yaml + ```yaml name: download_naip @@ -33,15 +66,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- naip_products/input_product --> tsk2{{download}} - inp1>user_input] -- input_item --> tsk1{{list}} - tsk2{{download}} -- downloaded_product --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/osm_road_geometries.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/osm_road_geometries.md index 0ba4612c..c266c945 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/osm_road_geometries.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/osm_road_geometries.md @@ -1,5 +1,45 @@ # data_ingestion/osm_road_geometries +Downloads road geometry for input region from Open Street Maps. The workflow downloads information from Open Street Maps for the target region and generates geometries for roads that intercept the input region bounding box. + +```{mermaid} + graph TD + inp1>user_input] + out1>roads] + tsk1{{download}} + inp1>user_input] -- input_region --> tsk1{{download}} + tsk1{{download}} -- roads --> out1>roads] +``` + +## Sources + +- **user_input**: List of external references. + +## Sinks + +- **roads**: Geometry collection with road geometries that intercept the input region bounding box. + +## Parameters + +- **network_type**: Type of roads that will be selected. One of: + - 'drive_service': get drivable streets, including service roads. + - 'walk': get all streets and paths that pedestrians can use (this network type ignores + one-way directionality). + - 'bike': get all streets and paths that cyclists can use. + - 'all': download all non-private OSM streets and paths (this is the default network type + unless you specify a different one). + - 'all_private': download all OSM streets and paths, including private-access ones. + - 'drive': get drivable public streets (but not service roads). +For more information see https://osmnx.readthedocs.io/en/stable/index.html. + +- **buffer_size**: Size of buffer, in meters, to search for nodes in OSM. + +## Tasks + +- **download**: Downloads road geometry for input region from Open Street Maps. + +## Workflow Yaml + ```yaml name: osm_road_geometries @@ -40,13 +80,4 @@ description: buffer_size: Size of buffer, in meters, to search for nodes in OSM. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>roads] - tsk1{{download}} - inp1>user_input] -- input_region --> tsk1{{download}} - tsk1{{download}} -- roads --> out1>roads] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel1/preprocess_s1.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel1/preprocess_s1.md index 643f8495..d25e498d 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel1/preprocess_s1.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel1/preprocess_s1.md @@ -1,8 +1,75 @@ # data_ingestion/sentinel1/preprocess_s1 +Downloads and preprocesses tiles of Sentinel-1 imagery that intersect with the input Sentinel-2 products in the input time range. The workflow fetches Sentinel-1 tiles that intersects with the Sentinel-2 products, downloads and preprocesses them, and produces Sentinel-1 rasters in the Sentinel-2 tiling system. + +```{mermaid} + graph TD + inp1>user_input] + inp2>s2_products] + out1>raster] + tsk1{{union}} + tsk2{{merge_geom_tr}} + tsk3{{list}} + tsk4{{filter}} + tsk5{{download}} + tsk6{{tile}} + tsk7{{group}} + tsk8{{merge}} + tsk1{{union}} -- merged/geometry --> tsk2{{merge_geom_tr}} + tsk2{{merge_geom_tr}} -- merged/input_item --> tsk3{{list}} + tsk3{{list}} -- sentinel_products/items --> tsk4{{filter}} + tsk4{{filter}} -- filtered_items/sentinel_product --> tsk5{{download}} + tsk5{{download}} -- downloaded_product/sentinel1_products --> tsk6{{tile}} + tsk6{{tile}} -- tiled_products/rasters --> tsk7{{group}} + tsk7{{group}} -- raster_groups/raster_group --> tsk8{{merge}} + inp1>user_input] -- time_range --> tsk2{{merge_geom_tr}} + inp2>s2_products] -- items --> tsk1{{union}} + inp2>s2_products] -- bounds_items --> tsk4{{filter}} + inp2>s2_products] -- sentinel2_products --> tsk6{{tile}} + tsk8{{merge}} -- merged_product --> out1>raster] +``` + +## Sources + +- **user_input**: Time range of interest. + +- **s2_products**: Sentinel-2 products whose geometries are used to select Sentinel-1 tiles. + +## Sinks + +- **raster**: Sentinel-1 rasters in the Sentinel-2 tiling system. + +## Parameters + +- **pc_key**: Planetary Computer API key. + +- **min_cover**: Minimum amount of cover required for a group to be used. + +- **dl_timeout**: Maximum time, in seconds, before a band reading operation times out. + +## Tasks + +- **union**: Create item with merged geometry from item list. + +- **merge_geom_tr**: Create item that contains the geometry from one item and the time range from another. + +- **list**: List Sentinel-1 GRD or RTC products given geometry and time range. + +- **filter**: Select items necessary to spatially cover the geometry of the bounds items. + +- **download**: Downloads the Sentinel-1 RTC product bands. + +- **tile**: Match Sentinel-1 products that intersect with Sentinel-2 tiles. + +- **group**: Groups raster files representing the same tile and moment in time that might have been partially generated and split due to the movement of Sentinel-1 through base stations. + +- **merge**: Merge items from the same absolute orbit into the appropriate MGRS (Sentinel-2 tiling system) tile. + +## Workflow Yaml + ```yaml -name: preprocess_s1 +name: preprocess_s1_rtc sources: user_input: - merge_geom_tr.time_range @@ -15,6 +82,7 @@ sinks: parameters: pc_key: null min_cover: 0.4 + dl_timeout: null tasks: union: op: merge_geometries @@ -32,10 +100,10 @@ tasks: op: download_sentinel1 parameters: api_key: '@from(pc_key)' + timeout_s: '@from(dl_timeout)' tile: - op: tile_sentinel1 - preprocess: - op: apply_sentinel1_snap_processing + op: tile_sentinel1_rtc + op_dir: tile_sentinel1 group: op: group_sentinel1_orbits merge: @@ -57,9 +125,6 @@ edges: destination: - tile.sentinel1_products - origin: tile.tiled_products - destination: - - preprocess.sentinel1_product -- origin: preprocess.preprocessed_product destination: - group.rasters - origin: group.raster_groups @@ -81,33 +146,4 @@ description: pc_key: Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - inp2>s2_products] - out1>raster] - tsk1{{union}} - tsk2{{merge_geom_tr}} - tsk3{{list}} - tsk4{{filter}} - tsk5{{download}} - tsk6{{tile}} - tsk7{{preprocess}} - tsk8{{group}} - tsk9{{merge}} - tsk1{{union}} -- merged/geometry --> tsk2{{merge_geom_tr}} - tsk2{{merge_geom_tr}} -- merged/input_item --> tsk3{{list}} - tsk3{{list}} -- sentinel_products/items --> tsk4{{filter}} - tsk4{{filter}} -- filtered_items/sentinel_product --> tsk5{{download}} - tsk5{{download}} -- downloaded_product/sentinel1_products --> tsk6{{tile}} - tsk6{{tile}} -- tiled_products/sentinel1_product --> tsk7{{preprocess}} - tsk7{{preprocess}} -- preprocessed_product/rasters --> tsk8{{group}} - tsk8{{group}} -- raster_groups/raster_group --> tsk9{{merge}} - inp1>user_input] -- time_range --> tsk2{{merge_geom_tr}} - inp2>s2_products] -- items --> tsk1{{union}} - inp2>s2_products] -- bounds_items --> tsk4{{filter}} - inp2>s2_products] -- sentinel2_products --> tsk6{{tile}} - tsk9{{merge}} -- merged_product --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel1/preprocess_s1_rtc.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel1/preprocess_s1_rtc.md deleted file mode 100644 index 5f5ece2a..00000000 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel1/preprocess_s1_rtc.md +++ /dev/null @@ -1,111 +0,0 @@ -# data_ingestion/sentinel1/preprocess_s1_rtc - -```yaml - -name: preprocess_s1_rtc -sources: - user_input: - - merge_geom_tr.time_range - s2_products: - - union.items - - filter.bounds_items - - tile.sentinel2_products -sinks: - raster: merge.merged_product -parameters: - pc_key: null - min_cover: 0.4 - dl_timeout: null -tasks: - union: - op: merge_geometries - merge_geom_tr: - op: merge_geometry_and_time_range - list: - op: list_sentinel1_products_pc - op_dir: list_sentinel1_products - parameters: - collection: rtc - filter: - op: select_necessary_coverage_items - parameters: - min_cover: '@from(min_cover)' - group_attribute: orbit_number - download: - op: download_sentinel1_rtc - parameters: - api_key: '@from(pc_key)' - timeout_s: '@from(dl_timeout)' - tile: - op: tile_sentinel1_rtc - op_dir: tile_sentinel1 - group: - op: group_sentinel1_orbits - merge: - op: merge_sentinel1_orbits -edges: -- origin: union.merged - destination: - - merge_geom_tr.geometry -- origin: merge_geom_tr.merged - destination: - - list.input_item -- origin: list.sentinel_products - destination: - - filter.items -- origin: filter.filtered_items - destination: - - download.sentinel_product -- origin: download.downloaded_product - destination: - - tile.sentinel1_products -- origin: tile.tiled_products - destination: - - group.rasters -- origin: group.raster_groups - destination: - - merge.raster_group -description: - short_description: Downloads and preprocesses tiles of Sentinel-1 imagery that intersect - with the input Sentinel-2 products in the input time range. - long_description: The workflow fetches Sentinel-1 tiles that intersects with the - Sentinel-2 products, downloads and preprocesses them, and produces Sentinel-1 - rasters in the Sentinel-2 tiling system. - sources: - user_input: Time range of interest. - s2_products: Sentinel-2 products whose geometries are used to select Sentinel-1 - tiles. - sinks: - raster: Sentinel-1 rasters in the Sentinel-2 tiling system. - parameters: - pc_key: Planetary Computer API key. - - -``` - -```{mermaid} - graph TD - inp1>user_input] - inp2>s2_products] - out1>raster] - tsk1{{union}} - tsk2{{merge_geom_tr}} - tsk3{{list}} - tsk4{{filter}} - tsk5{{download}} - tsk6{{tile}} - tsk7{{group}} - tsk8{{merge}} - tsk1{{union}} -- merged/geometry --> tsk2{{merge_geom_tr}} - tsk2{{merge_geom_tr}} -- merged/input_item --> tsk3{{list}} - tsk3{{list}} -- sentinel_products/items --> tsk4{{filter}} - tsk4{{filter}} -- filtered_items/sentinel_product --> tsk5{{download}} - tsk5{{download}} -- downloaded_product/sentinel1_products --> tsk6{{tile}} - tsk6{{tile}} -- tiled_products/rasters --> tsk7{{group}} - tsk7{{group}} -- raster_groups/raster_group --> tsk8{{merge}} - inp1>user_input] -- time_range --> tsk2{{merge_geom_tr}} - inp2>s2_products] -- items --> tsk1{{union}} - inp2>s2_products] -- bounds_items --> tsk4{{filter}} - inp2>s2_products] -- sentinel2_products --> tsk6{{tile}} - tsk8{{merge}} -- merged_product --> out1>raster] -``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/cloud_ensemble.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/cloud_ensemble.md index cbfcd622..33546b57 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/cloud_ensemble.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/cloud_ensemble.md @@ -1,5 +1,54 @@ # data_ingestion/sentinel2/cloud_ensemble +Computes the cloud probability of a Sentinel-2 L2A raster using an ensemble of five cloud segmentation models. The workflow computes cloud probabilities for each model independently, and averages them to obtain a single probability map. + +```{mermaid} + graph TD + inp1>sentinel_raster] + out1>cloud_probability] + tsk1{{cloud1}} + tsk2{{cloud2}} + tsk3{{cloud3}} + tsk4{{cloud4}} + tsk5{{cloud5}} + tsk6{{ensemble}} + tsk1{{cloud1}} -- cloud_probability/cloud1 --> tsk6{{ensemble}} + tsk2{{cloud2}} -- cloud_probability/cloud2 --> tsk6{{ensemble}} + tsk3{{cloud3}} -- cloud_probability/cloud3 --> tsk6{{ensemble}} + tsk4{{cloud4}} -- cloud_probability/cloud4 --> tsk6{{ensemble}} + tsk5{{cloud5}} -- cloud_probability/cloud5 --> tsk6{{ensemble}} + inp1>sentinel_raster] -- sentinel_raster --> tsk1{{cloud1}} + inp1>sentinel_raster] -- sentinel_raster --> tsk2{{cloud2}} + inp1>sentinel_raster] -- sentinel_raster --> tsk3{{cloud3}} + inp1>sentinel_raster] -- sentinel_raster --> tsk4{{cloud4}} + inp1>sentinel_raster] -- sentinel_raster --> tsk5{{cloud5}} + tsk6{{ensemble}} -- cloud_probability --> out1>cloud_probability] +``` + +## Sources + +- **sentinel_raster**: Sentinel-2 L2A raster. + +## Sinks + +- **cloud_probability**: Cloud probability map. + +## Tasks + +- **cloud1**: Computes cloud probabilities using a convolutional segmentation model for L2A. + +- **cloud2**: Computes cloud probabilities using a convolutional segmentation model for L2A. + +- **cloud3**: Computes cloud probabilities using a convolutional segmentation model for L2A. + +- **cloud4**: Computes cloud probabilities using a convolutional segmentation model for L2A. + +- **cloud5**: Computes cloud probabilities using a convolutional segmentation model for L2A. + +- **ensemble**: Computes ensemble cloud probabilities from all 5 models. + +## Workflow Yaml + ```yaml name: cloud_ensemble @@ -62,27 +111,4 @@ description: cloud_probability: Cloud probability map. -``` - -```{mermaid} - graph TD - inp1>sentinel_raster] - out1>cloud_probability] - tsk1{{cloud1}} - tsk2{{cloud2}} - tsk3{{cloud3}} - tsk4{{cloud4}} - tsk5{{cloud5}} - tsk6{{ensemble}} - tsk1{{cloud1}} -- cloud_probability/cloud1 --> tsk6{{ensemble}} - tsk2{{cloud2}} -- cloud_probability/cloud2 --> tsk6{{ensemble}} - tsk3{{cloud3}} -- cloud_probability/cloud3 --> tsk6{{ensemble}} - tsk4{{cloud4}} -- cloud_probability/cloud4 --> tsk6{{ensemble}} - tsk5{{cloud5}} -- cloud_probability/cloud5 --> tsk6{{ensemble}} - inp1>sentinel_raster] -- sentinel_raster --> tsk1{{cloud1}} - inp1>sentinel_raster] -- sentinel_raster --> tsk2{{cloud2}} - inp1>sentinel_raster] -- sentinel_raster --> tsk3{{cloud3}} - inp1>sentinel_raster] -- sentinel_raster --> tsk4{{cloud4}} - inp1>sentinel_raster] -- sentinel_raster --> tsk5{{cloud5}} - tsk6{{ensemble}} -- cloud_probability --> out1>cloud_probability] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/improve_cloud_mask.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/improve_cloud_mask.md index 08705065..730a0e62 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/improve_cloud_mask.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/improve_cloud_mask.md @@ -1,5 +1,55 @@ # data_ingestion/sentinel2/improve_cloud_mask +Improves cloud masks by merging the product cloud mask with cloud and shadow masks computed by machine learning segmentation models. This workflow computes cloud and shadow probabilities using segmentation models, thresholds them, and merges the models' masks with the product mask. + +```{mermaid} + graph TD + inp1>s2_raster] + inp2>product_mask] + out1>mask] + tsk1{{cloud}} + tsk2{{shadow}} + tsk3{{merge}} + tsk1{{cloud}} -- cloud_probability --> tsk3{{merge}} + tsk2{{shadow}} -- shadow_probability --> tsk3{{merge}} + inp1>s2_raster] -- sentinel_raster --> tsk1{{cloud}} + inp1>s2_raster] -- sentinel_raster --> tsk2{{shadow}} + inp2>product_mask] -- product_mask --> tsk3{{merge}} + tsk3{{merge}} -- merged_cloud_mask --> out1>mask] +``` + +## Sources + +- **s2_raster**: Sentinel-2 L2A raster. + +- **product_mask**: Cloud mask obtained from the product's quality indicators. + +## Sinks + +- **mask**: Improved cloud mask. + +## Parameters + +- **cloud_thr**: Confidence threshold to assign a pixel as cloud. + +- **shadow_thr**: Confidence threshold to assign a pixel as shadow. + +- **in_memory**: Whether to load the whole raster in memory when running predictions. Uses more memory (~4GB/worker) but speeds up inference for fast models. + +- **cloud_model**: ONNX file for the cloud model. Available models are 'cloud_model{idx}_cpu.onnx' with idx ∈ {1, 2} being FPN-based models, which are more accurate but slower, and idx ∈ {3, 4, 5} being cheaplab models, which are less accurate but faster. + +- **shadow_model**: ONNX file for the shadow model. 'shadow.onnx' is the only currently available model. + +## Tasks + +- **cloud**: Computes cloud probabilities using a convolutional segmentation model for L2A. + +- **shadow**: Computes shadow probabilities using a convolutional segmentation model for L2A. + +- **merge**: Merges cloud, shadow and product cloud masks into a single mask. + +## Workflow Yaml + ```yaml name: improve_cloud_mask @@ -64,20 +114,4 @@ description: available model. -``` - -```{mermaid} - graph TD - inp1>s2_raster] - inp2>product_mask] - out1>mask] - tsk1{{cloud}} - tsk2{{shadow}} - tsk3{{merge}} - tsk1{{cloud}} -- cloud_probability --> tsk3{{merge}} - tsk2{{shadow}} -- shadow_probability --> tsk3{{merge}} - inp1>s2_raster] -- sentinel_raster --> tsk1{{cloud}} - inp1>s2_raster] -- sentinel_raster --> tsk2{{shadow}} - inp2>product_mask] -- product_mask --> tsk3{{merge}} - tsk3{{merge}} -- merged_cloud_mask --> out1>mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/improve_cloud_mask_ensemble.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/improve_cloud_mask_ensemble.md index 01bebbf9..ea175a74 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/improve_cloud_mask_ensemble.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/improve_cloud_mask_ensemble.md @@ -1,5 +1,49 @@ # data_ingestion/sentinel2/improve_cloud_mask_ensemble +Improves cloud masks by merging the product cloud mask with cloud and shadow masks computed by an ensemble of machine learning segmentation models. This workflow computes cloud and shadow probabilities using and ensemble of segmentation models, thresholds them, and merges the models' masks with the product mask. + +```{mermaid} + graph TD + inp1>s2_raster] + inp2>product_mask] + out1>mask] + tsk1{{cloud}} + tsk2{{shadow}} + tsk3{{merge}} + tsk1{{cloud}} -- cloud_probability --> tsk3{{merge}} + tsk2{{shadow}} -- shadow_probability --> tsk3{{merge}} + inp1>s2_raster] -- sentinel_raster --> tsk1{{cloud}} + inp1>s2_raster] -- sentinel_raster --> tsk2{{shadow}} + inp2>product_mask] -- product_mask --> tsk3{{merge}} + tsk3{{merge}} -- merged_cloud_mask --> out1>mask] +``` + +## Sources + +- **s2_raster**: Sentinel-2 L2A raster. + +- **product_mask**: Cloud mask obtained from the product's quality indicators. + +## Sinks + +- **mask**: Improved cloud mask. + +## Parameters + +- **cloud_thr**: Confidence threshold to assign a pixel as cloud. + +- **shadow_thr**: Confidence threshold to assign a pixel as shadow. + +## Tasks + +- **cloud**: Computes the cloud probability of a Sentinel-2 L2A raster using an ensemble of five cloud segmentation models. + +- **shadow**: Computes shadow probabilities using a convolutional segmentation model for L2A. + +- **merge**: Merges cloud, shadow and product cloud masks into a single mask. + +## Workflow Yaml + ```yaml name: improve_cloud_mask_ensemble @@ -48,20 +92,4 @@ description: shadow_thr: Confidence threshold to assign a pixel as shadow. -``` - -```{mermaid} - graph TD - inp1>s2_raster] - inp2>product_mask] - out1>mask] - tsk1{{cloud}} - tsk2{{shadow}} - tsk3{{merge}} - tsk1{{cloud}} -- cloud_probability --> tsk3{{merge}} - tsk2{{shadow}} -- shadow_probability --> tsk3{{merge}} - inp1>s2_raster] -- sentinel_raster --> tsk1{{cloud}} - inp1>s2_raster] -- sentinel_raster --> tsk2{{shadow}} - inp2>product_mask] -- product_mask --> tsk3{{merge}} - tsk3{{merge}} -- merged_cloud_mask --> out1>mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2.md index 49010c0a..b7f845fe 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2.md @@ -1,5 +1,63 @@ # data_ingestion/sentinel2/preprocess_s2 +Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range. This workflow selects a minimum set of tiles that covers the input geometry, downloads Sentinel-2 imagery for the selected time range, and preprocesses it by generating a single multi-band raster at 10m resolution. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + out2>mask] + tsk1{{list}} + tsk2{{filter}} + tsk3{{download}} + tsk4{{group}} + tsk5{{merge}} + tsk1{{list}} -- sentinel_products/items --> tsk2{{filter}} + tsk2{{filter}} -- filtered_items/sentinel_product --> tsk3{{download}} + tsk3{{download}} -- raster/rasters --> tsk4{{group}} + tsk3{{download}} -- cloud/masks --> tsk4{{group}} + tsk4{{group}} -- raster_groups/raster_group --> tsk5{{merge}} + tsk4{{group}} -- mask_groups/mask_group --> tsk5{{merge}} + inp1>user_input] -- input_item --> tsk1{{list}} + inp1>user_input] -- bounds_items --> tsk2{{filter}} + tsk5{{merge}} -- output_raster --> out1>raster] + tsk5{{merge}} -- output_mask --> out2>mask] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: Sentinel-2 L2A rasters with all bands resampled to 10m resolution. + +- **mask**: Cloud mask at 10m resolution from the product's quality indicators. + +## Parameters + +- **min_tile_cover**: Minimum RoI coverage to consider a set of tiles sufficient. + +- **max_tiles_per_time**: Maximum number of tiles used to cover the RoI in each date. + +- **pc_key**: Optional Planetary Computer API key. + +- **dl_timeout**: Maximum time, in seconds, before a band reading operation times out. + +## Tasks + +- **list**: Lists Sentinel-2 products that intersect with input geometry and time range. + +- **filter**: Select items necessary to spatially cover the geometry of the bounds items. + +- **download**: Downloads and preprocesses Sentinel-2 products. + +- **group**: Groups raster files representing the same tile and moment in time that might have been partially generated and split due to the movement of Sentinel-2 through base stations. + +- **merge**: Combines raster files grouped by group_sentinel2_orbits into a single raster. + +## Workflow Yaml + ```yaml name: preprocess_s2 @@ -69,26 +127,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - out2>mask] - tsk1{{list}} - tsk2{{filter}} - tsk3{{download}} - tsk4{{group}} - tsk5{{merge}} - tsk1{{list}} -- sentinel_products/items --> tsk2{{filter}} - tsk2{{filter}} -- filtered_items/sentinel_product --> tsk3{{download}} - tsk3{{download}} -- raster/rasters --> tsk4{{group}} - tsk3{{download}} -- cloud/masks --> tsk4{{group}} - tsk4{{group}} -- raster_groups/raster_group --> tsk5{{merge}} - tsk4{{group}} -- mask_groups/mask_group --> tsk5{{merge}} - inp1>user_input] -- input_item --> tsk1{{list}} - inp1>user_input] -- bounds_items --> tsk2{{filter}} - tsk5{{merge}} -- output_raster --> out1>raster] - tsk5{{merge}} -- output_mask --> out2>mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2_ensemble_masks.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2_ensemble_masks.md index 133ee6f6..1b774adb 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2_ensemble_masks.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2_ensemble_masks.md @@ -1,5 +1,51 @@ # data_ingestion/sentinel2/preprocess_s2_ensemble_masks +Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range, and computes improved cloud masks using an ensemble of cloud and shadow segmentation models. This workflow selects a minimum set of tiles that covers the input geometry, downloads Sentinel-2 imagery for the selected time range, and preprocesses it by generating a single multi-band raster at 10m resolution. It then improves cloud masks by merging the product mask with cloud and shadow masks computed using an ensemble of cloud and shadow segmentation models. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + out2>mask] + tsk1{{s2}} + tsk2{{cloud}} + tsk1{{s2}} -- raster/s2_raster --> tsk2{{cloud}} + tsk1{{s2}} -- mask/product_mask --> tsk2{{cloud}} + inp1>user_input] -- user_input --> tsk1{{s2}} + tsk1{{s2}} -- raster --> out1>raster] + tsk2{{cloud}} -- mask --> out2>mask] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: Sentinel-2 L2A rasters with all bands resampled to 10m resolution. + +- **mask**: Cloud masks at 10m resolution. + +## Parameters + +- **min_tile_cover**: Minimum RoI coverage to consider a set of tiles sufficient. + +- **max_tiles_per_time**: Maximum number of tiles used to cover the RoI in each date. + +- **cloud_thr**: Confidence threshold to assign a pixel as cloud. + +- **shadow_thr**: Confidence threshold to assign a pixel as shadow. + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **s2**: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range. + +- **cloud**: Improves cloud masks by merging the product cloud mask with cloud and shadow masks computed by an ensemble of machine learning segmentation models. + +## Workflow Yaml + ```yaml name: preprocess_s2_ensemble_masks @@ -50,18 +96,4 @@ description: mask: Cloud masks at 10m resolution. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - out2>mask] - tsk1{{s2}} - tsk2{{cloud}} - tsk1{{s2}} -- raster/s2_raster --> tsk2{{cloud}} - tsk1{{s2}} -- mask/product_mask --> tsk2{{cloud}} - inp1>user_input] -- user_input --> tsk1{{s2}} - tsk1{{s2}} -- raster --> out1>raster] - tsk2{{cloud}} -- mask --> out2>mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2_improved_masks.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2_improved_masks.md index d69b1e58..5f9fa237 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2_improved_masks.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/sentinel2/preprocess_s2_improved_masks.md @@ -1,5 +1,59 @@ # data_ingestion/sentinel2/preprocess_s2_improved_masks +Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range, and computes improved cloud masks using cloud and shadow segmentation models. This workflow selects a minimum set of tiles that covers the input geometry, downloads Sentinel-2 imagery for the selected time range, and preprocesses it by generating a single multi-band raster at 10m resolution. It then improves cloud masks by merging the product mask with cloud and shadow masks computed using cloud and shadow segmentation models. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + out2>mask] + tsk1{{s2}} + tsk2{{cloud}} + tsk1{{s2}} -- raster/s2_raster --> tsk2{{cloud}} + tsk1{{s2}} -- mask/product_mask --> tsk2{{cloud}} + inp1>user_input] -- user_input --> tsk1{{s2}} + tsk1{{s2}} -- raster --> out1>raster] + tsk2{{cloud}} -- mask --> out2>mask] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: Sentinel-2 L2A rasters with all bands resampled to 10m resolution. + +- **mask**: Cloud masks at 10m resolution. + +## Parameters + +- **min_tile_cover**: Minimum RoI coverage to consider a set of tiles sufficient. + +- **max_tiles_per_time**: Maximum number of tiles used to cover the RoI in each date. + +- **cloud_thr**: Confidence threshold to assign a pixel as cloud. + +- **shadow_thr**: Confidence threshold to assign a pixel as shadow. + +- **in_memory**: Whether to load the whole raster in memory when running predictions. Uses more memory (~4GB/worker) but speeds up inference for fast models. + +- **cloud_model**: ONNX file for the cloud model. Available models are 'cloud_model{idx}_cpu.onnx' with idx ∈ {1, 2} being FPN-based models, which are more accurate but slower, and idx ∈ {3, 4, 5} being cheaplab models, which are less accurate but faster. + +- **shadow_model**: ONNX file for the shadow model. 'shadow.onnx' is the only currently available model. + +- **pc_key**: Optional Planetary Computer API key. + +- **dl_timeout**: Maximum time, in seconds, before a band reading operation times out. + +## Tasks + +- **s2**: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range. + +- **cloud**: Improves cloud masks by merging the product cloud mask with cloud and shadow masks computed by machine learning segmentation models. + +## Workflow Yaml + ```yaml name: preprocess_s2_improved_masks @@ -58,18 +112,4 @@ description: mask: Cloud masks at 10m resolution. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - out2>mask] - tsk1{{s2}} - tsk2{{cloud}} - tsk1{{s2}} -- raster/s2_raster --> tsk2{{cloud}} - tsk1{{s2}} -- mask/product_mask --> tsk2{{cloud}} - inp1>user_input] -- user_input --> tsk1{{s2}} - tsk1{{s2}} -- raster --> out1>raster] - tsk2{{cloud}} -- mask --> out2>mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/soil/soilgrids.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/soil/soilgrids.md index 9eccbf63..cd4f96df 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/soil/soilgrids.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/soil/soilgrids.md @@ -1,5 +1,51 @@ # data_ingestion/soil/soilgrids +Downloads digital soil mapping information from SoilGrids for the input geometry. The workflow downloads a raster containing the map and identifiers for the input geometry. SoilGrids is a system for digital soil mapping based on global compilation of soil profile data and environmental layers. + +```{mermaid} + graph TD + inp1>input_item] + out1>downloaded_raster] + tsk1{{download_soilgrids}} + inp1>input_item] -- input_item --> tsk1{{download_soilgrids}} + tsk1{{download_soilgrids}} -- downloaded_raster --> out1>downloaded_raster] +``` + +## Sources + +- **input_item**: Input geometry. + +## Sinks + +- **downloaded_raster**: Raster with the map and identifiers requested. + +## Parameters + +- **map**: Map to download. Options: + - wrb - World Reference Base classes and probabilites + - bdod - Bulk density - kg/dm^3 + - cec - Cation exchange capacity at ph 7 - cmol(c)/kg + - cfvo - Coarse fragments volumetric) - cm3/100cm3 (vol%) + - clay - Clay content - g/100g (%) + - nitrogen - Nitrogen - g/kg + - phh2o - Soil pH in H2O - pH + - sand - Sand content - g/100g (%) + - silt - Silt content - g/100g (%) + - soc - Soil organic carbon content - g/kg + - ocs - Soil organic carbon stock - kg/m^3 + - ocd - Organic carbon densities - kg/m^3 + +- **identifier**: Variable identifier to be downloaded. Depends on map. + - wrb: Acrisols, Albeluvisols, Alisols, Andosols, Arenosols, Calcisols, Cambisols, +Chernozems, Cryosols, Durisols, Ferralsols, Fluvisols, Gleysols, Gypsisols, Histosols, Kastanozems, Leptosols, Lixisols, Luvisols, MostProbable, Nitisols, Phaeozems, Planosols, Plinthosols, Podzols, Regosols, Solonchaks, Solonetz, Stagnosols, Umbrisols, Vertisols. +Other identifiers follow the nomenclature defined in the [link=https://www.isric.org/explore/soilgrids/faq-soilgrids#What_do_the_filename_codes_mean]SoilGrids documentation page: https://www.isric.org/explore/soilgrids/faq-soilgrids#What_do_the_filename_codes_mean[/]. + +## Tasks + +- **download_soilgrids**: Downloads digital soil mapping information from SoilGrids for the input geometry. + +## Workflow Yaml + ```yaml name: soilgrids @@ -47,13 +93,4 @@ description: \ documentation page: https://www.isric.org/explore/soilgrids/faq-soilgrids#What_do_the_filename_codes_mean[/]." -``` - -```{mermaid} - graph TD - inp1>input_item] - out1>downloaded_raster] - tsk1{{download_soilgrids}} - inp1>input_item] -- input_item --> tsk1{{download_soilgrids}} - tsk1{{download_soilgrids}} -- downloaded_raster --> out1>downloaded_raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/soil/usda.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/soil/usda.md index 7362b8a6..6f7c35f5 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/soil/usda.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/soil/usda.md @@ -1,5 +1,38 @@ # data_ingestion/soil/usda +Downloads USDA soil classification raster. The workflow will download a global raster with USDA soil classes at 1/30 degree resolution. + +```{mermaid} + graph TD + inp1>input_item] + out1>downloaded_raster] + tsk1{{datavibe_filter}} + tsk2{{download_usda_soils}} + tsk1{{datavibe_filter}} -- output_item/input_item --> tsk2{{download_usda_soils}} + inp1>input_item] -- input_item --> tsk1{{datavibe_filter}} + tsk2{{download_usda_soils}} -- downloaded_raster --> out1>downloaded_raster] +``` + +## Sources + +- **input_item**: Dummy input. + +## Sinks + +- **downloaded_raster**: Raster with USDA soil classes. + +## Parameters + +- **ignore**: Selection of each field of input item should be ignored (among "time_range", "geometry", or "all" for both of them). + +## Tasks + +- **datavibe_filter**: Filters out time range and/or geometry information from the input item. + +- **download_usda_soils**: Downloads a global raster with USDA soil classes at 1/30 degree resolution. + +## Workflow Yaml + ```yaml name: usda_soils @@ -34,15 +67,4 @@ description: "geometry", or "all" for both of them). -``` - -```{mermaid} - graph TD - inp1>input_item] - out1>downloaded_raster] - tsk1{{datavibe_filter}} - tsk2{{download_usda_soils}} - tsk1{{datavibe_filter}} -- output_item/input_item --> tsk2{{download_usda_soils}} - inp1>input_item] -- input_item --> tsk1{{datavibe_filter}} - tsk2{{download_usda_soils}} -- downloaded_raster --> out1>downloaded_raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye.md index 22cdbd87..4dbda7d0 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye.md @@ -1,5 +1,55 @@ # data_ingestion/spaceeye/spaceeye +Runs the SpaceEye cloud removal pipeline, yielding daily cloud-free images for the input geometry and time range. The workflow fetches both Sentinel-1 and Sentinel-2 tiles that cover the input geometry and time range, preprocesses them, computes cloud masks, and runs SpaceEye inference in a sliding window on the retrieved tiles. This workflow can be reused as a preprocess step in many applications that require cloud-free Sentinel-2 data. For more information about SpaceEye, read the paper: https://arxiv.org/abs/2106.08408. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{preprocess}} + tsk2{{spaceeye}} + tsk1{{preprocess}} -- s2_raster/s2_rasters --> tsk2{{spaceeye}} + tsk1{{preprocess}} -- s1_raster/s1_rasters --> tsk2{{spaceeye}} + tsk1{{preprocess}} -- cloud_mask/cloud_rasters --> tsk2{{spaceeye}} + inp1>user_input] -- user_input --> tsk1{{preprocess}} + inp1>user_input] -- input_data --> tsk2{{spaceeye}} + tsk2{{spaceeye}} -- raster --> out1>raster] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: Cloud-free rasters. + +## Parameters + +- **duration**: Time window, in days, considered in the inference. Controls the amount of temporal context for inpainting clouds. Larger windows require more compute and memory. + +- **time_overlap**: Overlap ratio of each temporal window. Controls the temporal step between windows as a fraction of the window size. + +- **min_tile_cover**: Minimum RoI coverage to consider a set of tiles sufficient. + +- **max_tiles_per_time**: Maximum number of tiles used to cover the RoI in each date. + +- **cloud_thr**: Confidence threshold to assign a pixel as cloud. + +- **shadow_thr**: Confidence threshold to assign a pixel as shadow. + +- **pc_key**: Optional Planetary Computer API key. + +- **s2_timeout**: Maximum time, in seconds, before a band reading operation times out. + +## Tasks + +- **preprocess**: Runs the SpaceEye preprocessing pipeline. + +- **spaceeye**: Performs SpaceEye inference to generate daily cloud-free images given Sentinel data and cloud masks. + +## Workflow Yaml + ```yaml name: spaceeye @@ -58,18 +108,4 @@ description: parameters: null -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{preprocess}} - tsk2{{spaceeye}} - tsk1{{preprocess}} -- s2_raster/s2_rasters --> tsk2{{spaceeye}} - tsk1{{preprocess}} -- s1_raster/s1_rasters --> tsk2{{spaceeye}} - tsk1{{preprocess}} -- cloud_mask/cloud_rasters --> tsk2{{spaceeye}} - inp1>user_input] -- user_input --> tsk1{{preprocess}} - inp1>user_input] -- input_data --> tsk2{{spaceeye}} - tsk2{{spaceeye}} -- raster --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_inference.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_inference.md index 53995783..20309895 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_inference.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_inference.md @@ -1,5 +1,66 @@ # data_ingestion/spaceeye/spaceeye_inference +Performs SpaceEye inference to generate daily cloud-free images given Sentinel data and cloud masks. The workflow will group input Sentinel-1, Sentinel-2, and cloud mask rasters into spatio-temporal windows and perform inference of each window. The windows will then be merged into rasters for the RoI. More information about SpaceEye available in the paper: https://arxiv.org/abs/2106.08408. + +```{mermaid} + graph TD + inp1>input_data] + inp2>s1_rasters] + inp3>s2_rasters] + inp4>cloud_rasters] + out1>raster] + tsk1{{group_s1}} + tsk2{{group_s2}} + tsk3{{group_mask}} + tsk4{{spaceeye}} + tsk5{{split}} + tsk1{{group_s1}} -- tile_sequences/s1_products --> tsk4{{spaceeye}} + tsk2{{group_s2}} -- tile_sequences/s2_products --> tsk4{{spaceeye}} + tsk3{{group_mask}} -- tile_sequences/cloud_masks --> tsk4{{spaceeye}} + tsk4{{spaceeye}} -- spaceeye_sequence/sequences --> tsk5{{split}} + inp1>input_data] -- input_data --> tsk1{{group_s1}} + inp1>input_data] -- input_data --> tsk2{{group_s2}} + inp1>input_data] -- input_data --> tsk3{{group_mask}} + inp2>s1_rasters] -- rasters --> tsk1{{group_s1}} + inp3>s2_rasters] -- rasters --> tsk2{{group_s2}} + inp4>cloud_rasters] -- rasters --> tsk3{{group_mask}} + tsk5{{split}} -- rasters --> out1>raster] +``` + +## Sources + +- **input_data**: Time range and region of interest. Will determine the spatio-temporal windows and region for the output rasters. + +- **s1_rasters**: Sentinel-1 rasters tiled to the Sentinel-2 grid. + +- **s2_rasters**: Sentinel-2 tile rasters for the input time range. + +- **cloud_rasters**: Cloud masks for each of the Sentinel-2 tiles. + +## Sinks + +- **raster**: Cloud-free rasters for the input time range and region of interest. + +## Parameters + +- **duration**: Time window, in days, considered in the inference. Controls the amount of temporal context for inpainting clouds. Larger windows require more compute and memory. + +- **time_overlap**: Overlap ratio of each temporal window. Controls the temporal step between windows as a fraction of the window size. + +## Tasks + +- **group_s1**: Groups Sentinel-1 tiles into time windows of defined duration. + +- **group_s2**: Groups Sentinel-2 tiles into time windows of defined duration. + +- **group_mask**: Groups Sentinel-2 cloud masks into time windows of defined duration. + +- **spaceeye**: Runs SpaceEye to remove clouds in input rasters. + +- **split**: Splits a list of multiple TileSequence back to a list of Rasters. + +## Workflow Yaml + ```yaml name: spaceeye_inference @@ -81,29 +142,4 @@ description: between windows as a fraction of the window size. -``` - -```{mermaid} - graph TD - inp1>input_data] - inp2>s1_rasters] - inp3>s2_rasters] - inp4>cloud_rasters] - out1>raster] - tsk1{{group_s1}} - tsk2{{group_s2}} - tsk3{{group_mask}} - tsk4{{spaceeye}} - tsk5{{split}} - tsk1{{group_s1}} -- tile_sequences/s1_products --> tsk4{{spaceeye}} - tsk2{{group_s2}} -- tile_sequences/s2_products --> tsk4{{spaceeye}} - tsk3{{group_mask}} -- tile_sequences/cloud_masks --> tsk4{{spaceeye}} - tsk4{{spaceeye}} -- spaceeye_sequence/sequences --> tsk5{{split}} - inp1>input_data] -- input_data --> tsk1{{group_s1}} - inp1>input_data] -- input_data --> tsk2{{group_s2}} - inp1>input_data] -- input_data --> tsk3{{group_mask}} - inp2>s1_rasters] -- rasters --> tsk1{{group_s1}} - inp3>s2_rasters] -- rasters --> tsk2{{group_s2}} - inp4>cloud_rasters] -- rasters --> tsk3{{group_mask}} - tsk5{{split}} -- rasters --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_interpolation.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_interpolation.md index 38140361..33772c17 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_interpolation.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_interpolation.md @@ -1,5 +1,52 @@ # data_ingestion/spaceeye/spaceeye_interpolation +Runs the SpaceEye cloud removal pipeline using an interpolation-based algorithm, yielding daily cloud-free images for the input geometry and time range. The workflow fetches Sentinel-2 tiles that cover the input geometry and time range, preprocesses them, computes cloud masks, and runs SpaceEye inference in a sliding window on the retrieved tiles. This workflow can be reused as a preprocess step in many applications that require cloud-free Sentinel-2 data. For more information about SpaceEye, read the [link=https://arxiv.org/abs/2106.08408]paper: https://arxiv.org/abs/2106.08408[/link]. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{preprocess}} + tsk2{{spaceeye}} + tsk1{{preprocess}} -- raster/s2_rasters --> tsk2{{spaceeye}} + tsk1{{preprocess}} -- mask/cloud_rasters --> tsk2{{spaceeye}} + inp1>user_input] -- user_input --> tsk1{{preprocess}} + inp1>user_input] -- input_data --> tsk2{{spaceeye}} + tsk2{{spaceeye}} -- raster --> out1>raster] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **raster**: Cloud-free rasters. + +## Parameters + +- **duration**: Time window, in days, considered in the inference. Controls the amount of temporal context for inpainting clouds. Larger windows require more compute and memory. + +- **time_overlap**: Overlap ratio of each temporal window. Controls the temporal step between windows as a fraction of the window size. + +- **min_tile_cover**: Minimum RoI coverage to consider a set of tiles sufficient. + +- **max_tiles_per_time**: Maximum number of tiles used to cover the RoI in each date. + +- **cloud_thr**: Confidence threshold to assign a pixel as cloud. + +- **shadow_thr**: Confidence threshold to assign a pixel as shadow. + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **preprocess**: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range, and computes improved cloud masks using cloud and shadow segmentation models. + +- **spaceeye**: Performs temporal damped interpolation to generate daily cloud-free images given Sentinel-2 data and cloud masks. + +## Workflow Yaml + ```yaml name: spaceeye_interpolation @@ -63,17 +110,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{preprocess}} - tsk2{{spaceeye}} - tsk1{{preprocess}} -- raster/s2_rasters --> tsk2{{spaceeye}} - tsk1{{preprocess}} -- mask/cloud_rasters --> tsk2{{spaceeye}} - inp1>user_input] -- user_input --> tsk1{{preprocess}} - inp1>user_input] -- input_data --> tsk2{{spaceeye}} - tsk2{{spaceeye}} -- raster --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_interpolation_inference.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_interpolation_inference.md index 07679d06..1bd24935 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_interpolation_inference.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_interpolation_inference.md @@ -1,5 +1,57 @@ # data_ingestion/spaceeye/spaceeye_interpolation_inference +Performs temporal damped interpolation to generate daily cloud-free images given Sentinel-2 data and cloud masks. The workflow will group input Sentinel-2 and cloud mask rasters into spatio-temporal windows and perform inference of each window. The windows will then be merged into rasters for the RoI. More information about SpaceEye available in the paper: https://arxiv.org/abs/2106.08408. + +```{mermaid} + graph TD + inp1>input_data] + inp2>s2_rasters] + inp3>cloud_rasters] + out1>raster] + tsk1{{group_s2}} + tsk2{{group_mask}} + tsk3{{spaceeye}} + tsk4{{split}} + tsk1{{group_s2}} -- tile_sequences/s2_products --> tsk3{{spaceeye}} + tsk2{{group_mask}} -- tile_sequences/cloud_masks --> tsk3{{spaceeye}} + tsk3{{spaceeye}} -- spaceeye_sequence/sequences --> tsk4{{split}} + inp1>input_data] -- input_data --> tsk1{{group_s2}} + inp1>input_data] -- input_data --> tsk2{{group_mask}} + inp2>s2_rasters] -- rasters --> tsk1{{group_s2}} + inp3>cloud_rasters] -- rasters --> tsk2{{group_mask}} + tsk4{{split}} -- rasters --> out1>raster] +``` + +## Sources + +- **input_data**: Time range and region of interest. Will determine the spatio-temporal windows and region for the output rasters. + +- **s2_rasters**: Sentinel-2 tile rasters for the input time range. + +- **cloud_rasters**: Cloud masks for each of the Sentinel-2 tiles. + +## Sinks + +- **raster**: Cloud-free rasters for the input time range and region of interest. + +## Parameters + +- **duration**: Time window, in days, considered in the inference. Controls the amount of temporal context for inpainting clouds. Larger windows require more compute and memory. + +- **time_overlap**: Overlap ratio of each temporal window. Controls the temporal step between windows as a fraction of the window size. + +## Tasks + +- **group_s2**: Groups Sentinel-2 tiles into time windows of defined duration. + +- **group_mask**: Groups Sentinel-2 cloud masks into time windows of defined duration. + +- **spaceeye**: Runs the interpolation version of SpaceEye to remove clouds in input rasters. + +- **split**: Splits a list of multiple TileSequence back to a list of Rasters. + +## Workflow Yaml + ```yaml name: spaceeye_interpolation_inference @@ -69,24 +121,4 @@ description: between windows as a fraction of the window size. -``` - -```{mermaid} - graph TD - inp1>input_data] - inp2>s2_rasters] - inp3>cloud_rasters] - out1>raster] - tsk1{{group_s2}} - tsk2{{group_mask}} - tsk3{{spaceeye}} - tsk4{{split}} - tsk1{{group_s2}} -- tile_sequences/s2_products --> tsk3{{spaceeye}} - tsk2{{group_mask}} -- tile_sequences/cloud_masks --> tsk3{{spaceeye}} - tsk3{{spaceeye}} -- spaceeye_sequence/sequences --> tsk4{{split}} - inp1>input_data] -- input_data --> tsk1{{group_s2}} - inp1>input_data] -- input_data --> tsk2{{group_mask}} - inp2>s2_rasters] -- rasters --> tsk1{{group_s2}} - inp3>cloud_rasters] -- rasters --> tsk2{{group_mask}} - tsk4{{split}} -- rasters --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_preprocess.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_preprocess.md index 88888c2c..c0a9da93 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_preprocess.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_preprocess.md @@ -1,8 +1,62 @@ # data_ingestion/spaceeye/spaceeye_preprocess +Runs the SpaceEye preprocessing pipeline. The workflow fetches both Sentinel-1 and Sentinel-2 tiles that cover the input geometry and time range and preprocesses them. It also computes improved cloud masks using cloud and shadow segmentation models. + +```{mermaid} + graph TD + inp1>user_input] + out1>s2_raster] + out2>s1_raster] + out3>cloud_mask] + tsk1{{s2}} + tsk2{{s1}} + tsk1{{s2}} -- raster/s2_products --> tsk2{{s1}} + inp1>user_input] -- user_input --> tsk1{{s2}} + inp1>user_input] -- user_input --> tsk2{{s1}} + tsk1{{s2}} -- raster --> out1>s2_raster] + tsk2{{s1}} -- raster --> out2>s1_raster] + tsk1{{s2}} -- mask --> out3>cloud_mask] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **s2_raster**: Sentinel-2 rasters. + +- **s1_raster**: Sentinel-1 rasters. + +- **cloud_mask**: Cloud and cloud shadow mask. + +## Parameters + +- **min_tile_cover**: Minimum RoI coverage to consider a set of tiles sufficient. + +- **max_tiles_per_time**: Maximum number of tiles used to cover the RoI in each date. + +- **cloud_thr**: Confidence threshold to assign a pixel as cloud. + +- **shadow_thr**: Confidence threshold to assign a pixel as shadow. + +- **pc_key**: Optional Planetary Computer API key. + +- **s1_timeout**: Maximum time, in seconds, before a band reading operation times out. + +- **s2_timeout**: Maximum time, in seconds, before a band reading operation times out. + +## Tasks + +- **s2**: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range, and computes improved cloud masks using cloud and shadow segmentation models. + +- **s1**: Downloads and preprocesses tiles of Sentinel-1 imagery that intersect with the input Sentinel-2 products in the input time range. + +## Workflow Yaml + ```yaml -name: spaceeye_preprocess +name: spaceeye_preprocess_rtc sources: user_input: - s2.user_input @@ -12,11 +66,12 @@ sinks: s1_raster: s1.raster cloud_mask: s2.mask parameters: - min_tile_cover: null + min_tile_cover: 0.4 max_tiles_per_time: null cloud_thr: null shadow_thr: null - pc_key: null + pc_key: '@SECRET(eywa-secrets, pc-sub-key)' + s1_timeout: null s2_timeout: null tasks: s2: @@ -27,9 +82,13 @@ tasks: cloud_thr: '@from(cloud_thr)' shadow_thr: '@from(shadow_thr)' pc_key: '@from(pc_key)' + in_memory: true dl_timeout: '@from(s2_timeout)' s1: workflow: data_ingestion/sentinel1/preprocess_s1 + parameters: + pc_key: '@from(pc_key)' + dl_timeout: '@from(s1_timeout)' edges: - origin: s2.raster destination: @@ -47,20 +106,4 @@ description: cloud_mask: Cloud and cloud shadow mask. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>s2_raster] - out2>s1_raster] - out3>cloud_mask] - tsk1{{s2}} - tsk2{{s1}} - tsk1{{s2}} -- raster/s2_products --> tsk2{{s1}} - inp1>user_input] -- user_input --> tsk1{{s2}} - inp1>user_input] -- user_input --> tsk2{{s1}} - tsk1{{s2}} -- raster --> out1>s2_raster] - tsk2{{s1}} -- raster --> out2>s1_raster] - tsk1{{s2}} -- mask --> out3>cloud_mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_preprocess_ensemble.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_preprocess_ensemble.md index 11bd46a0..7fcfa842 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_preprocess_ensemble.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/spaceeye/spaceeye_preprocess_ensemble.md @@ -1,5 +1,47 @@ # data_ingestion/spaceeye/spaceeye_preprocess_ensemble +Runs the SpaceEye preprocessing pipeline with an ensemble of cloud segmentation models. The workflow fetches both Sentinel-1 and Sentinel-2 tiles that cover the input geometry and time range and preprocesses them, it also computes improved cloud masks using cloud and shadow segmentation models. Cloud probabilities are computed with an ensemble of five models. + +```{mermaid} + graph TD + inp1>user_input] + out1>s2_raster] + out2>s1_raster] + out3>cloud_mask] + tsk1{{s2}} + tsk2{{s1}} + tsk1{{s2}} -- raster/s2_products --> tsk2{{s1}} + inp1>user_input] -- user_input --> tsk1{{s2}} + inp1>user_input] -- user_input --> tsk2{{s1}} + tsk1{{s2}} -- raster --> out1>s2_raster] + tsk2{{s1}} -- raster --> out2>s1_raster] + tsk1{{s2}} -- mask --> out3>cloud_mask] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **s2_raster**: Sentinel-2 rasters. + +- **s1_raster**: Sentinel-1 rasters. + +- **cloud_mask**: Cloud and cloud shadow mask. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **s2**: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range, and computes improved cloud masks using an ensemble of cloud and shadow segmentation models. + +- **s1**: Downloads and preprocesses tiles of Sentinel-1 imagery that intersect with the input Sentinel-2 products in the input time range. + +## Workflow Yaml + ```yaml name: spaceeye_preprocess_ensemble @@ -12,7 +54,7 @@ sinks: s1_raster: s1.raster cloud_mask: s2.mask parameters: - pc_key: null + pc_key: '@SECRET(eywa-secrets, pc-sub-key)' tasks: s2: workflow: data_ingestion/sentinel2/preprocess_s2_ensemble_masks @@ -43,20 +85,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>s2_raster] - out2>s1_raster] - out3>cloud_mask] - tsk1{{s2}} - tsk2{{s1}} - tsk1{{s2}} -- raster/s2_products --> tsk2{{s1}} - inp1>user_input] -- user_input --> tsk1{{s2}} - inp1>user_input] -- user_input --> tsk2{{s1}} - tsk1{{s2}} -- raster --> out1>s2_raster] - tsk2{{s1}} -- raster --> out2>s1_raster] - tsk1{{s2}} -- mask --> out3>cloud_mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_geometry.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_geometry.md index 1f54f5f3..7a80108a 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_geometry.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_geometry.md @@ -1,5 +1,34 @@ # data_ingestion/user_data/ingest_geometry +Adds user geometries into the cluster storage, allowing for them to be used on workflows. The workflow downloads geometries provided in the references and generates GeometryCollection objects with local assets that can be used in other operations. + +```{mermaid} + graph TD + inp1>user_input] + out1>geometry] + tsk1{{unpack}} + tsk2{{download}} + tsk1{{unpack}} -- ref_list/input_ref --> tsk2{{download}} + inp1>user_input] -- input_refs --> tsk1{{unpack}} + tsk2{{download}} -- downloaded --> out1>geometry] +``` + +## Sources + +- **user_input**: List of external references. + +## Sinks + +- **geometry**: GeometryCollections with downloaded assets. + +## Tasks + +- **unpack**: Unpacks the urls from the list of external references. + +- **download**: Downloads geometries provided in the reference and generates a GeometryCollection. + +## Workflow Yaml + ```yaml name: ingest_geometry @@ -30,15 +59,4 @@ description: geometry: GeometryCollections with downloaded assets. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>geometry] - tsk1{{unpack}} - tsk2{{download}} - tsk1{{unpack}} -- ref_list/input_ref --> tsk2{{download}} - inp1>user_input] -- input_refs --> tsk1{{unpack}} - tsk2{{download}} -- downloaded --> out1>geometry] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_raster.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_raster.md index 673bde0c..8d0274bb 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_raster.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_raster.md @@ -1,5 +1,34 @@ # data_ingestion/user_data/ingest_raster +Adds user rasters into the cluster storage, allowing for them to be used on workflows. The workflow downloads rasters provided in the references and generates Raster objects with local assets that can be used in other operations. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{unpack}} + tsk2{{download}} + tsk1{{unpack}} -- ref_list/input_ref --> tsk2{{download}} + inp1>user_input] -- input_refs --> tsk1{{unpack}} + tsk2{{download}} -- downloaded --> out1>raster] +``` + +## Sources + +- **user_input**: List of external references. + +## Sinks + +- **raster**: Rasters with downloaded assets. + +## Tasks + +- **unpack**: Unpacks the urls from the list of external references. + +- **download**: Downloads the raster from the input reference's url. + +## Workflow Yaml + ```yaml name: ingest_raster @@ -29,15 +58,4 @@ description: raster: Rasters with downloaded assets. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{unpack}} - tsk2{{download}} - tsk1{{unpack}} -- ref_list/input_ref --> tsk2{{download}} - inp1>user_input] -- input_refs --> tsk1{{unpack}} - tsk2{{download}} -- downloaded --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_smb.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_smb.md index 169fc3d6..75a4a2c7 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_smb.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/user_data/ingest_smb.md @@ -1,5 +1,48 @@ # data_ingestion/user_data/ingest_smb +Adds user rasters into the cluster storage from an SMB share, allowing for them to be used on workflows. The workflow downloads rasters from the provided SMB share and generates Raster objects with local assets that can be used in other operations. + +```{mermaid} + graph TD + inp1>user_input] + out1>rasters] + tsk1{{download}} + inp1>user_input] -- user_input --> tsk1{{download}} + tsk1{{download}} -- rasters --> out1>rasters] +``` + +## Sources + +- **user_input**: DataVibe containing the time range and geometry metadata of the set rasters to be downloaded. + +## Sinks + +- **rasters**: Rasters with downloaded assets. + +## Parameters + +- **server_name**: The name of the SMB server + +- **server_ip**: The IP address of the SMB server + +- **server_port**: The port to connect to on the SMB server + +- **username**: Username used to connect to server + +- **password**: Password to access server + +- **share_name**: Name of file share + +- **directory_path**: Path to directory containing rasters + +- **bands**: Ordered list of bands within the rasters + +## Tasks + +- **download**: Downloads rasters from an SMB share. + +## Workflow Yaml + ```yaml name: ingest_smb @@ -46,13 +89,4 @@ description: rasters: Rasters with downloaded assets. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>rasters] - tsk1{{download}} - inp1>user_input] -- user_input --> tsk1{{download}} - tsk1{{download}} -- rasters --> out1>rasters] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_chirps.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_chirps.md index 7245de19..92ed4cc3 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_chirps.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_chirps.md @@ -1,5 +1,40 @@ # data_ingestion/weather/download_chirps +Downloads accumulated precipitation data from the CHIRPS dataset. + +```{mermaid} + graph TD + inp1>user_input] + out1>product] + tsk1{{list_chirps}} + tsk2{{download_chirps}} + tsk1{{list_chirps}} -- chirps_products/chirps_product --> tsk2{{download_chirps}} + inp1>user_input] -- input_item --> tsk1{{list_chirps}} + tsk2{{download_chirps}} -- downloaded_product --> out1>product] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **product**: TIFF file containing accumulated precipitation. + +## Parameters + +- **freq**: daily or monthly frequencies + +- **res**: p05 for 0.05 degree resolution or p25 for 0.25 degree resolution, p25 is only available daily + +## Tasks + +- **list_chirps**: Lists products from the CHIRPS dataset with desired frequency and resolution for input geometry and time range. + +- **download_chirps**: Downloads accumulated precipitation data from listed products. + +## Workflow Yaml + ```yaml name: chirps @@ -36,15 +71,4 @@ description: only available daily -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>product] - tsk1{{list_chirps}} - tsk2{{download_chirps}} - tsk1{{list_chirps}} -- chirps_products/chirps_product --> tsk2{{download_chirps}} - inp1>user_input] -- input_item --> tsk1{{list_chirps}} - tsk2{{download_chirps}} -- downloaded_product --> out1>product] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_era5.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_era5.md index d56761dc..4b13dcc3 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_era5.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_era5.md @@ -1,5 +1,53 @@ # data_ingestion/weather/download_era5 +Hourly estimated weather variables. Hourly weather variables obtained from combining observations and numerical model runs to estimate the state of the atmosphere. + +```{mermaid} + graph TD + inp1>user_input] + out1>downloaded_product] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- era5_products/era5_product --> tsk2{{download}} + inp1>user_input] -- input_item --> tsk1{{list}} + tsk2{{download}} -- downloaded_product --> out1>downloaded_product] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **downloaded_product**: 30km resolution weather variables. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +- **variable**: Options are: + 2t - 2 meter temperature (default) + 100u - 100 meter U wind component + 100v - 100 meter V wind component + 10u - 10 meter U wind component + 10v - 10 meter V wind component + 2d - 2 meter dewpoint temperature + mn2t - Minimum temperature at 2 meters since previous post-processing + msl - Mean sea level pressure + mx2t - Maximum temperature at 2 meters since previous post-processing + sp - Surface pressure + ssrd - Surface solar radiation downwards + sst - Sea surface temperature + tp - Total precipitation + +## Tasks + +- **list**: Lists ERA5 products for input geometry and time range. + +- **download**: Downloads requested property from ERA5 products. + +## Workflow Yaml + ```yaml name: download_era5 @@ -43,15 +91,4 @@ description: \ radiation downwards\n sst - Sea surface temperature\n tp - Total precipitation" -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>downloaded_product] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- era5_products/era5_product --> tsk2{{download}} - inp1>user_input] -- input_item --> tsk1{{list}} - tsk2{{download}} -- downloaded_product --> out1>downloaded_product] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_era5_monthly.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_era5_monthly.md index 56122e61..2c5985dc 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_era5_monthly.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_era5_monthly.md @@ -1,5 +1,51 @@ # data_ingestion/weather/download_era5_monthly +Monthly estimated weather variables. Monthly weather variables obtained from combining observations and numerical model runs to estimate the state of the atmosphere. + +```{mermaid} + graph TD + inp1>user_input] + out1>downloaded_product] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- era5_products/era5_product --> tsk2{{download}} + inp1>user_input] -- input_item --> tsk1{{list}} + tsk2{{download}} -- downloaded_product --> out1>downloaded_product] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **downloaded_product**: 30km resolution weather variables. + +## Parameters + +- **cds_api_key**: api key for Copernicus CDS (https://cds.climate.copernicus.eu/user/register) + +- **variable**: Options are: + 2t - 2 meter temperature (default) + 100u - 100 meter U wind component + 100v - 100 meter V wind component + 10u - 10 meter U wind component + 10v - 10 meter V wind component + 2d - 2 meter dewpoint temperature + msl - Mean sea level pressure + sp - Surface pressure + ssrd - Surface solar radiation downwards + sst - Sea surface temperature + tp - Total precipitation + +## Tasks + +- **list**: Lists monthly ERA5 products for the input time range and geometry. + +- **download**: Downloads requested property from ERA5 products. + +## Workflow Yaml + ```yaml name: download_era5_monthly @@ -43,15 +89,4 @@ description: \ - Total precipitation" -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>downloaded_product] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- era5_products/era5_product --> tsk2{{download}} - inp1>user_input] -- input_item --> tsk1{{list}} - tsk2{{download}} -- downloaded_product --> out1>downloaded_product] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_gridmet.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_gridmet.md index e99907b3..8c5b81a4 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_gridmet.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_gridmet.md @@ -1,5 +1,54 @@ # data_ingestion/weather/download_gridmet +Daily surface meteorological properties from GridMET. The workflow downloads weather and hydrological data for the input time range. Data is available for the contiguous US and southern British Columbia surfaces from 1979-present, with a daily temporal resolution and a ~4-km (1/24th degree) spatial resolution. + +```{mermaid} + graph TD + inp1>user_input] + out1>downloaded_product] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- products/input_product --> tsk2{{download}} + inp1>user_input] -- input_item --> tsk1{{list}} + tsk2{{download}} -- downloaded_product --> out1>downloaded_product] +``` + +## Sources + +- **user_input**: Time range of interest. + +## Sinks + +- **downloaded_product**: Downloaded variable for each year in the input time range. + +## Parameters + +- **variable**: Options are: + bi - Burning Index + erc - Energy Release Component + etr - Daily reference evapotranspiration (alfafa, units = mm) + fm100 - Fuel Moisture (100-hr, units = %) + fm1000 - Fuel Moisture (1000-hr, units = %) + pet - Potential evapotranspiration (reference grass evapotranspiration, units = mm) + pr - Precipitation amount (daily total, units = mm) + rmax - Maximum relative humidity (units = %) + rmin - Minimum relative humidity (units = %) + sph - Specific humididy (units = kg/kg) + srad - Downward surface shortwave radiation (units = W/m^2) + th - Wind direction (degrees clockwise from North) + tmmn - Minimum temperature (units = K) + tmmx - Maximum temperature (units = K) + vpd - Vapor Pressure Deficit (units = kPa) + vs - Wind speed at 10m (units = m/s) + +## Tasks + +- **list**: Lists GridMET products of `variable` from years intersecting with input time range. + +- **download**: Downloads Climatology Lab weather products (TerraClimate and GridMET) defined by the input product. + +## Workflow Yaml + ```yaml name: download_gridmet @@ -46,15 +95,4 @@ description: \ vs - Wind speed at 10m (units = m/s)" -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>downloaded_product] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- products/input_product --> tsk2{{download}} - inp1>user_input] -- input_item --> tsk1{{list}} - tsk2{{download}} -- downloaded_product --> out1>downloaded_product] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_herbie.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_herbie.md index 4daaad77..a2bb5c8c 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_herbie.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_herbie.md @@ -1,5 +1,48 @@ # data_ingestion/weather/download_herbie +Downloads forecast data for provided location & time range using herbie python package. Herbie is a python package that downloads recent and archived numerical weather prediction (NWP) model outputs from different cloud archive sources. Its most popular capability is to download HRRR model data. NWP data in GRIB2 format can be read with xarray+cfgrib. Model data Herbie can retrieve includes the High Resolution Rapid Refresh (HRRR), Rapid Refresh (RAP), Global Forecast System (GFS), National Blend of Models (NBM), Rapid Refresh Forecast System - Prototype (RRFS), and ECMWF open data forecast products (ECMWF). + +```{mermaid} + graph TD + inp1>user_input] + out1>forecast] + tsk1{{list_herbie}} + tsk2{{download_herbie}} + tsk1{{list_herbie}} -- product/herbie_product --> tsk2{{download_herbie}} + inp1>user_input] -- input_item --> tsk1{{list_herbie}} + tsk2{{download_herbie}} -- forecast --> out1>forecast] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **forecast**: Grib file with the requested forecast. + +## Parameters + +- **model**: Model name as defined in the models template folder. CASE INSENSITIVE Below are examples of model types 'hrrr' HRRR contiguous United States model 'hrrrak' HRRR Alaska model (alias 'alaska') 'rap' RAP model 'gfs' Global Forecast System (atmosphere) 'gfs_wave' Global Forecast System (wave) 'rrfs' Rapid Refresh Forecast System prototype for more information see https://herbie.readthedocs.io/en/latest/user_guide/model_info.html + +- **product**: Output variable product file type (sfc (surface fields), prs (pressure fields), nat (native fields), subh (subhourly fields)). Not specifying this will use the first product in model template file. + +- **frequency**: frequency in hours of the forecast + +- **forecast_lead_times**: Forecast lead time in the format [start_time, end_time, increment] (in hours). This parameter can be None, and in this case see parameter 'forecast_start_date' for more details. You cannot specify 'forecast_lead_times' and 'forecast_start_date' at the same time. + +- **forecast_start_date**: latest datetime (in the format "%Y-%m-%d %H:%M") for which analysis (zero lead time) are retrieved. After this datetime, forecasts with progressively increasing lead times are retrieved. If this parameter is set to None and 'forecast_lead_times' is also set to None, then the workflow returns analysis (zero lead time) up to the latest analysis available, and from that point it returns forecasts with progressively increasing lead times. + +- **search_text**: It's a regular expression used to search on GRIB2 Index files and allow you to download just the layer of the file required instead of complete file. For more information on search_text refer to below url. https://blaylockbk.github.io/Herbie/_build/html/user_guide/searchString.html + +## Tasks + +- **list_herbie**: Lists herbie products. + +- **download_herbie**: Download herbie grib files. + +## Workflow Yaml + ```yaml name: download_herbie @@ -12,10 +55,8 @@ parameters: model: hrrr product: null frequency: 1 - forecast_lead_times: - - 0 - - 1 - - 1 + forecast_lead_times: null + forecast_start_date: null search_text: :TMP:2 m tasks: list_herbie: @@ -25,6 +66,7 @@ tasks: product: '@from(product)' frequency: '@from(frequency)' forecast_lead_times: '@from(forecast_lead_times)' + forecast_start_date: '@from(forecast_start_date)' search_text: '@from(search_text)' download_herbie: op: download_herbie @@ -57,21 +99,18 @@ description: will use the first product in model template file. frequency: frequency in hours of the forecast forecast_lead_times: Forecast lead time in the format [start_time, end_time, increment] - (in hours) + (in hours). This parameter can be None, and in this case see parameter 'forecast_start_date' + for more details. You cannot specify 'forecast_lead_times' and 'forecast_start_date' + at the same time. + forecast_start_date: latest datetime (in the format "%Y-%m-%d %H:%M") for which + analysis (zero lead time) are retrieved. After this datetime, forecasts with + progressively increasing lead times are retrieved. If this parameter is set + to None and 'forecast_lead_times' is also set to None, then the workflow returns + analysis (zero lead time) up to the latest analysis available, and from that + point it returns forecasts with progressively increasing lead times. search_text: It's a regular expression used to search on GRIB2 Index files and allow you to download just the layer of the file required instead of complete file. For more information on search_text refer to below url. https://blaylockbk.github.io/Herbie/_build/html/user_guide/searchString.html -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>forecast] - tsk1{{list_herbie}} - tsk2{{download_herbie}} - tsk1{{list_herbie}} -- product/herbie_product --> tsk2{{download_herbie}} - inp1>user_input] -- input_item --> tsk1{{list_herbie}} - tsk2{{download_herbie}} -- forecast --> out1>forecast] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_terraclimate.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_terraclimate.md index 23bdd08e..a8c31a4e 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_terraclimate.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/download_terraclimate.md @@ -1,5 +1,52 @@ # data_ingestion/weather/download_terraclimate +Monthly climate and hydroclimate properties from TerraClimate. The workflow downloads weather and hydrological data for the input time range. Data is available for global terrestrial surfaces from 1958-present, with a monthly temporal resolution and a ~4-km (1/24th degree) spatial resolution. + +```{mermaid} + graph TD + inp1>user_input] + out1>downloaded_product] + tsk1{{list}} + tsk2{{download}} + tsk1{{list}} -- products/input_product --> tsk2{{download}} + inp1>user_input] -- input_item --> tsk1{{list}} + tsk2{{download}} -- downloaded_product --> out1>downloaded_product] +``` + +## Sources + +- **user_input**: Time range of interest. + +## Sinks + +- **downloaded_product**: Downloaded variable for each year in the input time range. + +## Parameters + +- **variable**: Options are: + aet - Actual Evapotranspiration (monthly total, units = mm) + def - Climate Water Deficit (monthly total, units = mm) + pet - Potential evapotranspiration (monthly total, units = mm) + ppt - Precipitation (monthly total, units = mm) + q - Runoff (monthly total, units = mm) + soil - Soil Moisture (total column at end of month, units = mm) + srad - Downward surface shortwave radiation (units = W/m2) + swe - Snow water equivalent (at end of month, units = mm) + tmax - Max Temperature (average for month, units = C) + tmin - Min Temperature (average for month, units = C) + vap - Vapor pressure (average for month, units = kPa) + ws - Wind speed (average for month, units = m/s) + vpd - Vapor Pressure Deficit (average for month, units = kPa) + PDSI - Palmer Drought Severity Index (at end of month, units = unitless) + +## Tasks + +- **list**: Lists TerraClimate products of `variable` from years intersecting with input time range. + +- **download**: Downloads Climatology Lab weather products (TerraClimate and GridMET) defined by the input product. + +## Workflow Yaml + ```yaml name: download_terraclimate @@ -46,15 +93,4 @@ description: \ = unitless)" -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>downloaded_product] - tsk1{{list}} - tsk2{{download}} - tsk1{{list}} -- products/input_product --> tsk2{{download}} - inp1>user_input] -- input_item --> tsk1{{list}} - tsk2{{download}} -- downloaded_product --> out1>downloaded_product] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/get_ambient_weather.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/get_ambient_weather.md index d32b0f61..71ca7308 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/get_ambient_weather.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/get_ambient_weather.md @@ -1,5 +1,40 @@ # data_ingestion/weather/get_ambient_weather +Downloads weather data from an Ambient Weather station. The workflow connects to the Ambient Weather REST API and requests data for the input time range. The input geometry will be used to find a device inside the region. If not devices are found in the geometry, the workflow will fail. Connection to the API requires an API key and an App key. + +```{mermaid} + graph TD + inp1>user_input] + out1>weather] + tsk1{{get_weather}} + inp1>user_input] -- user_input --> tsk1{{get_weather}} + tsk1{{get_weather}} -- weather --> out1>weather] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **weather**: Weather data from the station. + +## Parameters + +- **api_key**: Ambient Weather API key. + +- **app_key**: Ambient Weather App key. + +- **limit**: Maximum number of data points. If -1, do not limit. + +- **feed_interval**: Interval between samples. Defined by the weather station. + +## Tasks + +- **get_weather**: Connects to the Ambient Weather REST API and requests weather data for the input time range from stations within input geometry. + +## Workflow Yaml + ```yaml name: get_ambient_weather @@ -40,13 +75,4 @@ description: feed_interval: Interval between samples. Defined by the weather station. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>weather] - tsk1{{get_weather}} - inp1>user_input] -- user_input --> tsk1{{get_weather}} - tsk1{{get_weather}} -- weather --> out1>weather] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/get_forecast.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/get_forecast.md index deb96ed3..5b560ecc 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/get_forecast.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/get_forecast.md @@ -1,5 +1,43 @@ # data_ingestion/weather/get_forecast +Downloads weather forecast data from NOAA Global Forecast System (GFS) for the input time range. The workflow downloads global forecast data from the Planetary Computer with 13km resolution between grid points. The workflow requires a SAS token to access the blob storage, which can be found at https://planetarycomputer.microsoft.com/dataset/storage/noaa-gfs. + +```{mermaid} + graph TD + inp1>user_input] + out1>forecast] + tsk1{{preprocessing}} + tsk2{{gfs_download}} + tsk3{{read_forecast}} + tsk1{{preprocessing}} -- time --> tsk2{{gfs_download}} + tsk1{{preprocessing}} -- location --> tsk3{{read_forecast}} + tsk2{{gfs_download}} -- global_forecast --> tsk3{{read_forecast}} + inp1>user_input] -- user_input --> tsk1{{preprocessing}} + tsk3{{read_forecast}} -- local_forecast --> out1>forecast] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **forecast**: Weather forecast data. + +## Parameters + +- **noaa_gfs_token**: SAS token to access blob storage. + +## Tasks + +- **preprocessing**: Gets the most relevant model date and forecast hour of product for the given input day, time and location. + +- **gfs_download**: Downloads the global forecast for the given input time. + +- **read_forecast**: Extracts the local data from a global forecast. + +## Workflow Yaml + ```yaml name: get_forecast @@ -48,18 +86,4 @@ description: noaa_gfs_token: SAS token to access blob storage. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>forecast] - tsk1{{preprocessing}} - tsk2{{gfs_download}} - tsk3{{read_forecast}} - tsk1{{preprocessing}} -- time --> tsk2{{gfs_download}} - tsk1{{preprocessing}} -- location --> tsk3{{read_forecast}} - tsk2{{gfs_download}} -- global_forecast --> tsk3{{read_forecast}} - inp1>user_input] -- user_input --> tsk1{{preprocessing}} - tsk3{{read_forecast}} -- local_forecast --> out1>forecast] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/herbie_forecast.md b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/herbie_forecast.md index faffe2fa..8f1d67d7 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/herbie_forecast.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_ingestion/weather/herbie_forecast.md @@ -1,5 +1,52 @@ # data_ingestion/weather/herbie_forecast +Downloads forecast observations for provided location & time range using herbie python package. Herbie is a python package that downloads recent and archived numerical weather prediction (NWP) model outputs from different cloud archive sources. Its most popular capability is to download HRRR model data. NWP data in GRIB2 format can be read with xarray+cfgrib. Model data Herbie can retrieve includes the High Resolution Rapid Refresh (HRRR), Rapid Refresh (RAP), Global Forecast System (GFS), National Blend of Models (NBM), Rapid Refresh Forecast System - Prototype (RRFS), and ECMWF open data forecast products (ECMWF). + +```{mermaid} + graph TD + inp1>user_input] + out1>weather_forecast] + out2>forecast_range] + tsk1{{forecast_range}} + tsk2{{forecast_download}} + tsk1{{forecast_range}} -- download_period/user_input --> tsk2{{forecast_download}} + inp1>user_input] -- user_input --> tsk1{{forecast_range}} + tsk2{{forecast_download}} -- weather_forecast --> out1>weather_forecast] + tsk1{{forecast_range}} -- download_period --> out2>forecast_range] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **weather_forecast**: Downloaded Forecast observations, cleaned, interpolated and mapped to each hour. + +- **forecast_range**: Time range of forecast observations. + +## Parameters + +- **forecast_lead_times**: Help to define forecast lead time in hours. Accept the input in range format. Example - (1, 25, 1) For more information refer below url. https://blaylockbk.github.io/Herbie/_build/html/reference_guide/_autosummary/herbie.archive.Herbie.html + +- **search_text**: It's a regular expression used to search on GRIB2 Index files and allow you to download just the layer of the file required instead of complete file. For more information on search_text refer to below url. https://blaylockbk.github.io/Herbie/_build/html/user_guide/searchString.html + +- **weather_type**: It's a user preferred text to represent weather parameter type (temperature, humidity, wind_speed etc). This is used as column name for the output returned by operator. + +- **model**: Model name as defined in the models template folder. CASE INSENSITIVE Below are examples of model types 'hrrr' HRRR contiguous United States model 'hrrrak' HRRR Alaska model (alias 'alaska') 'rap' RAP model 'gfs' Global Forecast System (atmosphere) 'gfs_wave' Global Forecast System (wave) 'rrfs' Rapid Refresh Forecast System prototype + +- **overwrite**: If true, look for GRIB2 file even if local copy exists. If false, use the local copy + +- **product**: Output variable product file type (sfc (surface fields), prs (pressure fields), nat (native fields), subh (subhourly fields)). Not specifying this will use the first product in model template file. + +## Tasks + +- **forecast_range**: Splits input time range according to frequency and number of hours in lead time. + +- **forecast_download**: Downloads forecast observations with Herbie. + +## Workflow Yaml + ```yaml name: forecast_weather @@ -75,17 +122,4 @@ description: by operator. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>weather_forecast] - out2>forecast_range] - tsk1{{forecast_range}} - tsk2{{forecast_download}} - tsk1{{forecast_range}} -- download_period/user_input --> tsk2{{forecast_download}} - inp1>user_input] -- user_input --> tsk1{{forecast_range}} - tsk2{{forecast_download}} -- weather_forecast --> out1>weather_forecast] - tsk1{{forecast_range}} -- download_period --> out2>forecast_range] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/chunk_onnx/chunk_onnx.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/chunk_onnx/chunk_onnx.md index dafb56ec..879d499a 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/chunk_onnx/chunk_onnx.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/chunk_onnx/chunk_onnx.md @@ -1,5 +1,49 @@ # data_processing/chunk_onnx/chunk_onnx +Runs an Onnx model over all rasters in the input to produce a single raster. This workflow is intended to apply an Onnx model over all rasters in the input to produce a single raster output. This can be used, for instance, to compute time-series analysis of a list of rasters that span multiple times. The analysis can be any computation that can be expressed as an Onnx model (for an example, see notebooks/crop_cycles/crop_cycles.ipynb). In order to run the model in parallel (and avoid running out of memory if the list of rasters is large), the input rasters are divided spatially into chunks (that span all times). The Onnx model is applied to these chunks and then combined back to produce the final output. + +```{mermaid} + graph TD + inp1>rasters] + out1>raster] + tsk1{{chunk_raster}} + tsk2{{list_to_sequence}} + tsk3{{compute_onnx}} + tsk4{{combine_chunks}} + tsk1{{chunk_raster}} -- chunk_series/chunk --> tsk3{{compute_onnx}} + tsk2{{list_to_sequence}} -- rasters_seq/input_raster --> tsk3{{compute_onnx}} + tsk3{{compute_onnx}} -- output_raster/chunks --> tsk4{{combine_chunks}} + inp1>rasters] -- rasters --> tsk1{{chunk_raster}} + inp1>rasters] -- list_rasters --> tsk2{{list_to_sequence}} + tsk4{{combine_chunks}} -- raster --> out1>raster] +``` + +## Sources + +- **rasters**: Input rasters. + +## Sinks + +- **raster**: Result of the Onnx model run. + +## Parameters + +- **model_file**: An Onnx model which needs to be deployed with "farmvibes-ai local add-onnx" command. + +- **step**: Size of the chunk in pixels. + +## Tasks + +- **chunk_raster**: Splits input rasters into a series of chunks. + +- **list_to_sequence**: Combines a list of Rasters into a RasterSequence. + +- **compute_onnx**: Runs the onnx model across chunks of the input rasters. + +- **combine_chunks**: Combines series of chunks into a final raster. + +## Workflow Yaml + ```yaml name: chunk_onnx @@ -60,20 +104,4 @@ description: step: Size of the chunk in pixels. -``` - -```{mermaid} - graph TD - inp1>rasters] - out1>raster] - tsk1{{chunk_raster}} - tsk2{{list_to_sequence}} - tsk3{{compute_onnx}} - tsk4{{combine_chunks}} - tsk1{{chunk_raster}} -- chunk_series/chunk --> tsk3{{compute_onnx}} - tsk2{{list_to_sequence}} -- rasters_seq/input_raster --> tsk3{{compute_onnx}} - tsk3{{compute_onnx}} -- output_raster/chunks --> tsk4{{combine_chunks}} - inp1>rasters] -- rasters --> tsk1{{chunk_raster}} - inp1>rasters] -- list_rasters --> tsk2{{list_to_sequence}} - tsk4{{combine_chunks}} -- raster --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/chunk_onnx/chunk_onnx_sequence.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/chunk_onnx/chunk_onnx_sequence.md index b4614c4a..f85ae376 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/chunk_onnx/chunk_onnx_sequence.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/chunk_onnx/chunk_onnx_sequence.md @@ -1,5 +1,45 @@ # data_processing/chunk_onnx/chunk_onnx_sequence +Runs an Onnx model over all rasters in the input to produce a single raster. This workflow is intended to run an Onnx model on all input rasters to produce a single raster output. This can be used, for instance, to compute time-series analysis of a list of rasters that span multiple times. The analysis can be any computation that can be expressed as an Onnx model (for an example, see notebooks/crop_cycles/crop_cycles.ipynb). In order to run the model in parallel (and avoid running out of memory if the list of rasters is large), the input rasters are divided spatially into chunks (that span all times). The Onnx model is applied to these chunks and then combined back to produce the final output. + +```{mermaid} + graph TD + inp1>rasters] + out1>raster] + tsk1{{chunk_raster}} + tsk2{{compute_onnx}} + tsk3{{combine_chunks}} + tsk1{{chunk_raster}} -- chunk_series/chunk --> tsk2{{compute_onnx}} + tsk2{{compute_onnx}} -- output_raster/chunks --> tsk3{{combine_chunks}} + inp1>rasters] -- rasters --> tsk1{{chunk_raster}} + inp1>rasters] -- input_raster --> tsk2{{compute_onnx}} + tsk3{{combine_chunks}} -- raster --> out1>raster] +``` + +## Sources + +- **rasters**: Input rasters. + +## Sinks + +- **raster**: Result of the Onnx model run. + +## Parameters + +- **model_file**: An Onnx model which needs to be deployed with "farmvibes-ai local add-onnx" command. + +- **step**: Size of the chunk in pixels. + +## Tasks + +- **chunk_raster**: Splits input rasters into a series of chunks. + +- **compute_onnx**: Runs the onnx model across chunks of the input rasters. + +- **combine_chunks**: Combines series of chunks into a final raster. + +## Workflow Yaml + ```yaml name: chunk_onnx_sequence @@ -55,18 +95,4 @@ description: step: Size of the chunk in pixels. -``` - -```{mermaid} - graph TD - inp1>rasters] - out1>raster] - tsk1{{chunk_raster}} - tsk2{{compute_onnx}} - tsk3{{combine_chunks}} - tsk1{{chunk_raster}} -- chunk_series/chunk --> tsk2{{compute_onnx}} - tsk2{{compute_onnx}} -- output_raster/chunks --> tsk3{{combine_chunks}} - inp1>rasters] -- rasters --> tsk1{{chunk_raster}} - inp1>rasters] -- input_raster --> tsk2{{compute_onnx}} - tsk3{{combine_chunks}} -- raster --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/clip/clip.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/clip/clip.md index 680a81e2..6f31f6c3 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/clip/clip.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/clip/clip.md @@ -1,5 +1,34 @@ # data_processing/clip/clip +Performs a soft clip on an input raster based on a provided reference geometry. The workflow outputs a new raster copied from the input raster with its geometry metadata as the intersection between the input raster's geometry and the provided reference geometry. The workflow raises an error if there is no intersection between both geometries. + +```{mermaid} + graph TD + inp1>raster] + inp2>input_geometry] + out1>clipped_raster] + tsk1{{clip_raster}} + inp1>raster] -- raster --> tsk1{{clip_raster}} + inp2>input_geometry] -- input_item --> tsk1{{clip_raster}} + tsk1{{clip_raster}} -- clipped_raster --> out1>clipped_raster] +``` + +## Sources + +- **raster**: Input raster to be clipped. + +- **input_geometry**: Reference geometry. + +## Sinks + +- **clipped_raster**: Clipped raster with the reference geometry. + +## Tasks + +- **clip_raster**: Soft clips the input raster based on the provided referente geometry. + +## Workflow Yaml + ```yaml name: clip @@ -29,15 +58,4 @@ description: parameters: null -``` - -```{mermaid} - graph TD - inp1>raster] - inp2>input_geometry] - out1>clipped_raster] - tsk1{{clip_raster}} - inp1>raster] -- raster --> tsk1{{clip_raster}} - inp2>input_geometry] -- input_item --> tsk1{{clip_raster}} - tsk1{{clip_raster}} -- clipped_raster --> out1>clipped_raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/gradient/raster_gradient.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/gradient/raster_gradient.md index c09c717b..b36ad676 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/gradient/raster_gradient.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/gradient/raster_gradient.md @@ -1,5 +1,30 @@ # data_processing/gradient/raster_gradient +Computes the gradient of each band of the input raster with a Sobel operator. + +```{mermaid} + graph TD + inp1>raster] + out1>gradient] + tsk1{{gradient}} + inp1>raster] -- input_raster --> tsk1{{gradient}} + tsk1{{gradient}} -- output_raster --> out1>gradient] +``` + +## Sources + +- **raster**: Input raster. + +## Sinks + +- **gradient**: Raster with the gradients. + +## Tasks + +- **gradient**: Computes the gradient of each band of the input raster with a Sobel operator. + +## Workflow Yaml + ```yaml name: raster_gradient @@ -23,13 +48,4 @@ description: parameters: null -``` - -```{mermaid} - graph TD - inp1>raster] - out1>gradient] - tsk1{{gradient}} - inp1>raster] -- input_raster --> tsk1{{gradient}} - tsk1{{gradient}} -- output_raster --> out1>gradient] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/heatmap/classification.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/heatmap/classification.md index d1ec2e5b..fef8e003 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/heatmap/classification.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/heatmap/classification.md @@ -1,5 +1,83 @@ # data_processing/heatmap/classification +Utilizes input Sentinel-2 satellite imagery & the sensor samples as labeled data that contain nutrient information (Nitrogen, Carbon, pH, Phosphorus) to train a model using Random Forest classifier. The inference operation predicts nutrients in soil for the chosen farm boundary. + The workflow generates a heatmap for selected nutrient. It relies on sample soil data that +contain information of nutrients. The quantity of samples define the accuracy of the heat map +generation. During the research performed testing with samples spaced at 200 feet, 100 feet and +50 feet. The 50 feet sample spaced distance provided results matching to the ground truth. +Generating heatmaps with this approach reduces the number of samples. It utilizes the logic +below behind the scenes to generate heatmap. + - Read the sentinel raster provided. + - Sensor samples needs to be uploaded into prescriptions entity in Azure + data manager for Agriculture (ADMAg). ADMAg is having hierarchy to hold + information of Party, Field, Seasons, Crop etc. Prior to + uploading prescriptions, it is required to build hierarchy and + a `prescription_map_id`. All prescriptions uploaded to ADMAg are + related to farm hierarchy through `prescription_map_id`. Please refer to + https://learn.microsoft.com/en-us/rest/api/data-manager-for-agri/ for + more information on ADMAg. + - Compute indices using the spyndex python package. + - Clip the satellite imagery & sensor samples using farm boundary. + - Perform spatial interpolation to find raster pixels within the offset distance + from sample location and assign the value of nutrients to group of pixels. + - Classify the data based on number of bins. + - Train the model using Random Forest classifier. + - Predict the nutrients using the satellite imagery. + - Generate a shape file using the predicted outputs. + +```{mermaid} + graph TD + inp1>input_raster] + inp2>samples] + out1>result] + tsk1{{compute_index}} + tsk2{{soil_sample_heatmap}} + tsk1{{compute_index}} -- index_raster/raster --> tsk2{{soil_sample_heatmap}} + inp1>input_raster] -- raster --> tsk1{{compute_index}} + inp2>samples] -- samples --> tsk2{{soil_sample_heatmap}} + tsk2{{soil_sample_heatmap}} -- result --> out1>result] +``` + +## Sources + +- **input_raster**: Input raster for index computation. + +- **samples**: External references to sensor samples for nutrients. + +## Sinks + +- **result**: Zip file containing cluster geometries. + +## Parameters + +- **attribute_name**: Nutrient property name in sensor samples geojson file. For example CARBON (C), Nitrogen (N), Phosphorus (P) etc., + +- **buffer**: Offset distance from sample to perform interpolate operations with raster. + +- **index**: Type of index to be used to generate heatmap. For example - evi, pri etc., + +- **bins**: Possible number of groups used to move value to nearest group using [numpy histogram](https://numpy.org/doc/stable/reference/generated/numpy.histogram.html) and to pre-process the data to support model training with classification . + +- **simplify**: Replace small polygons in input with value of their largest neighbor after converting from raster to vector. Accepts 'simplify' or 'convex' or 'none'. + +- **tolerance**: All parts of a [simplified geometry](https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoSeries.simplify.html) will be no more than tolerance distance from the original. It has the same units as the coordinate reference system of the GeoSeries. For example, using tolerance=100 in a projected CRS with meters as units means a distance of 100 meters in reality. + +- **data_scale**: Accepts True or False. Default is False. On True, it scale data using [StandardScalar] (https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html) from scikit-learn package. It Standardize features by removing the mean and scaling to unit variance. + +- **max_depth**: The maximum depth of the tree. If None, then nodes are expanded until all leaves are pure or until all leaves contain less than min_samples_split samples. For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + +- **n_estimators**: The number of trees in the forest. For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + +- **random_state**: Controls both the randomness of the bootstrapping of the samples used when building trees (if bootstrap=True) and the sampling of the features to consider when looking for the best split at each node (if max_features < n_features). For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + +## Tasks + +- **compute_index**: Computes an index from the bands of an input raster. + +- **soil_sample_heatmap**: Generate heatmap for nutrients using satellite or spaceEye imagery. + +## Workflow Yaml + ```yaml name: heatmap_intermediate @@ -59,10 +137,10 @@ description: \ the logic\nbelow behind the scenes to generate heatmap.\n - Read the sentinel\ \ raster provided.\n - Sensor samples needs to be uploaded into prescriptions\ \ entity in Azure\n data manager for Agriculture (ADMAg). ADMAg is having hierarchy\ - \ to hold\n information of Farmer, Field, Seasons, Crop, Boundary etc. Prior\ - \ to\n uploading prescriptions, it is required to build hierarchy and\n \ - \ a `prescription_map_id`. All prescriptions uploaded to ADMAg are\n related\ - \ to farm hierarchy through `prescription_map_id`. Please refer to\n https://learn.microsoft.com/en-us/rest/api/data-manager-for-agri/\ + \ to hold\n information of Party, Field, Seasons, Crop etc. Prior to\n uploading\ + \ prescriptions, it is required to build hierarchy and\n a `prescription_map_id`.\ + \ All prescriptions uploaded to ADMAg are\n related to farm hierarchy through\ + \ `prescription_map_id`. Please refer to\n https://learn.microsoft.com/en-us/rest/api/data-manager-for-agri/\ \ for\n more information on ADMAg.\n - Compute indices using the spyndex python\ \ package.\n - Clip the satellite imagery & sensor samples using farm boundary.\n\ \ - Perform spatial interpolation to find raster pixels within the offset distance\n\ @@ -103,17 +181,4 @@ description: n_features). For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) -``` - -```{mermaid} - graph TD - inp1>input_raster] - inp2>samples] - out1>result] - tsk1{{compute_index}} - tsk2{{soil_sample_heatmap}} - tsk1{{compute_index}} -- index_raster/raster --> tsk2{{soil_sample_heatmap}} - inp1>input_raster] -- raster --> tsk1{{compute_index}} - inp2>samples] -- samples --> tsk2{{soil_sample_heatmap}} - tsk2{{soil_sample_heatmap}} -- result --> out1>result] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/index/index.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/index/index.md index 11aade4f..6b730148 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/index/index.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/index/index.md @@ -1,5 +1,34 @@ # data_processing/index/index +Computes an index from the bands of an input raster. In addition to the indices 'ndvi', 'evi', 'msavi', 'ndre', 'reci', 'ndmi', 'methane' and 'pri' all indices in https://github.com/awesome-spectral-indices/awesome-spectral-indices are available (depending on the bands available on the corresponding satellite product). + +```{mermaid} + graph TD + inp1>raster] + out1>index_raster] + tsk1{{compute_index}} + inp1>raster] -- raster --> tsk1{{compute_index}} + tsk1{{compute_index}} -- index --> out1>index_raster] +``` + +## Sources + +- **raster**: Input raster. + +## Sinks + +- **index_raster**: Single-band raster with the computed index. + +## Parameters + +- **index**: The choice of index to be computed ('ndvi', 'evi', 'msavi', 'ndre', 'reci', 'ndmi', 'methane', 'pri' or any of the awesome-spectral-indices). + +## Tasks + +- **compute_index**: Computes `index` over the input raster. + +## Workflow Yaml + ```yaml name: index @@ -31,13 +60,4 @@ description: 'ndmi', 'methane', 'pri' or any of the awesome-spectral-indices). -``` - -```{mermaid} - graph TD - inp1>raster] - out1>index_raster] - tsk1{{compute_index}} - inp1>raster] -- raster --> tsk1{{compute_index}} - tsk1{{compute_index}} -- index --> out1>index_raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/linear_trend/chunked_linear_trend.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/linear_trend/chunked_linear_trend.md index 3f1b76b2..0585bc77 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/linear_trend/chunked_linear_trend.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/linear_trend/chunked_linear_trend.md @@ -1,5 +1,45 @@ # data_processing/linear_trend/chunked_linear_trend +Computes the pixel-wise linear trend of a list of rasters (e.g. NDVI). The workflow computes the linear trend over chunks of data, combining them into the final raster. + +```{mermaid} + graph TD + inp1>input_rasters] + out1>linear_trend_raster] + tsk1{{chunk_raster}} + tsk2{{linear_trend}} + tsk3{{combine_chunks}} + tsk1{{chunk_raster}} -- chunk_series/series --> tsk2{{linear_trend}} + tsk2{{linear_trend}} -- trend/chunks --> tsk3{{combine_chunks}} + inp1>input_rasters] -- rasters --> tsk1{{chunk_raster}} + inp1>input_rasters] -- rasters --> tsk2{{linear_trend}} + tsk3{{combine_chunks}} -- raster --> out1>linear_trend_raster] +``` + +## Sources + +- **input_rasters**: List of rasters to compute linear trend. + +## Sinks + +- **linear_trend_raster**: Raster with the trend and the test statistics. + +## Parameters + +- **chunk_step_y**: steps used to divide the rasters into chunks in the y direction (units are grid points). + +- **chunk_step_x**: steps used to divide the rasters into chunks in the x direction (units are grid points). + +## Tasks + +- **chunk_raster**: Splits input rasters into a series of chunks. + +- **linear_trend**: Computes the pixel-wise linear trend across rasters. + +- **combine_chunks**: Combines series of chunks into a final raster. + +## Workflow Yaml + ```yaml name: chunked_linear_trend @@ -45,18 +85,4 @@ description: (units are grid points). -``` - -```{mermaid} - graph TD - inp1>input_rasters] - out1>linear_trend_raster] - tsk1{{chunk_raster}} - tsk2{{linear_trend}} - tsk3{{combine_chunks}} - tsk1{{chunk_raster}} -- chunk_series/series --> tsk2{{linear_trend}} - tsk2{{linear_trend}} -- trend/chunks --> tsk3{{combine_chunks}} - inp1>input_rasters] -- rasters --> tsk1{{chunk_raster}} - inp1>input_rasters] -- rasters --> tsk2{{linear_trend}} - tsk3{{combine_chunks}} -- raster --> out1>linear_trend_raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/merge/match_merge_to_ref.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/merge/match_merge_to_ref.md index 1c0b0491..863b2323 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/merge/match_merge_to_ref.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/merge/match_merge_to_ref.md @@ -1,5 +1,52 @@ # data_processing/merge/match_merge_to_ref +Resamples input rasters to the reference rasters' grid. The workflow will produce input and reference raster pairs with intersecting geometries. For each pair, the input raster is resampled to match the reference raster's grid. Afterwards, all resampled rasters are groupped if they are contained in a reference raster geometry, and each raster group is matched into single raster. The output should contain the information available in the input rasters, gridded according to the reference rasters. + +```{mermaid} + graph TD + inp1>rasters] + inp2>ref_rasters] + out1>match_rasters] + tsk1{{pair}} + tsk2{{match}} + tsk3{{group}} + tsk4{{merge}} + tsk1{{pair}} -- paired_rasters1/ref_raster --> tsk2{{match}} + tsk1{{pair}} -- paired_rasters2/raster --> tsk2{{match}} + tsk2{{match}} -- output_raster/rasters --> tsk3{{group}} + tsk3{{group}} -- raster_groups/raster_sequence --> tsk4{{merge}} + inp1>rasters] -- rasters2 --> tsk1{{pair}} + inp2>ref_rasters] -- rasters1 --> tsk1{{pair}} + inp2>ref_rasters] -- group_by --> tsk3{{group}} + tsk4{{merge}} -- raster --> out1>match_rasters] +``` + +## Sources + +- **rasters**: Input rasters that will be resampled. + +- **ref_rasters**: Reference rasters. + +## Sinks + +- **match_rasters**: Rasters with information from the input rasters on the reference grid. + +## Parameters + +- **resampling**: Type of resampling when reprojecting the rasters. See [link=https://rasterio.readthedocs.io/en/latest/api/rasterio.enums.html#rasterio.enums.Resampling] rasterio documentation: https://rasterio.readthedocs.io/en/latest/api/rasterio.enums.html#rasterio.enums.Resampling[/] for all available resampling options. + +## Tasks + +- **pair**: Creates pairs of rasters with intersecting geometries between two input lists of Raster. + +- **match**: Resamples the input `raster` to match the grid of `ref_raster`. + +- **group**: Groups input rasters that are contained in the geometry of a reference raster. + +- **merge**: Merges rasters in a sequence to a single raster. + +## Workflow Yaml + ```yaml name: match_merge_to_ref @@ -59,23 +106,4 @@ description: for all available resampling options.' -``` - -```{mermaid} - graph TD - inp1>rasters] - inp2>ref_rasters] - out1>match_rasters] - tsk1{{pair}} - tsk2{{match}} - tsk3{{group}} - tsk4{{merge}} - tsk1{{pair}} -- paired_rasters1/ref_raster --> tsk2{{match}} - tsk1{{pair}} -- paired_rasters2/raster --> tsk2{{match}} - tsk2{{match}} -- output_raster/rasters --> tsk3{{group}} - tsk3{{group}} -- raster_groups/raster_sequence --> tsk4{{merge}} - inp1>rasters] -- rasters2 --> tsk1{{pair}} - inp2>ref_rasters] -- rasters1 --> tsk1{{pair}} - inp2>ref_rasters] -- group_by --> tsk3{{group}} - tsk4{{merge}} -- raster --> out1>match_rasters] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/outlier/detect_outlier.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/outlier/detect_outlier.md index 5a77e9fd..614702e8 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/outlier/detect_outlier.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/outlier/detect_outlier.md @@ -1,5 +1,46 @@ # data_processing/outlier/detect_outlier +Fits a single-component Gaussian Mixture Model (GMM) over input data to detect outliers according to the threshold parameter. The workflow outputs segmentation and outlier maps based on the threshold parameter and the likelihood of each sample belonging to the GMM component. It also yields heatmaps of the likelihood, and the mean of GMM's component. + +```{mermaid} + graph TD + inp1>rasters] + out1>segmentation] + out2>heatmap] + out3>outliers] + out4>mixture_means] + tsk1{{outlier}} + inp1>rasters] -- rasters --> tsk1{{outlier}} + tsk1{{outlier}} -- segmentation --> out1>segmentation] + tsk1{{outlier}} -- heatmap --> out2>heatmap] + tsk1{{outlier}} -- outliers --> out3>outliers] + tsk1{{outlier}} -- mixture_means --> out4>mixture_means] +``` + +## Sources + +- **rasters**: Input rasters. + +## Sinks + +- **segmentation**: Segmentation maps based on the likelihood of each sample belonging to the GMM's single-component. + +- **heatmap**: Likelihood maps. + +- **outliers**: Outlier maps based on the thresholded likelihood map. + +- **mixture_means**: Mean of the GMM. + +## Parameters + +- **threshold**: Likelihood threshold value to consider a sample as an outlier. + +## Tasks + +- **outlier**: Fits a single-component Gaussian Mixture Model (GMM) over input rasters to detect outliers according to the threshold parameter. + +## Workflow Yaml + ```yaml name: detect_outlier @@ -37,19 +78,4 @@ description: threshold: Likelihood threshold value to consider a sample as an outlier. -``` - -```{mermaid} - graph TD - inp1>rasters] - out1>segmentation] - out2>heatmap] - out3>outliers] - out4>mixture_means] - tsk1{{outlier}} - inp1>rasters] -- rasters --> tsk1{{outlier}} - tsk1{{outlier}} -- segmentation --> out1>segmentation] - tsk1{{outlier}} -- heatmap --> out2>heatmap] - tsk1{{outlier}} -- outliers --> out3>outliers] - tsk1{{outlier}} -- mixture_means --> out4>mixture_means] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/threshold/threshold_raster.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/threshold/threshold_raster.md index fbd3c354..ca237596 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/threshold/threshold_raster.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/threshold/threshold_raster.md @@ -1,5 +1,34 @@ # data_processing/threshold/threshold_raster +Thresholds values of the input raster if higher than the threshold parameter. + +```{mermaid} + graph TD + inp1>raster] + out1>thresholded_raster] + tsk1{{threshold_task}} + inp1>raster] -- raster --> tsk1{{threshold_task}} + tsk1{{threshold_task}} -- thresholded --> out1>thresholded_raster] +``` + +## Sources + +- **raster**: Input raster. + +## Sinks + +- **thresholded_raster**: Thresholded raster. + +## Parameters + +- **threshold**: Threshold value. + +## Tasks + +- **threshold_task**: Thresholds values of the input raster if higher than the threshold parameter. + +## Workflow Yaml + ```yaml name: threshold_raster @@ -28,13 +57,4 @@ description: threshold: Threshold value. -``` - -```{mermaid} - graph TD - inp1>raster] - out1>thresholded_raster] - tsk1{{threshold_task}} - inp1>raster] -- raster --> tsk1{{threshold_task}} - tsk1{{threshold_task}} -- thresholded --> out1>thresholded_raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/timeseries/timeseries_aggregation.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/timeseries/timeseries_aggregation.md index b9a12869..7b00c33a 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/timeseries/timeseries_aggregation.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/timeseries/timeseries_aggregation.md @@ -1,5 +1,38 @@ # data_processing/timeseries/timeseries_aggregation +Computes the mean, standard deviation, maximum, and minimum values of all regions of the raster and aggregates them into a timeseries. + +```{mermaid} + graph TD + inp1>raster] + inp2>input_geometry] + out1>timeseries] + tsk1{{summary}} + tsk2{{timeseries}} + tsk1{{summary}} -- summary/stats --> tsk2{{timeseries}} + inp1>raster] -- raster --> tsk1{{summary}} + inp2>input_geometry] -- input_geometry --> tsk1{{summary}} + tsk2{{timeseries}} -- timeseries --> out1>timeseries] +``` + +## Sources + +- **raster**: Input raster. + +- **input_geometry**: Geometry of interest. + +## Sinks + +- **timeseries**: Aggregated statistics of the raster. + +## Tasks + +- **summary**: Computes the mean, standard deviation, maximum, and minimum values across the whole raster. + +- **timeseries**: Aggregates list of summary statistics into a timeseries. + +## Workflow Yaml + ```yaml name: timeseries_aggregation @@ -30,17 +63,4 @@ description: timeseries: Aggregated statistics of the raster. -``` - -```{mermaid} - graph TD - inp1>raster] - inp2>input_geometry] - out1>timeseries] - tsk1{{summary}} - tsk2{{timeseries}} - tsk1{{summary}} -- summary/stats --> tsk2{{timeseries}} - inp1>raster] -- raster --> tsk1{{summary}} - inp2>input_geometry] -- input_geometry --> tsk1{{summary}} - tsk2{{timeseries}} -- timeseries --> out1>timeseries] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/data_processing/timeseries/timeseries_masked_aggregation.md b/docs/source/docfiles/markdown/workflow_yaml/data_processing/timeseries/timeseries_masked_aggregation.md index 443176b2..963f925d 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/data_processing/timeseries/timeseries_masked_aggregation.md +++ b/docs/source/docfiles/markdown/workflow_yaml/data_processing/timeseries/timeseries_masked_aggregation.md @@ -1,5 +1,46 @@ # data_processing/timeseries/timeseries_masked_aggregation +Computes the mean, standard deviation, maximum, and minimum values of all regions of the raster considered by the mask and aggregates them into a timeseries. + +```{mermaid} + graph TD + inp1>raster] + inp2>mask] + inp3>input_geometry] + out1>timeseries] + tsk1{{masked_summary}} + tsk2{{timeseries}} + tsk1{{masked_summary}} -- summary/stats --> tsk2{{timeseries}} + inp1>raster] -- raster --> tsk1{{masked_summary}} + inp2>mask] -- mask --> tsk1{{masked_summary}} + inp3>input_geometry] -- input_geometry --> tsk1{{masked_summary}} + tsk2{{timeseries}} -- timeseries --> out1>timeseries] +``` + +## Sources + +- **raster**: Input raster. + +- **mask**: Mask of the regions to be considered during summarization; + +- **input_geometry**: Geometry of interest. + +## Sinks + +- **timeseries**: Aggregated statistics of the raster considered by the mask. + +## Parameters + +- **timeseries_masked_thr**: Threshold of the maximum ratio of masked content allowed in a raster. The statistics of rasters with masked content above the threshold (e.g., heavily clouded) are not included in the timeseries. + +## Tasks + +- **masked_summary**: Computes the mean, standard deviation, maximum, and minimum values across non-masked regions of the raster. + +- **timeseries**: Aggregates list of summary statistics into a timeseries. + +## Workflow Yaml + ```yaml name: timeseries_masked_aggregation @@ -43,19 +84,4 @@ description: (e.g., heavily clouded) are not included in the timeseries. -``` - -```{mermaid} - graph TD - inp1>raster] - inp2>mask] - inp3>input_geometry] - out1>timeseries] - tsk1{{masked_summary}} - tsk2{{timeseries}} - tsk1{{masked_summary}} -- summary/stats --> tsk2{{timeseries}} - inp1>raster] -- raster --> tsk1{{masked_summary}} - inp2>mask] -- mask --> tsk1{{masked_summary}} - inp3>input_geometry] -- input_geometry --> tsk1{{masked_summary}} - tsk2{{timeseries}} -- timeseries --> out1>timeseries] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/canopy_cover.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/canopy_cover.md index 3b4f7ab2..11656a17 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/canopy_cover.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/canopy_cover.md @@ -1,5 +1,56 @@ # farm_ai/agriculture/canopy_cover +Estimates pixel-wise canopy cover for a region and date. The workflow retrieves the relevant Sentinel-2 products with Planetary Computer (PC) API, and computes the NDVI for each available tile and date. It applies a linear regressor trained with polynomial features (up to the 3rd degree) on top of the index raster to estimate canopy cover. The coeficients and intercept of the regressor were obtained beforehand using as ground-truth masked/annotated drone imagery, and are used for inference in this workflow. + +```{mermaid} + graph TD + inp1>user_input] + out1>ndvi] + out2>estimated_canopy_cover] + out3>ndvi_timeseries] + out4>canopy_timeseries] + tsk1{{ndvi_summary}} + tsk2{{canopy}} + tsk3{{canopy_summary_timeseries}} + tsk1{{ndvi_summary}} -- index/indices --> tsk2{{canopy}} + tsk2{{canopy}} -- estimated_canopy_cover/raster --> tsk3{{canopy_summary_timeseries}} + tsk1{{ndvi_summary}} -- merged_cloud_mask/mask --> tsk3{{canopy_summary_timeseries}} + inp1>user_input] -- user_input --> tsk1{{ndvi_summary}} + inp1>user_input] -- input_geometry --> tsk3{{canopy_summary_timeseries}} + tsk1{{ndvi_summary}} -- index --> out1>ndvi] + tsk2{{canopy}} -- estimated_canopy_cover --> out2>estimated_canopy_cover] + tsk1{{ndvi_summary}} -- timeseries --> out3>ndvi_timeseries] + tsk3{{canopy_summary_timeseries}} -- timeseries --> out4>canopy_timeseries] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **ndvi**: NDVI raster. + +- **estimated_canopy_cover**: Raster with pixel-wise canopy cover estimation; + +- **ndvi_timeseries**: Aggregated NDVI statistics of the retrieved tiles within the input geometry and time range. + +- **canopy_timeseries**: Aggregated canopy cover statistics. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **ndvi_summary**: Calculates NDVI statistics (mean, standard deviation, maximum and minimum) for the input geometry and time range. + +- **canopy**: Applies a linear regressor with pre-computed polynomial features on top of the index raster to estimate canopy cover. + +- **canopy_summary_timeseries**: Computes the mean, standard deviation, maximum, and minimum values of all regions of the raster considered by the mask and aggregates them into a timeseries. + +## Workflow Yaml + ```yaml name: canopy_cover @@ -53,25 +104,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>ndvi] - out2>estimated_canopy_cover] - out3>ndvi_timeseries] - out4>canopy_timeseries] - tsk1{{ndvi_summary}} - tsk2{{canopy}} - tsk3{{canopy_summary_timeseries}} - tsk1{{ndvi_summary}} -- index/indices --> tsk2{{canopy}} - tsk2{{canopy}} -- estimated_canopy_cover/raster --> tsk3{{canopy_summary_timeseries}} - tsk1{{ndvi_summary}} -- merged_cloud_mask/mask --> tsk3{{canopy_summary_timeseries}} - inp1>user_input] -- user_input --> tsk1{{ndvi_summary}} - inp1>user_input] -- input_geometry --> tsk3{{canopy_summary_timeseries}} - tsk1{{ndvi_summary}} -- index --> out1>ndvi] - tsk2{{canopy}} -- estimated_canopy_cover --> out2>estimated_canopy_cover] - tsk1{{ndvi_summary}} -- timeseries --> out3>ndvi_timeseries] - tsk3{{canopy_summary_timeseries}} -- timeseries --> out4>canopy_timeseries] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/change_detection.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/change_detection.md index 3cb9dc1e..92b49b29 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/change_detection.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/change_detection.md @@ -1,5 +1,71 @@ # farm_ai/agriculture/change_detection +Identifies changes/outliers over NDVI across dates. The workflow generates SpaceEye imagery for the input region and time range and computes NDVI raster for each date. It aggregates NDVI statistics (mean, standard deviation, maximum and minimum) in time and detects outliers across dates with a single-component Gaussian Mixture Model (GMM). + +```{mermaid} + graph TD + inp1>user_input] + out1>spaceeye_raster] + out2>index] + out3>timeseries] + out4>segmentation] + out5>heatmap] + out6>outliers] + out7>mixture_means] + tsk1{{spaceeye}} + tsk2{{ndvi}} + tsk3{{summary_timeseries}} + tsk4{{outliers}} + tsk1{{spaceeye}} -- raster --> tsk2{{ndvi}} + tsk2{{ndvi}} -- index_raster/raster --> tsk3{{summary_timeseries}} + tsk2{{ndvi}} -- index_raster/rasters --> tsk4{{outliers}} + inp1>user_input] -- user_input --> tsk1{{spaceeye}} + inp1>user_input] -- input_geometry --> tsk3{{summary_timeseries}} + tsk1{{spaceeye}} -- raster --> out1>spaceeye_raster] + tsk2{{ndvi}} -- index_raster --> out2>index] + tsk3{{summary_timeseries}} -- timeseries --> out3>timeseries] + tsk4{{outliers}} -- segmentation --> out4>segmentation] + tsk4{{outliers}} -- heatmap --> out5>heatmap] + tsk4{{outliers}} -- outliers --> out6>outliers] + tsk4{{outliers}} -- mixture_means --> out7>mixture_means] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **spaceeye_raster**: SpaceEye cloud-free rasters. + +- **index**: NDVI rasters. + +- **timeseries**: Aggregated NDVI statistics over the time range. + +- **segmentation**: Segmentation maps based on the likelihood of each sample belonging to the GMM's single-component. + +- **heatmap**: Likelihood maps. + +- **outliers**: Outlier maps. + +- **mixture_means**: Means of the GMM. + +## Parameters + +- **pc_key**: PlanetaryComputer API key. + +## Tasks + +- **spaceeye**: Runs the SpaceEye cloud removal pipeline, yielding daily cloud-free images for the input geometry and time range. + +- **ndvi**: Computes an index from the bands of an input raster. + +- **summary_timeseries**: Computes the mean, standard deviation, maximum, and minimum values of all regions of the raster and aggregates them into a timeseries. + +- **outliers**: Fits a single-component Gaussian Mixture Model (GMM) over input data to detect outliers according to the threshold parameter. + +## Workflow Yaml + ```yaml name: change_detection @@ -59,32 +125,4 @@ description: pc_key: PlanetaryComputer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>spaceeye_raster] - out2>index] - out3>timeseries] - out4>segmentation] - out5>heatmap] - out6>outliers] - out7>mixture_means] - tsk1{{spaceeye}} - tsk2{{ndvi}} - tsk3{{summary_timeseries}} - tsk4{{outliers}} - tsk1{{spaceeye}} -- raster --> tsk2{{ndvi}} - tsk2{{ndvi}} -- index_raster/raster --> tsk3{{summary_timeseries}} - tsk2{{ndvi}} -- index_raster/rasters --> tsk4{{outliers}} - inp1>user_input] -- user_input --> tsk1{{spaceeye}} - inp1>user_input] -- input_geometry --> tsk3{{summary_timeseries}} - tsk1{{spaceeye}} -- raster --> out1>spaceeye_raster] - tsk2{{ndvi}} -- index_raster --> out2>index] - tsk3{{summary_timeseries}} -- timeseries --> out3>timeseries] - tsk4{{outliers}} -- segmentation --> out4>segmentation] - tsk4{{outliers}} -- heatmap --> out5>heatmap] - tsk4{{outliers}} -- outliers --> out6>outliers] - tsk4{{outliers}} -- mixture_means --> out7>mixture_means] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/emergence_summary.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/emergence_summary.md index 1f29750c..ebc26dba 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/emergence_summary.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/emergence_summary.md @@ -1,5 +1,48 @@ # farm_ai/agriculture/emergence_summary +Calculates emergence statistics using thresholded MSAVI (mean, standard deviation, maximum and minimum) for the input geometry and time range. The workflow retrieves Sentinel2 products with Planetary Computer (PC) API, forwards them to a cloud detection model and combines the predicted cloud mask to the mask provided by PC. It computes the MSAVI for each available tile and date, thresholds them above a certain value and summarizes each with the mean, standard deviation, maximum and minimum values for the regions not obscured by clouds. Finally, it outputs a timeseries with such statistics for all available dates, filtering out heavily-clouded tiles. + +```{mermaid} + graph TD + inp1>user_input] + out1>timeseries] + tsk1{{s2}} + tsk2{{msavi}} + tsk3{{emergence}} + tsk4{{summary_timeseries}} + tsk1{{s2}} -- raster --> tsk2{{msavi}} + tsk2{{msavi}} -- index_raster/raster --> tsk3{{emergence}} + tsk3{{emergence}} -- thresholded_raster/raster --> tsk4{{summary_timeseries}} + tsk1{{s2}} -- mask --> tsk4{{summary_timeseries}} + inp1>user_input] -- user_input --> tsk1{{s2}} + inp1>user_input] -- input_geometry --> tsk4{{summary_timeseries}} + tsk4{{summary_timeseries}} -- timeseries --> out1>timeseries] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **timeseries**: Aggregated emergence statistics of the retrieved tiles within the input geometry and time range. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **s2**: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range, and computes improved cloud masks using cloud and shadow segmentation models. + +- **msavi**: Computes an index from the bands of an input raster. + +- **emergence**: Thresholds values of the input raster if higher than the threshold parameter. + +- **summary_timeseries**: Computes the mean, standard deviation, maximum, and minimum values of all regions of the raster considered by the mask and aggregates them into a timeseries. + +## Workflow Yaml + ```yaml name: emergence_summary @@ -59,21 +102,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>timeseries] - tsk1{{s2}} - tsk2{{msavi}} - tsk3{{emergence}} - tsk4{{summary_timeseries}} - tsk1{{s2}} -- raster --> tsk2{{msavi}} - tsk2{{msavi}} -- index_raster/raster --> tsk3{{emergence}} - tsk3{{emergence}} -- thresholded_raster/raster --> tsk4{{summary_timeseries}} - tsk1{{s2}} -- mask --> tsk4{{summary_timeseries}} - inp1>user_input] -- user_input --> tsk1{{s2}} - inp1>user_input] -- input_geometry --> tsk4{{summary_timeseries}} - tsk4{{summary_timeseries}} -- timeseries --> out1>timeseries] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/green_house_gas_fluxes.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/green_house_gas_fluxes.md index 37a25582..69a69764 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/green_house_gas_fluxes.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/green_house_gas_fluxes.md @@ -1,5 +1,34 @@ # farm_ai/agriculture/green_house_gas_fluxes +Computes Green House Fluxes for a region and date range The workflow follows the GHG Protocol guidelines published for Brazil (which are based on IPCC reports) to compute Green House Gas emission fluxes (sequestration versus emissions) for a given crop. + +```{mermaid} + graph TD + inp1>user_input] + out1>fluxes] + tsk1{{ghg}} + inp1>user_input] -- ghg --> tsk1{{ghg}} + tsk1{{ghg}} -- fluxes --> out1>fluxes] +``` + +## Sources + +- **user_input**: The user-provided inputs for GHG computation. + +## Sinks + +- **fluxes**: The computed fluxes for the given area and date range considering the user input data. + +## Parameters + +- **crop_type**: The type of the crop to compute GHG emissions. Supported crops are 'wheat', 'corn', 'cotton', and 'soybeans'. + +## Tasks + +- **ghg**: Computes Green House Gas emission fluxes based on emission factors based on IPCC methodology. + +## Workflow Yaml + ```yaml name: green_house_gas_fluxes @@ -31,13 +60,4 @@ description: 'wheat', 'corn', 'cotton', and 'soybeans'. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>fluxes] - tsk1{{ghg}} - inp1>user_input] -- ghg --> tsk1{{ghg}} - tsk1{{ghg}} -- fluxes --> out1>fluxes] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_classification.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_classification.md index c4343de2..ff5faf67 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_classification.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_classification.md @@ -1,5 +1,61 @@ # farm_ai/agriculture/heatmap_using_classification +The workflow generates a nutrient heatmap for samples provided by user by downloading the samples from user input. The samples provided are related with farm boundary and have required nutrient information to create a heatmap. + +```{mermaid} + graph TD + inp1>input_samples] + inp2>input_raster] + out1>result] + tsk1{{download_samples}} + tsk2{{soil_sample_heatmap_classification}} + tsk1{{download_samples}} -- geometry/samples --> tsk2{{soil_sample_heatmap_classification}} + inp1>input_samples] -- user_input --> tsk1{{download_samples}} + inp2>input_raster] -- input_raster --> tsk2{{soil_sample_heatmap_classification}} + tsk2{{soil_sample_heatmap_classification}} -- result --> out1>result] +``` + +## Sources + +- **input_raster**: Input raster for index computation. + +- **input_samples**: External references to sensor samples for nutrients. + +## Sinks + +- **result**: Zip file containing cluster geometries. + +## Parameters + +- **attribute_name**: Nutrient property name in sensor samples geojson file. For example CARBON (C), Nitrogen (N), Phosphorus (P) etc., + +- **buffer**: Offset distance from sample to perform interpolate operations with raster. + +- **index**: Type of index to be used to generate heatmap. For example - evi, pri etc., + +- **bins**: Possible number of groups used to move value to nearest group using [numpy histogram](https://numpy.org/doc/stable/reference/generated/numpy.histogram.html) and to pre-process the data to support model training with classification . + +- **simplify**: Replace small polygons in input with value of their largest neighbor after converting from raster to vector. Accepts 'simplify' or 'convex' or 'none'. + +- **tolerance**: All parts of a [simplified geometry](https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoSeries.simplify.html) will be no more than tolerance distance from the original. It has the same units as the coordinate reference system of the GeoSeries. For example, using tolerance=100 in a projected CRS with meters as units means a distance of 100 meters in reality. + +- **data_scale**: Accepts True or False. Default is False. On True, it scale data using [StandardScalar] (https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html) from scikit-learn package. It Standardize features by removing the mean and scaling to unit variance. + +- **max_depth**: The maximum depth of the tree. If None, then nodes are expanded until all leaves are pure or until all leaves contain less than min_samples_split samples. For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + +- **n_estimators**: The number of trees in the forest. For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + +- **random_state**: Controls both the randomness of the bootstrapping of the samples used when building trees (if bootstrap=True) and the sampling of the features to consider when looking for the best split at each node (if max_features < n_features). For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + +## Tasks + +- **download_samples**: Adds user geometries into the cluster storage, allowing for them to be used on workflows. + +- **soil_sample_heatmap_classification**: Utilizes input Sentinel-2 satellite imagery & the sensor samples as labeled data that contain nutrient information (Nitrogen, Carbon, pH, Phosphorus) to train a model using Random Forest classifier. The inference operation predicts nutrients in soil for the chosen farm boundary. + + +## Workflow Yaml + ```yaml name: heatmap_using_classification @@ -54,17 +110,4 @@ description: parameters: null -``` - -```{mermaid} - graph TD - inp1>input_samples] - inp2>input_raster] - out1>result] - tsk1{{download_samples}} - tsk2{{soil_sample_heatmap_classification}} - tsk1{{download_samples}} -- geometry/samples --> tsk2{{soil_sample_heatmap_classification}} - inp1>input_samples] -- user_input --> tsk1{{download_samples}} - inp2>input_raster] -- input_raster --> tsk2{{soil_sample_heatmap_classification}} - tsk2{{soil_sample_heatmap_classification}} -- result --> out1>result] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_classification_admag.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_classification_admag.md index 246b8094..07167ee9 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_classification_admag.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_classification_admag.md @@ -1,5 +1,71 @@ # farm_ai/agriculture/heatmap_using_classification_admag +This workflow integrate the ADMAG API to download prescriptions and generate heatmap. The prescriptions are related with farm boundary and the nutrient information. Each prescription represent a sensor sample at a location within a farm boundary. + +```{mermaid} + graph TD + inp1>admag_input] + inp2>input_raster] + out1>result] + tsk1{{prescriptions}} + tsk2{{soil_sample_heatmap_classification}} + tsk1{{prescriptions}} -- response/samples --> tsk2{{soil_sample_heatmap_classification}} + inp1>admag_input] -- admag_input --> tsk1{{prescriptions}} + inp2>input_raster] -- input_raster --> tsk2{{soil_sample_heatmap_classification}} + tsk2{{soil_sample_heatmap_classification}} -- result --> out1>result] +``` + +## Sources + +- **input_raster**: Input raster for index computation. + +- **admag_input**: Required inputs to download prescriptions from admag. + +## Sinks + +- **result**: Zip file containing cluster geometries. + +## Parameters + +- **base_url**: URL to access the registered app + +- **client_id**: Value uniquely identifies registered application in the Microsoft identity platform. Visit url https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app to register the app. + +- **client_secret**: Sometimes called an application password, a client secret is a string value your app can use in place of a certificate to identity itself. + +- **authority**: The endpoint URIs for your app are generated automatically when you register or configure your app. It is used by client to obtain authorization from the resource owner + +- **default_scope**: URL for default azure OAuth2 permissions + +- **attribute_name**: Nutrient property name in sensor samples geojson file. For example CARBON (C), Nitrogen (N), Phosphorus (P) etc., + +- **buffer**: Offset distance from sample to perform interpolate operations with raster. + +- **index**: Type of index to be used to generate heatmap. For example - evi, pri etc., + +- **bins**: Possible number of groups used to move value to nearest group using [numpy histogram](https://numpy.org/doc/stable/reference/generated/numpy.histogram.html) and to pre-process the data to support model training with classification . + +- **simplify**: Replace small polygons in input with value of their largest neighbor after converting from raster to vector. Accepts 'simplify' or 'convex' or 'none'. + +- **tolerance**: All parts of a [simplified geometry](https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoSeries.simplify.html) will be no more than tolerance distance from the original. It has the same units as the coordinate reference system of the GeoSeries. For example, using tolerance=100 in a projected CRS with meters as units means a distance of 100 meters in reality. + +- **data_scale**: Accepts True or False. Default is False. On True, it scale data using [StandardScalar] (https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html) from scikit-learn package. It Standardize features by removing the mean and scaling to unit variance. + +- **max_depth**: The maximum depth of the tree. If None, then nodes are expanded until all leaves are pure or until all leaves contain less than min_samples_split samples. For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + +- **n_estimators**: The number of trees in the forest. For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + +- **random_state**: Controls both the randomness of the bootstrapping of the samples used when building trees (if bootstrap=True) and the sampling of the features to consider when looking for the best split at each node (if max_features < n_features). For more details refer to (https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) + +## Tasks + +- **prescriptions**: Fetches prescriptions using ADMAg (Microsoft Azure Data Manager for Agriculture). + +- **soil_sample_heatmap_classification**: Utilizes input Sentinel-2 satellite imagery & the sensor samples as labeled data that contain nutrient information (Nitrogen, Carbon, pH, Phosphorus) to train a model using Random Forest classifier. The inference operation predicts nutrients in soil for the chosen farm boundary. + + +## Workflow Yaml + ```yaml name: heatmap_using_classification_admag @@ -76,17 +142,4 @@ description: default_scope: URL for default azure OAuth2 permissions -``` - -```{mermaid} - graph TD - inp1>admag_input] - inp2>input_raster] - out1>result] - tsk1{{prescriptions}} - tsk2{{soil_sample_heatmap_classification}} - tsk1{{prescriptions}} -- response/samples --> tsk2{{soil_sample_heatmap_classification}} - inp1>admag_input] -- admag_input --> tsk1{{prescriptions}} - inp2>input_raster] -- input_raster --> tsk2{{soil_sample_heatmap_classification}} - tsk2{{soil_sample_heatmap_classification}} -- result --> out1>result] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_neighboring_data_points.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_neighboring_data_points.md index e7fefb03..fd1ad086 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_neighboring_data_points.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/heatmap_using_neighboring_data_points.md @@ -1,5 +1,60 @@ # farm_ai/agriculture/heatmap_using_neighboring_data_points +Creates heatmap using the neighbors by performing spatial interpolation operations. It utilizes soil information collected at optimal sensor/sample locations and downloaded sentinel satellite imagery. The optimal location of nutrient samples are identified using workflow . The quantity of samples defines the accuracy of the heatmap generation. During the research performed testing on a 100 acre farm using sample count of approximately 20, 80, 130, 600. The research concluded that a sample count of 20 provided decent results, also accuracy of nutrient information improved with increase in sample count. + +```{mermaid} + graph TD + inp1>input_raster] + inp2>input_samples] + inp3>input_sample_clusters] + out1>result] + tsk1{{download_samples}} + tsk2{{download_sample_clusters}} + tsk3{{soil_sample_heatmap}} + tsk1{{download_samples}} -- geometry/samples --> tsk3{{soil_sample_heatmap}} + tsk2{{download_sample_clusters}} -- geometry/samples_boundary --> tsk3{{soil_sample_heatmap}} + inp1>input_raster] -- raster --> tsk3{{soil_sample_heatmap}} + inp2>input_samples] -- user_input --> tsk1{{download_samples}} + inp3>input_sample_clusters] -- user_input --> tsk2{{download_sample_clusters}} + tsk3{{soil_sample_heatmap}} -- result --> out1>result] +``` + +## Sources + +- **input_raster**: Sentinel-2 raster. + +- **input_samples**: Sensor samples with nutrient information. + +- **input_sample_clusters**: Clusters boundaries of sensor samples locations. + +## Sinks + +- **result**: Zip file containing heatmap output as shape files. + +## Parameters + +- **attribute_name**: Nutrient property name in sensor samples geojson file. For example: CARBON (C), Nitrogen (N), Phosphorus (P) etc., + +- **simplify**: Replace small polygons in input with value of their largest neighbor after converting from raster to vector. Accepts 'simplify' or 'convex' or 'none'. + +- **tolerance**: All parts of a [simplified geometry](https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoSeries.simplify.html) will be no more than tolerance distance from the original. It has the same units as the coordinate reference system of the GeoSeries. For example, using tolerance=100 in a projected CRS with meters as units means a distance of 100 meters in reality. + +- **algorithm**: Algorithm used to identify nearest neighbors. Accepts 'cluster overlap' or 'nearest neighbor' or 'kriging neighbor'. + +- **resolution**: Defines the output resolution as the ratio of input raster resolution. For example, if resolution is 5, the output heatmap is 5 times coarser than input raster. + +- **bins**: it defines the number of equal-width bins in the given range.Refer to this article to learn more about bins https://numpy.org/doc/stable/reference/generated/numpy.histogram.html + +## Tasks + +- **download_samples**: Adds user geometries into the cluster storage, allowing for them to be used on workflows. + +- **download_sample_clusters**: Adds user geometries into the cluster storage, allowing for them to be used on workflows. + +- **soil_sample_heatmap**: Generate heatmap for nutrients using satellite or spaceEye imagery. + +## Workflow Yaml + ```yaml name: heatmap_using_neighboring_data_points @@ -75,21 +130,4 @@ description: article to learn more about bins https://numpy.org/doc/stable/reference/generated/numpy.histogram.html -``` - -```{mermaid} - graph TD - inp1>input_raster] - inp2>input_samples] - inp3>input_sample_clusters] - out1>result] - tsk1{{download_samples}} - tsk2{{download_sample_clusters}} - tsk3{{soil_sample_heatmap}} - tsk1{{download_samples}} -- geometry/samples --> tsk3{{soil_sample_heatmap}} - tsk2{{download_sample_clusters}} -- geometry/samples_boundary --> tsk3{{soil_sample_heatmap}} - inp1>input_raster] -- raster --> tsk3{{soil_sample_heatmap}} - inp2>input_samples] -- user_input --> tsk1{{download_samples}} - inp3>input_sample_clusters] -- user_input --> tsk2{{download_sample_clusters}} - tsk3{{soil_sample_heatmap}} -- result --> out1>result] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/methane_index.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/methane_index.md index c6eaa654..48b02fe4 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/methane_index.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/methane_index.md @@ -1,5 +1,51 @@ # farm_ai/agriculture/methane_index +Computes methane index from ultra emitters for a region and date range. The workflow retrieves the relevant Sentinel-2 products with Planetary Computer (PC) API and crop the rasters for the region defined in user_input. All bands are normalized and an anti-aliasing guassian filter is applied to smooth and remove potential artifacts. An unsupervised K-Nearest Neighbor is applied to identify bands similar to band 12, and the index is computed by the difference between band 12 to the pixel-wise median of top K similar bands. + +```{mermaid} + graph TD + inp1>user_input] + out1>index] + out2>s2_raster] + out3>cloud_mask] + tsk1{{s2}} + tsk2{{clip}} + tsk3{{methane}} + tsk1{{s2}} -- raster --> tsk2{{clip}} + tsk2{{clip}} -- clipped_raster/raster --> tsk3{{methane}} + inp1>user_input] -- user_input --> tsk1{{s2}} + inp1>user_input] -- input_geometry --> tsk2{{clip}} + tsk3{{methane}} -- index_raster --> out1>index] + tsk1{{s2}} -- raster --> out2>s2_raster] + tsk1{{s2}} -- mask --> out3>cloud_mask] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **index**: Methane index raster. + +- **s2_raster**: Sentinel-2 raster. + +- **cloud_mask**: Cloud mask. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **s2**: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range, and computes improved cloud masks using cloud and shadow segmentation models. + +- **clip**: Performs a soft clip on an input raster based on a provided reference geometry. + +- **methane**: Computes an index from the bands of an input raster. + +## Workflow Yaml + ```yaml name: methane_index @@ -50,22 +96,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>index] - out2>s2_raster] - out3>cloud_mask] - tsk1{{s2}} - tsk2{{clip}} - tsk3{{methane}} - tsk1{{s2}} -- raster --> tsk2{{clip}} - tsk2{{clip}} -- clipped_raster/raster --> tsk3{{methane}} - inp1>user_input] -- user_input --> tsk1{{s2}} - inp1>user_input] -- input_geometry --> tsk2{{clip}} - tsk3{{methane}} -- index_raster --> out1>index] - tsk1{{s2}} -- raster --> out2>s2_raster] - tsk1{{s2}} -- mask --> out3>cloud_mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/ndvi_summary.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/ndvi_summary.md index c7307156..c97aabf3 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/ndvi_summary.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/ndvi_summary.md @@ -1,5 +1,44 @@ # farm_ai/agriculture/ndvi_summary +Calculates NDVI statistics (mean, standard deviation, maximum and minimum) for the input geometry and time range. The workflow retrieves the relevant Sentinel-2 products with Planetary Computer (PC) API, forwards them to a cloud detection model and combines the predicted cloud mask to the mask obtained from the product. The workflow computes the NDVI for each available tile and date, summarizing each with the mean, standard deviation, maximum and minimum values for the regions not obscured by clouds. Finally, it outputs a timeseries with such statistics for all available dates, ignoring heavily-clouded tiles. + +```{mermaid} + graph TD + inp1>user_input] + out1>timeseries] + tsk1{{s2}} + tsk2{{compute_ndvi}} + tsk3{{summary_timeseries}} + tsk1{{s2}} -- raster --> tsk2{{compute_ndvi}} + tsk2{{compute_ndvi}} -- index_raster/raster --> tsk3{{summary_timeseries}} + tsk1{{s2}} -- mask --> tsk3{{summary_timeseries}} + inp1>user_input] -- user_input --> tsk1{{s2}} + inp1>user_input] -- input_geometry --> tsk3{{summary_timeseries}} + tsk3{{summary_timeseries}} -- timeseries --> out1>timeseries] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **timeseries**: Aggregated NDVI statistics of the retrieved tiles within the input geometry and time range. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **s2**: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range, and computes improved cloud masks using cloud and shadow segmentation models. + +- **compute_ndvi**: Computes an index from the bands of an input raster. + +- **summary_timeseries**: Computes the mean, standard deviation, maximum, and minimum values of all regions of the raster considered by the mask and aggregates them into a timeseries. + +## Workflow Yaml + ```yaml name: ndvi_summary @@ -50,19 +89,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>timeseries] - tsk1{{s2}} - tsk2{{compute_ndvi}} - tsk3{{summary_timeseries}} - tsk1{{s2}} -- raster --> tsk2{{compute_ndvi}} - tsk2{{compute_ndvi}} -- index_raster/raster --> tsk3{{summary_timeseries}} - tsk1{{s2}} -- mask --> tsk3{{summary_timeseries}} - inp1>user_input] -- user_input --> tsk1{{s2}} - inp1>user_input] -- input_geometry --> tsk3{{summary_timeseries}} - tsk3{{summary_timeseries}} -- timeseries --> out1>timeseries] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/weed_detection.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/weed_detection.md index 086f04da..57c16c24 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/weed_detection.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/agriculture/weed_detection.md @@ -1,5 +1,54 @@ # farm_ai/agriculture/weed_detection +Generates shape files for similarly colored regions in the input raster. The workflow retrieves a remote raster and trains a Gaussian Mixture Model (GMM) over a subset of the input data with a fixed number of components. The GMM is then used to cluster all images pixels. Clustered regions are converted to polygons with a minimum size threshold. These polygons are then simplified to smooth their borders. All polygons of a given cluster are written to a single shapefile. All files are then compressed and returned as a single zip archive. + +```{mermaid} + graph TD + inp1>user_input] + out1>result] + tsk1{{download_raster}} + tsk2{{weed_detection}} + tsk1{{download_raster}} -- raster --> tsk2{{weed_detection}} + inp1>user_input] -- user_input --> tsk1{{download_raster}} + tsk2{{weed_detection}} -- result --> out1>result] +``` + +## Sources + +- **user_input**: External references to raster data. + +## Sinks + +- **result**: Zip file containing cluster geometries. + +## Parameters + +- **buffer**: Buffer size, in projected CRS, to apply to the input geometry before sampling training points. A negative number can be used to avoid sampling unwanted regions if the geometry is not very precise. + +- **no_data**: Value to use as nodata when reading the raster. Uses the raster's internal nodata value if not provided. + +- **clusters**: Number of clusters to use when segmenting the image. + +- **sieve_size**: Area of the minimum connected region. Smaller regions will have their class assigned to the largest adjancent region. + +- **simplify**: Method used to simplify the geometries. Accepts 'none', for no simplification, 'simplify', for tolerance-based simplification, and 'convex', for returning the convex hull. + +- **tolerance**: Tolerance for simplifcation algorithm. Only applicable if simplification method is 'simplify'. + +- **samples**: Number os samples to use during training. + +- **bands**: List of band indices to use during training and inference. + +- **alpha_index**: Positive index of alpha band, if used to filter out nodata values. + +## Tasks + +- **download_raster**: Adds user rasters into the cluster storage, allowing for them to be used on workflows. + +- **weed_detection**: Trains a Gaussian Mixture Model (GMM), cluster all images pixels, and convert clustered regions into polygons. + +## Workflow Yaml + ```yaml name: weed_detection @@ -69,15 +118,4 @@ description: alpha_index: Positive index of alpha band, if used to filter out nodata values. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>result] - tsk1{{download_raster}} - tsk2{{weed_detection}} - tsk1{{download_raster}} -- raster --> tsk2{{weed_detection}} - inp1>user_input] -- user_input --> tsk1{{download_raster}} - tsk2{{weed_detection}} -- result --> out1>result] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/carbon_local/admag_carbon_integration.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/carbon_local/admag_carbon_integration.md index 593c499e..ca7dddcb 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/carbon_local/admag_carbon_integration.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/carbon_local/admag_carbon_integration.md @@ -1,5 +1,58 @@ # farm_ai/carbon_local/admag_carbon_integration +Computes the offset amount of carbon that would be sequestered in a seasonal field using Microsoft Azure Data Manager for Agriculture (ADMAg) data. Derives carbon sequestration information. Microsoft Azure Data Manager for Agriculture (ADMAg) and the COMET-Farm API are used to obtain farming data and evaluate carbon offset. ADMAg is capable of describing important farming activities such as fertilization, tillage, and organic amendments applications, all of which are represented in the data manager. FarmVibes.AI retrieves this information from the data manager and builds SeasonalFieldInformation FarmVibes.AI objects. These objects are then used to call the COMET-Farm API and evaluate Carbon Offset Information. + +```{mermaid} + graph TD + inp1>baseline_admag_input] + inp2>scenario_admag_input] + out1>carbon_output] + tsk1{{baseline_seasonal_field_list}} + tsk2{{scenario_seasonal_field_list}} + tsk3{{admag_carbon}} + tsk1{{baseline_seasonal_field_list}} -- seasonal_field/baseline_seasonal_fields --> tsk3{{admag_carbon}} + tsk2{{scenario_seasonal_field_list}} -- seasonal_field/scenario_seasonal_fields --> tsk3{{admag_carbon}} + inp1>baseline_admag_input] -- admag_input --> tsk1{{baseline_seasonal_field_list}} + inp2>scenario_admag_input] -- admag_input --> tsk2{{scenario_seasonal_field_list}} + tsk3{{admag_carbon}} -- carbon_output --> out1>carbon_output] +``` + +## Sources + +- **baseline_admag_input**: List of ADMAgSeasonalFieldInput to retrieve SeasonalFieldInformation objects for baseline COMET-Farm API Carbon offset evaluation. + +- **scenario_admag_input**: List of ADMAgSeasonalFieldInput to retrieve SeasonalFieldInformation objects for scenarios COMET-Farm API Carbon offset evaluation. + +## Sinks + +- **carbon_output**: Carbon sequestration received for scenario information provided as input. + +## Parameters + +- **base_url**: Azure Data Manager for Agriculture host. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +- **client_id**: Azure Data Manager for Agriculture client id. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +- **client_secret**: Azure Data Manager for Agriculture client secret. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +- **authority**: Azure Data Manager for Agriculture authority. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +- **default_scope**: Azure Data Manager for Agriculture default scope. Please visit https://aka.ms/farmvibesDMA to check how to get these credentials. + +- **comet_support_email**: Comet support email. The email used to register for a COMET account. The requests are forwarded to comet with this email reference. This email is used by comet to share the information back to you for failed requests. + +- **ngrok_token**: NGROK session token. A token that FarmVibes uses to create a web_hook url that is shared with Comet in a request when running the workflow. Comet can use this link to send back a response to FarmVibes. NGROK is a service that creates temporary urls for local servers. To use NGROK, FarmVibes needs to get a token from this website, https://dashboard.ngrok.com/. + +## Tasks + +- **baseline_seasonal_field_list**: Generates SeasonalFieldInformation using ADMAg (Microsoft Azure Data Manager for Agriculture). + +- **scenario_seasonal_field_list**: Generates SeasonalFieldInformation using ADMAg (Microsoft Azure Data Manager for Agriculture). + +- **admag_carbon**: Computes the offset amount of carbon that would be sequestered in a seasonal field using the baseline (historical) and scenario (time range interested in) information. + +## Workflow Yaml + ```yaml name: admag_carbon_integration @@ -88,19 +141,4 @@ description: https://aka.ms/farmvibesDMA to check how to get these credentials. -``` - -```{mermaid} - graph TD - inp1>baseline_admag_input] - inp2>scenario_admag_input] - out1>carbon_output] - tsk1{{baseline_seasonal_field_list}} - tsk2{{scenario_seasonal_field_list}} - tsk3{{admag_carbon}} - tsk1{{baseline_seasonal_field_list}} -- seasonal_field/baseline_seasonal_fields --> tsk3{{admag_carbon}} - tsk2{{scenario_seasonal_field_list}} -- seasonal_field/scenario_seasonal_fields --> tsk3{{admag_carbon}} - inp1>baseline_admag_input] -- admag_input --> tsk1{{baseline_seasonal_field_list}} - inp2>scenario_admag_input] -- admag_input --> tsk2{{scenario_seasonal_field_list}} - tsk3{{admag_carbon}} -- carbon_output --> out1>carbon_output] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/carbon_local/carbon_whatif.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/carbon_local/carbon_whatif.md index b1c3b082..67e43dc4 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/carbon_local/carbon_whatif.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/carbon_local/carbon_whatif.md @@ -1,5 +1,40 @@ # farm_ai/carbon_local/carbon_whatif +Computes the offset amount of carbon that would be sequestered in a seasonal field using the baseline (historical) and scenario (time range interested in) information. To derive amount of carbon, it relies on seasonal information information provided for both baseline and scenario. The baseline represents historical information of farm practices used during each season that includes fertilizers, tillage, harvest and organic amendment. Minimum 2 years of baseline information required to execute the workflow. The scenario represents future farm practices planning to do during each season that includes fertilizers, tillage, harvest and organic amendment. For the scenario information provided, the workflow compute the offset amount of carbon that would be sequestrated in a seasonal field. Minimum 2years of baseline information required to execute the workflow. The requests received by workflow are forwarded to comet api. To know more information of comet refer to https://gitlab.com/comet-api/api-docs/-/tree/master/. To understand the enumerations and information accepted by comet refer to https://gitlab.com/comet-api/api-docs/-/blob/master/COMET-Farm_API_File_Specification.xlsx The request submitted get executed with in 5 minutes to max 2 hours. If response not received from comet within this time period, check comet_support_email for information on failed requests, if no emails received check status of requests by contacting to this support email address of comet "appnrel@colostate.edu". For public use comet limits 50 requests each day. If more requests need to send contact support email address. + +```{mermaid} + graph TD + inp1>baseline_seasonal_fields] + inp2>scenario_seasonal_fields] + out1>carbon_output] + tsk1{{comet_task}} + inp1>baseline_seasonal_fields] -- baseline_seasonal_fields --> tsk1{{comet_task}} + inp2>scenario_seasonal_fields] -- scenario_seasonal_fields --> tsk1{{comet_task}} + tsk1{{comet_task}} -- carbon_output --> out1>carbon_output] +``` + +## Sources + +- **baseline_seasonal_fields**: List of seasonal fields that holds the historical information of farm practices such as fertilizers, tillage, harvest and organic amendment. + +- **scenario_seasonal_fields**: List of seasonal fields that holds the future information of farm practices such as fertilizers, tillage, harvest and organic amendment. + +## Sinks + +- **carbon_output**: Carbon sequestration received for scenario information provided as input. + +## Parameters + +- **comet_support_email**: COMET-Farm API Registered email. The requests are forwarded to comet with this email reference. This email used by comet to share the information back to you for failed requests. + +- **ngrok_token**: NGROK session token. FarmVibes generate web_hook url and shared url with comet along the request to receive the response from comet. It's publicly accessible url and it's unique for each session. The url gets destroyed once the session ends. To start the ngrok session a token, it is generated from this url https://dashboard.ngrok.com/ + +## Tasks + +- **comet_task**: Computes the offset amount of carbon that would be sequestered in a seasonal field using the baseline (historical) and scenario (time range interested in) information. + +## Workflow Yaml + ```yaml name: carbon_whatif @@ -61,15 +96,4 @@ description: url https://dashboard.ngrok.com/ -``` - -```{mermaid} - graph TD - inp1>baseline_seasonal_fields] - inp2>scenario_seasonal_fields] - out1>carbon_output] - tsk1{{comet_task}} - inp1>baseline_seasonal_fields] -- baseline_seasonal_fields --> tsk1{{comet_task}} - inp2>scenario_seasonal_fields] -- scenario_seasonal_fields --> tsk1{{comet_task}} - tsk1{{comet_task}} -- carbon_output --> out1>carbon_output] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_cover_mapping/conservation_practices.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_cover_mapping/conservation_practices.md index 07ed936b..7d65b7c5 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_cover_mapping/conservation_practices.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_cover_mapping/conservation_practices.md @@ -1,5 +1,88 @@ # farm_ai/land_cover_mapping/conservation_practices +Identifies conservation practices (terraces and grassed waterways) using elevation data. The workflow classifies pixels in terraces or grassed waterways. It starts downloading NAIP and USGS 3DEP tiles. Then, it computes the elevation gradient using a Sobel filter. And it computes local clusters using an overlap clustering method. Then, it combines cluster and elevation tiles to compute the average elevation per cluster. Finally, it uses a CNN model to classify pixels in either terraces or grassed waterways. + +```{mermaid} + graph TD + inp1>user_input] + out1>dem_raster] + out2>naip_raster] + out3>dem_gradient] + out4>cluster] + out5>average_elevation] + out6>practices] + tsk1{{naip}} + tsk2{{cluster}} + tsk3{{dem}} + tsk4{{gradient}} + tsk5{{match_grad}} + tsk6{{match_elev}} + tsk7{{avg_elev}} + tsk8{{practice}} + tsk1{{naip}} -- raster/user_input --> tsk3{{dem}} + tsk1{{naip}} -- raster/input_raster --> tsk2{{cluster}} + tsk1{{naip}} -- raster/ref_rasters --> tsk6{{match_elev}} + tsk1{{naip}} -- raster/ref_rasters --> tsk5{{match_grad}} + tsk3{{dem}} -- raster --> tsk4{{gradient}} + tsk3{{dem}} -- raster/rasters --> tsk6{{match_elev}} + tsk4{{gradient}} -- gradient/rasters --> tsk5{{match_grad}} + tsk2{{cluster}} -- output_raster/input_cluster_raster --> tsk7{{avg_elev}} + tsk6{{match_elev}} -- match_rasters/input_dem_raster --> tsk7{{avg_elev}} + tsk7{{avg_elev}} -- output_raster/average_elevation --> tsk8{{practice}} + tsk5{{match_grad}} -- match_rasters/elevation_gradient --> tsk8{{practice}} + inp1>user_input] -- user_input --> tsk1{{naip}} + tsk3{{dem}} -- raster --> out1>dem_raster] + tsk1{{naip}} -- raster --> out2>naip_raster] + tsk4{{gradient}} -- gradient --> out3>dem_gradient] + tsk2{{cluster}} -- output_raster --> out4>cluster] + tsk7{{avg_elev}} -- output_raster --> out5>average_elevation] + tsk8{{practice}} -- output_raster --> out6>practices] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **dem_raster**: USGS 3DEP tiles that overlap the NAIP tiles that overlap the area of interest. + +- **naip_raster**: NAIP tiles that overlap the area of interest. + +- **dem_gradient**: A copy of the USGS 3DEP tiles where the pixel values are the gradient computed using the Sobel filter. + +- **cluster**: A copy of the NAIP tiles with one band representing the output of the overlap clustering method. Each pixel has a value between one and four. + +- **average_elevation**: A combination of the dem_gradient and cluster sinks, where each pixel value is the average elevation of all pixels that fall in the same cluster. + +- **practices**: A copy of the NAIP tile with one band where each pixel value refers to a conservation practice (0 = none, 1 = terraces, 2 = grassed waterways). + +## Parameters + +- **clustering_iterations**: The number of iterations used in the overlap clustering method. + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **naip**: Downloads NAIP tiles that intersect with the input geometry and time range. + +- **cluster**: Computes local clusters using an overlap clustering method. + +- **dem**: Downloads digital elevation map tiles that intersect with the input geometry and time range. + +- **gradient**: Computes the gradient of each band of the input raster with a Sobel operator. + +- **match_grad**: Resamples input rasters to the reference rasters' grid. + +- **match_elev**: Resamples input rasters to the reference rasters' grid. + +- **avg_elev**: Computes average elevation per-class in overlapping windows, combining cluster and elevation tiles. + +- **practice**: Classifies pixels in either terraces or grassed waterways using a CNN model. + +## Workflow Yaml + ```yaml name: conservation_practices @@ -95,41 +178,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>dem_raster] - out2>naip_raster] - out3>dem_gradient] - out4>cluster] - out5>average_elevation] - out6>practices] - tsk1{{naip}} - tsk2{{cluster}} - tsk3{{dem}} - tsk4{{gradient}} - tsk5{{match_grad}} - tsk6{{match_elev}} - tsk7{{avg_elev}} - tsk8{{practice}} - tsk1{{naip}} -- raster/user_input --> tsk3{{dem}} - tsk1{{naip}} -- raster/input_raster --> tsk2{{cluster}} - tsk1{{naip}} -- raster/ref_rasters --> tsk6{{match_elev}} - tsk1{{naip}} -- raster/ref_rasters --> tsk5{{match_grad}} - tsk3{{dem}} -- raster --> tsk4{{gradient}} - tsk3{{dem}} -- raster/rasters --> tsk6{{match_elev}} - tsk4{{gradient}} -- gradient/rasters --> tsk5{{match_grad}} - tsk2{{cluster}} -- output_raster/input_cluster_raster --> tsk7{{avg_elev}} - tsk6{{match_elev}} -- match_rasters/input_dem_raster --> tsk7{{avg_elev}} - tsk7{{avg_elev}} -- output_raster/average_elevation --> tsk8{{practice}} - tsk5{{match_grad}} -- match_rasters/elevation_gradient --> tsk8{{practice}} - inp1>user_input] -- user_input --> tsk1{{naip}} - tsk3{{dem}} -- raster --> out1>dem_raster] - tsk1{{naip}} -- raster --> out2>naip_raster] - tsk4{{gradient}} -- gradient --> out3>dem_gradient] - tsk2{{cluster}} -- output_raster --> out4>cluster] - tsk7{{avg_elev}} -- output_raster --> out5>average_elevation] - tsk8{{practice}} -- output_raster --> out6>practices] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_degradation/landsat_ndvi_trend.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_degradation/landsat_ndvi_trend.md index 8836bf98..8d1dcb46 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_degradation/landsat_ndvi_trend.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_degradation/landsat_ndvi_trend.md @@ -1,5 +1,42 @@ # farm_ai/land_degradation/landsat_ndvi_trend +Estimates a linear trend over NDVI computer over LANDSAT tiles that intersect with the input geometry and time range. The workflow downloads LANDSAT data, compute NDVI over them, and estimate a linear trend over chunks of data, combining them into a final trend raster. + +```{mermaid} + graph TD + inp1>user_input] + out1>ndvi] + out2>linear_trend] + tsk1{{landsat}} + tsk2{{trend}} + tsk1{{landsat}} -- raster --> tsk2{{trend}} + inp1>user_input] -- user_input --> tsk1{{landsat}} + tsk2{{trend}} -- ndvi_raster --> out1>ndvi] + tsk2{{trend}} -- linear_trend --> out2>linear_trend] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **ndvi**: NDVI rasters. + +- **linear_trend**: Raster with the trend and the test statistics. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **landsat**: Downloads and preprocesses LANDSAT tiles that intersect with the input geometry and time range. + +- **trend**: Computes the pixel-wise NDVI linear trend over the input raster. + +## Workflow Yaml + ```yaml name: landsat_ndvi_trend @@ -37,17 +74,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>ndvi] - out2>linear_trend] - tsk1{{landsat}} - tsk2{{trend}} - tsk1{{landsat}} -- raster --> tsk2{{trend}} - inp1>user_input] -- user_input --> tsk1{{landsat}} - tsk2{{trend}} -- ndvi_raster --> out1>ndvi] - tsk2{{trend}} -- linear_trend --> out2>linear_trend] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_degradation/ndvi_linear_trend.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_degradation/ndvi_linear_trend.md index b320cf82..85f3761a 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_degradation/ndvi_linear_trend.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/land_degradation/ndvi_linear_trend.md @@ -1,5 +1,38 @@ # farm_ai/land_degradation/ndvi_linear_trend +Computes the pixel-wise NDVI linear trend over the input raster. The workflow computes the NDVI from the input raster, calculates the linear trend over chunks of data, combining them into the final raster. + +```{mermaid} + graph TD + inp1>raster] + out1>ndvi_raster] + out2>linear_trend] + tsk1{{ndvi}} + tsk2{{chunked_linear_trend}} + tsk1{{ndvi}} -- index_raster/input_rasters --> tsk2{{chunked_linear_trend}} + inp1>raster] -- raster --> tsk1{{ndvi}} + tsk1{{ndvi}} -- index_raster --> out1>ndvi_raster] + tsk2{{chunked_linear_trend}} -- linear_trend_raster --> out2>linear_trend] +``` + +## Sources + +- **raster**: Input raster. + +## Sinks + +- **ndvi_raster**: NDVI raster. + +- **linear_trend**: Raster with the trend and the test statistics. + +## Tasks + +- **ndvi**: Computes an index from the bands of an input raster. + +- **chunked_linear_trend**: Computes the pixel-wise linear trend of a list of rasters (e.g. NDVI). + +## Workflow Yaml + ```yaml name: ndvi_linear_trend @@ -34,17 +67,4 @@ description: linear_trend: Raster with the trend and the test statistics. -``` - -```{mermaid} - graph TD - inp1>raster] - out1>ndvi_raster] - out2>linear_trend] - tsk1{{ndvi}} - tsk2{{chunked_linear_trend}} - tsk1{{ndvi}} -- index_raster/input_rasters --> tsk2{{chunked_linear_trend}} - inp1>raster] -- raster --> tsk1{{ndvi}} - tsk1{{ndvi}} -- index_raster --> out1>ndvi_raster] - tsk2{{chunked_linear_trend}} -- linear_trend_raster --> out2>linear_trend] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/segmentation/segment_basemap.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/segmentation/segment_basemap.md index 513eea50..38950101 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/segmentation/segment_basemap.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/segmentation/segment_basemap.md @@ -1,17 +1,65 @@ # farm_ai/segmentation/segment_basemap +Downloads basemap with BingMaps API and runs Segment Anything Model (SAM) over them with points and/or bounding boxes as prompts. The workflow lists and downloads basemaps tiles with BingMaps API, and merges them into a single raster. The raster is then split into chips of 1024x1024 pixels with an overlap defined by `spatial_overlap`. Chips intersecting with prompts are processed by SAM's image encoder, followed by prompt encoder and mask decoder. Before running the workflow, make sure the model has been imported into the cluster by running `scripts/export_prompt_segmentation_models.py`. The script will download the desired model weights from SAM repository, export the image encoder and mask decoder to ONNX format, and add them to the cluster. For more information, refer to the [FarmVibes.AI troubleshooting](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/TROUBLESHOOTING.html) page in the documentation. + +```{mermaid} + graph TD + inp1>user_input] + inp2>prompts] + out1>basemap] + out2>segmentation_mask] + tsk1{{basemap_download}} + tsk2{{basemap_segmentation}} + tsk1{{basemap_download}} -- merged_basemap/input_raster --> tsk2{{basemap_segmentation}} + inp1>user_input] -- input_geometry --> tsk1{{basemap_download}} + inp1>user_input] -- input_geometry --> tsk2{{basemap_segmentation}} + inp2>prompts] -- input_prompts --> tsk2{{basemap_segmentation}} + tsk1{{basemap_download}} -- merged_basemap --> out1>basemap] + tsk2{{basemap_segmentation}} -- segmentation_mask --> out2>segmentation_mask] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +- **prompts**: ExternalReferences to the point and/or bounding box prompts. These are GeoJSON with coordinates, label (foreground/background) and prompt id (in case, the raster contains multiple entities that should be segmented in a single workflow run). + +## Sinks + +- **basemap**: Merged basemap used as input to the segmentation. + +- **segmentation_mask**: Output segmentation masks. + +## Parameters + +- **bingmaps_api_key**: Required BingMaps API key. + +- **basemap_zoom_level**: Zoom level of interest, ranging from 0 to 20. For instance, a zoom level of 1 corresponds to a resolution of 78271.52 m/pixel, a zoom level of 10 corresponds to 152.9 m/pixel, and a zoom level of 19 corresponds to 0.3 m/pixel. For more information on zoom levels and their corresponding scale and resolution, please refer to the BingMaps API documentation at https://learn.microsoft.com/en-us/bingmaps/articles/understanding-scale-and-resolution + +- **model_type**: SAM's image encoder backbone architecture, among 'vit_h', 'vit_l', or 'vit_b'. Before running the workflow, make sure the desired model has been exported to the cluster by running `scripts/export_sam_models.py`. For more information, refer to the FarmVibes.AI troubleshooting page in the documentation. + +- **spatial_overlap**: Percentage of spatial overlap between chips in the range of [0.0, 1.0). + +## Tasks + +- **basemap_download**: Downloads Bing Maps basemap tiles and merges them into a single raster. + +- **basemap_segmentation**: Runs Segment Anything Model (SAM) over BingMaps basemap rasters with points and/or bounding boxes as prompts. + +## Workflow Yaml + ```yaml name: segment_basemap sources: user_input: - basemap_download.input_geometry - - sam_inference.input_geometry + - basemap_segmentation.input_geometry prompts: - - ingest_points.user_input + - basemap_segmentation.input_prompts sinks: basemap: basemap_download.merged_basemap - segmentation_mask: sam_inference.segmentation_mask + segmentation_mask: basemap_segmentation.segmentation_mask parameters: bingmaps_api_key: null basemap_zoom_level: 14 @@ -23,21 +71,15 @@ tasks: parameters: api_key: '@from(bingmaps_api_key)' zoom_level: '@from(basemap_zoom_level)' - ingest_points: - workflow: data_ingestion/user_data/ingest_geometry - sam_inference: - op: basemap_prompt_segmentation - op_dir: segment_anything + basemap_segmentation: + workflow: ml/segment_anything/basemap_prompt_segmentation parameters: model_type: '@from(model_type)' spatial_overlap: '@from(spatial_overlap)' edges: - origin: basemap_download.merged_basemap destination: - - sam_inference.input_raster -- origin: ingest_points.geometry - destination: - - sam_inference.input_prompts + - basemap_segmentation.input_raster description: short_description: Downloads basemap with BingMaps API and runs Segment Anything Model (SAM) over them with points and/or bounding boxes as prompts. @@ -62,22 +104,4 @@ description: segmentation_mask: Output segmentation masks. -``` - -```{mermaid} - graph TD - inp1>user_input] - inp2>prompts] - out1>basemap] - out2>segmentation_mask] - tsk1{{basemap_download}} - tsk2{{ingest_points}} - tsk3{{sam_inference}} - tsk1{{basemap_download}} -- merged_basemap/input_raster --> tsk3{{sam_inference}} - tsk2{{ingest_points}} -- geometry/input_prompts --> tsk3{{sam_inference}} - inp1>user_input] -- input_geometry --> tsk1{{basemap_download}} - inp1>user_input] -- input_geometry --> tsk3{{sam_inference}} - inp2>prompts] -- user_input --> tsk2{{ingest_points}} - tsk1{{basemap_download}} -- merged_basemap --> out1>basemap] - tsk3{{sam_inference}} -- segmentation_mask --> out2>segmentation_mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/segmentation/segment_s2.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/segmentation/segment_s2.md index a5c8a115..6cac4be5 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/segmentation/segment_s2.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/segmentation/segment_s2.md @@ -1,17 +1,63 @@ # farm_ai/segmentation/segment_s2 +Downloads Sentinel-2 imagery and runs Segment Anything Model (SAM) over them with points and/or bounding boxes as prompts. The workflow retrieves the relevant Sentinel-2 products with the Planetary Computer (PC) API, and splits the input rasters into chips of 1024x1024 pixels with an overlap defined by `spatial_overlap`. Chips intersecting with prompts are processed by SAM's image encoder, followed by prompt encoder and mask decoder. Before running the workflow, make sure the model has been imported into the cluster by running `scripts/export_prompt_segmentation_models.py`. The script will download the desired model weights from SAM repository, export the image encoder and mask decoder to ONNX format, and add them to the cluster. For more information, refer to the [FarmVibes.AI troubleshooting](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/TROUBLESHOOTING.html) page in the documentation. + +```{mermaid} + graph TD + inp1>user_input] + inp2>prompts] + out1>s2_raster] + out2>segmentation_mask] + tsk1{{preprocess_s2}} + tsk2{{s2_segmentation}} + tsk1{{preprocess_s2}} -- raster/input_raster --> tsk2{{s2_segmentation}} + inp1>user_input] -- user_input --> tsk1{{preprocess_s2}} + inp1>user_input] -- input_geometry --> tsk2{{s2_segmentation}} + inp2>prompts] -- input_prompts --> tsk2{{s2_segmentation}} + tsk1{{preprocess_s2}} -- raster --> out1>s2_raster] + tsk2{{s2_segmentation}} -- segmentation_mask --> out2>segmentation_mask] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +- **prompts**: ExternalReferences to the point and/or bounding box prompts. These are GeoJSON with coordinates, label (foreground/background) and prompt id (in case, the raster contains multiple entities that should be segmented in a single workflow run). + +## Sinks + +- **s2_raster**: Sentinel-2 rasters used as input for the segmentation. + +- **segmentation_mask**: Output segmentation masks. + +## Parameters + +- **model_type**: SAM's image encoder backbone architecture, among 'vit_h', 'vit_l', or 'vit_b'. Before running the workflow, make sure the desired model has been exported to the cluster by running `scripts/export_sam_models.py`. For more information, refer to the FarmVibes.AI troubleshooting page in the documentation. + +- **spatial_overlap**: Percentage of spatial overlap between chips in the range of [0.0, 1.0). + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **preprocess_s2**: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time range. + +- **s2_segmentation**: Runs Segment Anything Model (SAM) over Sentinel-2 rasters with points and/or bounding boxes as prompts. + +## Workflow Yaml + ```yaml name: segment_s2 sources: user_input: - preprocess_s2.user_input - - sam_inference.input_geometry + - s2_segmentation.input_geometry prompts: - - ingest_points.user_input + - s2_segmentation.input_prompts sinks: s2_raster: preprocess_s2.raster - segmentation_mask: sam_inference.segmentation_mask + segmentation_mask: s2_segmentation.segmentation_mask parameters: model_type: vit_b spatial_overlap: 0.5 @@ -21,21 +67,15 @@ tasks: workflow: data_ingestion/sentinel2/preprocess_s2 parameters: pc_key: '@from(pc_key)' - ingest_points: - workflow: data_ingestion/user_data/ingest_geometry - sam_inference: - op: s2_prompt_segmentation - op_dir: segment_anything + s2_segmentation: + workflow: ml/segment_anything/s2_prompt_segmentation parameters: model_type: '@from(model_type)' spatial_overlap: '@from(spatial_overlap)' edges: - origin: preprocess_s2.raster destination: - - sam_inference.input_raster -- origin: ingest_points.geometry - destination: - - sam_inference.input_prompts + - s2_segmentation.input_raster description: short_description: Downloads Sentinel-2 imagery and runs Segment Anything Model (SAM) over them with points and/or bounding boxes as prompts. @@ -60,22 +100,4 @@ description: segmentation_mask: Output segmentation masks. -``` - -```{mermaid} - graph TD - inp1>user_input] - inp2>prompts] - out1>s2_raster] - out2>segmentation_mask] - tsk1{{preprocess_s2}} - tsk2{{ingest_points}} - tsk3{{sam_inference}} - tsk1{{preprocess_s2}} -- raster/input_raster --> tsk3{{sam_inference}} - tsk2{{ingest_points}} -- geometry/input_prompts --> tsk3{{sam_inference}} - inp1>user_input] -- user_input --> tsk1{{preprocess_s2}} - inp1>user_input] -- input_geometry --> tsk3{{sam_inference}} - inp2>prompts] -- user_input --> tsk2{{ingest_points}} - tsk1{{preprocess_s2}} -- raster --> out1>s2_raster] - tsk3{{sam_inference}} -- segmentation_mask --> out2>segmentation_mask] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/sensor/optimal_locations.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/sensor/optimal_locations.md index 0b0ededd..354e86c1 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/sensor/optimal_locations.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/sensor/optimal_locations.md @@ -1,5 +1,63 @@ # farm_ai/sensor/optimal_locations +Identify optimal locations by performing clustering operation using Gaussian Mixture model on computed raster indices. The clustering operation separate computed raster indices values into n groups of equal variance, each group assigned a location and that location is considered as a +optimal locations. The sample locations generated provide information of latitude and longitude. The optimal location can be utilized to install sensors and collect +soil information. The index parameter used as input to run the computed index workflow internally using the input raster submitted. The selection of index parameter varies +based on requirement. The workflow supports all the indices supported by spyndex library (https://github.com/awesome-spectral-indices/awesome-spectral-indices#vegetation). +Below provided various indices that are used to identify optimal locations and generated a nutrients heatmap. +Enhanced Vegetation Index (EVI) - EVI is designed to minimize the influence of soil brightness and atmospheric conditions on vegetation assessment. It is calculated +using the red, blue, and near-infrared (NIR) bands. EVI is particularly useful for monitoring vegetation in regions with high canopy cover and in areas where atmospheric +interference is significant. This indices also used in notebook (notebooks/heatmaps/nutrients_using_neighbors.ipynb) that derive nutrient information for Carbon, Nitrogen, +and Phosphorus. +Photochemical Reflectance Index (PRI) - It is a vegetation index used to assess the light-use efficiency of plants in terms of photosynthesis and their response to +changes in light conditions, particularly variations in the blue and red parts of the electromagnetic spectrum. This index also used in notebook +(notebooks/heatmaps/nutrients_using_neighbors.ipynb) that derive nutrient information for pH. +The number of sample locations generated depend on input parameters submitted. Tune n_clusters and sieve_size parameters to generate more or less location data points. +For a 100 acre farm, +- 20 sample locations are generated using n_clusters=5 and sieve_size=10. +- 30 sample locations are generated using n_clusters=5 and sieve_size=20. +- 80 sample locations are generated using n_clusters=5 and sieve_size=5. +- 130 sample locations are generated using n_clusters=8 and sieve_size=5. + +```{mermaid} + graph TD + inp1>user_input] + inp2>input_raster] + out1>result] + tsk1{{compute_index}} + tsk2{{find_samples}} + tsk1{{compute_index}} -- index_raster/raster --> tsk2{{find_samples}} + inp1>user_input] -- user_input --> tsk2{{find_samples}} + inp2>input_raster] -- raster --> tsk1{{compute_index}} + tsk2{{find_samples}} -- locations --> out1>result] +``` + +## Sources + +- **input_raster**: List of computed raster indices generated using the sentinel 2 satellite imagery. + +- **user_input**: DataVibe with time range information. + +## Sinks + +- **result**: Zip file containing sample locations in a shape file (.shp) format. + +## Parameters + +- **n_clusters**: number of clusters used to generate sample locations. + +- **sieve_size**: Group the nearest neighbor pixel values. + +- **index**: Index used to generate sample locations. + +## Tasks + +- **compute_index**: Computes an index from the bands of an input raster. + +- **find_samples**: Find minimum soil sample locations by grouping indices values that are derived from satellite or spaceEye imagery bands. + +## Workflow Yaml + ```yaml name: optimal_locations @@ -71,17 +129,4 @@ description: index: Index used to generate sample locations. -``` - -```{mermaid} - graph TD - inp1>user_input] - inp2>input_raster] - out1>result] - tsk1{{compute_index}} - tsk2{{find_samples}} - tsk1{{compute_index}} -- index_raster/raster --> tsk2{{find_samples}} - inp1>user_input] -- user_input --> tsk2{{find_samples}} - inp2>input_raster] -- raster --> tsk1{{compute_index}} - tsk2{{find_samples}} -- locations --> out1>result] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/water/irrigation_classification.md b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/water/irrigation_classification.md index db666502..4ff91326 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/farm_ai/water/irrigation_classification.md +++ b/docs/source/docfiles/markdown/workflow_yaml/farm_ai/water/irrigation_classification.md @@ -1,5 +1,131 @@ # farm_ai/water/irrigation_classification +Develops 30m pixel-wise irrigation probability map. The workflow retrieves LANDSAT 8 Surface Reflectance (SR) image tile and land surface elevation DEM data, and runs four ops to compute irrigation probability map. The land surface elevation data source are 10m USGS DEM, or 30m Copernicus DEM; but Copernicus DEM is set as the default source in the workflow. Landsat Op compute_cloud_water_mask utilizes the qa_pixel band of image and NDVI index to generate mask of cloud cover and water bodies. Op compute_evaporative_fraction utilizes NDVI index, land surface temperature (LST), green and near infra-red bands, and DEM data to estimate evaporative flux (ETRF). Op compute_ngi_egi_layers utilizes NDVI index, ETRF estimates, green and near infra-red bands to generate NGI and EGI irrigation layers. Lastly op compute_irrigation_probability uses NGI and EGI layers along with LST band; and applies optimized logistic regression model to compute 30m pixel-wise irrigation probability map. The coeficients and intercept of the model were obtained beforehand using as ground-truth data from Nebraska state, USA for the year 2015. + +```{mermaid} + graph TD + inp1>user_input] + out1>landsat_bands] + out2>ndvi] + out3>cloud_water_mask] + out4>dem] + out5>evaporative_fraction] + out6>ngi] + out7>egi] + out8>lst] + out9>irrigation_probability] + tsk1{{landsat}} + tsk2{{ndvi}} + tsk3{{merge_geom}} + tsk4{{merge_geom_time_range}} + tsk5{{cloud_water_mask}} + tsk6{{dem}} + tsk7{{match_dem}} + tsk8{{evaporative_fraction}} + tsk9{{ngi_egi_layers}} + tsk10{{irrigation_probability}} + tsk1{{landsat}} -- raster/items --> tsk3{{merge_geom}} + tsk1{{landsat}} -- raster --> tsk2{{ndvi}} + tsk1{{landsat}} -- raster/landsat_raster --> tsk5{{cloud_water_mask}} + tsk1{{landsat}} -- raster/ref_rasters --> tsk7{{match_dem}} + tsk1{{landsat}} -- raster/landsat_raster --> tsk8{{evaporative_fraction}} + tsk1{{landsat}} -- raster/landsat_raster --> tsk9{{ngi_egi_layers}} + tsk1{{landsat}} -- raster/landsat_raster --> tsk10{{irrigation_probability}} + tsk2{{ndvi}} -- index/ndvi_raster --> tsk5{{cloud_water_mask}} + tsk2{{ndvi}} -- index/ndvi_raster --> tsk8{{evaporative_fraction}} + tsk2{{ndvi}} -- index/ndvi_raster --> tsk9{{ngi_egi_layers}} + tsk3{{merge_geom}} -- merged/geometry --> tsk4{{merge_geom_time_range}} + tsk4{{merge_geom_time_range}} -- merged/user_input --> tsk6{{dem}} + tsk6{{dem}} -- raster/rasters --> tsk7{{match_dem}} + tsk7{{match_dem}} -- match_rasters/dem_raster --> tsk8{{evaporative_fraction}} + tsk8{{evaporative_fraction}} -- evaporative_fraction --> tsk9{{ngi_egi_layers}} + tsk5{{cloud_water_mask}} -- cloud_water_mask/cloud_water_mask_raster --> tsk8{{evaporative_fraction}} + tsk5{{cloud_water_mask}} -- cloud_water_mask/cloud_water_mask_raster --> tsk9{{ngi_egi_layers}} + tsk5{{cloud_water_mask}} -- cloud_water_mask/cloud_water_mask_raster --> tsk10{{irrigation_probability}} + tsk9{{ngi_egi_layers}} -- ngi --> tsk10{{irrigation_probability}} + tsk9{{ngi_egi_layers}} -- egi --> tsk10{{irrigation_probability}} + tsk9{{ngi_egi_layers}} -- lst --> tsk10{{irrigation_probability}} + inp1>user_input] -- user_input --> tsk1{{landsat}} + inp1>user_input] -- time_range --> tsk4{{merge_geom_time_range}} + tsk1{{landsat}} -- raster --> out1>landsat_bands] + tsk2{{ndvi}} -- index --> out2>ndvi] + tsk5{{cloud_water_mask}} -- cloud_water_mask --> out3>cloud_water_mask] + tsk7{{match_dem}} -- match_rasters --> out4>dem] + tsk8{{evaporative_fraction}} -- evaporative_fraction --> out5>evaporative_fraction] + tsk9{{ngi_egi_layers}} -- ngi --> out6>ngi] + tsk9{{ngi_egi_layers}} -- egi --> out7>egi] + tsk9{{ngi_egi_layers}} -- lst --> out8>lst] + tsk10{{irrigation_probability}} -- irrigation_probability --> out9>irrigation_probability] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **landsat_bands**: Raster of Landsat bands. + +- **ndvi**: NDVI raster. + +- **cloud_water_mask**: Mask of cloud cover and water bodies. + +- **dem**: DEM raster. Options are CopernicusDEM30 and USGS3DEP. + +- **evaporative_fraction**: Raster with estimates of evaporative fraction flux. + +- **ngi**: Raster of NGI irrigation layer. + +- **egi**: Raster of EGI irrigation layer. + +- **lst**: Raster of land surface temperature. + +- **irrigation_probability**: Raster of irrigation probability map in 30m resolution. + +## Parameters + +- **ndvi_threshold**: NDVI index threshold value for masking water bodies. + +- **ndvi_hot_threshold**: Maximum NDVI index threshold value for selecting hot pixel. + +- **coef_ngi**: Coefficient of NGI layer in optimized logistic regression model. + +- **coef_egi**: Coefficient of EGI layer in optimized logistic regression model. + +- **coef_lst**: Coefficient of land surface temperature band in optimized logistic regression model. + +- **intercept**: Intercept value of optimized logistic regression model. + +- **dem_resolution**: Spatial resolution of the DEM. 10m and 30m are available. + +- **dem_provider**: Provider of the DEM. "USGS3DEP" and "CopernicusDEM30" are available. + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **landsat**: Downloads and preprocesses LANDSAT tiles that intersect with the input geometry and time range. + +- **ndvi**: Computes `index` over the input raster. + +- **merge_geom**: Create item with merged geometry from item list. + +- **merge_geom_time_range**: Create item that contains the geometry from one item and the time range from another. + +- **cloud_water_mask**: Merges landsat cloud mask and NDVI-based mask to produce a cloud water mask. + +- **dem**: Downloads digital elevation map tiles that intersect with the input geometry and time range. + +- **match_dem**: Resamples input rasters to the reference rasters' grid. + +- **evaporative_fraction**: Computes evaporative fraction layer based on the percentile values of lst_dem (created by treating land surface temperature with dem) and ndvi layers. The source of constants used is "Senay, G.B.; Bohms, S.; Singh, R.K.; Gowda, P.H.; Velpuri, N.M.; Alemu, H.; Verdin, J.P. Operational Evapotranspiration Mapping Using Remote Sensing and Weather Datasets - A New Parameterization for the SSEB Approach. JAWRA J. Am. Water Resour. Assoc. 2013, 49, 577–591. The land surface elevation data source are 10m USGS DEM, and 30m Copernicus DEM; but Copernicus DEM is set as default source in the workflow. + +- **ngi_egi_layers**: Computes NGI, EGI, and LST layers from landsat bands, ndvi layer, cloud water mask layer and evaporative fraction layer + +- **irrigation_probability**: Computes irrigation probability values for each pixel in raster using optimized logistic regression model with ngi, egi, and lst rasters as input + +## Workflow Yaml + ```yaml name: irrigation_classification @@ -145,60 +271,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>landsat_bands] - out2>ndvi] - out3>cloud_water_mask] - out4>dem] - out5>evaporative_fraction] - out6>ngi] - out7>egi] - out8>lst] - out9>irrigation_probability] - tsk1{{landsat}} - tsk2{{ndvi}} - tsk3{{merge_geom}} - tsk4{{merge_geom_time_range}} - tsk5{{cloud_water_mask}} - tsk6{{dem}} - tsk7{{match_dem}} - tsk8{{evaporative_fraction}} - tsk9{{ngi_egi_layers}} - tsk10{{irrigation_probability}} - tsk1{{landsat}} -- raster/items --> tsk3{{merge_geom}} - tsk1{{landsat}} -- raster --> tsk2{{ndvi}} - tsk1{{landsat}} -- raster/landsat_raster --> tsk5{{cloud_water_mask}} - tsk1{{landsat}} -- raster/ref_rasters --> tsk7{{match_dem}} - tsk1{{landsat}} -- raster/landsat_raster --> tsk8{{evaporative_fraction}} - tsk1{{landsat}} -- raster/landsat_raster --> tsk9{{ngi_egi_layers}} - tsk1{{landsat}} -- raster/landsat_raster --> tsk10{{irrigation_probability}} - tsk2{{ndvi}} -- index/ndvi_raster --> tsk5{{cloud_water_mask}} - tsk2{{ndvi}} -- index/ndvi_raster --> tsk8{{evaporative_fraction}} - tsk2{{ndvi}} -- index/ndvi_raster --> tsk9{{ngi_egi_layers}} - tsk3{{merge_geom}} -- merged/geometry --> tsk4{{merge_geom_time_range}} - tsk4{{merge_geom_time_range}} -- merged/user_input --> tsk6{{dem}} - tsk6{{dem}} -- raster/rasters --> tsk7{{match_dem}} - tsk7{{match_dem}} -- match_rasters/dem_raster --> tsk8{{evaporative_fraction}} - tsk8{{evaporative_fraction}} -- evaporative_fraction --> tsk9{{ngi_egi_layers}} - tsk5{{cloud_water_mask}} -- cloud_water_mask/cloud_water_mask_raster --> tsk8{{evaporative_fraction}} - tsk5{{cloud_water_mask}} -- cloud_water_mask/cloud_water_mask_raster --> tsk9{{ngi_egi_layers}} - tsk5{{cloud_water_mask}} -- cloud_water_mask/cloud_water_mask_raster --> tsk10{{irrigation_probability}} - tsk9{{ngi_egi_layers}} -- ngi --> tsk10{{irrigation_probability}} - tsk9{{ngi_egi_layers}} -- egi --> tsk10{{irrigation_probability}} - tsk9{{ngi_egi_layers}} -- lst --> tsk10{{irrigation_probability}} - inp1>user_input] -- user_input --> tsk1{{landsat}} - inp1>user_input] -- time_range --> tsk4{{merge_geom_time_range}} - tsk1{{landsat}} -- raster --> out1>landsat_bands] - tsk2{{ndvi}} -- index --> out2>ndvi] - tsk5{{cloud_water_mask}} -- cloud_water_mask --> out3>cloud_water_mask] - tsk7{{match_dem}} -- match_rasters --> out4>dem] - tsk8{{evaporative_fraction}} -- evaporative_fraction --> out5>evaporative_fraction] - tsk9{{ngi_egi_layers}} -- ngi --> out6>ngi] - tsk9{{ngi_egi_layers}} -- egi --> out7>egi] - tsk9{{ngi_egi_layers}} -- lst --> out8>lst] - tsk10{{irrigation_probability}} -- irrigation_probability --> out9>irrigation_probability] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/forest_ai/deforestation/alos_trend_detection.md b/docs/source/docfiles/markdown/workflow_yaml/forest_ai/deforestation/alos_trend_detection.md new file mode 100644 index 00000000..56cd8468 --- /dev/null +++ b/docs/source/docfiles/markdown/workflow_yaml/forest_ai/deforestation/alos_trend_detection.md @@ -0,0 +1,134 @@ +# forest_ai/deforestation/alos_trend_detection + +Detects increase/decrease trends in forest pixel levels over the user-input geometry and time range for the ALOS forest map. This workflow combines the alos_forest_extent_download_merge and ordinal_trend_detection workflows to detect increase/decrease trends in the forest pixel levels over the user-provided geometry and time range for the ALOS forest map. The ALOS PALSAR 2.1 Forest/Non-Forest Maps are downloaded in the alos_forest_extent_download_merge workflow. Then the ordinal_trend_detection workflow clips the ordinal raster to the user-provided geometry and time range and determines if there is an increasing or decreasing trend in the forest pixel levels over them. alos_trend_detection uses the Cochran-Armitage test to detect trends in the forest levels over the years. The null hypothesis is that there is no trend in the pixel levels over the list of rasters. The alternative hypothesis is that there is a trend in the forest pixel levels over the list of rasters (one for each year). It returns a p-value and a z-score. If the p-value is less than some significance level, the null hypothesis is rejected and the alternative hypothesis is accepted. If the z-score is positive, the trend is increasing. If the z-score is negative, the trend is decreasing. + +```{mermaid} + graph TD + inp1>user_input] + out1>merged_raster] + out2>categorical_raster] + out3>recoded_raster] + out4>clipped_raster] + out5>trend_test_result] + tsk1{{alos_forest_extent_download_merge}} + tsk2{{ordinal_trend_detection}} + tsk1{{alos_forest_extent_download_merge}} -- merged_raster/raster --> tsk2{{ordinal_trend_detection}} + inp1>user_input] -- user_input --> tsk1{{alos_forest_extent_download_merge}} + inp1>user_input] -- input_geometry --> tsk2{{ordinal_trend_detection}} + tsk1{{alos_forest_extent_download_merge}} -- merged_raster --> out1>merged_raster] + tsk1{{alos_forest_extent_download_merge}} -- categorical_raster --> out2>categorical_raster] + tsk2{{ordinal_trend_detection}} -- recoded_raster --> out3>recoded_raster] + tsk2{{ordinal_trend_detection}} -- clipped_raster --> out4>clipped_raster] + tsk2{{ordinal_trend_detection}} -- trend_test_result --> out5>trend_test_result] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **merged_raster**: Merged raster of the ALOS PALSAR 2.1 Forest/Non-Forest Map for the user-provided geometry and time range. + +- **categorical_raster**: Categorical raster of the ALOS PALSAR 2.1 Forest/Non-Forest Map for the user-provided geometry and time range before the merge operation. + +- **recoded_raster**: Recoded raster of the ALOS PALSAR 2.1 Forest/Non-Forest Map for the user-provided geometry and time range. + +- **clipped_raster**: Clipped ordinal raster for the user-provided geometry and time range. + +- **trend_test_result**: Cochran-armitage test results composed of p-value and z-score. + +## Parameters + +- **pc_key**: Planetary Computer API key. + +- **from_values**: Values to recode from. + +- **to_values**: Values to recode to. + +## Tasks + +- **alos_forest_extent_download_merge**: Downloads Advanced Land Observing Satellite (ALOS) forest/non-forest classification map and merges it into a single raster. + +- **ordinal_trend_detection**: Detects increase/decrease trends in the pixel levels over the user-input geometry and time range. + +## Workflow Yaml + +```yaml + +name: alos_trend_detection +sources: + user_input: + - alos_forest_extent_download_merge.user_input + - ordinal_trend_detection.input_geometry +sinks: + merged_raster: alos_forest_extent_download_merge.merged_raster + categorical_raster: alos_forest_extent_download_merge.categorical_raster + recoded_raster: ordinal_trend_detection.recoded_raster + clipped_raster: ordinal_trend_detection.clipped_raster + trend_test_result: ordinal_trend_detection.trend_test_result +parameters: + pc_key: null + from_values: + - 4 + - 3 + - 0 + - 2 + - 1 + to_values: + - 0 + - 0 + - 0 + - 1 + - 1 +tasks: + alos_forest_extent_download_merge: + workflow: data_ingestion/alos/alos_forest_extent_download_merge + parameters: + pc_key: '@from(pc_key)' + ordinal_trend_detection: + workflow: forest_ai/deforestation/ordinal_trend_detection + parameters: + from_values: '@from(from_values)' + to_values: '@from(to_values)' +edges: +- origin: alos_forest_extent_download_merge.merged_raster + destination: + - ordinal_trend_detection.raster +description: + short_description: Detects increase/decrease trends in forest pixel levels over + the user-input geometry and time range for the ALOS forest map. + long_description: This workflow combines the alos_forest_extent_download_merge and + ordinal_trend_detection workflows to detect increase/decrease trends in the forest + pixel levels over the user-provided geometry and time range for the ALOS forest + map. The ALOS PALSAR 2.1 Forest/Non-Forest Maps are downloaded in the alos_forest_extent_download_merge + workflow. Then the ordinal_trend_detection workflow clips the ordinal raster + to the user-provided geometry and time range and determines if there is an increasing + or decreasing trend in the forest pixel levels over them. alos_trend_detection + uses the Cochran-Armitage test to detect trends in the forest levels over the + years. The null hypothesis is that there is no trend in the pixel levels over + the list of rasters. The alternative hypothesis is that there is a trend in the + forest pixel levels over the list of rasters (one for each year). It returns a + p-value and a z-score. If the p-value is less than some significance level, the + null hypothesis is rejected and the alternative hypothesis is accepted. If the + z-score is positive, the trend is increasing. If the z-score is negative, the + trend is decreasing. + sources: + user_input: Time range and geometry of interest. + sinks: + merged_raster: Merged raster of the ALOS PALSAR 2.1 Forest/Non-Forest Map for + the user-provided geometry and time range. + categorical_raster: Categorical raster of the ALOS PALSAR 2.1 Forest/Non-Forest + Map for the user-provided geometry and time range before the merge operation. + recoded_raster: Recoded raster of the ALOS PALSAR 2.1 Forest/Non-Forest Map for + the user-provided geometry and time range. + clipped_raster: Clipped ordinal raster for the user-provided geometry and time + range. + trend_test_result: Cochran-armitage test results composed of p-value and z-score. + parameters: + pc_key: Planetary Computer API key. + from_values: Values to recode from. + to_values: Values to recode to. + + +``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/forest_ai/deforestation/ordinal_trend_detection.md b/docs/source/docfiles/markdown/workflow_yaml/forest_ai/deforestation/ordinal_trend_detection.md new file mode 100644 index 00000000..bb347a72 --- /dev/null +++ b/docs/source/docfiles/markdown/workflow_yaml/forest_ai/deforestation/ordinal_trend_detection.md @@ -0,0 +1,123 @@ +# forest_ai/deforestation/ordinal_trend_detection + +Detects increase/decrease trends in the pixel levels over the user-input geometry and time range. This workflow prepares rasters to perform the Cochran-Armitage trend test over a user-provided geometry and time range. Initially, it recodes the input raster according to the 'from_values' and 'to_values' parameters. For example, if the original raster has values (2, 1, 3, 4, 5) and the default values of 'from_values' and 'to_values' are respectively [1, 2, 3, 4, 5] and [6, 7, 8, 9, 10], the recoded raster will have values (7, 6, 8, 9, 10). The workflow then clips the user-provided geometries and computes an ordinal raster. It also counts each unique pixel present in the recoded rasters to create a pixel frequency contingency table. This data is used to determine if there is an increasing or decreasing trend in pixel levels. The Cochran-Armitage test is a non-parametric test used to ascertain this trend. The null hypothesis assumes no trend in pixel levels, while the alternative hypothesis assumes a trend exists. The test returns a p-value and a z-score. If the p-value is less than some significance level, the null hypothesis is rejected in favor of the alternative. A positive z-score indicates an increasing trend, while a negative one indicates a decreasing trend. + +```{mermaid} + graph TD + inp1>raster] + inp2>input_geometry] + out1>recoded_raster] + out2>trend_test_result] + out3>clipped_raster] + tsk1{{recode_raster}} + tsk2{{clip}} + tsk3{{compute_pixel_count}} + tsk4{{trend_test}} + tsk1{{recode_raster}} -- recoded_raster/raster --> tsk2{{clip}} + tsk2{{clip}} -- clipped_raster/raster --> tsk3{{compute_pixel_count}} + tsk3{{compute_pixel_count}} -- pixel_count --> tsk4{{trend_test}} + inp1>raster] -- raster --> tsk1{{recode_raster}} + inp2>input_geometry] -- input_geometry --> tsk2{{clip}} + tsk1{{recode_raster}} -- recoded_raster --> out1>recoded_raster] + tsk4{{trend_test}} -- ordinal_trend_result --> out2>trend_test_result] + tsk2{{clip}} -- clipped_raster --> out3>clipped_raster] +``` + +## Sources + +- **raster**: Raster to be processed and tested for trends. + +- **input_geometry**: Reference geometry. + +## Sinks + +- **recoded_raster**: Recoded raster for the user-provided geometry and time range. + +- **trend_test_result**: Cochran-armitage test results composed of p-value and z-score. + +- **clipped_raster**: Clipped ordinal raster for the user-provided geometry and time range. + +## Parameters + +- **from_values**: List of values to recode from. + +- **to_values**: List of values to recode to. + +## Tasks + +- **recode_raster**: Recodes values of the input raster. + +- **clip**: Performs a soft clip on an input raster based on a provided reference geometry. + +- **compute_pixel_count**: Counts the pixel values in the input raster. + +- **trend_test**: Detects increase/decrease trends over a list of Rasters. + +## Workflow Yaml + +```yaml + +name: ordinal_trend_detection +sources: + raster: + - recode_raster.raster + input_geometry: + - clip.input_geometry +sinks: + recoded_raster: recode_raster.recoded_raster + trend_test_result: trend_test.ordinal_trend_result + clipped_raster: clip.clipped_raster +parameters: + from_values: [] + to_values: [] +tasks: + recode_raster: + op: recode_raster + parameters: + from_values: '@from(from_values)' + to_values: '@from(to_values)' + clip: + workflow: data_processing/clip/clip + compute_pixel_count: + op: compute_pixel_count + trend_test: + op: ordinal_trend_test +edges: +- origin: recode_raster.recoded_raster + destination: + - clip.raster +- origin: clip.clipped_raster + destination: + - compute_pixel_count.raster +- origin: compute_pixel_count.pixel_count + destination: + - trend_test.pixel_count +description: + short_description: Detects increase/decrease trends in the pixel levels over the + user-input geometry and time range. + long_description: This workflow prepares rasters to perform the Cochran-Armitage + trend test over a user-provided geometry and time range. Initially, it recodes + the input raster according to the 'from_values' and 'to_values' parameters. For + example, if the original raster has values (2, 1, 3, 4, 5) and the default values + of 'from_values' and 'to_values' are respectively [1, 2, 3, 4, 5] and [6, 7, 8, + 9, 10], the recoded raster will have values (7, 6, 8, 9, 10). The workflow then + clips the user-provided geometries and computes an ordinal raster. It also counts + each unique pixel present in the recoded rasters to create a pixel frequency contingency + table. This data is used to determine if there is an increasing or decreasing + trend in pixel levels. The Cochran-Armitage test is a non-parametric test used + to ascertain this trend. The null hypothesis assumes no trend in pixel levels, + while the alternative hypothesis assumes a trend exists. The test returns a p-value + and a z-score. If the p-value is less than some significance level, the null hypothesis + is rejected in favor of the alternative. A positive z-score indicates an increasing + trend, while a negative one indicates a decreasing trend. + sources: + raster: Raster to be processed and tested for trends. + input_geometry: Reference geometry. + sinks: + recoded_raster: Recoded raster for the user-provided geometry and time range. + trend_test_result: Cochran-armitage test results composed of p-value and z-score. + clipped_raster: Clipped ordinal raster for the user-provided geometry and time + range. + + +``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/helloworld.md b/docs/source/docfiles/markdown/workflow_yaml/helloworld.md index e8c6f4eb..9dc52e08 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/helloworld.md +++ b/docs/source/docfiles/markdown/workflow_yaml/helloworld.md @@ -1,5 +1,30 @@ # helloworld +Hello world! Small test workflow that generates an image of the Earth with countries that intersect with the input geometry highlighted in orange. + +```{mermaid} + graph TD + inp1>user_input] + out1>raster] + tsk1{{hello}} + inp1>user_input] -- user_input --> tsk1{{hello}} + tsk1{{hello}} -- raster --> out1>raster] +``` + +## Sources + +- **user_input**: Input geometry. + +## Sinks + +- **raster**: Raster with highlighted countries. + +## Tasks + +- **hello**: Test op that generates an image of the Earth with countries that intersect with the input geometry highlighted in orange. + +## Workflow Yaml + ```yaml name: helloworld @@ -21,13 +46,4 @@ description: raster: Raster with highlighted countries. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>raster] - tsk1{{hello}} - inp1>user_input] -- user_input --> tsk1{{hello}} - tsk1{{hello}} -- raster --> out1>raster] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/ml/crop_segmentation.md b/docs/source/docfiles/markdown/workflow_yaml/ml/crop_segmentation.md index 7f6b0232..20f17572 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/ml/crop_segmentation.md +++ b/docs/source/docfiles/markdown/workflow_yaml/ml/crop_segmentation.md @@ -1,5 +1,50 @@ # ml/crop_segmentation +Runs a crop segmentation model based on NDVI from SpaceEye imagery along the year. The workflow generates SpaceEye cloud-free data for the input region and time range and computes NDVI over those. NDVI values sampled regularly along the year are stacked as bands and used as input to the crop segmentation model. + +```{mermaid} + graph TD + inp1>user_input] + out1>segmentation] + tsk1{{spaceeye}} + tsk2{{ndvi}} + tsk3{{group}} + tsk4{{inference}} + tsk1{{spaceeye}} -- raster --> tsk2{{ndvi}} + tsk2{{ndvi}} -- index_raster/rasters --> tsk3{{group}} + tsk3{{group}} -- sequence/input_raster --> tsk4{{inference}} + inp1>user_input] -- user_input --> tsk1{{spaceeye}} + tsk4{{inference}} -- output_raster --> out1>segmentation] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **segmentation**: Crop segmentation map at 10m resolution. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +- **model_file**: Path to the ONNX file containing the model architecture and weights. + +- **model_bands**: Number of NDVI bands to stack as the model input. + +## Tasks + +- **spaceeye**: Runs the SpaceEye cloud removal pipeline using an interpolation-based algorithm, yielding daily cloud-free images for the input geometry and time range. + +- **ndvi**: Computes an index from the bands of an input raster. + +- **group**: Selects "num" entries from a Raster list so that the output sequence has a fixed length. + +- **inference**: Processes a sequence of rasters with an ONNX model. + +## Workflow Yaml + ```yaml name: crop_segmentation @@ -62,19 +107,4 @@ description: model_bands: Number of NDVI bands to stack as the model input. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>segmentation] - tsk1{{spaceeye}} - tsk2{{ndvi}} - tsk3{{group}} - tsk4{{inference}} - tsk1{{spaceeye}} -- raster --> tsk2{{ndvi}} - tsk2{{ndvi}} -- index_raster/rasters --> tsk3{{group}} - tsk3{{group}} -- sequence/input_raster --> tsk4{{inference}} - inp1>user_input] -- user_input --> tsk1{{spaceeye}} - tsk4{{inference}} -- output_raster --> out1>segmentation] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/ml/dataset_generation/datagen_crop_segmentation.md b/docs/source/docfiles/markdown/workflow_yaml/ml/dataset_generation/datagen_crop_segmentation.md index f494620b..7617ebdd 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/ml/dataset_generation/datagen_crop_segmentation.md +++ b/docs/source/docfiles/markdown/workflow_yaml/ml/dataset_generation/datagen_crop_segmentation.md @@ -1,5 +1,46 @@ # ml/dataset_generation/datagen_crop_segmentation +Generates a dataset for crop segmentation, based on NDVI raster and Crop Data Layer (CDL) maps. The workflow generates SpaceEye cloud-free data for the input region and time range and computes NDVI over those. It also downloads CDL maps for the years comprised in the time range. + +```{mermaid} + graph TD + inp1>user_input] + out1>ndvi] + out2>cdl] + tsk1{{spaceeye}} + tsk2{{ndvi}} + tsk3{{cdl}} + tsk1{{spaceeye}} -- raster --> tsk2{{ndvi}} + inp1>user_input] -- user_input --> tsk1{{spaceeye}} + inp1>user_input] -- user_input --> tsk3{{cdl}} + tsk2{{ndvi}} -- index_raster --> out1>ndvi] + tsk3{{cdl}} -- raster --> out2>cdl] +``` + +## Sources + +- **user_input**: Time range and geometry of interest. + +## Sinks + +- **ndvi**: NDVI rasters. + +- **cdl**: CDL map for the years comprised in the input time range. + +## Parameters + +- **pc_key**: Optional Planetary Computer API key. + +## Tasks + +- **spaceeye**: Runs the SpaceEye cloud removal pipeline using an interpolation-based algorithm, yielding daily cloud-free images for the input geometry and time range. + +- **ndvi**: Computes an index from the bands of an input raster. + +- **cdl**: Downloads crop classes maps in the continental USA for the input time range. + +## Workflow Yaml + ```yaml name: datagen_crop_segmentation @@ -42,19 +83,4 @@ description: pc_key: Optional Planetary Computer API key. -``` - -```{mermaid} - graph TD - inp1>user_input] - out1>ndvi] - out2>cdl] - tsk1{{spaceeye}} - tsk2{{ndvi}} - tsk3{{cdl}} - tsk1{{spaceeye}} -- raster --> tsk2{{ndvi}} - inp1>user_input] -- user_input --> tsk1{{spaceeye}} - inp1>user_input] -- user_input --> tsk3{{cdl}} - tsk2{{ndvi}} -- index_raster --> out1>ndvi] - tsk3{{cdl}} -- raster --> out2>cdl] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/ml/driveway_detection.md b/docs/source/docfiles/markdown/workflow_yaml/ml/driveway_detection.md index 4e90413e..d7ee4456 100644 --- a/docs/source/docfiles/markdown/workflow_yaml/ml/driveway_detection.md +++ b/docs/source/docfiles/markdown/workflow_yaml/ml/driveway_detection.md @@ -1,5 +1,60 @@ # ml/driveway_detection +Detects driveways in front of houses. The workflow downloads road geometry from Open Street Maps and segments the front of houses in the input image using a machine learning model. It then uses the input image, segmentation map, road geometry, and input property boundaries to detect the presence of driveways in the front of each house. + +```{mermaid} + graph TD + inp1>input_raster] + inp2>property_boundaries] + out1>properties] + out2>driveways] + tsk1{{segment}} + tsk2{{osm}} + tsk3{{detect}} + tsk1{{segment}} -- segmentation_raster --> tsk3{{detect}} + tsk2{{osm}} -- roads --> tsk3{{detect}} + inp1>input_raster] -- input_raster --> tsk1{{segment}} + inp1>input_raster] -- input_raster --> tsk3{{detect}} + inp1>input_raster] -- user_input --> tsk2{{osm}} + inp2>property_boundaries] -- property_boundaries --> tsk3{{detect}} + tsk3{{detect}} -- properties_with_driveways --> out1>properties] + tsk3{{detect}} -- driveways --> out2>driveways] +``` + +## Sources + +- **input_raster**: Aerial imagery of the region of interest with RBG + NIR bands. + +- **property_boundaries**: Property boundary information for the region of interest. + +## Sinks + +- **properties**: Boundaries of properties that contain a driveway. + +- **driveways**: Regions of each property boundary where a driveway was detected. + +## Parameters + +- **min_region_area**: Minimum contiguous region that will be considered as a potential driveway, in meters. + +- **ndvi_thr**: Only areas under this NDVI threshold will be considered for driveways. + +- **car_size**: Expected size of a car, in pixels, defined as [height, width]. + +- **num_kernels**: Number of rotated kernels to try to fit a car inside a potential driveway region. + +- **car_thr**: Ratio of pixels of a kernel that have to be inside a region in order to consider it a parkable spot. + +## Tasks + +- **segment**: Segments the front of houses in the input raster using a machine learning model. + +- **osm**: Downloads road geometry for input region from Open Street Maps. + +- **detect**: Detects driveways in the front of each house, using the input image, segmentation map, road geometry, and input property boundaries. + +## Workflow Yaml + ```yaml name: driveway_detection @@ -65,23 +120,4 @@ description: to consider it a parkable spot. -``` - -```{mermaid} - graph TD - inp1>input_raster] - inp2>property_boundaries] - out1>properties] - out2>driveways] - tsk1{{segment}} - tsk2{{osm}} - tsk3{{detect}} - tsk1{{segment}} -- segmentation_raster --> tsk3{{detect}} - tsk2{{osm}} -- roads --> tsk3{{detect}} - inp1>input_raster] -- input_raster --> tsk1{{segment}} - inp1>input_raster] -- input_raster --> tsk3{{detect}} - inp1>input_raster] -- user_input --> tsk2{{osm}} - inp2>property_boundaries] -- property_boundaries --> tsk3{{detect}} - tsk3{{detect}} -- properties_with_driveways --> out1>properties] - tsk3{{detect}} -- driveways --> out2>driveways] ``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/ml/segment_anything/basemap_prompt_segmentation.md b/docs/source/docfiles/markdown/workflow_yaml/ml/segment_anything/basemap_prompt_segmentation.md new file mode 100644 index 00000000..67fa8bae --- /dev/null +++ b/docs/source/docfiles/markdown/workflow_yaml/ml/segment_anything/basemap_prompt_segmentation.md @@ -0,0 +1,97 @@ +# ml/segment_anything/basemap_prompt_segmentation + +Runs Segment Anything Model (SAM) over BingMaps basemap rasters with points and/or bounding boxes as prompts. The workflow splits the input BingMaps basemap rasters into chips of 1024x1024 pixels with an overlap defined by `spatial_overlap`. Chips intersecting with prompts are processed by SAM's image encoder, followed by prompt encoder and mask decoder. Before running the workflow, make sure the model has been imported into the cluster by running `scripts/export_prompt_segmentation_models.py`. The script will download the desired model weights from SAM repository, export the image encoder and mask decoder to ONNX format, and add them to the cluster. For more information, refer to the [FarmVibes.AI troubleshooting](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/TROUBLESHOOTING.html) page in the documentation. + +```{mermaid} + graph TD + inp1>input_raster] + inp2>input_geometry] + inp3>input_prompts] + out1>segmentation_mask] + tsk1{{ingest_points}} + tsk2{{sam_inference}} + tsk1{{ingest_points}} -- geometry/input_prompts --> tsk2{{sam_inference}} + inp1>input_raster] -- input_raster --> tsk2{{sam_inference}} + inp2>input_geometry] -- input_geometry --> tsk2{{sam_inference}} + inp3>input_prompts] -- user_input --> tsk1{{ingest_points}} + tsk2{{sam_inference}} -- segmentation_mask --> out1>segmentation_mask] +``` + +## Sources + +- **input_geometry**: Geometry of interest within the raster for the segmentation. + +- **input_raster**: BingMaps basemap rasters used as input for the segmentation. + +- **input_prompts**: ExternalReferences to the point and/or bounding box prompts. These are GeoJSON with coordinates, label (foreground/background) and prompt id (in case, the raster contains multiple entities that should be segmented in a single workflow run). + +## Sinks + +- **segmentation_mask**: Output segmentation masks. + +## Parameters + +- **model_type**: SAM's image encoder backbone architecture, among 'vit_h', 'vit_l', or 'vit_b'. Before running the workflow, make sure the desired model has been exported to the cluster by running `scripts/export_sam_models.py`. For more information, refer to the FarmVibes.AI troubleshooting page in the documentation. + +- **spatial_overlap**: Percentage of spatial overlap between chips in the range of [0.0, 1.0). + +## Tasks + +- **ingest_points**: Adds user geometries into the cluster storage, allowing for them to be used on workflows. + +- **sam_inference**: Runs SAM over the input BingMaps basemap raster with points and bounding boxes as prompts. + +## Workflow Yaml + +```yaml + +name: basemap_prompt_segmentation +sources: + input_raster: + - sam_inference.input_raster + input_geometry: + - sam_inference.input_geometry + input_prompts: + - ingest_points.user_input +sinks: + segmentation_mask: sam_inference.segmentation_mask +parameters: + model_type: vit_b + spatial_overlap: 0.5 +tasks: + ingest_points: + workflow: data_ingestion/user_data/ingest_geometry + sam_inference: + op: basemap_prompt_segmentation + op_dir: segment_anything + parameters: + model_type: '@from(model_type)' + spatial_overlap: '@from(spatial_overlap)' +edges: +- origin: ingest_points.geometry + destination: + - sam_inference.input_prompts +description: + short_description: Runs Segment Anything Model (SAM) over BingMaps basemap rasters + with points and/or bounding boxes as prompts. + long_description: The workflow splits the input BingMaps basemap rasters into chips + of 1024x1024 pixels with an overlap defined by `spatial_overlap`. Chips intersecting + with prompts are processed by SAM's image encoder, followed by prompt encoder + and mask decoder. Before running the workflow, make sure the model has been imported + into the cluster by running `scripts/export_prompt_segmentation_models.py`. The + script will download the desired model weights from SAM repository, export the + image encoder and mask decoder to ONNX format, and add them to the cluster. For + more information, refer to the [FarmVibes.AI troubleshooting](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/TROUBLESHOOTING.html) + page in the documentation. + sources: + input_geometry: Geometry of interest within the raster for the segmentation. + input_raster: BingMaps basemap rasters used as input for the segmentation. + input_prompts: ExternalReferences to the point and/or bounding box prompts. These + are GeoJSON with coordinates, label (foreground/background) and prompt id (in + case, the raster contains multiple entities that should be segmented in a single + workflow run). + sinks: + segmentation_mask: Output segmentation masks. + + +``` \ No newline at end of file diff --git a/docs/source/docfiles/markdown/workflow_yaml/ml/segment_anything/s2_prompt_segmentation.md b/docs/source/docfiles/markdown/workflow_yaml/ml/segment_anything/s2_prompt_segmentation.md new file mode 100644 index 00000000..2428583f --- /dev/null +++ b/docs/source/docfiles/markdown/workflow_yaml/ml/segment_anything/s2_prompt_segmentation.md @@ -0,0 +1,97 @@ +# ml/segment_anything/s2_prompt_segmentation + +Runs Segment Anything Model (SAM) over Sentinel-2 rasters with points and/or bounding boxes as prompts. The workflow splits the input Sentinel-2 rasters into chips of 1024x1024 pixels with an overlap defined by `spatial_overlap`. Chips intersecting with prompts are processed by SAM's image encoder, followed by prompt encoder and mask decoder. Before running the workflow, make sure the model has been imported into the cluster by running `scripts/export_prompt_segmentation_models.py`. The script will download the desired model weights from SAM repository, export the image encoder and mask decoder to ONNX format, and add them to the cluster. For more information, refer to the [FarmVibes.AI troubleshooting](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/TROUBLESHOOTING.html) page in the documentation. + +```{mermaid} + graph TD + inp1>input_raster] + inp2>input_geometry] + inp3>input_prompts] + out1>segmentation_mask] + tsk1{{ingest_points}} + tsk2{{sam_inference}} + tsk1{{ingest_points}} -- geometry/input_prompts --> tsk2{{sam_inference}} + inp1>input_raster] -- input_raster --> tsk2{{sam_inference}} + inp2>input_geometry] -- input_geometry --> tsk2{{sam_inference}} + inp3>input_prompts] -- user_input --> tsk1{{ingest_points}} + tsk2{{sam_inference}} -- segmentation_mask --> out1>segmentation_mask] +``` + +## Sources + +- **input_geometry**: Geometry of interest within the raster for the segmentation. + +- **input_raster**: Sentinel-2 rasters used as input for the segmentation. + +- **input_prompts**: ExternalReferences to the point and/or bounding box prompts. These are GeoJSON with coordinates, label (foreground/background) and prompt id (in case, the raster contains multiple entities that should be segmented in a single workflow run). + +## Sinks + +- **segmentation_mask**: Output segmentation masks. + +## Parameters + +- **model_type**: SAM's image encoder backbone architecture, among 'vit_h', 'vit_l', or 'vit_b'. Before running the workflow, make sure the desired model has been exported to the cluster by running `scripts/export_sam_models.py`. For more information, refer to the FarmVibes.AI troubleshooting page in the documentation. + +- **spatial_overlap**: Percentage of spatial overlap between chips in the range of [0.0, 1.0). + +## Tasks + +- **ingest_points**: Adds user geometries into the cluster storage, allowing for them to be used on workflows. + +- **sam_inference**: Runs SAM over the input Sentinel-2 raster with points and bounding boxes as prompts. + +## Workflow Yaml + +```yaml + +name: s2_prompt_segmentation +sources: + input_raster: + - sam_inference.input_raster + input_geometry: + - sam_inference.input_geometry + input_prompts: + - ingest_points.user_input +sinks: + segmentation_mask: sam_inference.segmentation_mask +parameters: + model_type: vit_b + spatial_overlap: 0.5 +tasks: + ingest_points: + workflow: data_ingestion/user_data/ingest_geometry + sam_inference: + op: s2_prompt_segmentation + op_dir: segment_anything + parameters: + model_type: '@from(model_type)' + spatial_overlap: '@from(spatial_overlap)' +edges: +- origin: ingest_points.geometry + destination: + - sam_inference.input_prompts +description: + short_description: Runs Segment Anything Model (SAM) over Sentinel-2 rasters with + points and/or bounding boxes as prompts. + long_description: The workflow splits the input Sentinel-2 rasters into chips of + 1024x1024 pixels with an overlap defined by `spatial_overlap`. Chips intersecting + with prompts are processed by SAM's image encoder, followed by prompt encoder + and mask decoder. Before running the workflow, make sure the model has been imported + into the cluster by running `scripts/export_prompt_segmentation_models.py`. The + script will download the desired model weights from SAM repository, export the + image encoder and mask decoder to ONNX format, and add them to the cluster. For + more information, refer to the [FarmVibes.AI troubleshooting](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/TROUBLESHOOTING.html) + page in the documentation. + sources: + input_geometry: Geometry of interest within the raster for the segmentation. + input_raster: Sentinel-2 rasters used as input for the segmentation. + input_prompts: ExternalReferences to the point and/or bounding box prompts. These + are GeoJSON with coordinates, label (foreground/background) and prompt id (in + case, the raster contains multiple entities that should be segmented in a single + workflow run). + sinks: + segmentation_mask: Output segmentation masks. + + +``` \ No newline at end of file diff --git a/docs/source/index.md b/docs/source/index.md index 465cc703..e22ffdb8 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -35,6 +35,7 @@ Additionally, the following user guides and links may be helpful: docfiles/markdown/CLIENT docfiles/markdown/WORKFLOWS docfiles/markdown/NOTEBOOK_LIST + docfiles/markdown/REST_API docfiles/markdown/CACHE docfiles/markdown/SECRETS docfiles/markdown/TROUBLESHOOTING diff --git a/notebooks/admag/azure_data_manager_for_agriculture_and_comet_farm_api_example.ipynb b/notebooks/admag/azure_data_manager_for_agriculture_and_comet_farm_api_example.ipynb index 30296b19..e20c3428 100644 --- a/notebooks/admag/azure_data_manager_for_agriculture_and_comet_farm_api_example.ipynb +++ b/notebooks/admag/azure_data_manager_for_agriculture_and_comet_farm_api_example.ipynb @@ -16,7 +16,7 @@ "\n", "This notebook shows how to use [Microsoft Azure Data Manager for Agriculture](https://aka.ms/farmvibesDMA) (ADMAg) and the [COMET-Farm API](https://gitlab.com/comet-api/api-docs/-/tree/master/) to derive carbon sequestration information for agricultural fields. The idea is to obtain farming data from Microsoft Azure Data Manager for Agriculture and input this data directly into the COMET-Farm API. In this notebook, we use a single workflow to calculate soil carbon sequestration using ADMAg ids. The steps executed by the `farm_ai/carbon_local/admag_carbon_integration` are the following:\n", "\n", - "1. FarmVibes.AI needs the farmer_id, boundary_id, and a seasonal_field_id (`ADMAgSeasonalFieldInput`), to retrieve farming data from Azure Data Manager for Agriculture. \n", + "1. FarmVibes.AI needs the party_id, and a seasonal_field_id (`ADMAgSeasonalFieldInput`), to retrieve farming data from Azure Data Manager for Agriculture. \n", "\n", "2. The information is sent back to FarmVibes.AI (Tillage, Fertilization, Organic Amendments, Planting, Harvest, …).\n", "\n", @@ -53,17 +53,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "3685ff85", "metadata": {}, "outputs": [], "source": [ - "import os\n", "from typing import List\n", - "from datetime import datetime, timezone\n", "\n", - "from vibe_core.datamodel import RunStatus\n", - "from vibe_core.client import FarmvibesAiClient, get_default_vibe_client, get_local_service_url\n", + "from vibe_core.client import FarmvibesAiClient, get_default_vibe_client\n", "from vibe_core.data import ADMAgSeasonalFieldInput" ] }, @@ -80,7 +77,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "1698286c", "metadata": {}, "outputs": [], @@ -90,15 +87,13 @@ "# ADMAg client id\n", "CLIENT_ID = \"\"\n", "# ADMAg client secret\n", - "CLIENT_SECRET = \"@SECRET(eywa-secrets, data-manager-ag-secret)\"\n", + "CLIENT_SECRET = \"\"\n", "# ADMAg authority\n", "AUTHORITY = \"\"\n", "# ADMAg default scope\n", "DEFAULT_SCOPE = \"\"\n", - "# Farmer ADMAg ID\n", - "FARMER_ID = \"\"\n", - "# Boundary ADMAg ID\n", - "BOUNDARY_ID = \"\"\n", + "# Party ADMAg ID\n", + "PARTY_ID = \"\"\n", "# A list of seasonal field scenarios ids from ADMAg\n", "SCENARIO_IDS = []\n", "# A list of baseline seasonal field ids from ADMAg\n", @@ -113,27 +108,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "be3373e2", "metadata": {}, "outputs": [], "source": [ "def get_seasonal_field_inputs(\n", - " farmer_id: str,\n", - " boundary_id: str,\n", + " party_id: str,\n", " seasonal_field_ids: List[str]\n", ") -> List[ADMAgSeasonalFieldInput]:\n", " return [\n", " ADMAgSeasonalFieldInput(\n", - " farmer_id=FARMER_ID,\n", - " boundary_id=BOUNDARY_ID,\n", + " party_id=party_id,\n", " seasonal_field_id=seasonal_field_id\n", " )\n", " for seasonal_field_id in seasonal_field_ids\n", " ]\n", "\n", - "baseline_admag_inputs = get_seasonal_field_inputs(FARMER_ID, BOUNDARY_ID, BASELINE_IDS)\n", - "scenario_admag_inputs = get_seasonal_field_inputs(FARMER_ID, BOUNDARY_ID, SCENARIO_IDS)" + "baseline_admag_inputs = get_seasonal_field_inputs(PARTY_ID, BASELINE_IDS)\n", + "scenario_admag_inputs = get_seasonal_field_inputs(PARTY_ID, SCENARIO_IDS)" ] }, { @@ -147,7 +140,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "0b299fb0", "metadata": {}, "outputs": [], @@ -167,7 +160,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "69526660", "metadata": {}, "outputs": [], @@ -177,27 +170,381 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "a00f3b59", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
Workflow: farm_ai/carbon_local/admag_carbon_integration\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1;32mWorkflow:\u001b[0m \u001b[1;4;38;5;27mfarm_ai/carbon_local/admag_carbon_integration\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Description:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mDescription:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    Computes the offset amount of carbon that would be sequestered in a seasonal field using        \n",
+       "    Microsoft Azure Data Manager for Agriculture (ADMAg) data. Derives carbon sequestration         \n",
+       "    information. Microsoft Azure Data Manager for Agriculture (ADMAg) and the COMET-Farm API are    \n",
+       "    used to obtain farming data and evaluate carbon offset.  ADMAg is capable of describing         \n",
+       "    important farming activities such as fertilization, tillage, and organic amendments             \n",
+       "    applications, all of which are represented in the data manager. FarmVibes.AI retrieves this     \n",
+       "    information from the data manager and builds SeasonalFieldInformation FarmVibes.AI objects.     \n",
+       "    These objects are then used to call the COMET-Farm API and evaluate Carbon Offset Information.  \n",
+       "
\n" + ], + "text/plain": [ + " Computes the offset amount of carbon that would be sequestered in a seasonal field using \n", + " Microsoft Azure Data Manager for Agriculture (ADMAg) data. Derives carbon sequestration \n", + " information. Microsoft Azure Data Manager for Agriculture (ADMAg) and the COMET-Farm API are \n", + " used to obtain farming data and evaluate carbon offset. ADMAg is capable of describing \n", + " important farming activities such as fertilization, tillage, and organic amendments \n", + " applications, all of which are represented in the data manager. FarmVibes.AI retrieves this \n", + " information from the data manager and builds SeasonalFieldInformation FarmVibes.AI objects. \n", + " These objects are then used to call the COMET-Farm API and evaluate Carbon Offset Information. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Sources:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSources:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - baseline_admag_input (vibe_core.data.farm.ADMAgSeasonalFieldInput): List of                   \n",
+       "    ADMAgSeasonalFieldInput to retrieve SeasonalFieldInformation objects for baseline COMET-Farm API\n",
+       "    Carbon offset evaluation.                                                                       \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mbaseline_admag_input\u001b[0m (\u001b[34mvibe_core.data.farm.ADMAgSeasonalFieldInput\u001b[0m): List of \n", + " ADMAgSeasonalFieldInput to retrieve SeasonalFieldInformation objects for baseline COMET-Farm API\n", + " Carbon offset evaluation. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - scenario_admag_input (vibe_core.data.farm.ADMAgSeasonalFieldInput): List of                   \n",
+       "    ADMAgSeasonalFieldInput to retrieve SeasonalFieldInformation objects for scenarios COMET-Farm   \n",
+       "    API Carbon offset evaluation.                                                                   \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mscenario_admag_input\u001b[0m (\u001b[34mvibe_core.data.farm.ADMAgSeasonalFieldInput\u001b[0m): List of \n", + " ADMAgSeasonalFieldInput to retrieve SeasonalFieldInformation objects for scenarios COMET-Farm \n", + " API Carbon offset evaluation. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Sinks:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSinks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - carbon_output (vibe_core.data.core_types.CarbonOffsetInfo): Carbon sequestration received for \n",
+       "    scenario information provided as input.                                                         \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mcarbon_output\u001b[0m (\u001b[34mvibe_core.data.core_types.CarbonOffsetInfo\u001b[0m): Carbon sequestration received for \n", + " scenario information provided as input. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Parameters:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mParameters:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - base_url (default: None): Azure Data Manager for Agriculture host. Please visit               \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mbase_url\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture host. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - client_id (default: None): Azure Data Manager for Agriculture client id. Please visit         \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mclient_id\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture client id. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - client_secret (default: None): Azure Data Manager for Agriculture client secret. Please visit \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mclient_secret\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture client secret. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - authority (default: None): Azure Data Manager for Agriculture authority. Please visit         \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mauthority\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture authority. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - default_scope (default: None): Azure Data Manager for Agriculture default scope. Please visit \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mdefault_scope\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture default scope. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - comet_support_email (default: None): Comet support email. The email used to register for a    \n",
+       "    COMET account. The requests are forwarded to comet with this email reference.  This email is    \n",
+       "    used by comet to share the information back to you for failed requests.                         \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mcomet_support_email\u001b[0m (\u001b[34mdefault: None\u001b[0m): Comet support email. The email used to register for a \n", + " COMET account. The requests are forwarded to comet with this email reference. This email is \n", + " used by comet to share the information back to you for failed requests. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - ngrok_token (default: None): NGROK session token. A token that FarmVibes uses to create a     \n",
+       "    web_hook url that is shared with Comet in a request when running the workflow. Comet can use    \n",
+       "    this link to send back a response to FarmVibes.  NGROK is a service that creates temporary urls \n",
+       "    for local servers. To use NGROK, FarmVibes needs to get a token from this website,              \n",
+       "    https://dashboard.ngrok.com/.                                                                   \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mngrok_token\u001b[0m (\u001b[34mdefault: None\u001b[0m): NGROK session token. A token that FarmVibes uses to create a \n", + " web_hook url that is shared with Comet in a request when running the workflow. Comet can use \n", + " this link to send back a response to FarmVibes. NGROK is a service that creates temporary urls \n", + " for local servers. To use NGROK, FarmVibes needs to get a token from this website, \n", + " https://dashboard.ngrok.com/. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Tasks:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mTasks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - baseline_seasonal_field_list: Generates SeasonalFieldInformation using ADMAg (Microsoft Azure \n",
+       "    Data Manager for Agriculture).                                                                  \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mbaseline_seasonal_field_list\u001b[0m: Generates SeasonalFieldInformation using ADMAg (Microsoft Azure \n", + " Data Manager for Agriculture). \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - scenario_seasonal_field_list: Generates SeasonalFieldInformation using ADMAg (Microsoft Azure \n",
+       "    Data Manager for Agriculture).                                                                  \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mscenario_seasonal_field_list\u001b[0m: Generates SeasonalFieldInformation using ADMAg (Microsoft Azure \n", + " Data Manager for Agriculture). \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - admag_carbon: Computes the offset amount of carbon that would be sequestered in a seasonal    \n",
+       "    field using the baseline (historical) and scenario (time range interested in) information.      \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1madmag_carbon\u001b[0m: Computes the offset amount of carbon that would be sequestered in a seasonal \n", + " field using the baseline (historical) and scenario (time range interested in) information. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "client.document_workflow(CARBON_WORKFLOW)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "e8bdefac", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
    "source": [
     "run = client.run(\n",
     "    CARBON_WORKFLOW,\n",
     "    \"Carbon what-if scenario\",\n",
     "    input_data={\n",
-    "        \"baseline_admag_input\": baseline_admag_inputs,\n",
-    "        \"scenario_admag_input\": scenario_admag_inputs,\n",
+    "        \"baseline_admag_input\": baseline_admag_inputs, \n",
+    "        \"scenario_admag_input\": scenario_admag_inputs, # type: ignore\n",
     "    },\n",
     "    parameters={\n",
     "        \"base_url\": BASE_URL,\n",
@@ -224,12 +571,23 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 8,
    "id": "16345f43",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'-0.074 Mg Co2e/year'"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
-    "run.output['carbon_output'][0].carbon"
+    "run.output['carbon_output'][0].carbon # type: ignore"
    ]
   }
  ],
diff --git a/notebooks/admag/azure_data_manager_for_agriculture_example.ipynb b/notebooks/admag/azure_data_manager_for_agriculture_example.ipynb
index d8be84ca..be50e40f 100644
--- a/notebooks/admag/azure_data_manager_for_agriculture_example.ipynb
+++ b/notebooks/admag/azure_data_manager_for_agriculture_example.ipynb
@@ -8,7 +8,7 @@
    "source": [
     "# Microsoft Azure Data Manager for Agriculture and NDVI summary workflows into a single custom workflow\n",
     "\n",
-    "In this notebook, we will explain how to connect FarmVibes.AI with [Microsoft Azure Data Manager for Agriculture](https://aka.ms/farmvibesDMA), and provide an example of how to leverage the FarmVibes.AI workflows using ADMAg inputs. We will demonstrate how to compose the ADMAg and NDVI summary workflows into a single custom workflow, and check the results for the user's agriculture field."
+    "In this notebook, we will explain how to connect FarmVibes.AI with [Microsoft Azure Data Manager for Agriculture](https://aka.ms/farmvibesDMA), and provide an example of how to leverage the FarmVibes.AI workflows using [ADMAg for Agri](https://learn.microsoft.com/en-us/rest/api/data-manager-for-agri/). We will demonstrate how to compose the ADMAg and NDVI summary workflows into a single custom workflow, and check the results for the user's agriculture field. The Notebook use ADMAg version 2023-11-01-preview for demonstration."
    ]
   },
   {
@@ -37,7 +37,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 1,
    "id": "b2e34591",
    "metadata": {},
    "outputs": [],
@@ -59,7 +59,7 @@
    "source": [
     "## Define Azure Data Manager for Agriculture entities\n",
     "\n",
-    "We will start by providing the parameters that specify the Azure Data Manager for Agriculture connection (e.g., seasonal field, boundary, and farmer identifiers). Please, check Microsoft Azure Data Manager for Agriculture [documentation](https://aka.ms/farmvibesDMA) to check how to obtain these fields.\n",
+    "We will start by providing the parameters that specify the Azure Data Manager for Agriculture connection (e.g., seasonal field, and farmer identifiers). Please, check Microsoft Azure Data Manager for Agriculture [documentation](https://learn.microsoft.com/en-us/rest/api/data-manager-for-agri/) to check how to obtain these fields.\n",
     "\n",
     "In the next cell, we retrieve the `CLIENT_SECRET` variable from the `data-manager-ag-secret` registered on the FarmVibes.AI cluster. To create a new key on the cluster you may want to use the following command on project's root folder:\n",
     "\n",
@@ -75,22 +75,21 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 2,
    "id": "4afec3ab",
    "metadata": {},
    "outputs": [],
    "source": [
     "WORKFLOW_NAME = \"data_ingestion/admag/admag_seasonal_field\"\n",
     "\n",
-    "BASE_URL = \"\"\n",
-    "CLIENT_ID = \"\"\n",
-    "CLIENT_SECRET = \"@SECRET(eywa-secrets, data-manager-ag-secret)\"\n",
-    "AUTHORITY = \"\"\n",
-    "DEFAULT_SCOPE = \"\"\n",
+    "BASE_URL = \"\"\n",
+    "CLIENT_ID = \"\"\n",
+    "CLIENT_SECRET = \"\"\n",
+    "AUTHORITY = \"\"\n",
+    "DEFAULT_SCOPE = \"\"\n",
     "\n",
-    "FARMER_ID = \"\"\n",
-    "SEASONAL_FIELD_ID=\"\"\n",
-    "BOUNDARY_ID=\"\""
+    "PARTY_ID = \"\"\n",
+    "SEASONAL_FIELD_ID=\"\""
    ]
   },
   {
@@ -101,20 +100,19 @@
    "source": [
     "## Create Seasonal Field input\n",
     "\n",
-    "Azure Data Manager for Agriculture uses `farmer_id`, `seasonal_field_id`, and `boundary_id` to identify a crop during a given season. This triple will be used to create a DataVibe subclass `SeasonalFieldInformation` that contains farm-related operations (e.g., fertilization, harvest, tillage, planting, crop name) that is used as input to the workflow (`data_ingestion/admag/admag_seasonal_field`). "
+    "Azure Data Manager for Agriculture uses `party_id` and `seasonal_field_id` to identify a crop during a given season. This triple will be used to create a DataVibe subclass `SeasonalFieldInformation` that contains farm-related operations (e.g., fertilization, harvest, tillage, planting, crop name) that is used as input to the workflow (`data_ingestion/admag/admag_seasonal_field`). "
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 3,
    "id": "f63c1b1b",
    "metadata": {},
    "outputs": [],
    "source": [
     "input_data = ADMAgSeasonalFieldInput(\n",
-    "    farmer_id=FARMER_ID,\n",
+    "    party_id=PARTY_ID,\n",
     "    seasonal_field_id=SEASONAL_FIELD_ID,\n",
-    "    boundary_id=BOUNDARY_ID,\n",
     ")"
    ]
   },
@@ -131,7 +129,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 4,
    "id": "ea8f8112",
    "metadata": {},
    "outputs": [],
@@ -141,20 +139,279 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 5,
    "id": "6ad9225c",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
Workflow: data_ingestion/admag/admag_seasonal_field\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1;32mWorkflow:\u001b[0m \u001b[1;4;38;5;27mdata_ingestion/admag/admag_seasonal_field\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Description:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mDescription:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    Generates SeasonalFieldInformation using ADMAg (Microsoft Azure Data Manager for Agriculture).  \n",
+       "    The workflow creates a DataVibe subclass SeasonalFieldInformation that contains farm-related    \n",
+       "    operations (e.g., fertilization, harvest, tillage, planting, crop name).                        \n",
+       "
\n" + ], + "text/plain": [ + " Generates SeasonalFieldInformation using ADMAg (Microsoft Azure Data Manager for Agriculture). \n", + " The workflow creates a DataVibe subclass SeasonalFieldInformation that contains farm-related \n", + " operations (e.g., fertilization, harvest, tillage, planting, crop name). \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Sources:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSources:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - admag_input (vibe_core.data.farm.ADMAgSeasonalFieldInput): Unique identifiers for ADMAg       \n",
+       "    seasonal field, and party.                                                                      \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1madmag_input\u001b[0m (\u001b[34mvibe_core.data.farm.ADMAgSeasonalFieldInput\u001b[0m): Unique identifiers for ADMAg \n", + " seasonal field, and party. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Sinks:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSinks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - seasonal_field (vibe_core.data.farm.SeasonalFieldInformation): Crop SeasonalFieldInformation  \n",
+       "    which contains SeasonalFieldInformation that contains farm-related operations (e.g.,            \n",
+       "    fertilization, harvest, tillage, planting, crop name).                                          \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mseasonal_field\u001b[0m (\u001b[34mvibe_core.data.farm.SeasonalFieldInformation\u001b[0m): Crop SeasonalFieldInformation \n", + " which contains SeasonalFieldInformation that contains farm-related operations (e.g., \n", + " fertilization, harvest, tillage, planting, crop name). \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Parameters:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mParameters:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - base_url (default: None): Azure Data Manager for Agriculture host. Please visit               \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mbase_url\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture host. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - client_id (default: None): Azure Data Manager for Agriculture client id. Please visit         \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mclient_id\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture client id. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - client_secret (default: None): Azure Data Manager for Agriculture client secret. Please visit \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mclient_secret\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture client secret. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - authority (default: None): Azure Data Manager for Agriculture authority. Please visit         \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mauthority\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture authority. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - default_scope (default: None): Azure Data Manager for Agriculture default scope. Please visit \n",
+       "    https://aka.ms/farmvibesDMA to check how to get these credentials.                              \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mdefault_scope\u001b[0m (\u001b[34mdefault: None\u001b[0m): Azure Data Manager for Agriculture default scope. Please visit \n", + " https://aka.ms/farmvibesDMA to check how to get these credentials. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Tasks:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mTasks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - admag_seasonal_field: Establishes the connection with ADMAg and fetches seasonal field        \n",
+       "    information.                                                                                    \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1madmag_seasonal_field\u001b[0m: Establishes the connection with ADMAg and fetches seasonal field \n", + " information. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "client.document_workflow(WORKFLOW_NAME)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "3ae9e9d6", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
    "source": [
     "run = client.run(\n",
     "    WORKFLOW_NAME,\n",
@@ -185,10 +442,21 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 7,
    "id": "fdfd9eda",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "SeasonalFieldInformation(id='6ee1f27b-c1b8-4e5a-a5c5-d862745229e4', time_range=(datetime.datetime(2000, 2, 15, 0, 0, tzinfo=datetime.timezone.utc), datetime.datetime(2000, 9, 5, 0, 0, tzinfo=datetime.timezone.utc)), bbox=(-117.04672810633345, 47.03859765371245, -117.04516997816333, 47.039879416641384), geometry={'type': 'MultiPolygon', 'coordinates': [[[[-117.0466947519078, 47.038850194363874], [-117.045889480774, 47.03859765371245], [-117.045889480774, 47.03859765371245], [-117.045889480774, 47.03859765371245], [-117.04516997816333, 47.039188503538426], [-117.04555593651739, 47.039807942872116], [-117.04627543912807, 47.039879416641384], [-117.04672810633345, 47.03963640582586], [-117.0466947519078, 47.038850194363874]]]]}, assets=[], crop_name='Alfalfa', crop_type='annual', properties={'pre_1980': 'Irrigation (Pre 1980s)', 'crp_type': 'None', 'crp_start': '', 'crp_end': '', 'year_1980_2000': 'Irrigated: Annual Crops in Rotation', 'year_1980_2000_tillage': 'Intensive Tillage'}, fertilizers=[], harvests=[{'is_grain': True, 'start_date': '2000-09-05T00:00:00Z', 'end_date': '2000-09-05T00:00:00Z', 'crop_yield': 39.0, 'stray_stover_hay_removal': '0'}, {'is_grain': True, 'start_date': '2000-09-05T00:00:00Z', 'end_date': '2000-09-05T00:00:00Z', 'crop_yield': 39.0, 'stray_stover_hay_removal': '0'}], tillages=[{'start_date': '2000-01-01T00:00:00Z', 'end_date': '2000-01-01T00:00:00Z', 'implement': 'Reduced Tillage'}, {'start_date': '2000-01-01T00:00:00Z', 'end_date': '2000-01-01T00:00:00Z', 'implement': 'Reduced Tillage'}], organic_amendments=[])"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
     "run.output['seasonal_field'][0]"
    ]
@@ -206,10 +474,29 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 8,
    "id": "035246fb",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "'Seasonal field planting date: 2000/02/15'\n",
+      "'Seasonal field harvest date: 2000/09/05'\n",
+      "{'coordinates': [[[[-117.0466947519078, 47.038850194363874],\n",
+      "                   [-117.045889480774, 47.03859765371245],\n",
+      "                   [-117.045889480774, 47.03859765371245],\n",
+      "                   [-117.045889480774, 47.03859765371245],\n",
+      "                   [-117.04516997816333, 47.039188503538426],\n",
+      "                   [-117.04555593651739, 47.039807942872116],\n",
+      "                   [-117.04627543912807, 47.039879416641384],\n",
+      "                   [-117.04672810633345, 47.03963640582586],\n",
+      "                   [-117.0466947519078, 47.038850194363874]]]],\n",
+      " 'type': 'MultiPolygon'}\n"
+     ]
+    }
+   ],
    "source": [
     "seasonal_field = run.output['seasonal_field'][0]\n",
     "\n",
@@ -232,10 +519,218 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 10,
    "id": "fc0fde75",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
Workflow: farm_ai/agriculture/ndvi_summary\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1;32mWorkflow:\u001b[0m \u001b[1;4;38;5;27mfarm_ai/agriculture/ndvi_summary\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Description:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mDescription:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    Calculates NDVI statistics (mean, standard deviation, maximum and minimum) for the input        \n",
+       "    geometry and time range. The workflow retrieves the relevant Sentinel-2 products with Planetary \n",
+       "    Computer (PC) API, forwards them to a cloud detection model and combines the predicted cloud    \n",
+       "    mask to the mask obtained from the product. The workflow computes the NDVI for each available   \n",
+       "    tile and date, summarizing each with the mean, standard deviation, maximum and minimum values   \n",
+       "    for the regions not obscured by clouds. Finally, it outputs a timeseries with such statistics   \n",
+       "    for all available dates, ignoring heavily-clouded tiles.                                        \n",
+       "
\n" + ], + "text/plain": [ + " Calculates NDVI statistics (mean, standard deviation, maximum and minimum) for the input \n", + " geometry and time range. The workflow retrieves the relevant Sentinel-2 products with Planetary \n", + " Computer (PC) API, forwards them to a cloud detection model and combines the predicted cloud \n", + " mask to the mask obtained from the product. The workflow computes the NDVI for each available \n", + " tile and date, summarizing each with the mean, standard deviation, maximum and minimum values \n", + " for the regions not obscured by clouds. Finally, it outputs a timeseries with such statistics \n", + " for all available dates, ignoring heavily-clouded tiles. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Sources:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSources:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - user_input (vibe_core.data.core_types.DataVibe): Time range and geometry of interest.         \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1muser_input\u001b[0m (\u001b[34mvibe_core.data.core_types.DataVibe\u001b[0m): Time range and geometry of interest. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Sinks:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSinks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - timeseries (List[vibe_core.data.core_types.TimeSeries]): Aggregated NDVI statistics of the    \n",
+       "    retrieved tiles within the input geometry and time range.                                       \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mtimeseries\u001b[0m (\u001b[34mList[vibe_core.data.core_types.TimeSeries]\u001b[0m): Aggregated NDVI statistics of the \n", + " retrieved tiles within the input geometry and time range. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Parameters:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mParameters:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - pc_key (default: ): Optional Planetary Computer API key.                                      \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mpc_key\u001b[0m (\u001b[34mdefault: \u001b[0m): Optional Planetary Computer API key. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "Tasks:\n",
+       "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mTasks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - s2: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time     \n",
+       "    range, and computes improved cloud masks using cloud and shadow segmentation models.            \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1ms2\u001b[0m: Downloads and preprocesses Sentinel-2 imagery that covers the input geometry and time \n", + " range, and computes improved cloud masks using cloud and shadow segmentation models. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - compute_ndvi: Computes an index from the bands of an input raster.                            \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1mcompute_ndvi\u001b[0m: Computes an index from the bands of an input raster. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - summary_timeseries: Computes the mean, standard deviation, maximum, and minimum values of all \n",
+       "    regions of the raster considered by the mask and aggregates them into a timeseries.             \n",
+       "
\n" + ], + "text/plain": [ + " - \u001b[1msummary_timeseries\u001b[0m: Computes the mean, standard deviation, maximum, and minimum values of all \n", + " regions of the raster considered by the mask and aggregates them into a timeseries. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "client.document_workflow(\"farm_ai/agriculture/ndvi_summary\")" ] @@ -255,7 +750,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "ede223f5", "metadata": {}, "outputs": [], @@ -296,7 +791,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "250cb567", "metadata": {}, "outputs": [], @@ -328,7 +823,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "2b797c26", "metadata": {}, "outputs": [], @@ -348,7 +843,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "98d061af", "metadata": {}, "outputs": [], @@ -371,7 +866,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "9ab5e280", "metadata": {}, "outputs": [], diff --git a/notebooks/crop_cycles/env.yaml b/notebooks/crop_cycles/env.yaml index bf4e4221..9b1606d5 100644 --- a/notebooks/crop_cycles/env.yaml +++ b/notebooks/crop_cycles/env.yaml @@ -10,6 +10,7 @@ dependencies: - tf2onnx=1.9.3 - rioxarray=0.3.1 - ipykernel=6.15.2 + - ipywidgets~=8.0.2 - yaml=0.2.5 - matplotlib=3.5.3 - pip~=21.2.4 diff --git a/notebooks/forest/download_alos_forest_map.ipynb b/notebooks/forest/download_alos_forest_map.ipynb new file mode 100644 index 00000000..b5834c38 --- /dev/null +++ b/notebooks/forest/download_alos_forest_map.ipynb @@ -0,0 +1,497 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Download ALOS Forest Extent Dataset\n", + "In this notebook, we download an [ALOS Forest Extent](https://planetarycomputer.microsoft.com/dataset/alos-fnf-mosaic) map using FarmVibes.AI, and visualize it.\n", + "\n", + "The ALOS PALSAR/PALSAR-2 Annual Mosaic is a dataset that provides annual observations of forest extent produced by JAXA's ALOS and ALOS-2 satellites. The dataset spans from 2015 to 2020 and covers the whole globe. Each dataset (provided as Rasters) contains the following categories:\n", + "```txt\n", + "0 - No data\n", + "1 - Forest (>90% canopy cover)\n", + "2 - Forest (10-90% canopy cover)\n", + "3 - Non-forest\n", + "4 - Water\n", + "```\n", + "\n", + "The download process involves the following steps:\n", + "1. Listing of the products that intersect with the user-provided geometry and time range.\n", + "2. Downloading each raster listed in the previous step.\n", + "\n", + "The output is provided as the categorical rasters listed in step 1.\n", + "\n", + "NOTE: To install the required packages used in this notebook, see [this README file](../README.md)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from vibe_core.client import get_default_vibe_client" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Create Vibe client and document the ALOS download workflow\n", + "\n", + "Before executing the [workflow](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/WORKFLOWS.html), let's observe its documentation using a FarmVibes.AI python client." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "text/html": [
+                            "
Workflow: data_ingestion/alos/alos_forest_extent_download_merge\n",
+                            "
\n" + ], + "text/plain": [ + "\u001b[1;32mWorkflow:\u001b[0m \u001b[1;4;38;5;27mdata_ingestion/alos/alos_forest_extent_download_merge\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Description:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mDescription:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    Downloads Advanced Land Observing Satellite (ALOS) forest/non-forest classification map and     \n",
+                            "    merges it into a single raster. The workflow lists the ALOS forest/non-forest classification    \n",
+                            "    products that intersect with the input geometry and time range (available range 2015-2020), and \n",
+                            "    downloads the filtered products. The workflow processes the downloaded products and merge them  \n",
+                            "    into a single raster.                                                                           \n",
+                            "
\n" + ], + "text/plain": [ + " Downloads Advanced Land Observing Satellite (ALOS) forest/non-forest classification map and \n", + " merges it into a single raster. The workflow lists the ALOS forest/non-forest classification \n", + " products that intersect with the input geometry and time range (available range 2015-2020), and \n", + " downloads the filtered products. The workflow processes the downloaded products and merge them \n", + " into a single raster. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Sources:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSources:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - user_input (vibe_core.data.core_types.DataVibe): Geometry of interest for which to download   \n",
+                            "    the ALOS forest/non-forest classification map.                                                  \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1muser_input\u001b[0m (\u001b[34mvibe_core.data.core_types.DataVibe\u001b[0m): Geometry of interest for which to download \n", + " the ALOS forest/non-forest classification map. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Sinks:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSinks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - merged_raster (vibe_core.data.rasters.Raster): ALOS forest/non-forest classification products \n",
+                            "    converted to raster and merged.                                                                 \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mmerged_raster\u001b[0m (\u001b[34mvibe_core.data.rasters.Raster\u001b[0m): ALOS forest/non-forest classification products \n", + " converted to raster and merged. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - categorical_raster (vibe_core.data.rasters.CategoricalRaster): ALOS forest/non-forest         \n",
+                            "    classification products that intersect with the input geometry & time range.                    \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mcategorical_raster\u001b[0m (\u001b[34mvibe_core.data.rasters.CategoricalRaster\u001b[0m): ALOS forest/non-forest \n", + " classification products that intersect with the input geometry & time range. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Parameters:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mParameters:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - pc_key (default: ): Planetary computer API key.                                               \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mpc_key\u001b[0m (\u001b[34mdefault: \u001b[0m): Planetary computer API key. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Tasks:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mTasks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - alos_forest_extent_download: Downloads Advanced Land Observing Satellite (ALOS)               \n",
+                            "    forest/non-forest classification map.                                                           \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1malos_forest_extent_download\u001b[0m: Downloads Advanced Land Observing Satellite (ALOS) \n", + " forest/non-forest classification map. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - group_rasters_by_time: This op groups rasters in time according to 'criterion'.               \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mgroup_rasters_by_time\u001b[0m: This op groups rasters in time according to 'criterion'. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - merge: Merges rasters in a sequence to a single raster.                                       \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mmerge\u001b[0m: Merges rasters in a sequence to a single raster. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "client = get_default_vibe_client()\n", + "\n", + "WORKFLOW_NAME = \"data_ingestion/alos/alos_forest_extent_download_merge\"\n", + "client.document_workflow(WORKFLOW_NAME)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Define input Geometry and Time Range\n", + "\n", + "Next, we are going to define the geometry of interest and the time range that will be considered to download the ALOS products. The workflow will download all the tiles that intersect with the input." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from shapely import geometry as shpg\n", + "from datetime import datetime\n", + "\n", + "# GeoJSON data\n", + "geo_json = {\n", + " \"type\": \"Feature\",\n", + " \"geometry\": {\n", + " \"type\": \"Polygon\",\n", + " \"coordinates\": [\n", + " [\n", + " [-86.773827, 14.575498],\n", + " [-86.770459, 14.579300],\n", + " [-86.764283, 14.575102],\n", + " [-86.769591, 14.567595],\n", + " [-86.773827, 14.575498],\n", + " ]\n", + " ],\n", + " },\n", + " \"properties\": {},\n", + "}\n", + "\n", + "geom = shpg.shape(geo_json[\"geometry\"])\n", + "time_range = (datetime(2020, 1, 1), datetime(2020, 1, 2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Run FarmVibes.AI Workflow\n", + "\n", + "In this step, the client requests the workflow execution on the FarmVines Cluster. Note that we provide the following inputs to the client.run call:\n", + "\n", + "1. Workflow name. Users can list the existing workflows by calling the command `client.list_workflows()`. They also can refer to the existing [workflow list](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/WORKFLOW_LIST.html).\n", + "2. Workflow execution name: The name we give for this particular workflow execution. \n", + "3. Geometry of interest.\n", + "4. Time range.\n", + "5. Parameters list. Check the [workflow](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/WORKFLOWS.html) documentation page to see how parameters are provided. We used the `pc_key` parameter, which corresponds to the Planetary Computer API key, that is useful to download planetary computer imagery.\n", + "\n", + "Please refer to the [SECRETS documentation](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/SECRETS.html) to learn how a secret can be added to the FarmVibes.AI cluster." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "application/vnd.jupyter.widget-view+json": {
+                            "model_id": "188eac6094214bf7aa3adc3e2f204972",
+                            "version_major": 2,
+                            "version_minor": 0
+                        },
+                        "text/plain": [
+                            "Output()"
+                        ]
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "text/html": [
+                            "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                }
+            ],
+            "source": [
+                "run = client.run(\n",
+                "    WORKFLOW_NAME,\n",
+                "    \"Download ALOS Forest Map\",\n",
+                "    geometry=geom,\n",
+                "    time_range=time_range,\n",
+                "    parameters={\"pc_key\": \"@SECRET(eywa-secrets, pc-sub-key)\"},\n",
+                ")\n",
+                "run.monitor()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "metadata": {},
+            "source": [
+                "### Read the output data\n",
+                "\n",
+                "In the next cell, we adopt the user-provided geometry to read the output raster and create some buffer around it."
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 5,
+            "metadata": {},
+            "outputs": [],
+            "source": [
+                "# Add shared notebook library to path\n",
+                "import sys\n",
+                "from vibe_core.data import CategoricalRaster, Raster\n",
+                "from shapely.geometry import box\n",
+                "from typing import cast\n",
+                "\n",
+                "sys.path.append(\"../\")\n",
+                "from shared_nb_lib.raster import read_raster\n",
+                "from shared_nb_lib.plot import plot_categorical_map\n",
+                "\n",
+                "# Define your geometry\n",
+                "bounding_box = box(*geom.buffer(0.01).bounds)\n",
+                "\n",
+                "# Get the bounds of the geometry\n",
+                "minx, miny, maxx, maxy = bounding_box.bounds\n",
+                "\n",
+                "merged_raster = cast(Raster, run.output[\"merged_raster\"][0])\n",
+                "categories = cast(CategoricalRaster, run.output[\"categorical_raster\"][0]).categories\n",
+                "\n",
+                "out_image = read_raster(merged_raster, bounding_box)[0]"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "metadata": {},
+            "source": [
+                "### Plot the result map\n",
+                "\n",
+                "Finally, we plot the raster image with the existing categories and the user-provided geometry (red area within the plot)."
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 6,
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsAAAAHHCAYAAACxwu7KAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAA9hAAAPYQGoP6dpAACgx0lEQVR4nOzdd1xV9f/A8dcFBBwMN6II7pXiNreoiSMyrTQ0cqelErn9ZokjV2m40oYr08xcWZlmhnvkQtOchHsPQFRA4f7+4MeNCxe4e76fj8d96D3jcz7n3HO57/u+n6FQKpVKhBBCCCGEcBBOlq6AEEIIIYQQ5iQBsBBCCCGEcCgSAAshhBBCCIciAbAQQgghhHAoEgALIYQQQgiHIgGwEEIIIYRwKBIACyGEEEIIhyIBsBBCCCGEcCgSAAshhBBCCIciAbAQQgghhHAoEgALAXzxxRcoFAqaNGmS6zYKhYJhw4blW9bp06d56623KFu2LG5ubvj6+tK7d29Onz6tcfu///6b119/HX9/f9zd3SlbtiwvvfQS8+fPz/dYffv2RaFQaHxs3bo13/3N7caNG0RGRhITE6PV9suXL1edz969e3OsVyqV+Pn5oVAoePnll41cWyGEEPbKxdIVEMIarFq1ioCAAP766y8uXrxI5cqV9Spnw4YNhIaGUqxYMQYMGECFChW4dOkSS5YsYd26daxZs4Zu3bqptt+/fz9BQUGUL1+eQYMG4ePjw9WrVzl48CBz585l+PDh+R7Tzc2Nb775JsfywMBAvc7BlG7cuMGkSZMICAigbt26Wu/n7u7O6tWradGihdryXbt2ce3aNdzc3IxcUyGEEPZMAmDh8OLi4ti/fz8bNmxg8ODBrFq1iokTJ+pcTmxsLGFhYVSsWJHdu3dTsmRJ1br333+fli1bEhYWxsmTJ6lYsSIAn3zyCV5eXhw+fBhvb2+18u7cuaPVcV1cXHjrrbd0rq82njx5QqFChUxSti46d+7Mjz/+yLx583Bx+e/P1urVq2nQoAH37t2zYO2EEELYGmkCIRzeqlWrKFq0KF26dOH1119n1apVepXz6aef8uTJE7766iu14BegRIkSfPnllzx+/JhZs2aplsfGxlKrVq0cwS9AqVKl9KqHJl988QW1atVSNckYOnQo8fHxatu0adOGF154gaNHj9KqVSsKFSrE//73PwBSUlKYOHEilStXxs3NDT8/P8aMGUNKSopaGdu3b6dFixZ4e3tTpEgRqlWrpipj586dNGrUCIB+/fqpmjYsX7483/qHhoZy//59tm/frlqWmprKunXr6NWrl8Z9PvvsM5o1a0bx4sUpWLAgDRo0YN26dTm2y2zasmrVKqpVq4a7uzsNGjRg9+7d+dZLCCGEbZIAWDi8VatW0b17d1xdXQkNDeXChQscPnxY53J+/vlnAgICaNmypcb1rVq1IiAggF9//VW1zN/fn6NHj3Lq1Cm96w9w7949tUdCQoJqXWRkJEOHDsXX15fZs2fz2muv8eWXX9KhQweePXumVs79+/fp1KkTdevWJSoqiqCgINLT03nllVf47LPPCAkJYf78+bz66qt8/vnn9OzZU7Xv6dOnefnll0lJSWHy5MnMnj2bV155hX379gFQo0YNJk+eDMA777zDypUrWblyJa1atcr3/AICAmjatCnff/+9atlvv/1GQkICb775psZ95s6dS7169Zg8eTLTpk3DxcWFN954Q+36Z9q1axcRERG89dZbTJ48mfv379OxY0eDXxchhBBWSimEAzty5IgSUG7fvl2pVCqV6enpynLlyinff//9HNsCyqFDh2osJz4+Xgkou3btmufxXnnlFSWgTExMVCqVSuXvv/+udHZ2Vjo7OyubNm2qHDNmjHLbtm3K1NRUrerfp08fJZDj0bp1a6VSqVTeuXNH6erqquzQoYMyLS1Ntd+CBQuUgHLp0qWqZa1bt1YCysWLF6sdY+XKlUonJyflnj171JYvXrxYCSj37dunVCqVys8//1wJKO/evZtrfQ8fPqwElMuWLdPq/JYtW6YElIcPH1YuWLBA6eHhoXzy5IlSqVQq33jjDWVQUJBSqVQq/f39lV26dFHbN3O7TKmpqcoXXnhB2bZtW7XlmdfsyJEjqmWXL19Wuru7K7t166ZVPYUQQtgWyQALh7Zq1SpKly5NUFAQkPFzeM+ePVmzZg1paWlal/Po0SMAPDw88twuc31iYiIAL730EgcOHOCVV17hxIkTzJo1i+DgYMqWLcvmzZu1Ora7uzvbt29Xe8yePRuAP/74g9TUVCIiInBy+u/tPmjQIDw9PXNkQ93c3OjXr5/ash9//JEaNWpQvXp1tSxz27ZtAYiOjgZQNeP46aefSE9P16ruuujRowdPnz7ll19+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zHkh4//TDoOz9Ak1mQq/naL28v0oFQp+X9SblKJWPN2bEA7k/v37lCpVikuXLlm6KsLOpaamEhAQwJEjR3TeV68AOCIigvfff1/1eO+992jatCkJCQm88847+hQpHIymTG3WDK6umdz4efE5HpbyaR245wY1EqDPBYtVwypFzYrKkWHXtCwrTa9noduJtA//HoBjQ9twrVVVI9dUCMvp27cvCoUixyPrzKmWqNOrr76q1baffPIJXbt2JSAgQLUsPDycBg0a4ObmRt26dTXud/LkSVq2bIm7uzt+fn7MmjUr32M9evSIiIgI/P39KViwIM2aNePw4cNq2yiVSj7++GPKlClDwYIFad++PRcu/PfHOSUlhbCwMDw9PalatSp//PGH2v6ffvopw4cP1+rchXm5uroyatQoxo4dq/O+enWCe//99zUuX7hwoV5RuBD25JErfFIXPj8Ek47C6kqQrNc7TWikVPLSsNUUuv+YO7XLcuDDLpaukRBG17FjR5YtW6a2LPuMptpKTU3F1dXVGNXK15MnT1iyZAnbtm3Lsa5///4cOnSIkydP5liXmJhIhw4daN++PYsXL+bvv/+mf//+eHt755lYGzhwIKdOnWLlypX4+vry3Xff0b59e/755x/Kli0LwKxZs5g3bx4rVqygQoUKfPTRRwQHB/PPP//g7u7OV199xdGjRzlw4AC//fYbvXr14vbt2ygUCuLi4vj6668ltrFCmfd17969GTlyJKdPn6ZWrVpa72/UwYI6derE+vXrjVmkEFrRlC22ZBZ4UQ24XATKPYHhpy1WDatlSGfDwK/3ELDjLM/dC7DtyzDS3NS/XRhzZjkhLMXNzQ0fHx+1R2Yn8127dtG4cWPc3NwoU6YM48aN4/nz56p927Rpw7Bhw4iIiKBEiRIEB2eMy3jq1Ck6depEkSJFKF26NGFhYdy7d0+137p166hduzYFCxakePHitG/fnsePHxMZGcmKFSv46aefVNnonTt3aqz3li1bcHNz48UXX1RbPm/ePIYOHZprM8lVq1aRmprK0qVLqVWrFm+++Sbh4eHMmTMn12v09OlT1q9fz6xZs2jVqhWVK1cmMjKSypUrs2jRIiAj+xsVFcWECRPo2rUrderU4dtvv+XGjRts2rQJgDNnzvDKK69Qq1Ythg4dyt27d1XX5d1332XmzJla93XKrH/m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fVDjERERPSgmwETDkMlkgqurK6ZMmaKU+fn5QafTwWQyKWVarVZJfgEgMDAQ165dAwC0t7fj6tWriI6OVupdXFwQFRUFi8UypPNtb29Hc3Oz1XxdXV3x+OOPK9sgLly4ALPZjBkzZlhd29nZiccee2xI50NERNQfJsBEdqzv6Q0AoFKp7th3OxTUavUd/fbdijEQt27dAgAUFRUhKCjIqk6j0TzcBImIiAaBe4CJhiG9Xo/u7m6cPHlSKfvzzz/R0NCA8PDwAfXh7e2NgIAAnD59Winr6elBdXV1v9eNGDECPT09VmX+/v74/fffrZLgmpoaq7ECAwOt5tvd3Y2qqirldXh4ODQaDZqamjBx4kSrv3Hjxg0oJiIioqHAJ8BEw1BYWBjmzp2L1157DTk5OfD09MTatWsRFBSEuXPnDrift99+GxkZGZg4cSImTZqEzMxMtLW1Kac73E1ISAhOnDiBxYsXQ6PRYPTo0YiNjUVLSws++ugjLFy4EEeOHEFJSQm8vLyU65YvX47NmzcjLCwMkyZNwscff4zr168r9Z6enkhNTcXKlSthsVgQExOD9vZ2VFZWwsvLC0uXLn2g94qIiGiw+ASYaJjKy8tDVFQU5syZA4PBABFBcXHxHdse+pOWloaXXnoJSUlJMBgM8PDwQFxcHEaOHHnPa9LT03Hp0iWEhobC398fwN9PpLOysrBz505MnjwZp06dsjptAgBWr16NxMRELF26FAaDAZ6ensqP73pt2LAB69evR0ZGBvR6PWbOnImioiKMHz9+EO8MERHRw1HJv7FhkIiGJYvFAr1ej0WLFmHDhg22ng4REZFNcAsEkQO7fPkyjh49iunTp6OjowM7duzAxYsXsWTJEltPjYiIyGa4BYLIganVauTn5+OJJ57A1KlTUVdXh/Lycuj1eltPjYiIyGa4BYKIiIiInAqfABMRERGRU2ECTEREREROhQkwERERETkVJsBERERE5FSYABMRERGRU2ECTEREREROhQkwERERETkVJsBERERE5FSYABMRERGRU/k/Buq14vCXkkoAAAAASUVORK5CYII=",
+                        "text/plain": [
+                            "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "color_dict = {\n", + " 0: \"black\",\n", + " 1: \"darkgreen\",\n", + " 2: \"lightgreen\",\n", + " 3: \"gray\",\n", + " 4: \"blue\",\n", + "}\n", + "\n", + "plot_categorical_map(\n", + " out_image[0],\n", + " color_dict,\n", + " categories,\n", + " geom.exterior.xy,\n", + " extent=[minx, maxx, miny, maxy],\n", + " title=\"ALOS Forest Map\",\n", + ")" + ] + } + ], + "metadata": { + "description": "This notebook downloads the ALOS (Advanced Land Observing Satellite) forest extent maps", + "disk_space": "", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.15" + }, + "name": "Download ALOS forest extent maps", + "running_time": "", + "tags": [ + "Remote Sensing", + "Deforestation", + "Sustainability" + ] + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/notebooks/forest/download_glad_forest_map.ipynb b/notebooks/forest/download_glad_forest_map.ipynb new file mode 100644 index 00000000..28bb42d2 --- /dev/null +++ b/notebooks/forest/download_glad_forest_map.ipynb @@ -0,0 +1,442 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3c0a2457", + "metadata": {}, + "source": [ + "# Download GLAD Forest Extent Dataset\n", + "\n", + "Here's a simple example of how to download [GLAD forest extent maps](https://glad.umd.edu/dataset/GLCLUC2020) on FarmVibes. Just like the other FarmVibes.AI notebooks, you can refer to [this README file](README.md) to see how to install the required packages" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "d12f59be", + "metadata": {}, + "outputs": [], + "source": [ + "from vibe_core.client import get_default_vibe_client" + ] + }, + { + "cell_type": "markdown", + "id": "10cf50ca", + "metadata": {}, + "source": [ + "### Create vibe client and document the GLAD download workflow\n", + "\n", + "The following cell creates a new FarmVibes.AI client which is able to communicate with the FarmVibes.AI backend. Next, it documents \n", + "the `glad_forest_extent_download_merge` workflow." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "88bdcacb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "text/html": [
+                            "
Workflow: data_ingestion/glad/glad_forest_extent_download_merge\n",
+                            "
\n" + ], + "text/plain": [ + "\u001b[1;32mWorkflow:\u001b[0m \u001b[1;4;38;5;27mdata_ingestion/glad/glad_forest_extent_download_merge\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Description:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mDescription:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    Downloads Global Land Analysis (GLAD) forest extent data and merges them into a single raster.  \n",
+                            "    The workflow lists the GLAD forest products that intersect with the input geometry and time     \n",
+                            "    range, and downloads the filtered products. The downloaded products are merged into a single    \n",
+                            "    raster and classified. The result tiles have pixel values categorized into two classes - 0      \n",
+                            "    (non-forest) and 1 (forest). This workflow uses the same forest definition as the Food and      \n",
+                            "    Agriculture Organization of the United Nations (FAO).                                           \n",
+                            "
\n" + ], + "text/plain": [ + " Downloads Global Land Analysis (GLAD) forest extent data and merges them into a single raster. \n", + " The workflow lists the GLAD forest products that intersect with the input geometry and time \n", + " range, and downloads the filtered products. The downloaded products are merged into a single \n", + " raster and classified. The result tiles have pixel values categorized into two classes - 0 \n", + " (non-forest) and 1 (forest). This workflow uses the same forest definition as the Food and \n", + " Agriculture Organization of the United Nations (FAO). \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Sources:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSources:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - input_item (vibe_core.data.core_types.DataVibe): Geometry of interest for which to download   \n",
+                            "    the GLAD forest extent data.                                                                    \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1minput_item\u001b[0m (\u001b[34mvibe_core.data.core_types.DataVibe\u001b[0m): Geometry of interest for which to download \n", + " the GLAD forest extent data. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Sinks:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSinks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - merged_product (vibe_core.data.rasters.Raster): Merged GLAD forest extent product to geometry \n",
+                            "    of interest.                                                                                    \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mmerged_product\u001b[0m (\u001b[34mvibe_core.data.rasters.Raster\u001b[0m): Merged GLAD forest extent product to geometry \n", + " of interest. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - categorical_raster (vibe_core.data.rasters.Raster): Raster with the GLAD forest extent data.  \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mcategorical_raster\u001b[0m (\u001b[34mvibe_core.data.rasters.Raster\u001b[0m): Raster with the GLAD forest extent data. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Tasks:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mTasks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - glad_forest_extent_download: Downloads Global Land Analysis (GLAD) forest extent data.        \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mglad_forest_extent_download\u001b[0m: Downloads Global Land Analysis (GLAD) forest extent data. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - group_rasters_by_time: This op groups rasters in time according to 'criterion'.               \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mgroup_rasters_by_time\u001b[0m: This op groups rasters in time according to 'criterion'. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - merge: Merges rasters in a sequence to a single raster.                                       \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mmerge\u001b[0m: Merges rasters in a sequence to a single raster. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "client = get_default_vibe_client()\n", + "\n", + "WORKFLOW_NAME = \"data_ingestion/glad/glad_forest_extent_download_merge\"\n", + "client.document_workflow(WORKFLOW_NAME)" + ] + }, + { + "cell_type": "markdown", + "id": "696f2717", + "metadata": {}, + "source": [ + "### Create sample geometry and time range\n", + "\n", + "Like most FarmVibes.AI workflows, the user input involves a geometry and a time-range. The following cell creates a `shapely` geometry and a time range object to be provided as the workflow input." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "868a2720", + "metadata": {}, + "outputs": [], + "source": [ + "from shapely import geometry as shpg\n", + "from datetime import datetime\n", + "\n", + "# GeoJSON data\n", + "geo_json = {\n", + " \"type\": \"Feature\",\n", + " \"geometry\": {\n", + " \"type\": \"Polygon\",\n", + " \"coordinates\": [\n", + " [\n", + " [-86.773827, 14.575498],\n", + " [-86.770459, 14.579301],\n", + " [-86.764283, 14.575102],\n", + " [-86.769591, 14.567595],\n", + " [-86.773827, 14.575497],\n", + " ]\n", + " ],\n", + " },\n", + " \"properties\": {},\n", + "}\n", + "\n", + "geom = shpg.shape(geo_json[\"geometry\"])\n", + "time_range = datetime(2020, 1, 1), datetime(2020, 1, 2)" + ] + }, + { + "cell_type": "markdown", + "id": "c2604106", + "metadata": {}, + "source": [ + "### Execute FarmVibes.AI to download the GLAD Forest extent tiles" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "bc8ffe3a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "application/vnd.jupyter.widget-view+json": {
+                            "model_id": "9e1e6f1ff0bd4d87828384a5e88db045",
+                            "version_major": 2,
+                            "version_minor": 0
+                        },
+                        "text/plain": [
+                            "Output()"
+                        ]
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "text/html": [
+                            "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                }
+            ],
+            "source": [
+                "run = client.run(\n",
+                "    WORKFLOW_NAME,\n",
+                "    \"Download GLAD Forest Map\",\n",
+                "    geometry=geom,\n",
+                "    time_range=time_range,\n",
+                ")\n",
+                "run.monitor()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "57a4c441",
+            "metadata": {},
+            "source": [
+                "### Visualize the Resulting data cropped to the input geometry with some Buffer\n",
+                "\n",
+                "In the next cell, we use the user-provided geometry to read the output raster and create some buffer around it. Next, we plot the raster image and the user geometry in red."
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 13,
+            "id": "4ccd5569",
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "image/png": "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06YNEhISkJCQgMzMTAQHB2vcdFuex/I816R9+/bo3bu30gsAHjx4AADw9/ev9J4WLVogPT0deXl5Sstf7rV77949MMbQtGlTpQsMDw8P3Lp1C2lpaYr3zZo1Czt27IC7uztCQkKwadMmxf1OXRg+fDi+//57JCQk4MKFCyqbbAHgxo0bGDRoEJycnCCRSODh4YGRI0cCQKU8eXt7V+oY1axZMwCosmmbWDbqbUssipOTE+rWrYv4+PhK68rvgdbmRFkeIDt37lzl+vv376NRo0ZqpVWexyZNmmidH21VrLEBgFwuVzyzKhQKK21fsSa/evVqjBkzBj///DN+//13REREYMWKFYiOjkb9+vVrnbewsDAsWLAAEyZMgJubG958880qt8vKykL37t0hkUiwdOlSNG7cGDY2Nrh69SrmzZsHuVxe67wQy0XBk1icfv36YceOHfj777/Rvn17naWblJSECxcuYNq0aejevbvSOrlcjvDwcBw4cKDSc4qq7Nu3DwAQEhJSq3yVP6t6586dSutu374Nd3f3Gh9Fady4MRhjaNiwoaI2Vp1WrVqhVatWWLhwoaJj0tatWxWDHHAcp0VJyjRo0ACdO3fGmTNnMGXKFIhEVZ/Gzpw5g4yMDPz000/o1q2bYnlSUlKV2z958qTSYzl3794FAPj5+WmdX2KeqNmWWJy5c+fCzs4O48aNw7NnzyqtZ//25NRUea1z7ty5eOedd5ReQ4cORffu3dVuuj1w4AB27NiBjh07olevXlrlp1zdunURFBSEPXv2KHq8AmU1299//x19+/atMY3BgwdDKBRiyZIllY4PYwwZGRkAyu4py2QypfWtWrWCQCBQGjHJ3t5eKS+a+uyzz7B48WJMnz5d5TblNeSK+S0uLsbmzZur3F4mk2Hbtm1K227btg0eHh5o166d1nkl5olqnsTiNG3aFAcOHEBYWBj8/f0VIwwxxpCUlIQDBw5AIBBU2cS4Zs2aSp1TBAIB/u///g/79+9HUFCQyudDBwwYgOnTp+Pq1ato27atYvkPP/wABwcHFBcXK0YYOn/+PAIDA/H999/rpMxffvklQkND0bFjR4wfPx4FBQXYsGEDnJycEBkZWeP7GzdujM8++wwLFixAcnIyBg4cCEdHRyQlJeHw4cOYOHEiZs+ejdOnT2PatGl499130axZM8hkMuzbtw9C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",
+                        "text/plain": [
+                            "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from shapely.geometry import box\n", + "import matplotlib.pyplot as plt\n", + "from vibe_core.data import CategoricalRaster, Raster\n", + "from typing import cast\n", + "\n", + "import sys\n", + "sys.path.append(\"../\")\n", + "from shared_nb_lib.raster import read_raster\n", + "\n", + "\n", + "# Define your geometry\n", + "bounding_box = box(* geom.buffer(0.01).bounds)\n", + "\n", + "# Get the bounds of the geometry\n", + "minx, miny, maxx, maxy = bounding_box.bounds\n", + "\n", + "merged_raster = cast(Raster, run.output[\"merged_product\"][0])\n", + "categories = cast(CategoricalRaster, run.output[\"categorical_raster\"][0]).categories\n", + "\n", + "out_image = read_raster(merged_raster, bounding_box)[0]\n", + "\n", + "cmap = plt.get_cmap(\"Greens\", len(categories))\n", + "\n", + "# Plot the cropped image with latitude and longitude in the axes\n", + "plt.imshow(out_image[0], cmap=cmap, extent=[minx, maxx, miny, maxy])\n", + "\n", + "# Add a legend\n", + "legend = plt.legend(\n", + " handles=[\n", + " plt.Rectangle((0, 0), 1, 1, color=cmap(0)),\n", + " plt.Rectangle((0, 0), 1, 1, color=cmap(1)),\n", + " ],\n", + " labels=categories,\n", + ")\n", + "\n", + "# Plot geom on top of the cropped image\n", + "plt.plot(*geom.exterior.xy, color=\"red\")\n", + "\n", + "plt.title(\"GLAD Forest Map\")\n", + "plt.xlabel(\"Longitude\")\n", + "plt.ylabel(\"Latitude\")\n", + "\n", + "\n", + "plt.show()" + ] + } + ], + "metadata": { + "description": "This notebook downloads the Global Land Analysis (GLAD) forest extent maps.", + "disk_space": "", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.15" + }, + "name": "Download Glad Forest Map", + "running_time": "", + "tags": [ + "Remote Sensing", + "Deforestation", + "Sustainability" + ] + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/notebooks/forest/download_hansen_forest_map.ipynb b/notebooks/forest/download_hansen_forest_map.ipynb new file mode 100644 index 00000000..00e44fc3 --- /dev/null +++ b/notebooks/forest/download_hansen_forest_map.ipynb @@ -0,0 +1,939 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3c0a2457", + "metadata": {}, + "source": [ + "# Download Hansen Forest Change\n", + "\n", + "In this notebook, we download layers from the [Hansen Dataset](https://storage.googleapis.com/earthenginepartners-hansen/GFC-2022-v1.10/download.html) using FarmVibes.AI and visualize it. The data, distributed under the [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/), illustrates how forests changed from 2000 to 2022 with 30 meter resolution and covers the whole planet. Users can use this dataset to observe how the forest changed over time in a region of interest.\n", + "\n", + "This global dataset, split into 10x10 degree tiles, contains seven files per tile. Each file has unsigned 8-bit values and a resolution of around 30 meters per pixel at the equator. The dataset includes the following layers:\n", + "\n", + " - `treecover2000`: Tree cover in the year 2000, defined as canopy closure for all vegetation taller than 5m in height. Encoded as a percentage per output grid cell, in the range 0–100.\n", + " - `gain`: Forest gain during the period 2000-2012, defined as the inverse of loss, or a non-forest to forest change entirely within the study period. Encoded as either 1 (gain) or 0 (no gain).\n", + " - `lossyear`: Forest loss during the period 2000-2022, defined as a stand-replacement disturbance, or a change from a forest to non-forest state. Encoded as either 0 (no loss) or else a value in the range 1-22, representing loss detected primarily in the year 2001-2022, respectively.\n", + " - `datamask`: Three values representing areas of no data (0), mapped land surface (1), and persistent water bodies (2) based on 2000-2012.\n", + " - `first`: Circa year 2000 Landsat 7 cloud-free image composite (first).\n", + "Reference multispectral imagery from the first available year, typically 2000. \n", + " - `last`: cloud-free image composites for the last year in the series (e.g., 2022). \n", + " \n", + " Only the 'lossyear' and 'last' categories are updated annually. The reflectance values in the imagery are scaled to an 8-bit data range.\n", + "\n", + "Dataset Reference:\n", + "\n", + "Hansen, M. C., P. V. Potapov, R. Moore, M. Hancher, S. A. Turubanova, A. Tyukavina, D. Thau, S. V. Stehman, S. J. Goetz, T. R. Loveland, A. Kommareddy, A. Egorov, L. Chini, C. O. Justice, and J. R. G. Townshend. 2013. High-Resolution Global Maps of 21st-Century Forest Cover Change. Science 342 (15 November): 850-53. Data available on-line from: https://glad.earthengine.app/view/global-forest-change." + ] + }, + { + "cell_type": "markdown", + "id": "bfa4f4fc", + "metadata": {}, + "source": [ + "### Micromamba environment setup\n", + "To install the required packages, see [this README file](../README.md). You can activate the environment with the following command:\n", + "\n", + "\n", + "```bash\n", + "$ micromamba activate farmvibes-ai\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "447dcf5f", + "metadata": {}, + "outputs": [], + "source": [ + "from shapely import geometry as shpg\n", + "from datetime import datetime\n", + "\n", + "from matplotlib.ticker import MaxNLocator\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.colors as mcolors\n", + "import matplotlib.ticker as ticker\n", + "\n", + "from shapely.geometry import box\n", + "import matplotlib.pyplot as plt\n", + "from typing import cast\n", + "\n", + "import sys\n", + "\n", + "sys.path.append(\"../\")\n", + "from shared_nb_lib.raster import read_raster\n", + "\n", + "from vibe_core.data import DataVibe, Raster\n", + "from vibe_core.client import get_default_vibe_client" + ] + }, + { + "cell_type": "markdown", + "id": "3a8aff46", + "metadata": {}, + "source": [ + "### Create Vibe client and document the hansen download workflow\n", + "\n", + "Before executing the [workflow](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/WORKFLOWS.html), let's observe its documentation using a FarmVibes.AI python client." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "99fa0c54", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "text/html": [
+                            "
Workflow: data_ingestion/hansen/hansen_forest_change_download\n",
+                            "
\n" + ], + "text/plain": [ + "\u001b[1;32mWorkflow:\u001b[0m \u001b[1;4;38;5;27mdata_ingestion/hansen/hansen_forest_change_download\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Description:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mDescription:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    Downloads and merges Global Forest Change (Hansen) rasters that intersect the user-provided     \n",
+                            "    geometry/time range. The workflow lists Global Forest Change (Hansen) products that intersect   \n",
+                            "    the user-provided geometry/time range, downloads the data for each of them, and merges the      \n",
+                            "    rasters. The dataset is available at 30m resolution and is updated annually. The data contains  \n",
+                            "    information on forest cover, loss, and gain. The default dataset version is GFC-2022-v1.10 and  \n",
+                            "    is passed to the workflow as the parameter tiles_folder_url. For the default version, the       \n",
+                            "    dataset is available from 2000 to 2022.  Dataset details can be found at                        \n",
+                            "    https://storage.googleapis.com/earthenginepartners-hansen/GFC-2022-v1.10/download.html.         \n",
+                            "
\n" + ], + "text/plain": [ + " Downloads and merges Global Forest Change (Hansen) rasters that intersect the user-provided \n", + " geometry/time range. The workflow lists Global Forest Change (Hansen) products that intersect \n", + " the user-provided geometry/time range, downloads the data for each of them, and merges the \n", + " rasters. The dataset is available at 30m resolution and is updated annually. The data contains \n", + " information on forest cover, loss, and gain. The default dataset version is GFC-2022-v1.10 and \n", + " is passed to the workflow as the parameter tiles_folder_url. For the default version, the \n", + " dataset is available from 2000 to 2022. Dataset details can be found at \n", + " https://storage.googleapis.com/earthenginepartners-hansen/GFC-2022-v1.10/download.html. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Sources:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSources:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - input_item (vibe_core.data.core_types.DataVibe): User-provided geometry and time range.       \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1minput_item\u001b[0m (\u001b[34mvibe_core.data.core_types.DataVibe\u001b[0m): User-provided geometry and time range. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Sinks:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSinks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - merged_raster (vibe_core.data.rasters.Raster): Merged Global Forest Change (Hansen) data as a \n",
+                            "    raster.                                                                                         \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mmerged_raster\u001b[0m (\u001b[34mvibe_core.data.rasters.Raster\u001b[0m): Merged Global Forest Change (Hansen) data as a \n", + " raster. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - downloaded_raster (vibe_core.data.rasters.Raster): Individual Global Forest Change (Hansen)   \n",
+                            "    rasters prior to the merge operation.                                                           \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mdownloaded_raster\u001b[0m (\u001b[34mvibe_core.data.rasters.Raster\u001b[0m): Individual Global Forest Change (Hansen) \n", + " rasters prior to the merge operation. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Parameters:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mParameters:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - layer_name (default: None): Name of the Global Forest Change (Hansen) layer. Can be any of the\n",
+                            "    following names 'treecover2000', 'loss', 'gain', 'lossyear', 'datamask', 'first', 'last'.       \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mlayer_name\u001b[0m (\u001b[34mdefault: None\u001b[0m): Name of the Global Forest Change (Hansen) layer. Can be any of the\n", + " following names 'treecover2000', 'loss', 'gain', 'lossyear', 'datamask', 'first', 'last'. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - tiles_folder_url (default:                                                                    \n",
+                            "    https://storage.googleapis.com/earthenginepartners-hansen/GFC-2022-v1.10/): URL to the Global   \n",
+                            "    Forest Change (Hansen) dataset. It specifies the dataset version and is used to download the    \n",
+                            "    data.                                                                                           \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mtiles_folder_url\u001b[0m (\u001b[34mdefault: \u001b[0m \n", + " \u001b[34mhttps://storage.googleapis.com/earthenginepartners-hansen/GFC-2022-v1.10/\u001b[0m): URL to the Global \n", + " Forest Change (Hansen) dataset. It specifies the dataset version and is used to download the \n", + " data. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Tasks:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mTasks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - list: Lists Global Forest Change (Hansen) products that intersect the user-provided           \n",
+                            "    geometry/time range.                                                                            \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mlist\u001b[0m: Lists Global Forest Change (Hansen) products that intersect the user-provided \n", + " geometry/time range. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - download: Downloads Global Forest Change (Hansen) data.                                       \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mdownload\u001b[0m: Downloads Global Forest Change (Hansen) data. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - group: This op groups rasters in time according to 'criterion'.                               \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mgroup\u001b[0m: This op groups rasters in time according to 'criterion'. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - merge: Merges rasters in a sequence to a single raster.                                       \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mmerge\u001b[0m: Merges rasters in a sequence to a single raster. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "client = get_default_vibe_client()\n", + "\n", + "WORKFLOW_NAME = \"data_ingestion/hansen/hansen_forest_change_download\"\n", + "client.document_workflow(WORKFLOW_NAME)" + ] + }, + { + "cell_type": "markdown", + "id": "b894d84c", + "metadata": {}, + "source": [ + "### Setting up Input Geometry and Time Frame\n", + " \n", + "Now, we will establish the desired geometry and time frame for downloading the Hansen products. The workflow will fetch and merge all the tiles that intersect with the given input." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f12b5333", + "metadata": {}, + "outputs": [], + "source": [ + "# GeoJSON definition of a polygon over the potential forest area\n", + "geo_json = {\n", + " \"type\": \"Feature\",\n", + " \"geometry\": {\n", + " \"type\": \"Polygon\",\n", + " \"coordinates\": [\n", + " [\n", + " [-86.773827, 14.575496],\n", + " [-86.770459, 14.579302],\n", + " [-86.764283, 14.575102],\n", + " [-86.769591, 14.567595],\n", + " [-86.773827, 14.575496],\n", + " ]\n", + " ],\n", + " },\n", + " \"properties\": {},\n", + "}\n", + "\n", + "geom = shpg.shape(geo_json[\"geometry\"])\n", + "time_range = datetime(2000, 1, 1), datetime(2022, 1, 2)" + ] + }, + { + "cell_type": "markdown", + "id": "fb34e580", + "metadata": {}, + "source": [ + "### Run FarmVibes.AI Workflow\n", + "\n", + "To execute the workflow users need to provide the geometry of interest (`geom`), time range (`time_range`), and the name of the layer to be downloaded as a workflow parameter (`layer_name`). The layer can be any value from the set (`treecover2000`, `gain`, `lossyear`, `datamask`, `first`, `last`).\n", + "\n", + "In the next cell, we initiate two `runs` for the `treecover2000` and `lossyear` layers, and then wait for both workflows to complete (`client.monitor(runs)`)." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "76b0f81f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "application/vnd.jupyter.widget-view+json": {
+                            "model_id": "a2e39cd7cde14fa4b96039434eed5ede",
+                            "version_major": 2,
+                            "version_minor": 0
+                        },
+                        "text/plain": [
+                            "Output()"
+                        ]
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "text/html": [
+                            "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                }
+            ],
+            "source": [
+                "runs = []\n",
+                "\n",
+                "for layer_name in [\"treecover2000\", \"lossyear\"]:\n",
+                "    run = client.run(\n",
+                "        WORKFLOW_NAME,\n",
+                "        \"Hansen dataset download\",\n",
+                "        geometry=geom,\n",
+                "        time_range=time_range,\n",
+                "        parameters={\"layer_name\": layer_name},\n",
+                "    )\n",
+                "    runs.append(run)\n",
+                "\n",
+                "client.monitor(runs)"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "4b517e3c",
+            "metadata": {},
+            "source": [
+                "### Visualizing Dataset Details\n",
+                " \n",
+                "In the upcoming cells, we will depict the changes in the forest over the years within the user's region of interest. Following that, we will examine the division of the area in terms of forest and non-forest proportions. Finally, we will assess how the percentage of forest pixels has evolved over time."
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "44e97e42",
+            "metadata": {},
+            "source": [
+                "#### Plot forest loss over time\n",
+                "\n",
+                "In the following cell, we create a plot function that reads the `treecover2000` layer and the `lossyear`. The `treecover2000` layer has pixel values ranging from 0 to 100 that represents the percentage of tree cover in the area. Here, we use a black to green colormap. Then, we plot the `lossyear` with pixel values enconded as 0 (no loss) or else a value in the range 1-20, representing loss detected primarily in the year 2001-2022, respectively. The second layer is depicted using a yellow to red colormap. "
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 5,
+            "id": "e9c3e812",
+            "metadata": {},
+            "outputs": [],
+            "source": [
+                "def plot_hansen_map(treecover2000: Raster, lossyear: Raster, geom: shpg.Polygon, first_year: int):\n",
+                "\n",
+                "    colors = [\"black\", \"green\"]\n",
+                "    cmap = mcolors.LinearSegmentedColormap.from_list(\"mycmap\", colors)\n",
+                "\n",
+                "    # Define your geometry\n",
+                "    bounding_box = box(*geom.buffer(0.01).bounds)\n",
+                "\n",
+                "    # Get the bounds of the geometry\n",
+                "    minx, miny, maxx, maxy = bounding_box.bounds\n",
+                "\n",
+                "    merged_raster = cast(Raster, treecover2000)\n",
+                "    out_image = read_raster(merged_raster, bounding_box)[0]\n",
+                "\n",
+                "    loss_image = read_raster(cast(Raster, lossyear), bounding_box)[0][0]\n",
+                "    \n",
+                "    # Create a masked array where the mask is True for zero values\n",
+                "    masked_loss = np.ma.masked_where(loss_image == 0, loss_image)\n",
+                "\n",
+                "    # Set data type to float\n",
+                "    masked_loss = masked_loss.astype(float)\n",
+                "    masked_loss += first_year\n",
+                "\n",
+                "    # Plot the cropped image with latitude and longitude in the axes\n",
+                "    plt.imshow(out_image[0], cmap=cmap, extent=[minx, maxx, miny, maxy])\n",
+                "\n",
+                "    loss_cmap = plt.cm.get_cmap(\"YlOrRd\").copy()\n",
+                "    loss_cmap.set_bad(color=\"none\")\n",
+                "\n",
+                "    # Plot the loss image on top of the cropped image\n",
+                "    plt.imshow(masked_loss, cmap=loss_cmap, alpha=0.8, extent=[minx, maxx, miny, maxy])\n",
+                "\n",
+                "    # Plot geom on top of the cropped image\n",
+                "    plt.plot(*geom.exterior.xy, color=\"blue\")\n",
+                "\n",
+                "    # Add a legend for the loss_image\n",
+                "    cbar = plt.colorbar()\n",
+                "    tick_locator = ticker.MaxNLocator(nbins=max(loss_image.flatten()))\n",
+                "    cbar.locator = tick_locator\n",
+                "    cbar.update_ticks()\n",
+                "\n",
+                "    cbar.set_label(\"Year for the forest to non-forest transition\")\n",
+                "\n",
+                "    plt.title(\"Forest Extent\")\n",
+                "    plt.xlabel(\"Longitude\")\n",
+                "    plt.ylabel(\"Latitude\")\n",
+                "\n",
+                "    plt.text(\n",
+                "        0.11,\n",
+                "        -0.005,\n",
+                "        \"Source: Hansen/UMD/Google/USGS/NASA\",\n",
+                "        fontsize=7,\n",
+                "        transform=plt.gcf().transFigure,\n",
+                "    )\n",
+                "\n",
+                "    plt.show()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "b334b0e1",
+            "metadata": {},
+            "source": [
+                "### Plot the `treecover2000` and `lossyear` rasters"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 6,
+            "id": "223eef5c",
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "image/png": "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7bfXX3+dXr16ZQ35/cIXvoDrugwaNMhqIjJx8MEHc/DBB/Ozn/2M5557jhEjRvCHP/yBX/3qV4AXAbOzMH36dF577TWuu+46/vu//5vLL7+cm2++OXCM7fq9e/emvLyc1tbWnDQyuWJntjVChAg7D1FIcIQIOwF77bUXhxxyCHfccQebN29O7V+1ahX//Oc/rQnJTIwdO5Z4PM6VV16ZpgVwXZePPvoIgC1bttDS0hL4/eCDDyYWi9HY2JjaV1ZWFqhLR2HFihVcd911XHrppfzwhz/kRz/6EbfccgtLly4NHGe7fjweZ9y4cdx7772sWrUqrexNmza1qU5lZWWpcOgIESLsOYg0JREi7CT89re/5aSTTqK6upqJEyemQoIrKyuZMWNG1vO/8IUv8Ktf/Yqf/OQnrF+/njFjxlBeXs66detYsGABF198MZdddhlPPPEEkyZN4owzzuCAAw6gpaWFv/zlLymBLxg2bBiPPfYYv/vd7+jXrx+DBg3iiCOOyFiHF198kbvuustat+rqahoaGjjvvPP44he/yK9//WsArrzySh588EEuuOACXn311ZRGKOz6v/nNb3jyySc54ogjuOiiizjooIP4+OOPefHFF3nsscf4+OOP8+h1v6333HMP06ZNY/jw4XTt2pVTTjkl73IiRIjQydiFkT8RIuyxkJDg559/PuNxjz32mDtixAi3tLTUraiocE855RR39erVgWMkJHjTpk3WMu699173qKOOcsvKytyysjJ38ODBbk1NjbtmzRrXdV33rbfecidMmOB+4QtfcEtKStwePXq4xx57rPvYY48Fynn99dfdkSNHuqWlpS6QMTw4W0iwnDt16lQ3Ho+7K1asCJz/wgsvuAUFBe73v//9nK5fV1fn1tTUuPvss49bWFjoVlVVuccff7z7xz/+MXWMhASboc9S19tvvz21b+vWre7ZZ5/tduvWzQWi8OAIEfYQOK4beYdFiBAhQoQIEXY9Ip+SCBEiRIgQIcJugYiURIgQIUKECBF2C0SkJEKECBEiRIiwWyAiJREiRIgQIcJuhJkzZzJ8+HDKy8vp06cPY8aMSct51NDQQE1NDT179qRr166MGzeOurq61O8vv/wyZ511Fvvssw+lpaUMGTKEm266Ke1aS5Ys4bDDDqO4uJj999+fOXPm7OzmZURESiJEiBAhQoTdCEuX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yI033sj69etzKqdbt24ccMABrF27FoA333yTW265hVWrVqVMQl/5yld4+umnmTVrFn/4wx+s5RxxxBG0tLSwfv16DjzwQOsxua74GCFCWxB3oCCeIOZAS8LxImciRIiw05Grm1Om8z+L+OCDDzjzzDNZsmRJKt395s2bOfbYY/nb3/5G79698y5ztyUl55xzTmBZZoBRo0ZxzjnncMEFF+RcztatW3nzzTc555xzAC+tLmBNrZspre5LL71ELBajT58+OV87wp6P6n3X23/Q9vhORDwGZ57xfnCnzuzUxvpMHLcxGN4rav1Mzr4RIlhw22t7p/toiQlHR2fp/QJ9nsLEkzbCc8CanVnzCPli8uTJfPrpp/zf//0fQ4YMAWD16tWcd955TJkyhb/+9a95l7lL85Rs3bqVl156KZX6dt26dbz00ku888479OzZk6FDhwa2wsJCqqqqApqK448/nltuuSX1/2WXXcbSpUtZv349zz33HN/61reIx+OcddZZAAwePJj999+f733ve/zrX//izTff5Prrr+fRRx9NOe0sW7aMG2+8kZdffpm33nqLu+++m6lTp/Ld736X7t27t62xLfhOXuLwJ85fYPeCN7dMgseWV8OM7pFyEvgrFm9L1mkLvh+KuZnoSAdCnfRNe/BvxfNvqcePuBG7crP61PleJBeGWX+zvmF9K/ZvnbJf++DIZuaI0PvFn0dtzY1OMsQ22eSEQ2tycxwoiEMs5uLYIlEMtNruj+67tqrMdS4J8QsQx0L9PEkf6b7SjtTii6O3IjzfgRJ8XxntdK3boT/zifCy+WfkC/OZ6Ezo50/73Ggn0LDR2vZM6nsGQQdvnRtJ3iUZDyRJopSh3w19j0vxHFXFIXY76WH2An1tIbphCTzCnMa1r1IBnpN7r5D+2AlwcNu95YOZM2cyfPhwysvL6dOnD2PGjGHNmiAja2hooKamhp49e9K1a1fGjRtHXV3QbDtlyhSGDRtGcXExhxxySNp1bHm9HMehrKwsp3ouXryYW2+9NUVIwEthP2vWLB5++OG82izYpZqSF154gWOPPTb1v/hjnHfeecyZMyenMt58800+/PDD1P/vvvsuZ511Fh999BG9e/fmqKOOYvny5Sk1UmFhIQ899BCXX345p5xyClu3bmX//ffnjjvuYPTo0YBnhvnb3/7GjBkzaGxsZNCg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TJw4EWlpaUhJScGECROQk5ODnj17AgAGDRqEjh07YuTIkXjiiSdQUFCABx98ELm5uTYJzYYNGwAApaWlOHDgADZs2ICYmJhTRlw0URdWQi5OCxQXFyM1NRVFRUVn/C7s19JWt51nFn4t7QR+XW1VEU7dP3v2bIwZMwaADJ5211134c0330RFRQUGDx6M559/3qaa+fHHHzFu3DisWLECiYmJGD16NP7xj3/A57PkEU5ltW7dGrt27arVNkULV1LiwkRsbCwmT55crZ7zTMCvpa1uO88s/FraCfy62qoiGllBXFwcpk+fjunTp4dN07p1a3z44YcnXFZdwpWUuHDhwoULFy7qBdzgaS5cuHDhwoWLegGXlLhw4cKFCxcu6gVcUuLChQsXLly4qBdwSYkLFy5cuHDhol7AJSVnEL777jtceeWVaNy4MVJSUtC7d28sX748JN2cOXNw3nnnIS4uDunp6cjNzQ2b565du6BpmuNn3jwrlP26devQv39/NGjQAA0bNsTgwYOxcaM9TPTXX3+Niy++GHFxcWjZsiWeeOKJ06qdc+bMCZumsLAQALBixQrH34/nrIn63E5q6/nnn4/Y2Fj85je/wZw5c2rcxlPd1mjyDZfPmjVrzqh2Aqf/OwrA8fe33nrL/L0231EXJwHCxRmDc845R1x22WVi48aN4rvvvhO33nqrSEhIEPv27TPT/POf/xTNmjUTb7zxhvj+++/Fxo0bxYIFC8LmGQgExL59+2yfhx9+WCQlJYmSkhIhhBAlJSUiLS1NjBkzRmzdulVs3rxZDB8+XGRkZIjKykohhBBFRUUiIyNDXHfddWLz5s3izTffFPHx8eLFF188bdpZVlYWkmbw4MHikksuMfNZvny5ACC2bdtmSxcMBs+odv7www8iISFBTJw4UWzZskX861//El6vVyxatKjG7TyVbY0m3507dwoAYunSpba8aGyfKe08E95RIYQAIGbPnm1Ld+zYMfP32nxHXdQ+XFJyhuDAgQMCgPj000/Na8XFxQKAWLJkiRBCiEOHDon4+HixdOnSEyorKytL3Hjjjeb3devWCQBi9+7d5rWvv/5aABDbt28XQgjx/PPPi4YNG4qKigozzaRJk0S7du1qVPapbKeKwsJC4ff7xWuvvWZeownv8OHDJ1R2fW/nvffeKzp16mRLd80114jBgwfXuPxT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",
+                        "text/plain": [
+                            "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "treecover2000 = runs[0].output[\"merged_raster\"][0]\n", + "lossyear = runs[1].output[\"merged_raster\"][0]\n", + "\n", + "plot_hansen_map(treecover2000, lossyear, geom, time_range[0].year)" + ] + }, + { + "cell_type": "markdown", + "id": "a8be22b0", + "metadata": {}, + "source": [ + "### Plot the proportion of forest/non-forest pixels\n", + "\n", + "In the next cell, the proportion of forest/non-forest pixels is plotted. This is done by analyzing the `lossyear` raster, which represents forest loss over time. The cell calculates the ratio of forest pixels to total pixels within the specified geometry. Then, a pie chart is created using matplotlib to visually compare the proportion of forest and non-forest pixels. Finally, we show the loss table over time in case the user wants to access the values used to plot the graphs." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "b1be08cf", + "metadata": {}, + "outputs": [], + "source": [ + "def read_loss_dict(lossyear: Raster, geom: shpg.Polygon, nodata: int = 255):\n", + " # Read the raster\n", + " loss_image = read_raster(cast(Raster, lossyear), geom, nodata=nodata)[0][0]\n", + "\n", + " # Count the frequency of each value in the loss_image\n", + " unique, counts = np.unique(loss_image, return_counts=True)\n", + "\n", + " loss_dict = {uni: count for uni, count in zip(unique, counts)}\n", + "\n", + " # Delete 255 from the dictionary\n", + " del loss_dict[nodata]\n", + "\n", + " return loss_dict\n", + "\n", + "\n", + "def plot_forest_ratio(lossyear: Raster, geom: shpg.Polygon):\n", + " # Read the raster\n", + "\n", + " loss_dict = read_loss_dict(lossyear, geom)\n", + "\n", + " # Amount of pixels\n", + " total_pixels = sum(loss_dict.values())\n", + "\n", + " # Forest Pixels\n", + " forest_pixels = loss_dict[0]\n", + " forest_ratio = forest_pixels / total_pixels\n", + "\n", + " # Plot a matplotlib pie chart comparing forest and not forest pixels\n", + " labels = \"Forest\", \"Not Forest\"\n", + "\n", + " sizes = [forest_ratio, 1 - forest_ratio]\n", + "\n", + " fig1, ax1 = plt.subplots()\n", + " ax1.pie(sizes, labels=labels, autopct=\"%1.1f%%\", startangle=90)\n", + " ax1.axis(\"equal\")\n", + "\n", + " # Title\n", + " plt.title(\"Forest/Non-Forest pixels proportion\")\n", + "\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "7e73283c", + "metadata": {}, + "source": [ + "### Plot the Forest/Non-Forest pie chart" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "7fe9a3ef", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_forest_ratio(lossyear, geom)" + ] + }, + { + "cell_type": "markdown", + "id": "ec65f6ba", + "metadata": {}, + "source": [ + "### Plot the Forest change over time\n", + "\n", + "In the next cell, we create a `plot_forest_loss` function that takes a raster image of forest loss per year and a polygon geometry as inputs. It reads the raster data and calculates the percentage of total forest loss for each year. The function then generates a bar plot with the percentage of forest loss for each year in the dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "0354f1bb", + "metadata": {}, + "outputs": [], + "source": [ + "def plot_forest_loss(lossyear: Raster, geom: shpg.Polygon):\n", + " # Read the raster\n", + " loss_dict = read_loss_dict(lossyear, geom)\n", + "\n", + " # Amount of pixels\n", + " total_pixels = sum(loss_dict.values())\n", + "\n", + " # Pixel count\n", + " new_values = {key: 100 * loss_dict[key] / total_pixels for key in loss_dict}\n", + "\n", + " # Remove the key 0 as it is not a loss. It is the forest \n", + " # pixels that have not been lost.\n", + " new_values.pop(0, None)\n", + "\n", + " # Create lists of the years and pixel counts\n", + " years = list(new_values.keys())\n", + " years = [year + time_range[0].year for year in years]\n", + "\n", + " pixel_counts = list(new_values.values())\n", + "\n", + " # Create a bar plot\n", + " plt.bar(years, pixel_counts)\n", + "\n", + " # Set the labels for the x and y axes\n", + " plt.xlabel(\"Year\")\n", + " plt.ylabel(\"Forest Loss (%)\")\n", + " plt.title(\"Forest to Non-Forest affected area (%) over time\")\n", + "\n", + " # Set x-axis to only use integer values\n", + " ax = plt.gca()\n", + " ax.xaxis.set_major_locator(MaxNLocator(integer=True))\n", + "\n", + " plt.xticks(range(min(years), max(years) + 1), rotation=90)\n", + "\n", + " # Show the plot\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0065c6e2", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjIAAAHcCAYAAADMakA2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAA9hAAAPYQGoP6dpAABPWUlEQVR4nO3deXRMh/sG8Gcmy2SfRJCFSGJrROyEiH0LjZ2iSlClvrSaKkottdVStVXsbe1aamup2mOntbYlRFRCLImWCoKQ5P390ZP7M7JIJhOTq8/nnHuOu8w778yduZ7cbTQiIiAiIiJSIa25GyAiIiIyFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRmU1qaiqGDx8OLy8vaLVatG/fHgDw4MEDvPPOO3B3d4dGo0F4eLhZ+8yLuLg4aDQaLFu2zNytmFR8fDxsbGxw+PBhk9S7ffs27O3tsW3bNpPUU4Nly5ZBo9EgLi7O3K28UhhkCrmMD35Ww4gRI8zdXpYmT56MzZs352rZGzduYNy4cThz5oxJe9i3b5/yPp08eTLT/N69e8PBwcGkz5lbz/b2/NCtWzez9PQi8+fPL5D/mL/55htMnz4dnTt3xvLly/Hhhx8C+PcztGzZMvzvf//DypUr0bNnT5M/d0G9plfVhAkTULt2bQQHByvTDh8+jOrVq8PR0RGNGjXChQsXMj1u8ODBCAkJyTTd1dUV77zzDsaMGVOgfZtDXraBlH+W5m6AcmfChAnw9fU1mBYQEGCmbnI2efJkdO7cWfnrOic3btzA+PHj4ePjg6pVqxZIP+PGjcOWLVsKpHZ+DB48GLVq1TKY5uPjY55mXmD+/PkoWrQoevfubdK6e/fuRYkSJTBr1qxM0+vUqYNPP/3UpM/3rIJ6Ta+iv/76C8uXL8fy5cuVaUlJSWjXrh3q1KmD/v37Y9myZejUqRN+//13WFhYAADOnTuHJUuWZPnHBAAMGDAAX375Jfbu3YsmTZq8lNfyMmS3DezZsye6desGnU5nnsZeUQwyKtGqVSvUrFnT5HWTk5Nhb29v8rqFRdWqVbF161acOnUK1atXN3c7BurXr4/OnTubvK6a1umtW7fg7Oyc5XR/f/+X35BKPH78GNbW1tBqX85O9VWrVsHS0hJt2rRRph09ehSPHj3C+vXrYWNjg5YtW8LX1xeXLl3Ca6+9BgAIDw9Hv379sl2XFSpUQEBAAJYtW6aqIJOamor09HRYW1vn6XEWFhZKyCPT4aGlV8TevXtRv3592Nvbw9nZGe3atcP58+cNlhk3bhw0Gg2ioqLQvXt3uLi4oF69esr8VatWoUaNGrC1tUWRIkXQrVs3xMfHG9SIiYlBp06d4O7uDhsbG5QsWRLdunVDUlISAECj0SA5ORnLly9XDpdk9xfvvn37lD0Sffr0UZZ/dnf/999/r/RUtGhR9OjRA9evX8/1+/L+++/DxcUF48aNy9Xy8+fPR8WKFaHT6eDp6YlBgwbh7t27Bss0atQIAQEBiIqKQuPGjWFnZ4cSJUrg888/z3VfuXH69Gm0atUKTk5OcHBwQNOmTXHs2DGDZTIOPe7fvx8DBw5E8eLFUbJkSWX+zz//rHwuHB0dERoainPnzhnUSEhIQJ8+fVCyZEnodDp4eHigXbt2ynF8Hx8fnDt3Dvv371fWUaNGjXLs/YsvvkDdunXh6uoKW1tb1KhRA+vXr1fmZ5xHEhkZiXPnzil1Mw67xcbG4qefflKmZ/SSkpKCTz/9FGXLloVOp4OXlxeGDx+OlJSUTD2sWrUKgYGBsLOzg4uLCxo0aICdO3fm6jXdvXsX4eHh8PLygk6nQ9myZTFt2jSkp6cbPMfdu3fRu3dv6PV6ODs7o1evXpk+L9m5c+cOhg4dikqVKsHBwQFOTk5o1aoVfvvtN4PlMt6T7777DqNHj0aJEiVgZ2eHe/fuAQB++eUXtGzZEnq9HnZ2dmjYsGGm81iuXLmCgQMH4rXXXoOtrS1cXV3xxhtv5Ppcjc2bN6N27doGh2MfPXoEGxsb2NjYAACKFCkCAHj48KHymNOnT2P8+PE51m7evDm2bNkCEXlhH5cvX8Ybb7yBIkWKwM7ODnXq1MFPP/2kzE9MTISlpWWWzxkdHQ2NRoOIiAhlWm7Wc8Zn9YsvvsDs2bNRpkwZ6HQ6REVFZdljTtvArM6R8fHxQevWrbFv3z7UrFkTtra2qFSpEvbt2wcA2LhxIypVqgQbGxvUqFEDp0+fzvScFy5cQOfOnVGkSBHY2NigZs2a+PHHH1/4fr4yhAq1pUuXCgDZvXu3/PXXXwZDhl27domlpaWUL19ePv/8cxk/frwULVpUXFxcJDY2Vlnu008/FQDi7+8v7dq1k/nz58u8efNERGTSpEmi0Wika9euMn/+fKWGj4+P/PPPPyIikpKSIr6+vuLp6SmTJk2Sr776SsaPHy+1atWSuLg4ERFZuXKl6HQ6qV+/vqxcuVJWrlwpR44cyfK1JSQkyIQJEwSA9O/fX1n+zz//NHjttWrVklmzZsmIESPE1tbWoKfsREZGCgD5/vvvlec4efKkMr9Xr15ib29v8JiM96dZs2Yyd+5cee+998TCwkJq1aolT548UZZr2LCheHp6ipeXl3zwwQcyf/58adKkiQCQbdu25bxCn+ntm2++ybRO09LSRETk7NmzYm9vLx4eHjJx4kSZOnWq+Pr6ik6nk2PHjim1Mt4jf39/adiwocydO1emTp0qIiIrVqwQjUYjLVu2lLlz58q0adPEx8dHnJ2dDT4XdevWFb1eL6NHj5avvvpKJk+eLI0bN5b9+/eLiMimTZukZMmS4ufnp6yjnTt35vgaS5YsKQMHDpSIiAiZOXOmBAYGCgDZunWriIg8ePBAVq5cKX5+flKyZEmlbkJCgqxcuVKKFi0qVatWVaY/ePBA0tLSpEWLFmJnZyfh4eGyaNEiee+998TS0lLatWtn8Pzjxo0TAFK3bl2ZPn26zJkzR7p37y4ff/zxC19TcnKyVK5cWVxdXeWTTz6RhQsXSlhYmGg0Gvnggw+U50hPT5cGDRqIVquVgQMHyty5c6VJkyZSuXJlASBLly7N8T06fvy4lClTRkaMGCGLFi2SCRMmSIkSJUSv18v169czfV78/f2latWqMnPmTJkyZYokJyfLnj17xNraWoKCgmTGjBkya9YsqVy5slhbW8svv/yi1Pj++++lSpUqMnbsWFm8eLF88skn4uLiIt7e3pKcnJxjn0+ePBFbW1sZMmSIwfTY2FixsLCQL774QuLi4iQ8PFz0er0kJyfL48ePpXTp0hIREZFjbRGRVatWCQD5448/clwuISFB3NzcxNHRUUaNGiUzZ86UKlWqiFarlY0bNyrLNWnSRPz9/TM9fvz48WJhYSEJCQkikvv1HBsbq7z/pUuXlqlTp8qsWbPkypUrWfaZ0zYw4/v67PfP29tbXnvtNfHw8JBx48bJrFmzpESJEuLg4CCrVq2SUqVKydSpU2Xq1Kmi1+ulbNmyynZC5N9thV6vF39/f5k2bZpERERIgwYNRKPRGLwvrzIGmUIu44Of1ZChatWqUrx4cbl9+7Yy7bfffhOtVithYWHKtIz/qN98802D54iLixMLCwv57LPPDKb/8ccfYmlpqUw/ffq0Eg5yYm9vL7169crV6zt+/HiWG/0nT55I8eLFJSAgQB49eqRM37p1qwCQsWPH5lj32SBz9+5dcXFxkbZt2yrznw8yt27dEmtra2nRooXBRiIiIkIJHRkaNmwoAGTFihXKtJSUFHF3d5dOnTq98DVn9JbVkLGBa9++vVhbWyuhTkTkxo0b4ujoKA0aNFCmZXw+6tWrJ6mpqcr0+/fvi7Ozs/Tr18/guRMSEkSv1yvT//nnHwEg06dPz7HnihUrSsOGDV/42jI8fPjQYPzJkycSEBAgTZo0MZjesGFDqVixYqbHe3t7S2hoqMG0lStXilarlYMHDxpMX7hwoQCQw4cPi4hITEyMaLVa6dChg8G6FPk3fLzoNU2cOFHs7e3l4sWLBtNHjBghFhYWcvXqVRER2bx5swCQzz//XFkmNTVV6tevn6sg8/jx40z9xcbGik6nkwkTJijTMj4vpUuXNnhf09PTpVy5chISEmLwuh4+fCi+vr7SvHlzg2nPO3r0aKbPcVYuXbokAGTu3LmZ5k2fPl0sLCwEgNja2sqaNWtEROSzzz6TgIAAg89kdo4cOSIAZO3atTkuFx4eLgAM1v/9+/fF19dXfHx8lPdy0aJFWQYjf39/g89fbtdzRpBxcnKSW7duvfD1iGS/DcwuyAAw+INvx44dynv6bGDKeG2RkZHKtKZNm0qlSpXk8ePHyrT09HSpW7eulCtXLlf9qh0PLanEvHnzsGvXLoMBAG7evIkzZ86gd+/eyq5dAKhcuTKaN2+e5aWNAwYMMBjfuHEj0tPT0aVLF/z999/K4O7ujnLlyiEyMhIAoNfrAQA7duxQdh8XlBMnTuDWrVsYOHCgsusaAEJDQ+Hn52ewO/lF9Ho9wsPD8eOPP2a5WxYAdu/ejSdPniA8PNzgvIN+/frByckp0/M5ODigR48eyri1tTUCAwNx+fLlXPc1duzYTOvU3d0daWlp2LlzJ9q3b4/SpUsry3t4eKB79+44dOiQcljh2T6fPfa+a9cu3L17F2+++abBOrWwsEDt2rWVdWprawtra2vs27cP//zzT657fxFbW1vl3//88w+SkpJQv359nDp1yuia33//PSpUqAA/Pz+D15RxbkXGa9q8eTPS09MxduzYTOeQaDSaXD1P/fr14eLiYvA8zZo1Q1paGg4cOAAA2LZtGywtLfG///1PeayFhQXef//9XL0enU6n9JeWlobbt2/DwcEBr732WpbvU69evQze1zNnziAmJgbdu3fH7du3lT6Tk5PRtGlTHDhwQDlE8uzjnj59itu3b6Ns2bJwdnZ+4Tq5ffs2AMDFxSXTvKFDh+L69es4evQorl+/jjfffBM3btzAlClTMHv2bKSmpuL9999HqVKlEBgYmOWl2xl1//777xz72LZtGwIDAw0Ohzs4OKB///6Ii4tTDvV07NgRlpaWWLt2rbLc2bNnERUVha5duyrTcrueM3Tq1AnFihXLsUdj+fv7IygoSBmvXbs2AKBJkyYoVapUpukZ25k7d+5g79696NKlC+7fv6+8htu3byMkJAQxMTF5OhSvVjzZVyUCAwOzPNn3ypUrAKCcXPesChUqYMeOHZlO/nz+6qeYmBiICMqVK5flc1tZWSmPGzJkCGbOnInVq1ejfv36aNu2LXr06KGEHFPJ6XX5+fnh0KFDear3wQcfYNasWRg3bhx++OGHXD+ftbU1SpcurczPULJkyUz/Kbq4uOD3339XxhMSEgzm6/V6g/9QKlWqhGbNmmXqJSEhAQ8fPsx2naanpyM+Ph4VK1ZUpme1TgFkewKlk5MTgH//M502bRo++ugjuLm5oU6dOmjdujXCwsLg7u6e5WNzY+vWrZg0aRLOnDljcP5KboJEdmJiYnD+/Pls/zO5desWAODPP/+EVqs1+mThmJgY/P777y98nitXrsDDwyPTZfxZrbespKenY86cOZg/fz5iY2ORlpamzHN1dc20fHbruFevXtk+R1JSElxcXPDo0SNMmTIFS5cuxfXr1w3OR8k4v+1FJJtzWNzc3ODm5qaMf/zxx2jatCmaNm2K0aNHY8+ePVi7di0iIyMRGhqKuLg4gxO8M+q+6LNx5coV5T/yZ1WoUEGZHxAQgKJFi6Jp06ZYt24dJk6cCABYu3YtLC0t0bFjR+VxuV3PGZ5//03p2bAC/P8fjV5eXllOz/ij49KlSxARjBkzJtvL2G/duoUSJUqYuuVChUHmP+jZ/0yBfzeoGo0GP//8c5Zn1D+7oZ4xYwZ69+6NH374ATt37sTgwYMxZcoUHDt2zOAk08ImY6/MuHHjst0rkxfZXXnw7Mbew8PDYN7SpUsL7FLfrNYpAKxcuTLLQGJp+f9f/fDwcLRp0wabN2/Gjh07MGbMGEyZMgV79+5FtWrV8tzLwYMH0bZtWzRo0ADz58+Hh4cHrKyssHTpUqxZsybP9Z59TZUqVcLMmTOznP/8Rj8/z9O8eXMMHz48y/nly5c3yfNMnjwZY8aMwdtvv42JEyeiSJEi0Gq1CA8Pz3RSMZD9Op4+fXq2ty7I+O6+//77WLp0KcLDwxEUFAS9Xq/ctyir53pWRqjKzR67Y8eOYf369Th79iwA4Ntvv8WYMWMQFBSEoKAgLFq0CFu3bjXYm5lRt2jRoi+sn1vdunVDnz59cObMGVStWhXr1q1D06ZNDZ4jr+v5+ffflLLbnrxoO5Ox7oYOHZrlvXoAoGzZsibosHBjkFE5b29vAP+ekf+8CxcuoGjRoi+8FLdMmTIQEfj6+uZqI12pUiVUqlQJo0ePxpEjRxAcHIyFCxdi0qRJAPL2V3d2yz77up7fqxAdHa3Mz4vw8HDMnj0b48ePz3TJ77PP9+zhnCdPniA2NjbLPScvknH4L8Oze1ByUqxYMdjZ2WW7TrVa7Qv/0y5TpgwAoHjx4rnqvUyZMvjoo4/w0UcfISYmBlWrVsWMGTOwatUqAHlbpxs2bICNjQ127NhhcL+MpUuX5rpGdj3+9ttvaNq0aY79lClTBunp6YiKisrx3kTZ1ShTpgwePHjwwvfN29sbe/bswYMHDwzCflbrLSvr169H48aN8fXXXxtMv3v3bq7+U89Yx05OTi/sdf369ejVqxdmzJihTHv8+HGurrAqVaoUbG1tERsbm+NyIoLBgwfjgw8+UHq7ceMGPD09lWU8PT0zHerIqJuxZyU73t7e2X4nMuZnaN++Pd59913l8NLFixcxcuRIg8fldj0bIz97HvMiY1tlZWVVIK9DLXiOjMp5eHigatWqWL58ucFG6ezZs9i5cydef/31F9bo2LEjLCwsMH78+Ey7j0VEOUZ+7949pKamGsyvVKkStFqtweEDe3v7XF+CmhGynl++Zs2aKF68OBYuXGhQ++eff8b58+cRGhqaq/rPytgr88MPP2S6k3CzZs1gbW2NL7/80uA9+Prrr5GUlGTU8zVr1sxgeH4PTXYsLCzQokUL/PDDDwaXaSYmJmLNmjWoV6+ecmgoOyEhIXBycsLkyZPx9OnTTPP/+usvAP9eKvv48WODeWXKlIGjo6PR69TCwgIajcbgUElcXFy+73TapUsXXL9+HUuWLMk079GjR0hOTgbw739iWq0WEyZMyLS34dl1m91r6tKlC44ePYodO3Zkmnf37l3lO/D6668jNTUVCxYsUOanpaVh7ty5uXo9FhYWmb5v33//fa7PaahRowbKlCmDL774Ag8ePMg0P2MdZ/dcc+fONVhH2bGyskLNmjVx4sSJHJdbtmwZ4uPjMWrUKGWam5ubEjSePn2KS5cuZdpDePLkSej1+hcG/ddffx2//vorjh49qkxLTk7G4sWL4ePjY3Ao0dnZGSEhIVi3bh2+++47WFtbZ7o5XW7XszHy8n3Jj+LFi6NRo0ZYtGgRbt68mWn+s5+BVxn3yLwCpk+fjlatWiEoKAh9+/bFo0ePMHfuXOj1+lzdP6VMmTKYNGkSRo4cibi4OLRv3x6Ojo6IjY3Fpk2b0L9/fwwdOhR79+7Fe++9hzfeeAPly5dHamoqVq5cCQsLC3Tq1EmpV6NGDezevRszZ86Ep6cnfH19szy2nfHczs7OWLhwIRwdHWFvb4/atWvD19cX06ZNQ58+fdCwYUO8+eabSExMxJw5c+Dj46Pcyj6vMs6V+e233wz2VBUrVgwjR47E+PHj0bJlS7Rt2xbR0dGYP38+atWqZbAr/GWYNGkSdu3ahXr16mHgwIGwtLTEokWLkJKSkqv71Tg5OWHBggXo2bMnqlevjm7duqFYsWK4evUqfvrpJwQHByMiIgIXL15E06ZN0aVLF/j7+8PS0hKbNm1CYmKiwc8l1KhRAwsWLMCkSZNQtmxZFC9ePNvzb0JDQzFz5ky0bNkS3bt3x61btzBv3jyULVvW4ByivOrZsyfWrVuHAQMGIDIyEsHBwUhLS8OFCxewbt067NixAzVr1kTZsmUxatQoTJw4EfXr10fHjh2h0+lw/PhxeHp6YsqUKTm+pmHDhuHHH39E69at0bt3b9SoUQPJycn4448/sH79esTFxaFo0aJo06YNgoODMWLECMTFxcHf3x8bN27M9TknrVu3xoQJE9CnTx/UrVsXf/zxB1avXm2wRzAnWq0WX331FVq1aoWKFSuiT58+KFGiBK5fv47IyEg4OTkpd7Ru3bo1Vq5cCb1eD39/fxw9ehS7d+/O8lycrLRr1w6jRo3CvXv3sgzR9+/fxyeffILJkyfD0dFRmd65c2clUB4+fBiPHz/O9MfVrl270KZNmxfuxRgxYgS+/fZbtGrVCoMHD0aRIkWwfPlyxMbGYsOGDZlO7O7atSt69OiB+fPnIyQkJNNe2NyuZ2PkZRuYX/PmzUO9evVQqVIl9OvXD6VLl0ZiYiKOHj2Ka9euZbov0SvJDFdKUR5kXK53/PjxHJfbvXu3BAcHi62trTg5OUmbNm0kKirKYJmMy6+fvQfNszZs2CD16tUTe3t7sbe3Fz8/Pxk0aJBER0eLiMjly5fl7bffljJlyoiNjY0UKVJEGjduLLt37zaoc+HCBWnQoIHY2toKgBdeiv3DDz+Iv7+/WFpaZrpsde3atVKtWjXR6XRSpEgReeutt+TatWs51hMxvPz6eRnvw/P3kRH593JrPz8/sbKyEjc3N/nf//6X6Z412V0y3KtXL/H29s5Xb886deqUhISEiIODg9jZ2Unjxo0z3ZPnRZ+PyMhICQkJEb1eLzY2NlKmTBnp3bu3nDhxQkRE/v77bxk0aJD4+fmJvb296PV6qV27tqxbt86gTkJCgoSGhoqjo6MAeOGl2F9//bWUK1dOdDqd+Pn5ydKlS5X3/Vl5ufxa5N/LuKdNmyYVK1YUnU4nLi4uUqNGDRk/frwkJSUZLPvNN98onx0XFxdp2LCh7Nq1K1ev6f79+zJy5EgpW7asWFtbS9GiRaVu3bryxRdfGNxT6Pbt29KzZ09xcnISvV4vPXv2VG5TkJvLrz/66CPx8PAQW1tbCQ4OlqNHj0rDhg0NennR5+X06dPSsWNHcXV1FZ1OJ97e3tKlSxfZs2ePssw///wjffr0kaJFi4qDg4OEhITIhQsXxNvbO1e3SkhMTBRLS0tZuXJllvOHDRsmNWvWNLgMXOTf+wWFhYWJs7Oz+Pn5yfbt2w3mnz9/XrlPVm78+eef0rlzZ3F2dhYbGxsJDAxU7k30vHv37inboFWrVmW5TG7Wc8bl1y+6RcGzstsGZnf5dVafdQAyaNAgg2nZ9fLnn39KWFiYuLu7i5WVlZQoUUJat24t69evz3XPaqYRycXtFImI6D+tb9++uHjxIg4ePGiymuHh4Thw4ABOnjz50s4roVcPgwwREb3Q1atXUb58eezZs8fgF7CNdfv2bXh7e2PdunW5OpePKDsMMkRERKRavGqJiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVOuVvyFeeno6bty4AUdHR17eR0REpBIigvv378PT0zPTDQ+f9coHmRs3bpjsx+SIiIjo5YqPj8/xR4lf+SCTcbvs+Pj4F/4+DRERERUO9+7dg5eXl8HPXmTllQ8yGYeTnJycGGSIiIhU5kWnhfBkXyIiIlItBhkiIiJSLbMGmQMHDqBNmzbw9PSERqPB5s2bs112wIAB0Gg0mD179kvrj4iIiAo3swaZ5ORkVKlSBfPmzctxuU2bNuHYsWPw9PR8SZ0RERGRGpj1ZN9WrVqhVatWOS5z/fp1vP/++9ixYwdCQ0NfUmdERESkBoX6qqX09HT07NkTw4YNQ8WKFXP1mJSUFKSkpCjj9+7dK6j2iIiIyMwK9cm+06ZNg6WlJQYPHpzrx0yZMgV6vV4ZeDM8IiKiV1ehDTInT57EnDlzsGzZsjz9tMDIkSORlJSkDPHx8QXYJREREZlToQ0yBw8exK1bt1CqVClYWlrC0tISV65cwUcffQQfH59sH6fT6ZSb3/EmeERERK+2QnuOTM+ePdGsWTODaSEhIejZsyf69Oljpq6IiIioMDFrkHnw4AEuXbqkjMfGxuLMmTMoUqQISpUqBVdXV4Plrays4O7ujtdee+1lt0pERESFkFmDzIkTJ9C4cWNlfMiQIQCAXr16YdmyZWbqioiIiNTCrEGmUaNGEJFcLx8XF1dwzRAREZHqFNqTfYmIiIhepNCe7EtEpGY+I34yWa24qbyrOVF2uEeGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFSLQYaIiIhUi0GGiIiIVItBhoiIiFTLrEHmwIEDaNOmDTw9PaHRaLB582Zl3tOnT/Hxxx+jUqVKsLe3h6enJ8LCwnDjxg3zNUxERESFilmDTHJyMqpUqYJ58+Zlmvfw4UOcOnUKY8aMwalTp7Bx40ZER0ejbdu2ZuiUiIiICiNLcz55q1at0KpVqyzn6fV67Nq1y2BaREQEAgMDcfXqVZQqVepltEhERESFmFmDTF4lJSVBo9HA2dk522VSUlKQkpKijN+7d+8ldEZERETmoJqTfR8/foyPP/4Yb775JpycnLJdbsqUKdDr9crg5eX1ErskIiKil0kVQebp06fo0qULRAQLFizIcdmRI0ciKSlJGeLj419Sl0RERPSyFfpDSxkh5sqVK9i7d2+Oe2MAQKfTQafTvaTuiIiIyJwKdZDJCDExMTGIjIyEq6uruVsiIiKiQsSsQebBgwe4dOmSMh4bG4szZ86gSJEi8PDwQOfOnXHq1Cls3boVaWlpSEhIAAAUKVIE1tbW5mqbiIiICgmzBpkTJ06gcePGyviQIUMAAL169cK4cePw448/AgCqVq1q8LjIyEg0atToZbVJREREhZRZg0yjRo0gItnOz2keERERkSquWiIiIiLKCoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqRaDDBEREakWgwwRERGpFoMMERERqZaluRsgIiIyNZ8RP5msVtzUUJPVItPjHhkiIiJSLQYZIiIiUi2zBpkDBw6gTZs28PT0hEajwebNmw3miwjGjh0LDw8P2NraolmzZoiJiTFPs0RERFTomDXIJCcno0qVKpg3b16W8z///HN8+eWXWLhwIX755RfY29sjJCQEjx8/fsmdEhERUWFk1pN9W7VqhVatWmU5T0Qwe/ZsjB49Gu3atQMArFixAm5ubti8eTO6dev2MlslIiKiQqjQniMTGxuLhIQENGvWTJmm1+tRu3ZtHD16NNvHpaSk4N69ewYDERERvZoKbZBJSEgAALi5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4tatW6hevboyLS0tDQcOHEBERARSUlJgYWFh8BidTgedTveyWyUiIiIzKNRBpmnTpvjjjz8MpvXp0wd+fn74+OOPM4UYIiIi+m8p1EHG0dERAQEBBtPs7e3h6uqaaToRERH99xTqIENERFQY+Yz4yWS14qaGmqzWf5Hqgsy+ffvM3QIREREVEoX6qiUiIiKinDDIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoxyBAREZFqMcgQERGRajHIEBERkWoV6iAzZcoU1KpVC46OjihevDjat2+P6Ohoc7dFREREhUShDjL79+/HoEGDcOzYMezatQtPnz5FixYtkJycbO7WiIiIqBCwNHcDOdm+fbvB+LJly1C8eHGcPHkSDRo0MFNXREREVFgU6iDzvKSkJABAkSJFsl0mJSUFKSkpyvi9e/cKvC8iIiIyj0J9aOlZ6enpCA8PR3BwMAICArJdbsqUKdDr9crg5eX1ErskIiKil0k1QWbQoEE4e/YsvvvuuxyXGzlyJJKSkpQhPj7+JXVIREREL5sqDi2999572Lp1Kw4cOICSJUvmuKxOp4NOp3tJnREREZE5FeogIyJ4//33sWnTJuzbtw++vr7mbomIiIgKkUIdZAYNGoQ1a9bghx9+gKOjIxISEgAAer0etra2Zu6OiIiIzK1QnyOzYMECJCUloVGjRvDw8FCGtWvXmrs1IiIiKgQK9R4ZETF3C0RERFSIFeo9MkREREQ5YZAhIiIi1WKQISIiItVikCEiIiLVKtQn+xIRUdZ8RvxkslpxU0NNVovoZeMeGSIiIlItBhkiIiJSLQYZIiIiUi0GGSIiIlItBhkiIiJSLQYZIiIiUi1efp0Pprz8EeAlkERERHnFPTJERESkWgwy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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_forest_loss(lossyear, geom)" + ] + }, + { + "cell_type": "markdown", + "id": "b7e20044", + "metadata": {}, + "source": [ + "### Displaying the Forest Loss Pixels Over Time\n", + "\n", + "Finally, create a function that reads the forest loss data for each year and plots a table showing the pixel count for each respective year." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "eb6bc18d", + "metadata": {}, + "outputs": [], + "source": [ + "def show_loss_table(lossyear: Raster, geom: shpg.Polygon):\n", + " # Read the raster\n", + " loss_dict = read_loss_dict(lossyear, geom)\n", + "\n", + " # Create a dictionary with the loss_dict values\n", + " data = {\n", + " \"Year\": [year + time_range[0].year for year in list(loss_dict.keys())[1:]],\n", + " \"#Pixels\": list(loss_dict.values())[1:],\n", + " }\n", + "\n", + " # Create a dataframe from the dictionary\n", + " df_loss = pd.DataFrame(data)\n", + "\n", + " # Sort the dataframe by the 'Year' column\n", + " df_loss = df_loss.sort_values(\"Year\")\n", + "\n", + " # Reset the index of the dataframe\n", + " df_loss = df_loss.reset_index(drop=True)\n", + "\n", + " # Amount of pixels\n", + " total_pixels = sum(loss_dict.values())\n", + " \n", + " return total_pixels, df_loss" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "01810a05", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total pixels: 1786\n", + "\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Year#Pixels
0200123
120043
2200798
320082
420112
52012244
6201328
72016183
8201768
920191
\n", + "
" + ], + "text/plain": [ + " Year #Pixels\n", + "0 2001 23\n", + "1 2004 3\n", + "2 2007 98\n", + "3 2008 2\n", + "4 2011 2\n", + "5 2012 244\n", + "6 2013 28\n", + "7 2016 183\n", + "8 2017 68\n", + "9 2019 1" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "total_pixels, df_loss = show_loss_table(lossyear, geom)\n", + "\n", + "print(f\"Total pixels: {total_pixels}\\n\")\n", + "\n", + "# Print the dataframe without the indexes\n", + "df_loss" + ] + } + ], + "metadata": { + "description": "This notebook contains functions to download and process the Global Forest Change (Hansen) maps.", + "disk_space": "", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + }, + "name": "Download Global Forest Change (Hansen) maps.", + "running_time": "", + "tags": [ + "Remote Sensing", + "Deforestation", + "Sustainability" + ] + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/notebooks/forest/forest_change_detection.ipynb b/notebooks/forest/forest_change_detection.ipynb new file mode 100644 index 00000000..6261efde --- /dev/null +++ b/notebooks/forest/forest_change_detection.ipynb @@ -0,0 +1,901 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Detecting Forest Changes with FarmVibes.AI\n", + "\n", + "This notebook demonstrates how to detect forest changes in ALOS PALSAR 2.1 Forest/Non-Forest maps using FarmVibes.AI. The reader can check [this notebook](./download_alos_forest_map.ipynb) to see how to download and visualize ALOS forest maps.\n", + "\n", + "This notebook is divided into the following sections:\n", + "\n", + "1. **Workflow setup**: It checks the workflow documentation using the FarmVibes.AI python client, and define the evaluation geometry and time range.\n", + "2. **Running the workflow**: The section shows how to execute the forest changes workflow and provide its parameters.\n", + "3. **Interpreting the results**. Finally, we will visualize and discuss the results." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Micromamba environment setup\n", + "To install the required packages, see [this README file](../README.md). You can activate the environment with the following command:\n", + "```bash\n", + "$ micromamba activate farmvibes-ai\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Workflow setup\n", + "\n", + "In this Jupyter notebook, we are going to run the `forest_ai/deforestation/forest_change_detection` workflow in FarmVibes.AI, \n", + "designed to analyze changes in forest coverage over a specific time range within a user-defined geographical area. \n", + "The next cells will document the workflow using the FarmVibes.AI default client and define the user input (geometry + time-range).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "text/html": [
+                            "
Workflow: forest_ai/deforestation/alos_trend_detection\n",
+                            "
\n" + ], + "text/plain": [ + "\u001b[1;32mWorkflow:\u001b[0m \u001b[1;4;38;5;27mforest_ai/deforestation/alos_trend_detection\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Description:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mDescription:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    Detects increase/decrease trends in forest pixel levels over the user-input geometry and time   \n",
+                            "    range for the ALOS forest map. This workflow combines the alos_forest_extent_download_merge and \n",
+                            "    ordinal_trend_detection workflows to detect increase/decrease trends in the forest pixel levels \n",
+                            "    over the user-provided geometry and time range for the ALOS forest map. The ALOS PALSAR 2.1     \n",
+                            "    Forest/Non-Forest Maps are downloaded in the alos_forest_extent_download_merge workflow.  Then  \n",
+                            "    the ordinal_trend_detection workflow clips the ordinal raster to the user-provided geometry and \n",
+                            "    time range and determines if there is an increasing or decreasing trend in the forest pixel     \n",
+                            "    levels over them. alos_trend_detection uses the Cochran-Armitage test to detect trends in the   \n",
+                            "    forest levels over the years.  The null hypothesis is that there is no trend in the pixel levels\n",
+                            "    over the list of rasters. The alternative hypothesis is that there is a trend in the forest     \n",
+                            "    pixel levels over the list of rasters (one for each year). It returns a p-value and a z-score.  \n",
+                            "    If the p-value is less than some significance level, the null hypothesis is rejected and the    \n",
+                            "    alternative hypothesis is accepted. If the z-score is positive, the trend is increasing.  If the\n",
+                            "    z-score is negative, the trend is decreasing.                                                   \n",
+                            "
\n" + ], + "text/plain": [ + " Detects increase/decrease trends in forest pixel levels over the user-input geometry and time \n", + " range for the ALOS forest map. This workflow combines the alos_forest_extent_download_merge and \n", + " ordinal_trend_detection workflows to detect increase/decrease trends in the forest pixel levels \n", + " over the user-provided geometry and time range for the ALOS forest map. The ALOS PALSAR 2.1 \n", + " Forest/Non-Forest Maps are downloaded in the alos_forest_extent_download_merge workflow. Then \n", + " the ordinal_trend_detection workflow clips the ordinal raster to the user-provided geometry and \n", + " time range and determines if there is an increasing or decreasing trend in the forest pixel \n", + " levels over them. alos_trend_detection uses the Cochran-Armitage test to detect trends in the \n", + " forest levels over the years. The null hypothesis is that there is no trend in the pixel levels\n", + " over the list of rasters. The alternative hypothesis is that there is a trend in the forest \n", + " pixel levels over the list of rasters (one for each year). It returns a p-value and a z-score. \n", + " If the p-value is less than some significance level, the null hypothesis is rejected and the \n", + " alternative hypothesis is accepted. If the z-score is positive, the trend is increasing. If the\n", + " z-score is negative, the trend is decreasing. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Sources:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSources:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - user_input (vibe_core.data.core_types.DataVibe): Time range and geometry of interest.         \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1muser_input\u001b[0m (\u001b[34mvibe_core.data.core_types.DataVibe\u001b[0m): Time range and geometry of interest. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Sinks:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mSinks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - merged_raster (vibe_core.data.rasters.Raster): Merged raster of the ALOS PALSAR 2.1           \n",
+                            "    Forest/Non-Forest Map for the user-provided geometry and time range.                            \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mmerged_raster\u001b[0m (\u001b[34mvibe_core.data.rasters.Raster\u001b[0m): Merged raster of the ALOS PALSAR 2.1 \n", + " Forest/Non-Forest Map for the user-provided geometry and time range. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - categorical_raster (vibe_core.data.rasters.CategoricalRaster): Categorical raster of the ALOS \n",
+                            "    PALSAR 2.1 Forest/Non-Forest Map for the user-provided geometry and time range before the merge \n",
+                            "    operation.                                                                                      \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mcategorical_raster\u001b[0m (\u001b[34mvibe_core.data.rasters.CategoricalRaster\u001b[0m): Categorical raster of the ALOS \n", + " PALSAR 2.1 Forest/Non-Forest Map for the user-provided geometry and time range before the merge \n", + " operation. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - recoded_raster (vibe_core.data.rasters.Raster): Recoded raster of the ALOS PALSAR 2.1         \n",
+                            "    Forest/Non-Forest Map for the user-provided geometry and time range.                            \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mrecoded_raster\u001b[0m (\u001b[34mvibe_core.data.rasters.Raster\u001b[0m): Recoded raster of the ALOS PALSAR 2.1 \n", + " Forest/Non-Forest Map for the user-provided geometry and time range. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - clipped_raster (vibe_core.data.rasters.Raster): Clipped ordinal raster for the user-provided  \n",
+                            "    geometry and time range.                                                                        \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mclipped_raster\u001b[0m (\u001b[34mvibe_core.data.rasters.Raster\u001b[0m): Clipped ordinal raster for the user-provided \n", + " geometry and time range. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - trend_test_result (vibe_core.data.core_types.OrdinalTrendTest): Cochran-armitage test results \n",
+                            "    composed of p-value and z-score.                                                                \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mtrend_test_result\u001b[0m (\u001b[34mvibe_core.data.core_types.OrdinalTrendTest\u001b[0m): Cochran-armitage test results \n", + " composed of p-value and z-score. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Parameters:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mParameters:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - pc_key (default: None): Planetary Computer API key.                                           \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mpc_key\u001b[0m (\u001b[34mdefault: None\u001b[0m): Planetary Computer API key. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - from_values (default: task defined): Values to recode from.                                   \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mfrom_values\u001b[0m (\u001b[34mdefault: task defined\u001b[0m): Values to recode from. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - to_values (default: task defined): Values to recode to.                                       \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mto_values\u001b[0m (\u001b[34mdefault: task defined\u001b[0m): Values to recode to. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+                            "Tasks:\n",
+                            "
\n" + ], + "text/plain": [ + "\n", + "\u001b[1;32mTasks:\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - alos_forest_extent_download_merge: Downloads Advanced Land Observing Satellite (ALOS)         \n",
+                            "    forest/non-forest classification map and merges it into a single raster.                        \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1malos_forest_extent_download_merge\u001b[0m: Downloads Advanced Land Observing Satellite (ALOS) \n", + " forest/non-forest classification map and merges it into a single raster. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
    - ordinal_trend_detection: Detects increase/decrease trends in the pixel levels over the        \n",
+                            "    user-input geometry and time range.                                                             \n",
+                            "
\n" + ], + "text/plain": [ + " - \u001b[1mordinal_trend_detection\u001b[0m: Detects increase/decrease trends in the pixel levels over the \n", + " user-input geometry and time range. \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import sys\n", + "\n", + "from shapely.geometry import box\n", + "from shapely import geometry as shpg\n", + "from typing import cast\n", + "from datetime import datetime\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "from matplotlib import pyplot as plt\n", + "from typing import Optional, List\n", + "\n", + "from vibe_core.client import get_default_vibe_client\n", + "from vibe_core.data import CategoricalRaster, Raster\n", + "from vibe_core.data import CategoricalRaster\n", + "\n", + "sys.path.append(\"../\")\n", + "from shared_nb_lib.raster import read_raster\n", + "from shared_nb_lib.plot import plot_categorical_maps\n", + "\n", + "\n", + "# Create the FarmVibes.AI default client\n", + "client = get_default_vibe_client()\n", + "\n", + "WORKFLOW_NAME = \"forest_ai/deforestation/alos_trend_detection\"\n", + "client.document_workflow(WORKFLOW_NAME)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Workflow discussion\n", + "\n", + "The workflow tasks involve downloading Advanced Land Observing Satellite (ALOS) forest/non-forest classification maps and merging them into a single raster (`alos_forest_extent_download_merge`). The ALOS products are clipped to the user's geometry (`clip`), and the result is used to calculate the cochran-armitage trend test (`trend_rest_result`). This test checks if there has been a statistically significant trend in the forest distribution over time.\n", + "\n", + "The `user_input` is composed of a geometry and a time-range, which will be defined in the next cell.\n", + "\n", + "As output (`sinks`), the workflow provides a list of merged rasters (`merged_raster`) that encompass the user input geometry for each year defined in the time-range, the products are available in the [Planetary Computer dataset](https://planetarycomputer.microsoft.com/dataset/alos-fnf-mosaic).\n", + "It also produces a list of categorical rasters (`categorical_raster`) that intersect with the user-provided geometry and time range. The distinction between `categorical_raster` and `merged_raster` is that multiple `categorical_raster` tiles can be combined to form the `merged_raster` if the user's geometry intersects with more than one forest tile. The `recoded_raster` contains the rasters with the recoded values for the forest maps. Finally, `trend_rest_result` determines whether the pixel distribution has changed over time. This is useful for determining if there is statistical evidence of trend in the forest area over time. This change could represent either an increase or decrease in the frequency of forest pixels (i.e., only changes are detected).\n", + "\n", + "The workflow parameters are the Planetary Computer API key (`pc_key`) and the recode rasters parameters that are used to map the values from the dataset raster to the recoded raster. For example, if the original raster has values `(2, 1, 3, 4, 5)` and assuming the default values of `from_values` and `to_values` are respectively `[1, 2, 3, 4, 5]` and `[6, 7, 8, 9, 10`], the recoded raster will have values `(7, 6, 8, 9, 10)`.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "geo_json = {\n", + " \"type\": \"Feature\",\n", + " \"geometry\": {\n", + " \"type\": \"Polygon\",\n", + " \"coordinates\": [\n", + " [\n", + " [-86.783827, 14.565498],\n", + " [-86.780459, 14.569303],\n", + " [-86.774283, 14.565106],\n", + " [-86.779591, 14.557595],\n", + " [-86.783827, 14.565498],\n", + " ]\n", + " ],\n", + " },\n", + " \"properties\": {},\n", + "}\n", + "\n", + "\n", + "geom = shpg.shape(geo_json[\"geometry\"])\n", + "time_range = ((datetime(2017, 1, 1), datetime(2020, 12, 31)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Running the Workflow\n", + "\n", + "Observe that we pass the geometry and time-range as workflow inputs, along with the following parameters:\n", + "\n", + "* `pc_key`: This corresponds to the Planetary Computer API key, which is useful for downloading planetary computer imagery.\n", + "* `from_values`: Values to recode from, for the ALOS dataset the default value is `[4, 3, 0, 2, 1]`.\n", + "* `to_values`: Values to recode to, `[0, 0, 0, 1, 1]` are the default values for the ALOS dataset.\n", + "\n", + "\n", + "For this particular case, we are mapping the forest values from [ALOS dataset](https://planetarycomputer.microsoft.com/dataset/alos-fnf-mosaic) to `1` and `2` depending on the canopy cover level and everything else to `0`.\n", + "\n", + "| Encoded Value | Description | Recoded Value (Forest-Level) | Recoded Value Semantics |\n", + "| ------------- | ----------- | ----------- | --------------|\n", + "| 0 | No data | 0 | Non-Forest |\n", + "| 1 | Forest (>90% canopy cover) | 2 | Dense-Forest |\n", + "| 2 | Forest (10-90% canopy cover) | 1 | Forest |\n", + "| 3 | Non-forest | 0 | Non-Forest |\n", + "| 4 | Water | 0 | Non-Forest |\n", + "\n", + "Please check the [workflow documentation page](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/WORKFLOWS.html) to see how parameters are provided. Also, refer to the [SECRETS documentation](https://microsoft.github.io/farmvibes-ai/docfiles/markdown/SECRETS.html) to learn how a secret can be added to the FarmVibes.AI cluster.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "application/vnd.jupyter.widget-view+json": {
+                            "model_id": "671c2cedcf4a49b2a183d9014f732178",
+                            "version_major": 2,
+                            "version_minor": 0
+                        },
+                        "text/plain": [
+                            "Output()"
+                        ]
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                },
+                {
+                    "data": {
+                        "text/html": [
+                            "
\n"
+                        ],
+                        "text/plain": []
+                    },
+                    "metadata": {},
+                    "output_type": "display_data"
+                }
+            ],
+            "source": [
+                "# Execute the workflow\n",
+                "run = client.run(\n",
+                "    WORKFLOW_NAME,\n",
+                "    \"Forest Change Detection\",\n",
+                "    geometry=geom,\n",
+                "    time_range=time_range,\n",
+                "    parameters={\n",
+                "        \"pc_key\": \"@SECRET(eywa-secrets, pc-sub-key)\",\n",
+                "        \"from_values\": [4, 3, 0, 2, 1],\n",
+                "        \"to_values\": [0, 0, 0, 1, 2]\n",
+                "    },\n",
+                ")\n",
+                "run.monitor()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "metadata": {},
+            "source": [
+                "## 3. Interpreting the results\n",
+                "\n",
+                "The `trend_rest_result` is an output from the workflow run, which performs a trend test (Cochan-Armitage). The result of this test includes a `csv` file containing a contingency table, which shows the distribution of pixel counts across the different categories of land cover for each year. This allows us to observe how the distribution of pixel categories has changed over time."
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 4,
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "text/html": [
+                            "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
2017/01/01-2017/12/312018/01/01-2018/12/312019/01/01-2019/12/312020/01/01-2020/12/31
category
Non-Forest178.049.0107.069.0
Forest675.0628.0553.0363.0
Dense-forest273.0449.0466.0694.0
\n", + "
" + ], + "text/plain": [ + " 2017/01/01-2017/12/31 2018/01/01-2018/12/31 \\\n", + "category \n", + "Non-Forest 178.0 49.0 \n", + "Forest 675.0 628.0 \n", + "Dense-forest 273.0 449.0 \n", + "\n", + " 2019/01/01-2019/12/31 2020/01/01-2020/12/31 \n", + "category \n", + "Non-Forest 107.0 69.0 \n", + "Forest 553.0 363.0 \n", + "Dense-forest 466.0 694.0 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "trend_test_test_results = run.output[\"trend_test_result\"][0] # type: ignore\n", + "df = pd.read_csv(trend_test_test_results.assets[0].path_or_url, index_col=0) # type: ignore\n", + "\n", + "\n", + "level_names = [\"Non-Forest\", \"Forest\", \"Dense-forest\"]\n", + "index = dict(zip(df.index, level_names))\n", + "df.index = df.index.map(index)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Read the output data\n", + "\n", + "In the next cell, we adopt the user-provided geometry to read the output raster and create some buffer around it." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Define your geometry\n", + "bounding_box = box(*geom.buffer(0.01).bounds)\n", + "\n", + "# Get the bounds of the geometry\n", + "minx, miny, maxx, maxy = bounding_box.bounds\n", + "\n", + "merged_rasters = run.output[\"merged_raster\"]\n", + "categories = cast(CategoricalRaster, run.output[\"categorical_raster\"][0]).categories\n", + "forest_images = []\n", + "\n", + "for raster in merged_rasters:\n", + " merged_raster = cast(Raster, raster)\n", + " forest_images.append(read_raster(merged_raster, bounding_box)[0][0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot the result map\n", + "\n", + "Finally, we plot the raster images with the existing categories and the user-provided geometry (red area within the plot)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABEAAAAK7CAYAAADyevqvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3wURf8H8M8lIQkthB5CSei9N0EpASQUARFFAwTFilKeoIDh+akEVJqoEVGxgIgGESlWpCm9FwFBunQCCJiEAEkgud8fee68u+zubb3bu3zer1deyt3u7Oze3tzszHdmLFar1QoiIiIiIiIiIj8W4O0MEBEREREREREZjQ0gREREREREROT32ABCRERERERERH6PDSBERERERERE5PfYAEJEREREREREfo8NIERERERERETk99gAQkRERERERER+jw0gREREREREROT32ABCRERERERERH6PDSBERERERERE5PfYAEJERKb04YcfwmKxoG3btqLbWCwWjBw50m1ahw4dwpAhQ1C5cmWEhIQgMjISgwcPxqFDhwS3/+OPP/Dwww8jKioKoaGhqFy5Mu6//368//77bo/1xBNPwGKxCP6tXLnS7f6edvHiRSQlJWHfvn2ytp8/f779fDZv3lzgfavViqpVq8JiseCBBx7QObdERERE6gV5OwNERERCUlJSEB0djZ07d+LEiROoVauWqnSWLVuGuLg4lClTBk899RSqV6+O06dPY+7cuViyZAkWLVqE/v3727ffunUrYmJiUK1aNTzzzDOIiIjAuXPnsH37drz33nsYNWqU22OGhITgs88+K/B606ZNVZ2DkS5evIhJkyYhOjoazZo1k71faGgoFi5ciPvuu8/p9Q0bNuD8+fMICQnROadERERE2rABhIiITOfUqVPYunUrli1bhueeew4pKSmYOHGi4nROnjyJ+Ph41KhRAxs3bkT58uXt7/3nP/9Bhw4dEB8fjwMHDqBGjRoAgDfffBOlSpXCrl27EB4e7pTelStXZB03KCgIQ4YMUZxfOW7duoVixYoZkrYSvXr1wrfffotZs2YhKOjf6sTChQvRsmVLXL161Yu5IyIiIiqIQ2CIiMh0UlJSULp0afTu3RsPP/wwUlJSVKXz1ltv4datW/jkk0+cGj8AoFy5cvj4449x8+ZNzJgxw/76yZMn0bBhwwKNHwBQ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i/T0dPTu3dttGgMHDsSFCxfw6aefFnjv9u3buHnzJoD8c3TVrFkzALAPQSlevDgAFFiCV64SJUrgo48+QlJSEvr06SO6XWBgICwWi9P8HadPn8Z3330nuP22bduc5gY5d+4cvv/+e3Tv3l2XyBUiIiIqfBgBQkREpvDDDz/gxo0b6Nu3r+D799xzD8qXL4+UlBSnpV53796NN954o8D2nTt3xn333YcvvvgCgwcPRuPGjfHUU0+hevXqOH36NObOnYurV6/i66+/Rs2aNe37jRo1Crdu3UL//v1Rr1495OTkYOvWrfjmm28QHR1dYEJSpcqXL48JEyZg0qRJ6NGjB/r27YujR4/iww8/ROvWrTFkyBC3acTHx2Px4sUYPnw41q1bh3vvvRe5ubk4cuQIFi9ejFWrVqFVq1aYPHkyNm7ciN69eyMqKgpXrlzBhx9+iCpVqtgjYmrWrInw8HDMmTMHJUuWRPHixdG2bVtUr15d9jk9/vjjbrfp3bs33nnnHfTo0QODBg3ClStX8MEHH6BWrVqCw5QaNWqE2NhYjB49GiEhIfjwww8BAJMmTZKdLyIiIiIn3l6GhoiIyGq1Wvv06WMNDQ213rx5U3SbJ554wlqkSBHr1atXrVarVXC5Wdvf66+/bt/vwIED1ri4OGulSpWsRYoUsUZERFjj4uKsf/zxR4Fj/PLLL9Ynn3zSWq9ePWuJEiWswcHB1lq1allHjRplvXz5stvzePzxx63Fixd3u93s2bOt9erVsxYpUsRasWJF6/PPP2/9559/nLbp1KmTtWHDhoL75+TkWKdPn25t2LChNSQkxFq6dGlry5YtrZMmTbKmp6dbrVar9ddff7X269fPGhkZaQ0ODrZGRkZa4+LirMeOHXNK6/vvv7c2aNDAGhQU5HZJXMdlcKUILYM7d+5ca+3ata0hISHWevXqWT///HPrxIkTra7VEfxveeOvvvrKvn3z5s2t69atkzwmERERkRSL1SoQ50tERETkJRaLBSNGjMDs2bO9nRUiIiLyI5wDhIiIiIiIiIj8HhtAiIiIiIiIiMjvsQGEiIiIiIiIiPweV4EhIiIiU+H0ZERERGQERoAQERERERERkd9jAwgRERERERER+T02gBARERERERGR32MDCBERERERERH5PTaAEBEREREREZHfYwMIEREREREREfk9NoAQERERERERkd9jAwgRERERERER+T02gBARERERERGR32MDCBERERERERH5PTaAEBEREREREZHfYwMIEREREREREfk9NoAQERERERERkd9jAwgRERERERER+T02gBARERERERGR32MDCBERERERERH5PTaAEBEREREREZHfYwMIEREREREREfk9NoAQERERERERkd9jAwgRERERERER+T02gBARERERERGR32MDCBERERERERH5PTaAEBEREREREZHfYwMIEREREREREfk9NoAQERERERERkd9jAwgRERERERER+T02gBARERERERGR32MDCBERERERERH5PTaAEBEREREREZHfYwMIEREREREREfk9NoAQ+bldu3Zh5MiRaNiwIYoXL45q1aph4MCBOHbsWIFtDx8+jB49eqBEiRIoU6YM4uPj8ffffxfY7s0330Tfvn1RsWJFWCwWJCUlCR47OjoaFotF8K927dp6nyoRkV/xZvkNAGvXrkVMTAzKlSuH8PBwtGnTBl9++aWep0hERORRQd7OABEZa/r06diyZQseeeQRNGnSBJcuXcLs2bPRokULbN++HY0aNQIAnD9/Hh07dkSpUqUwZcoUZGZmYubMmfjjjz+wc+dOBAcH29N85ZVXEBERgebNm2PVqlWix05OTkZmZqbTa2fOnMErr7yC7t27G3PCRER+wpvl9w8//IAHH3wQ7dq1Q1JSEiwWCxYvXoyhQ4fi6tWrGDNmjOHnT0REpDsrEfm1LVu2WLOzs51eO3bsmDUkJMQ6ePBg+2vPP/+8tWjRotYzZ87YX1uzZo0VgPXjjz922v/UqVNWq9Vq/fvvv60ArBMnTpSdn9dff90KwLplyxblJ0NEVIh4s/y+//77rZGRkdasrCz7a3fu3LHWrFnT2qRJE41nRkRE5B0cAkPk59q3b+/U+wcAtWvXRsOGDXH48GH7a0uXLsUDDzyAatWq2V/r1q0b6tSpg8WLFzvtHx0drTo/CxcuRPXq1dG+fXvVaRARFQbeLL8zMjJQunRphISE2F8LCgpCuXLlULRoURVnQ0RE5H1sACEqhKxWKy5fvoxy5coBAC5cuIArV66gVatWBbZt06YNfv/9d12O+/vvv+Pw4cMYNGiQLukRERU2niq/O3fujEOHDuHVV1/FiRMncPLkSbz++uvYvXs3xo8fr+kciIiIvIVzgBAV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THjNlPO1a1aqVClvZ4F8AMtv38Nrpo4vXTeW30RE6imaqCMvL8/p79y5c2jcuDHi4uKwc+dOpKenIz09HTt27MBjjz2Gpk2b4ty5c0blnYiIiIiIiIhIFk0zlY4YMQK1a9fGV199hVatWqFkyZIoWbIkWrdujZSUFNSsWRMjRozQK69ERERERERERKpoagD57bff0KVLF9H3u3btil9//VXLIYhUCwkJwcSJExESEuLtrPgMXjPleM2I9MfvlXK8ZurwuhERFS6aVoGpUKECevTogQULFgi+Hx8fj1WrVuHKlSuqM0hEREREROQJXAWGyL9pigAZPHgwUlJSMHr0aBw/ftw+N8jx48cxatQoLFy4EIMHD9Yrr0REREREREREqihaBcbV9OnTcfXqVcyePRsffPABAgLy21Py8vJgtVoRFxeH6dOn65JRIiIiIiIiIiK1NDWABAcH48svv8S4ceOwYsUKnDlzBgAQFRWFnj17omnTprpkkoiIiIiIiIhIC00NIDZNmjRBkyZN9EiKiIiIiIiIiEh3muYAISIiIiIiIiLyBZoiQAICAmCxWNxul5ubq+UwRERERERERESaaGoAee211wo0gOTm5uL06dP47rvvULduXTzwwAOaMkhEREREREREpJWmBpCkpCTR91JTU3HPPfegTp06Wg5BRERERERERKSZYXOAVKpUCcOHD8frr79u1CGIiIiIiIjIJK5du4YKFSrg9OnT3s4K+bmcnBxER0dj9+7divYzdBLU4sWL49SpU0YegoiIiIiIyC888cQTsFgsBf5OnDjh1Tw9+OCDsrZ988030a9fP0RHR9tfGz16NFq2bImQkBA0a9ZMcL8DBw6gQ4cOCA0NRdWqVTFjxgy3x7px4wYSEhIQFRWFokWLon379ti1a5fTNlarFa+99hoqVaqEokWLolu3bjh+/Lj9/ezsbMTHxyMsLAx16tTB2rVrnfZ/6623MGrUKFnnTp4VHByMsWPH4uWXX1a0n2ENIAcPHsSsWbM4BIaIiIiIiEimHj16IDU11emvevXqqtLKycnROXfibt26hblz5+Kpp54q8N6TTz6JRx99VHC/jIwMdO/eHVFRUdizZw/eeustJCUl4ZNPPpE83tNPP401a9bgyy+/xB9//IHu3bujW7duuHDhgn2bGTNmYNasWZgzZw527NiB4sWLIzY2FllZWQCATz75BHv27MG2bdvw7LPPYtCgQbBarQCAU6dO4dNPP8Wbb76p9pKQQWz39eDBg7F582YcOnRI9r6aGkCqV6+OGjVqFPgrU6YMmjZtisuXL+Odd97RcggiIiIiIqJCIyQkBBEREU5/gYGBAIANGzagTZs2CAkJQaVKlZCYmIi7d+/a9+3cuTNGjhyJhIQElCtXDrGxsQDyO6d79uyJEiVKoGLFioiPj8fVq1ft+y1ZsgSNGzdG0aJFUbZsWXTr1g03b95EUlISvvjiC3z//ff2aJT169cL5nvFihUICQnBPffc4/T6rFmzMGLECNSoUUNwv5SUFOTk5GDevHlo2LAhHnvsMYwePVryOfL27dtYunQpZsyYgY4dO6JWrVpISkpCrVq18NFHHwHIj/5ITk7GK6+8gn79+qFJkyZYsGABLl68iO+++w4AcPjwYfTt2xcNGzbEiBEj8Pfff9uvy/PPP4/p06cjLCxM4tP6ly3/ts9m5MiR9vfeeecdNG7cGMWLF0fVqlXxwgsvIDMz0/7+/PnzER4ejlWrVqF+/fooUaKEvSHMJi8vD5MnT0aVKlXs0TQrV660v3/69GlYLBYsWrQI7du3R2hoKBo1aoQNGzbYr0etWrUwc+ZMp3zv27fPbZSR1LmdPXsW/fr1Q4kSJRAWFoaBAwfi8uXLAIBjx47BYrHgyJEjTum9++67qFmzpv3f7u5Psfu6dOnSuPfee7Fo0SKJT8aZpgaQTp06Ffjr3Lkzhg0bhvfffx9nzpxB165dtRyCiIiIiIio0Ltw4QJ69eqF1q1bY//+/fjoo48wd+5cvPHGG07bffHFFwgODsaWLVswZ84cpKWloUuXLmjevDl2796NlStX4vLlyxg4cCCA/MUr4uLi8OSTT+Lw4cNYv349HnroIVitVowdOxYDBw50ikpp3769YP42bdqEli1bKj6vbdu2oWPHjggODra/Fhsbi6NHj+Kff/4R3Ofu3bvIzc1FaGio0+tFixbF5s2bAeRHcFy6dAndunWzv1+qVCm0bdsW27ZtAwA0bdoUmzdvxu3bt7Fq1SpUqlQJ5cqVQ0pKCkJDQ9G/f39Z5/DRRx9hxIgRePbZZ/HHH3/ghx9+QK1atezvBwQEYNasWTh06BC++OIL/Pbbbxg/frxTGrdu3cLMmTPx5ZdfYuPGjTh79izGjh1rf/+9997D22+/jZkzZ+LAgQOIjY1F3759nYb0AMC4cePw0ksv4ffff0e7du3Qp08fXLt2DRaLBU8++SQ+//xzp+0///xzeyOS0nPLy8tDv379cP36dWzYsAFr1qzBX3/9ZY/2qVOnDlq1aoWUlBSnNFNSUjBo0CAAcHt/2rje1zZt2rTBpk2bxD8cV1YiIiIiIiKypqenWwFYp52eZk2+nqz5b9rpadb/Z+/O42O4/z+AvzYnQcQdKRJnirrVUa27bnWVukJLVSkaN70EratVQfX4ts6iqi16aV1130Ko+yZxxRURJEjm90e6+9vdzO7OzM7szm5ez8cjD3Z35jOfOfazn/nM+/P5ABASEhKEe/fumf7S0tJEt9+3b1/B19dXyJMnj+nv1VdfFQRBEN577z0hMjJSyMzMNC0/b948IW/evEJGRoYgCILQqFEjoUaNGhZpTp48WWjRooXFewkJCQIA4dSpU0JcXJwAQLh48aLNPHXo0MHhsevQoYPQr18/m59PmDBBqFatWrb3X375ZeGtt96yeO/YsWMCAOH48eM206tfv77QqFEj4cqVK8LTp0+F77//XvDx8REqVKggCIIg7Ny5UwAgXL161WK9rl27Ct26dRMEQRAeP34sDB48WIiIiBBq164tbN++Xbh9+7ZQpkwZ4fLly8L7778vlC1bVmjRooWQmJhoMy9hYWHC+++/b/Nzaz/99JNQqFAh0+uFCxcKAISzZ8+a3ps3b55QrFgxi2188sknFuk8//zzwuDBgwVBEIQLFy5kXbvTppk+f/LkiVCiRAlh+vTpgiAIwpUrVwRfX19h7969pv0vXLiwsGjRIkX7tn79esHX11e4fPmy6T3judu3b58gCIIwa9YsoWzZsqbPT506JQAQTpw4IQiC4+tTEMSva6PZs2cLERERNvNvzakIkH79+mHv3r02P9+3bx/69evnzCaIiIiIiIg8WsmSJZE/f37T39SpU20u26RJE8THx5v+5syZAyCru0b9+vVhMBhMyzZo0ACpqalITEw0vWcdhXH48GFs3rwZefPmNf09++yzAIBz586hWrVqaNasGapUqYKuXbvi22+/tRl5Yc+jR4+yRWSoYfv27RZ5N0YTfP/99xAEAc888wwCAwMxZ84c9OjRAz4+0m9x/f39MW/ePFy4cAH79+/Hiy++iJEjR2LYsGE4dOgQ1qxZ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Z0lNX+yakFK+qslVxwSQHhHiqvyQ5wgMDERoaKjFn6+vLwBg69atqFOnDgIDA1G8eHGMGzfOol7euHFjDBkyBNHR0ShcuDBatmwJADh69Chat26NvHnzolixYoiKijI1CgDAzz//jCpVqiB37twoVKgQmjdvjgcPHiAmJgaLFy/Gr7/+arpP2LJli2i+165di8DAQNSrV8/i/dKlS6N58+b4/vvv8fDhQ7v7/v333+O9995DmzZtUKZMGQwaNAht2rTBzJkzTct8/vnnGDBgAN544w1UqlQJX3/9NYKCgrBgwQIAwIkTJ9C4cWPUrl0bPXr0QHBwMC5cuAAAGDNmDAYNGoRSpUpJOhe///47nn/+eeTKlQuFCxdGp06dLPJau3Zt5MuXD6GhoejZs6epEQYAtmzZAoPBgE2bNqF27doICgrCCy+8gFOnTlls46uvvkLZsmUREBCAyMhIfP/99xafGwwGfPXVV2jdujVy586NMmXK4OeffzZ93rRpUwwZMsRinZs3byIgIACbNm1StG93795Fnz59UKBAAQQFBaF169Y4c+YMACAlJQW5c+fO1kCxevVq5MuXz3SOExIS0K1bN4SEhKBgwYLo0KGDRdeo119/HR07dsQnn3yCsLAwREZGAgB8fX3Rpk0brFixwmbencEGEJ148OABqlWr5rA1cvXq1dizZw/CwsIkpVu5cmWL1uMdO3aYPitZsmS21uWJEycib968aN26NQAgIyMDbdu2xePHj7Fr1y4sXrwYixYtwkcffaR4X6VUQtWqCDhb4VXScEL6pVUlWyz0Wy83HER64OqbXCNPbez11Hzb46ldH4n05MqVK2jTpg2ef/55HD58GF999RXmz5+Pjz/+2GK5xYsXIyAgADt37sTXX3+N5ORkNG3aFDVq1MCBAwfw999/48aNG+jWrRsA4Nq1a+jRowf69euHEydOYMuWLejcuTMEQcCoUaPQrVs3i6iUF154QTR/27dvR61atbK9f/z4cdSpUwcffPABihUrhn79+mHr1q0QBCHbsunp6ciVK5fFe7lz5zbdwzx+/BhxcXFo3ry56XMfHx80b94cu3fvBgBUq1YNBw4cwN27dxEXF4dHjx6hXLly2LFjBw4ePIhhw4ZJOt5//vknOnXqhDZt2uDQoUPYtGmTRTebJ0+eYPLkyTh8+DDWrFmDixcv4vXX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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "color_dict = {\n", + " 0: \"black\",\n", + " 1: \"darkgreen\",\n", + " 2: \"lightgreen\",\n", + " 3: \"gray\",\n", + " 4: \"blue\",\n", + "}\n", + "\n", + "titles = [\n", + " str(raster.time_range[0].year)\n", + " for raster in run.output[\"merged_raster\"]\n", + "]\n", + "\n", + "plot_categorical_maps(\n", + " forest_images,\n", + " color_dict,\n", + " categories,\n", + " titles=titles,\n", + " suptitle=\"ALOS Forest Map\",\n", + " geom_exterior=geom.exterior.xy,\n", + " extent=[minx, maxx, miny, maxy],\n", + " figsize=(10, 7),\n", + " xlabel=\"Longitude\",\n", + " ylabel=\"Latitude\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Read the ordinal raster data" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "recoded_rasters = run.output[\"recoded_raster\"]\n", + "forest_images = []\n", + "\n", + "for raster in recoded_rasters:\n", + " ordinal_raster = cast(Raster, raster)\n", + " forest_images.append(read_raster(ordinal_raster, bounding_box)[0][0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Present the results using plot\n", + "\n", + "Although we've observed a change in the frequency of forest pixels over the years, we can use statistical testing to determine whether there is a significant trend in the forest change or it is simply the result of random fluctuations in the data. " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA8gAAAK7CAYAAAAuk6bZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3gU1d4H8O+m05LQQygJvVcpAtKRKgoqaMBQVASlGBAw3CsQsFBsEfVVrkpTEJGmIoIUpXcMCFIjLRD6TUKABJLs+0furrub2dmpu7Ob7+d5eDS7s2fOzM6eOWd+p5jMZrMZRERERERERIWcn6czQERERERERGQEbCATERERERERgQ1kIiIiIiIiIgBsIBMREREREREBYAOZiIiIiIiICAAbyEREREREREQA2EAmIiIiIiIiAsAGMhEREREREREANpCJiIiIiIiIALCBTEREXuTcuXMwmUxYuHChZmkuXLgQJpMJ586d0yxNIiIi8k5sIBMRFUKWRqHlX0BAACpWrIihQ4fi0qVLns6e4U2aNAkmkwnPPPOM4PuWhvx7773nMq2dO3eiX79+KF++PIKDgxEdHY0RI0bgwoULgtvv2LEDPXv2RMWKFRESEoIqVaqgT58+WLp0qct9dezY0e57t/134sQJl593t7/++gsJCQmSH14kJCTAZDLBz88PFy9eLPB+RkYGihQpApPJhNGjR2ucWyIi8gUBns4AERF5zowZM1C1alVkZWVhz549WLhwIXbs2IGjR48iJCTE09kzJLPZjG+//RbR0dH46aefcPv2bZQoUUJRWh9//DFeffVVVKtWDWPGjEGFChVw/PhxfPnll/juu++wbt06tGnTxrr9999/j2eeeQZNmjTBq6++ipIlS+Ls2bPYtm0bvvjiCwwcONDlPitVqoSZM2cWeD0yMlLRMejpr7/+wvTp09GxY0dER0dL/lxwcDC+/fZbTJo0ye71VatWaZxDIiLyNWwgExEVYj179kTz5s0BAC+++CLKlCmD2bNn48cff8SAAQM8nDtj+v3335GSkoItW7age/fuWLVqFYYMGSI7nZ07dyIuLg6PPPII1q9fj6JFi1rfe/nll9G2bVs8/fTTOHbsGEqWLAkgP0Jar1497NmzB0FBQXbpXbt2TdJ+w8LC8Nxzz8nOrytmsxlZWVkoUqSI5mnL1atXL8EG8tKlS9G7d2+sXLnSQzkjIiKjYxdrIiKyateuHQAgOTnZ7vUTJ07g6aefRqlSpRASEoLmzZvjxx9/LPD5tLQ0jBs3DtHR0QgODkalSpUwePBg3Lhxw7rNtWvX8MILL6B8+fIICQlB48aNsWjRIsG0hg4dirCwMISHh2PIkCFIS0sTzLfU/B07dgydO3dGkSJFUKlSJbz11lvIy8uTc4qwZMkS1KtXD506dULXrl2xZMkSWZ+3ePPNN2EymbBo0SK7xjEAVK9eHXPmzEFqairmzZtnfT05ORktWrQo0DgGgHLlyinKh6OcnBy8+eabqF69urXL97/+9S9kZ2fbbRcdHY3HHnsMGzZsQPPmzVGkSBFrXtPS0hAXF4fKlSsjODgYNWrUwOzZswuc62XLluGhhx5CiRIlEBoaioYNG+Kjjz4CkD8MoH///gCATp06WbuC//777y6PYeDAgUhKSrLrNn7lyhVs2bJFMMp+//59TJ06FQ899BDCwsJQrFgxtGvXDr/99pvddrZd5z/88ENERUWhSJEi6NChA44ePer65BIRkeExgkxERFaWsZ6WiCWQ36hs27YtKlasiPj4eBQrVgzLly9H3759sXLlSvTr1w8AkJmZiXbt2uH48eN4/vnn0axZM9y4cQM//vgjUlJSUKZMGdy7dw8dO3bEmTNnMHr0aFStWhXff/89hg4dirS0NLz66qsA8qORTzzxBHbs2IGRI0eibt26WL16tWCkVmr+rly5gk6dOiEnJ8e63X/+8x9ZEc/s7GysXLkSr732GgAgJiYGw4YNw5UrVxARESE5nbt372Lz5s1o164dqlatKrjNM888g5deeglr165FfHw8ACAqKgqbN29GSkoKKlWqJHl/tnJzc+0eWABASEgIihcvDiC/J8GiRYvw9NNP47XXXsPevXsxc+ZMHD9+HKtXr7b73MmTJxETE4MRI0Zg+PDhqF27Nu7evYsOHTrg0qVLGDFiBKpUqYJdu3Zh8uTJSE1NRWJiIgBg48aNiImJQZcuXTB79mwAwPHjx7Fz5068+uqraN++PcaOHYu5c+fiX//6F+rWrQsA1v+Kad++PSpVqoSlS5dixowZAIDvvvsOxYsXR+/evQtsn5GRgS+//BIxMTEYPnw4bt++ja+++grdu3fHvn370KRJE7vtFy9ejNu3b2PUqFHIysrCRx99hM6dO+PPP/9E+fLlXX8JRERkXGYiIip0FixYYAZg3rRpk/n69evmixcvmlesWGEuW7asOTg42Hzx4kXrtl26dDE3bNjQnJWVZX0tLy/P3KZNG3PNmjWtr02dOtUMwLxq1aoC+8vLyzObzWZzYmKiGYD5m2++sb53//59c+vWrc3Fixc3Z2RkmM1ms3nNmjVmAOY5c+ZYt8vJyTG3a9fODMC8YMEC2fmLi4szAzDv3bvX+tq1a9fMYWFhZgDms2fPujxvK1asMAMwnz592mw2m80ZGRnmkJAQ84cffmi33dmzZ80AzO+++65gOklJSWYA5ldffVV0f40aNTKXKlXK+vdXX31lBmAOCgoyd+rUyTxlyhTz9u3bzbm5uS7zbjabzR06dDADKPBvyJAhdvl68cUX7T43YcIEMwDzli1brK9FRUWZAZjXr19vt+2bb75pLlasmPnUqVN2r8fHx5v9/f3NFy5cMJvNZvOrr75qDg0NNefk5DjN7/fff28GYP7tt98kHd+0adPMAMzXr183T5gwwVyjRg3rey1atDAPGzbMbDabzQDMo0aNsr6Xk5Njzs7Otkvrv//9r7l8+fLm559/3vqa5XstUqSIOSUlxfr63r17zQDM48aNk5RPIiIyLnaxJiIqxLp27YqyZcuicuXKePrpp1GsWDH8+OOP1ujkrVu3sGXLFgwYMAC3b9/GjRs3cOPGDdy8eRPdu3fH6dOnrbNer1y5Eo0bN7ZGbG2ZTCYAwLp16xAREYGYmBjre4GBgRg7diwyMzOxdetW63YBAQF4+eWXrdv5+/tjzJgxdunKyd+6devw8MMPo2XLltbPly1bFoMGDZJ8vpYsWYLmzZujRo0aAIASJUqgd+/esrtZ37592/p5MSVKlEBGRob17+effx7r169Hx44dsWPHDrz55pto164datasiV27dknad3R0NDZu3Gj3zzJWd926dQCA8ePH233GEjH/+eef7V6vWrUqunfvbvfa999/j3bt2qFkyZLW7+PGjRvo2rUrcnNzsW3bNgBAeHg47ty5g40bN0rKt1wDBw7EmTNnsH//fut/nU1i5u/vb+22npeXh1u3biEnJwfNmzfHoUOHCmzft29fVKxY0fp3y5Yt0apVK+v5IyIi78Uu1kREhdinn36KWrVqIT09HfPnz8e2bdsQHBxsff/MmTMwm82YMmUKpkyZIpjGtWvXULFiRSQnJ+Opp54S3d/58+dRs2ZN+PnZP5+1dJs9f/689b8VKlSwdvu1qF27tt3fcvJ3/vx5tGrVqsD7jmk6k5aWhnXr1mH06NE4c+aM9fW2bdti5cqVOHXqFGrVqiUpLUvD2NJQdkZohuzu3buje/fuuHv3Lg4ePIjvvvsOn3/+OR577DGcOHHC5VjkYsWKoWvXroLvnT9/Hn5+ftYHABYREREIDw+3fj8WQt3DT58+jSNHjqBs2bKC+7BMJvbKK69g+fLl1iWrunXrhgEDBqBHjx6i+ZeqadOmqFOnDpYuXYrw8HBERESgc+fOTrdftGgR3n//fZw4cQIPHjywvi50jDVr1izwWq1atbB8+XJN8k5ERJ7DBjIRUSHWsmVL6yzWffv2xSOPPIKBAwfi5MmTKF68uHVSpQkTJhSIFFo4NqbcyZ35+/7775GdnY33338f77//foH3lyxZgunTp0tKq0aNGggICMCRI0ecbpOdnY2TJ09avx9HRYsWRbt27dCuXTuUKVMG06dPxy+//KJoRm1Hloi/K0Ljt/Py8vDoo48WmEHawvIQoVy5ckhKSsKGDRvwyy+/4JdffsGCBQswePBgwUnblBg4cCA+++wzlChRAs8880yBBzMW33zzDYYOHYq+ffti4sSJKFeuHPz9/TFz5swCE9YREZFvYwOZiIgAwNog6NSpEz755BPEx8ejWrVqAPK7QTuLOlpUr17d5Uy+UVFROHLkCPLy8uwaK5bZhqOioqz/3bx5MzIzM+2iyCdPnrRLT07+oqKicPr06QKvO6bpzJIlS9CgQQNMmzatwHvz5s3D0qVLJTeQixUrhk6dOmHLli04f/689bhtLV++HNnZ2XjsscdcpmdpRKempkravzNRUVHIy8vD6dOn7SbDunr1KtLS0gTz6ah69erIzMx0+X0AQFBQEPr06YM+ffogLy8Pr7zyCubNm4cpU6agRo0akhvqzgwcOBBTp05Famoqvv76a6fbrVixAtWqVcOqVavs9in0XQMQvI5OnTola61mIiIyJo5BJiIiq44dO6Jly5ZITExEVlYWypUrh44dO2LevHmCja/r169b//+pp57C4cOHC8x0DOTPSg3kr0975coVfPfdd9b3cnJy8PHHH6N48eLo0KGDdbucnBx89tln1u1yc3Px8ccf26UrJ3+9evXCnj17sG/fPrv3pYwfvnjxIrZt24YBAwbg6aefLvBv2LBhOHPmDPbu3esyLYs33ngDZrMZQ4cOxb179+zeO3v2LCZNmoQKFSpgxIgR1tc3b94smJZl7KvU7uLO9OrVCwCsM01bfPDBBwAgOAO0owEDBmD37t3YsGFDgffS0tKQk5MDALh586bde35+fmjUqBEAWJeUKlasmPVzSlSvXh2JiYmYOXOm3dhzR/7+/gD+uU4BYO/evdi9e7fg9mvWrLGObQeAffv2Ye/evejZs6eifBIRkXEwgkxERHYmTpyI/v37Y+HChRg5ciQ+/fRTPPLII2jYsCGGDx+OatWq4erVq9i9ezdSUlJw+PBh6+dWrFiB/v374/nnn8dDDz2EW7du4ccff8Tnn3+Oxo0b46WXXsK8efMwdOhQHDx4ENHR0VixYgV27tyJxMRE63jbPn36oG3btoiPj8e5c+dQr149rFq1Cunp6QXyKzV/kyZNwtdff40ePXrg1VdftS7zZIlqi1m6dCnMZjMef/xxwfd79eqFgIAALFmyxG6c8+bNm5GVlVVg+759+6J9+/Z47733MH78eDRq1AhDhw5FhQoVcOLECXzxxRfIy8vDunXr7JbceuKJJ1C1alX06dMH1atXx507d7Bp0yb89NNPaNGiBfr06ePi2xXXuHFjDBkyBP/5z3+QlpaGDh06YN++fVi0aBH69u2LTp06uUxj4sSJ+PHHH/HYY49h6NCheOihh3Dnzh38+eefWLFiBc6dO4cyZcrgxRdfxK1bt9C5c2dUqlQJ58+fx8cff4wmTZpYo9dNmjSBv78/Zs+ejfT0dAQHB6Nz586y1ny2LB0m5rHHHsOqVavQr18/9O7dG2fPnsXnn3+OevXqITMzs8D2NWrUwCOPPIKXX34Z2dnZSExMROnSpZ12KyciIi/iySm0iYjIMyzLPO3fv7/Ae7m5uebq1aubq1evbl2CJzk52Tx48GBzRESEOTAw0FyxYkXzY489Zl6xYoXdZ2/evGkePXq0uWLFiuagoCBzpUqVzEOGDDHfuHHDus3Vq1fNw4YNM5cpU8YcFBRkbtiwod2yTbZpxcbGmkNDQ81hYWHm2NhY8x9//FFgmSc5+Tty5Ii5Q4cO5pCQEHPFihXNb775pnXpJLFlnho2bGiuUqWK6Dnt2LGjuVy5cuYHDx5YlwNy9u/rr7+2fm7btm3mJ554wlymTBlzYGCguUqVKubhw4ebz507V2Af3377rfnZZ581V69e3VykSBFzSEiIuV69euZ///vf1iWyxHTo0MFcv3590W0ePHhgnj59urlq1armwMBAc+XKlc2TJ0+2W0bLbM5f5ql3796Cady+fds8efJkc40aNcxBQUHmMmXKmNu0aWN+7733zPfv3zebzflLZnXr1s1crlw5c1BQkLlKlSrmESNGmFNTU+3S+uKLL8zVqlUz+/v7u1zyyXaZJzFwWOYpLy/P/M4775ijoqLMwcHB5qZNm5rXrl1rHjJkiDkqKsq6ne3yXe+//765cuXK5uDgYHO7du3Mhw8fFt0nERF5B5PZbNOfiIiIiIgEnTt3DlWrVsW7776LCRMmeDo7RESkA45BJiIiIiIiIgIbyEREREREREQA2EAmIiIiIiIiAgBwDDIRERERERERGEEmIiIiIiIiAsAGMhEREREREREANpCJiIiIiIiIALCBTERERERERASADWQiIiIiIiIiAGwgExEREREREQFgA5mIiIiIiIgIABvIRERERERERADYQCYiIiIiIiICwAYyEREREREREQA2kImIiIiIiIgAsIFMREREREREBIANZCIiIiIiIiIAbCATERERERERAWADmYiIiIiIiAgAG8hEREREREREANhAJiIiIiIiIgLABjIRERERERERADaQiYiIiIiIiACwgUxEREREREQEgA1kIiIiIiIiIgBsIBMREREREREBYAOZiIiIiIiICAAbyEREREREREQA2EAmIiIiIiIiAsAGMhEREREREREANpCJiIiIiIiIALCBTERERERERASADWQiIiIiIiIiAGwgExEREREREQFgA5nI5+3fvx+jR49G/fr1UaxYMVSpUgUDBgzAqVOnCmx7/Phx9OjRA8WLF0epUqUQGxuL69evF9ju7bffxuOPP47y5cvDZDIhISFBcN/R0dEwmUyC/2rWrKn1oRIR+RRPlt8AsGnTJnTq1AllypRBeHg4WrZsia+//lrLQyQiMpwAT2eAiPQ1e/Zs7Ny5E/3790ejRo1w5coVfPLJJ2jWrBn27NmDBg0aAABSUlLQvn17hIWF4Z133kFmZibee+89/Pnnn9i3bx+CgoKsab7xxhuIiIhA06ZNsWHDBqf7TkxMRGZmpt1r58+fxxtvvIFu3brpc8BERD7Ck+X3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ixYtwpQpU7ymReRPVvpdsfwujOU3y28i8sDfLXQiOf7++2+hbNmywkMPPSSkpqYKBw8eFEaPHi2Eh4cLqampju0eeOABoV69esKGDRuEv/76S7jvvvuEunXrOpamSE9PFxISEoQtW7a4pH/48GHBZrMJv/76q+j+p02bJuzevVvYs2ePMGnSJCE8PFxYsmSJbserBX+es/379wsRERHCsGHDhH379gl79uwRBg4cKJQqVcrR1c2M/H2dCUJB9CYyMlK4dOmSLsdIZDR//65YfrP8ZvlNREqwgUyWsW3bNqFr165CmTJlhBIlSgj33HOP8Msvv7hsc/nyZWHw4MFCdHS0UKZMGaFPnz4uS1UcO3ZMACCsWrXK5XPjx48XKleu7NKlzFnHjh2FUqVKCZGRkUKLFi0K7des/HnOli9fLrRu3VooVaqUULp0aaFTp07Cpk2bND9GrfnznAmCILRs2VLo37+/psdE5G8sv5Vj+a0cy28i0oJNEATBnxFsIiIiIiIiIjPgOshEREREREREYAOZiIiIiIiICAAbyEREREREREQA2EAmIiIiIiIiAsAGMhEREREREREANpCJiIiIiIiIALCBTERERERERASADWQiIiIiIiIiAGwgExEREREREQFgA5mIiIiIiIgIABvIRERERERERADYQCYiIiIiIiICwAYyEREREREREQA2kImIiIiIiIgAsIFMREREREREBIANZCIiIiIiIiIAbCATERERERERAWADmYiIiIiIiAgAG8hEREREREREANhAJiIiIiIiIgLABjIRERERERERADaQiYiIiIiIiACwgUxEREREREQEgA1kIiIiIiIiIgBsIBMREREREREBYAOZiIiIiIiICAAbyEREREREREQA2EAmIiIiIiIiAsAGMhEREREREREANpCJiIiIiIiIALCBTEREZFqrV6+GzWbD6tWrDdlfhw4d0KFDB0P2RUREZEZsIBMRUVCbM2cObDYbtm/f7u+syLJgwQKkpKT4OxtEREQBKczfGSAiIiJx7dq1w40bN1CkSBHHawsWLMCePXuQlJTkv4wREREFKDaQiYiITCokJASRkZH+zgYREVHQYBdrIiIiL/7880/06NEDJUuWRPHixdG5c2ds3rzZZRt7V+0NGzZg1KhRiImJQbFixdCnTx/8/fffLtvm5+cjOTkZcXFxiIqKQseOHbFv3z5UrVoVTzzxhGM79zHIHTp0wM8//4wTJ07AZrPBZrOhatWqLvs/fvy4y748jWP+7LPPUKNGDRQtWhTNmzfHunXrRI89NzcXEyZMQM2aNREREYHKlStj7NixyM3NVXweiYiIzI4RZCIiIgl79+5F27ZtUbJkSYwdOxbh4eH49NNP0aFDB6xZswYtWrRw2X748OEoXbo0JkyYgOPHjyMlJQUvvPACvv76a8c248ePx7Rp09C7d29069YNu3btQrdu3ZCTkyOZl1dffRWXL19Geno6ZsyYAQAoXry44mOaNWsWhgwZglatWiEpKQlHjx7F/fffjzJlyqBy5cqO7fLz83H//fdj/fr1ePbZZ1GnTh389ddfmDFjBg4dOoSlS5cq3jcREZGZsYFMREQk4bXXXsOtW7ewfv16VK9eHQDw+OOPIyEhAWPHjsWaNWtcti9btiyWL18Om80GoKCROXPmTFy+fBmlSpXCuXPn8N577+HBBx/EkiVLHJ+bOHEikpOTJfNy77334o477sClS5cwcOBAVcdz69YtvPLKK2jcuDFWrVrlGN9ct25dPPvssy4N5AULFmDlypVYs2YN2rRp43i9fv36GDp0KDZu3IhWrVqpygcREZEZsYs1ERGRB3l5eVi+fDkefPBBR+MYACpWrIj+/ftj/fr1uHLlistnnn32WUfjGADatm2LvLw8nDhxAgDw+++/4/bt23juuedcPjd8+HAdj+Qf27dvR2ZmJoYOHeoy+dcTTzyBUqVKuWz7zTffoE6dOrjzzjtx/vx5x79OnToBAFatWmVInomIiIzCCDIREZEHf//9N65fv46EhIRC79WpUwf5+fk4deoU6tWr53i9SpUqLtuVLl0aAHDp0iUAcDSUa9as6bJdmTJlHNvqyb7/WrVqubweHh7u8hAAAA4fPoz9+/cjJiZGNK3MzEx9MklEROQnbCATERFpKDQ0VPR1QRB03a9z1NpZXl6e6jTz8/PRoEEDvPfee6LvO3fHJiIiCgRsIBMREXkQExODqKgoHDx4sNB7Bw4cQEhIiOJGYnx8PADgyJEjqFatmuP1CxcuOKLMUjw1hO3R56ysLJfX7RFj9/0fPnzY0VUaKBibfOzYMTRq1MjxWo0aNbBr1y507tzZ436JiIgCCccgExEReRAaGoquXbvi+++/d1k+6dy5c1iwYAHatGmDkiVLKkqzc+fOCAsLw3/+8x+X1z/88ENZny9WrBguX75c6PUaNWoAANauXet4LS8vD5999pnLds2aNUNMTAw++eQT3Lx50/H6nDlzCjWuH3nkEZw+fRqff/55of3duHED165dk5VnIiIiq2AEmYiICMDs2bPx22+/FXo9OTkZK1asQJs2bfDcc88hLCwMn376KXJzczFt2jTF+6lQoQJefPFFvPvuu7j//vvRvXt37Nq1C7/++ivKlSvnNVLbtGlTfP311xg1ahTuvvtuFC9eHL1790a9evVwzz33YPz48bh48SLKlCmDhQsX4vbt2y6fDw8Px1tvvYUhQ4agU6dOePTRR3Hs2DF88cUXhcYgJyYmYtGiRRg6dChWrVqF1q1bIy8vDwcOHMCiRYuwbNkyNGvWTPE5ICIiMis2kImIiIBCEV27J554AuvWrcP48eMxZcoU5Ofno0WLFpg3b16hNZDlevvttxEVFYXPP/8cK1euRMuWLbF8+XK0adMGkZGRkp997rnnkJqaii+++AIzZsxAfHw8evfuDQCYP38+hgwZgqlTpyI6OhpPPfUUOnbsiHvvvdcljWeffRZ5eXmYPn06xowZgwYNGuCHH37A66+/7rJdSEgIli5dihkzZmDu3LlYsmQJoqKiUL16dbz44ouoXbu2quMnIiIyK5ug96whRERE5FVWVhZKly6Nt956C6+++qq/s0NERBSUOAaZiIjIYDdu3Cj0WkpKCgCgQ4cOxmaGiIiIHNjFmoiIyGBff/015syZg549e6J48eJYv349vvrqK3Tt2hWtW7f2d/aIiIiCFhvIREREBmvYsCHCwsIwbdo0XLlyxTFx11tvveXvrBEREQU1jkEmIiIiIiIiAscgExEREREREQFgA5mIiIiIiIgIABvIRERERERERADYQCYiIiIiIiICwAYyEREREREREQA2kImIiIiIiIgAsIFMREREREREBIANZCIiIiIiIiIAbCATERERERERAQD+H4l7q0uIpNJrAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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sWKFVq5cqZUrV2rz5s166623JEmnTp1Sx44d1a1bNx04cECbNm1SmzZtZBjXpt58/PHHiouL05gxY3TgwAGNHTtWw4YNs06z+bfQ0FCdOnVKvr6+mjJlik6dOqX27dvrzz//VPPmzfXQQw9p7969mjVrlt5//32NHj3a5vz4+Hi5ubkpISFBs2fPVnJysho1aqTq1atr586dWrNmjZKSktSuXbs71v/KK6+oXbt21r88nDp1StHR0ffcB8wxBwAAgCSpfPny2rdvn7777jtt375dp0+flru7uyRp0qRJWrFihZYsWaJevXpJkrKysrRw4UL5+PhIkp599llt2LBBY8aM0alTp3T16lW1adNGYWFhkqQqVapY7zV8+HC9/fbbatOmjSQpIiJCP//8s+bMmaPOnTvfUJurq6uCg4NlsVjk5+en4OBgSdLMmTMVGhqq6dOny2KxqHz58jp58qRee+01xcXFWefMly1bVhMmTLBeb/To0apevbrGjh1rbZs/f75CQ0N16NAhpaWl3bZ+T09PpaenW+uwB0bMAQAAIEkyDEMWi0V79+5VWlqaAgIC5O3tbX0dPXpUR44csR4fHh5uDeWSFBISotOnT0uSqlWrpsaNG6tKlSp6+umnNW/ePJ0/f16SdOHCBR05ckTdu3e3uf7o0aOt178+xcTb21uVKlW6Zc0HDhxQVFSULJb//6HbunXrKi0tTX/88Ye1rWbNmjbn7d27Vxs3brS5f/ny5SVd+0vA7erPLYyYAwAAQNK1kBsREaG0tDSFhITcdN70Pz9wWbBgQZt9FotFWVlZkq6NcK9bt05btmzR119/rWnTpumNN97Qtm3bVKhQIUnSvHnzVKdOHZtruLq6Sro2//zSpUs3vc/d8PLystlOS0tTy5YtNX78+BuODQkJuW39ERER91zPzRDMAQAAoG+++Ub79+/Xyy+/rJIlSyoxMVEFChRQeHj4XV/TYrGobt26qlu3ruLi4hQWFqbly5dr4MCBKl68uH777Td16tTppueWKFEiW/eoUKGCli5dah3tl66tde7j46OSJUve8rwaNWpo6dKlCg8PV4ECN4/Et6vfzc1NmZmZ2aoxuwjmAAAATiY9PV2JiYnKzMxUUlKS1qxZo3HjxqlFixZ67rnn5OLioqioKLVq1UoTJkxQuXLldPLkSX311Vdq3bq1atWqdcd7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a8WKFfL19VXz5s119epVnThxQn/++afKli2r1157zdFlwk4mTZqkMWPGaNCgQZozZ44efPBBjRgxQl999ZVKly6t+vXra+fOnY4uE3YSHx+v5s2by8/PT++8845WrlyplStX6p133pG/v7+aN2+uDz/80NFlArgLPPnTSbi4uCgxMVGnTp3Se++9p0WLFiktLU0tWrRQjx491LRpU1ksFkeXCTsJDAzU119/rcjISKWkpKhw4cL69ttvVa9ePUnS7t271bx5cyUmJjq4UthDRESEZs6cqWbNmkmSDh06pOjoaCUmJqpAgQJ66aWXdODAAX399dcOrhT2UK5cOb300kvq16/fTffPnDlT77zzjg4fPpzHlQG4V4yYO5lq1app2rRpOnnypBYuXKiUlBS1aNFCpUqVUlxcnKPLg51cvnxZfn5+kq5NY3J1dZWPj491v6+vry5evOio8mBnp0+fVoUKFazbZcuWVUpKivWvYt26ddPWrVsdVR7s7Pjx44qJibnl/saNG+uPP/7Iw4oA2AvB3En8ezTc3d1dHTt21Pr163XkyBF16dJFCxcudExxsLtKlSpp/vz5kq792TsgIECLFy+27v/kk09Urlw5R5UHOytXrpzWrVtn3d64caPc3NwUHBwsSfLw8OAvYvlIpUqV9P77799y//z581WxYsU8rAiAvTCVxUlcn8oSGBh4y2MMw+Af73xi7dq1atWqlbKysuTi4qK1a9eqZ8+e8vf3l4uLi3bs2KFFixapXbt2ji4VdvDZZ5/pmWeeUevWreXh4aFly5apf//+GjdunCRpzpw5io+P58Pf+cSmTZvUokULlS5dWjExMQoKCpIkJSUlacOGDfrtt9/01VdfqX79+g6uFEBOEcydxMiRIzVo0CAVKlTI0aUgjxw7dky7du1SzZo1FR4erqSkJM2YMUMXL17U448/rkcffdTRJcKOVq9erY8++kjp6emKjY1Vz549rfv++usvSWLpxHzk2LFjmjVrlr7//nvrZ0WCg4MVFRWl559/XuHh4Y4tEMBdIZgDAAAAJsAcc0iSrl69quPHjzu6DOQR+tu50N8AcH8gmEOS9NNPPykiIsLRZSCP0N/Ohf7Of2bOnKmYmBi1a9dOGzZssNl39uxZlS5d2kGVAbgXBHMAAO4jU6dO1aBBg1S+fHm5u7urefPm1g/6SlJmZqZ+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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def plot_pixel_distribution(\n", + " df: pd.DataFrame,\n", + " highlight_column: Optional[int] = None,\n", + " ax: Optional[plt.Axes] = None,\n", + " use_legend: bool = True,\n", + " colors: Optional[List[\"str\"]] = None,\n", + " title: Optional[str] = \"Pixel Distribution Over Time\",\n", + "):\n", + " filtered_df = df.copy()\n", + " # Extract the year from the column names\n", + " filtered_df.columns = [label[:4] for label in filtered_df.columns]\n", + " # Transpose the DataFrame\n", + " df_transposed = filtered_df.transpose()\n", + "\n", + " # Normalize the data so that the pixel counts sum to 100% for each year\n", + " df_normalized = df_transposed.div(df_transposed.sum(axis=1), axis=0) * 100\n", + "\n", + " if colors: \n", + " ax = df_normalized.plot(kind=\"bar\", stacked=True, ax=ax, color=colors)\n", + " else:\n", + " ax = df_normalized.plot(kind=\"bar\", stacked=True, ax=ax)\n", + "\n", + " # Highlight the specified column by setting its alpha to 1\n", + " if highlight_column is not None:\n", + " # Apply alpha to all bars\n", + " for container in ax.containers:\n", + " for bar in container:\n", + " bar.set_alpha(0.3)\n", + "\n", + " for container in ax.containers:\n", + " container[highlight_column].set_alpha(1)\n", + "\n", + " ax.set_title(title)\n", + " ax.set_ylabel(\"Pixel Distribution\")\n", + " ax.set_xlabel(\"Category\")\n", + "\n", + " # Add a legend outside of the plot\n", + " if use_legend:\n", + " ax.legend(bbox_to_anchor=(1.05, 1), loc=\"upper left\") \n", + " else:\n", + " ax.get_legend().remove()\n", + "\n", + " return df_normalized\n", + "\n", + "\n", + "color_dict = {\n", + " 0: \"grey\",\n", + " 1: \"lightgreen\",\n", + " 2: \"darkgreen\",\n", + "}\n", + "\n", + "titles = [str(raster.time_range[0].year) for raster in recoded_rasters]\n", + "\n", + "# We plot the categorical raster pixel distribution again for\n", + "# better visualization of the pixel distribution over time\n", + "plot_categorical_maps(\n", + " forest_images,\n", + " color_dict,\n", + " level_names,\n", + " titles=titles,\n", + " suptitle=\"Recoded ALOS Forest Map\",\n", + " geom_exterior=geom.exterior.xy,\n", + " extent=[minx, maxx, miny, maxy],\n", + " figsize=(10, 7),\n", + " xlabel=\"Longitude\",\n", + " ylabel=\"Latitude\",\n", + ")\n", + "\n", + "# Filter out the \"no data\" category\n", + "filtered_df = df\n", + "colors = [color_dict[level_names.index(cat)] for cat in filtered_df.index]\n", + "# get the corresponding colors\n", + "_ = plot_pixel_distribution(filtered_df, use_legend=True, colors=colors)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Conclusion\n", + "\n", + "Finally, we employed the Cochan-Armitage trend test. This test is specifically designed to determine if there is an increasing/decreasing trend between the two categorical variables. In our case, the two variables are 'forest/non-forest pixels distribution' and 'year'. By applying the trend test, we can quantitatively assess whether the changes we've observed in pixel categories over time are statistically significant, or if they could be attributed to random variation.\n", + "\n", + "The conclusion of this test is printed in the next cell." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "******* COCHAN-ARMITAGE TREND TEST RESULTS *******\n", + "p-value 6.127822361209561e-60\n", + "significance level 0.05\n", + "z_score 16.329103461498548\n", + "******* CONCLUSION *******\n", + "The null hypothesis is rejected.\n", + "The categorical rasters are positively dependent, so the level of forest cover is increasing.\n" + ] + } + ], + "source": [ + "SIGNIFICANCE_LEVEL = 0.05\n", + "\n", + "print(\"******* COCHAN-ARMITAGE TREND TEST RESULTS *******\")\n", + "print(f\"p-value {trend_test_test_results.p_value}\")\n", + "print(f\"significance level {SIGNIFICANCE_LEVEL}\")\n", + "print(f\"z_score {trend_test_test_results.z_score}\")\n", + "\n", + "print(\"******* CONCLUSION *******\")\n", + "if trend_test_test_results.p_value < SIGNIFICANCE_LEVEL:\n", + " print(\"The null hypothesis is rejected.\")\n", + " \n", + " if trend_test_test_results.z_score > 0:\n", + " print(\"The categorical rasters are positively dependent, so the level of forest cover is increasing.\")\n", + " else:\n", + " print(\"The categorical rasters are negatively dependent, so the level of forest cover is decreasing.\")\n", + "\n", + "else:\n", + " print(\"The null hypothesis is not rejected. The categorical rasters are independent.\")" + ] + } + ], + "metadata": { + "description": "Helps users to detect forest changes", + "disk_space": "", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + }, + "name": "Detecting Forest Changes", + "running_time": "", + "tags": [ + "Remote Sensing", + "Deforestation", + "Sustainability" + ] + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/notebooks/heatmaps/notebook_lib/utils.py b/notebooks/heatmaps/notebook_lib/utils.py index 82013373..ec52c060 100644 --- a/notebooks/heatmaps/notebook_lib/utils.py +++ b/notebooks/heatmaps/notebook_lib/utils.py @@ -77,9 +77,7 @@ def create_heatmap_admag( imagery: Raster, farm_infO: Dict[str, str], parameters: Dict[str, Any] ) -> str: sample_inputs = ADMAgSeasonalFieldInput( - farmer_id=farm_infO["farmer_id"], - seasonal_field_id=farm_infO["seasonal_field_id"], - boundary_id=farm_infO["boundary_id"], + party_id=farm_infO["party_id"], seasonal_field_id=farm_infO["seasonal_field_id"] ) inputs = {"input_raster": imagery, "admag_input": sample_inputs} @@ -161,9 +159,8 @@ def get_seasonal_field( farm_infO: Dict[str, str], parameters: Dict[str, Any] ) -> Dict[str, Any]: sample_inputs = ADMAgSeasonalFieldInput( - farmer_id=farm_infO["farmer_id"], + party_id=farm_infO["party_id"], seasonal_field_id=farm_infO["seasonal_field_id"], - boundary_id=farm_infO["boundary_id"], ) inputs = {"admag_input": sample_inputs} diff --git a/notebooks/heatmaps/nutrients_using_classification_admag.ipynb b/notebooks/heatmaps/nutrients_using_classification_admag.ipynb index 497ed334..55a2fc6c 100755 --- a/notebooks/heatmaps/nutrients_using_classification_admag.ipynb +++ b/notebooks/heatmaps/nutrients_using_classification_admag.ipynb @@ -7,7 +7,7 @@ "source": [ "# FarmVibes.AI Nutrients Heatmap\n", "\n", - "This notebook demonstrates how to run the heatmap workflow on sentinel imagery by integrating with [Microsoft Azure Data Manager for Agriculture (ADMAg)](https://learn.microsoft.com/en-us/azure/data-manager-for-agri/). The workflow accepts Farmer_ID, Seasonal_Field_ID and Boundary_ID information to download samples of soil properties (such as carbon and nitrogen) from ADMAg, and generate an interpolated heatmap based on the input imagery.\n", + "This notebook demonstrates how to run the heatmap workflow on sentinel imagery by integrating with [Microsoft Azure Data Manager for Agriculture (ADMAg)](https://learn.microsoft.com/en-us/azure/data-manager-for-agri/). The workflow accepts Party_ID and Seasonal_Field_ID information to download samples of soil properties (such as carbon and nitrogen) from ADMAg, and generate an interpolated heatmap based on the input imagery. The notebook is using the ADMAg version 2023-11-01-preview for demonstration.\n", "\n", "### Micromamba environment setup\n", "Before running this notebook, let's build a micromamba environment. If you do not have micromamba installed, please follow the instructions from the [micromamba installation guide](https://mamba.readthedocs.io/en/latest/installation/micromamba-installation.html).\n", @@ -92,21 +92,20 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# Farm information\n", "FARM_INFO = {\n", - " \"farmer_id\": \"\",\n", - " \"boundary_id\": \"\",\n", - " \"seasonal_field_id\": \"\"\n", + " \"party_id\": \"\",\n", + " \"seasonal_field_id\": '',\n", "}" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -156,7 +155,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -166,7 +165,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -218,7 +217,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -680,7 +679,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -728,6 +727,26 @@ ")" ] }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/home/azureuser/.cache/farmvibes-ai/data/assets/8d11c61e-afc3-4656-aaf7-65503a7937d0/result.zip'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "archive_path" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/notebooks/segment_anything/basemap_segmentation.ipynb b/notebooks/segment_anything/basemap_segmentation.ipynb index 4a259530..6ab7113a 100644 --- a/notebooks/segment_anything/basemap_segmentation.ipynb +++ b/notebooks/segment_anything/basemap_segmentation.ipynb @@ -55,7 +55,7 @@ "**If you are importing the ONNX files to your cluster for the first time**, make sure the following environment is configured:\n", "\n", "```bash\n", - "$ micromamba env create -f env_cpu.yml\n", + "$ micromamba env create -f env_cpu.yaml\n", "$ micromamba activate segment_anything_cpu\n", "```\n", "\n", diff --git a/notebooks/segment_anything/sam_exploration.ipynb b/notebooks/segment_anything/sam_exploration.ipynb index a990ae1d..31b5d4d3 100644 --- a/notebooks/segment_anything/sam_exploration.ipynb +++ b/notebooks/segment_anything/sam_exploration.ipynb @@ -33,13 +33,13 @@ "Without GPU support (CPU):\n", "\n", "```bash\n", - "$ micromamba env create -f env_cpu.yml\n", + "$ micromamba env create -f env_cpu.yaml\n", "$ micromamba activate segment_anything_cpu\n", "```\n", "\n", "With GPU support:\n", "```bash\n", - "$ micromamba env create -f env_gpu.yml\n", + "$ micromamba env create -f env_gpu.yaml\n", "$ micromamba activate segment_anything\n", "```" ] @@ -899,7 +899,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.8.17" }, "name": "Field boundary segmentation (SAM exploration)", "orig_nbformat": 4, diff --git a/notebooks/segment_anything/sentinel2_segmentation.ipynb b/notebooks/segment_anything/sentinel2_segmentation.ipynb index 7b75ae0f..f5c8c549 100644 --- a/notebooks/segment_anything/sentinel2_segmentation.ipynb +++ b/notebooks/segment_anything/sentinel2_segmentation.ipynb @@ -34,7 +34,7 @@ "**If you are importing the ONNX files to your cluster for the first time**, make sure the following environment is configured:\n", "\n", "```bash\n", - "$ micromamba env create -f env_cpu.yml\n", + "$ micromamba env create -f env_cpu.yaml\n", "$ micromamba activate segment_anything_cpu\n", "```\n", "\n", @@ -147,9 +147,9 @@ "source": [ "## Workflow setup\n", "\n", - "FarmVibes.AI has a few workflows related to SAM. The `ml/segment_anything/prompt_segmentation` is the basic workflow that takes a Sentinel-2 raster, an input geometry of the Region of Interest (RoI), and an `ExternalReferenceList` pointing to a GeoDataFrame containing the points and/or bounding boxes used as prompts, their labels (`foreground` or `background`) and associated prompt ids (indicating the prompt to which a point belongs), and returns a CategoricalRaster with the segmentation results (one per prompt).\n", + "FarmVibes.AI has a few workflows related to SAM. The `ml/segment_anything/s2_prompt_segmentation` is the basic workflow that takes a Sentinel-2 raster, an input geometry of the Region of Interest (RoI), and an `ExternalReferenceList` pointing to a GeoDataFrame containing the points and/or bounding boxes used as prompts, their labels (`foreground` or `background`) and associated prompt ids (indicating the prompt to which a point belongs), and returns a CategoricalRaster with the segmentation results (one per prompt).\n", "\n", - "To facilitate its use, we also provide the `farm_ai/segmentation/segment_s2` workflow, which combines the `data_ingestion/sentinel2/preprocess_s2` workflow to download Sentinel-2 imagery and the `ml/segment_anything/prompt_segmentation` workflow to run the segmentation. In addition to the `ExternalReferenceList` inputs for the prompts, this workflow expects a `DataVibe` with the geometry and a time range of interest.\n", + "To facilitate its use, we also provide the `farm_ai/segmentation/segment_s2` workflow, which combines the `data_ingestion/sentinel2/preprocess_s2` workflow to download Sentinel-2 imagery and the `ml/segment_anything/s2_prompt_segmentation` workflow to run the segmentation. In addition to the `ExternalReferenceList` inputs for the prompts, this workflow expects a `DataVibe` with the geometry and a time range of interest.\n", "\n", "Before inspecting how the workflow is defined, let's instantiate our client:\n" ] diff --git a/notebooks/sentinel/field_level_spectral_indices.ipynb b/notebooks/sentinel/field_level_spectral_indices.ipynb index 672feae6..52db3d86 100644 --- a/notebooks/sentinel/field_level_spectral_indices.ipynb +++ b/notebooks/sentinel/field_level_spectral_indices.ipynb @@ -296,7 +296,7 @@ "idx_list = np.linspace(0, len(cloud_free_rasters) - 1, num=10, dtype=int)\n", "for raster_idx in idx_list:\n", " run = client.run(\n", - " \"ml/segment_anything/prompt_segmentation\", \n", + " \"ml/segment_anything/s2_prompt_segmentation\", \n", " f\"SAM - Raster {raster_idx}\", \n", " input_data={\n", " \"input_raster\": cloud_free_rasters[raster_idx], \n", diff --git a/notebooks/shared_nb_lib/plot.py b/notebooks/shared_nb_lib/plot.py index 36d6742f..fd406270 100644 --- a/notebooks/shared_nb_lib/plot.py +++ b/notebooks/shared_nb_lib/plot.py @@ -1,13 +1,15 @@ import io from copy import deepcopy -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, Tuple import matplotlib import matplotlib.pyplot as plt import numpy as np from IPython.core.display import Image from IPython.display import display +from matplotlib.axes import Axes from matplotlib.colors import ListedColormap +from matplotlib.figure import Figure from numpy._typing import NDArray @@ -30,16 +32,22 @@ def transparent_cmap(cmap: ListedColormap, max_alpha: float = 0.8, N: int = 255) return mycmap -def plot_categorical_map( +def _plot_categorical_map( dataset: List[List[float]], color_dict: Dict[int, str], labels: List[str], geom_exterior: Optional[NDArray[Any]] = None, extent: Optional[List[float]] = None, - title: str = "Category Map", - xlabel: str = "longitude", - ylabel: str = "latitude", + title: str = "", + xlabel: str = "", + ylabel: str = "", + fig: Optional[Figure] = None, + ax: Optional[Axes] = None, ): + # Plot the figure + if not fig or not ax: + fig, ax = plt.subplots() + # Create a colormap from the color dictionary cmap = ListedColormap([color_dict[x] for x in color_dict.keys()]) # type: ignore @@ -49,22 +57,92 @@ def plot_categorical_map( norm = matplotlib.colors.BoundaryNorm(norm_bins, len(labels), clip=True) fmt = matplotlib.ticker.FuncFormatter(lambda x, _: labels[norm(x)]) # type: ignore - # Plot the figure - fig, ax = plt.subplots() - extent = extent or [0, len(dataset[0]), 0, len(dataset)] im = ax.imshow(dataset, cmap=cmap, extent=extent, norm=norm) if geom_exterior is not None: # Plot geom on top of the cropped image - plt.plot(*geom_exterior, color="red") + ax.plot(*geom_exterior, color="red") - plt.title(title) - plt.xlabel(xlabel) - plt.ylabel(ylabel) + if title: + ax.set_title(title) + if xlabel: + ax.set_xlabel(xlabel) + if ylabel: + ax.set_ylabel(ylabel) diff = norm_bins[1:] - norm_bins[:-1] tickz = norm_bins[:-1] + diff / 2 - fig.colorbar(im, format=fmt, ticks=tickz) + + return im, fmt, tickz + + +def plot_categorical_map( + dataset: List[List[float]], + color_dict: Dict[int, str], + labels: List[str], + geom_exterior: Optional[NDArray[Any]] = None, + extent: Optional[List[float]] = None, + title: str = "Category Map", + xlabel: str = "longitude", + ylabel: str = "latitude", + fig: Optional[Figure] = None, + ax: Optional[Axes] = None, +): + im, fmt, tickz = _plot_categorical_map( + dataset=dataset, + color_dict=color_dict, + labels=labels, + geom_exterior=geom_exterior, + extent=extent, + title=title, + xlabel=xlabel, + ylabel=ylabel, + fig=fig, + ax=ax, + ) + + plt.colorbar(im, format=fmt, ticks=tickz) + plt.show() + + return im, fmt, tickz + + +def plot_categorical_maps( + datasets: List[List[List[float]]], + color_dict: Dict[int, str], + labels: List[str], + titles: List[str], + suptitle: str, + geom_exterior: Optional[NDArray[Any]] = None, + extent: Optional[List[float]] = None, + xlabel: str = "", + ylabel: str = "", + n_cols: int = 2, + figsize: Tuple[int, int] = (12, 10), +): + rows = int(np.ceil(len(datasets) / n_cols)) + fig, axes = plt.subplots(rows, n_cols, figsize=figsize, sharex=True, sharey=True) + + im, fmt, tickz = None, None, None + for i, dataset in enumerate(datasets): + im, fmt, tickz = _plot_categorical_map( + dataset=dataset, + color_dict=color_dict, + labels=labels, + geom_exterior=geom_exterior, + extent=extent, + title=titles[i], + fig=fig, + ax=axes[i // n_cols, i % n_cols], # type: ignore + ) + fig.supxlabel(xlabel) + fig.supylabel(ylabel) + fig.suptitle(suptitle) + + fig.subplots_adjust(right=0.8) + cbar_ax = fig.add_axes([0.85, 0.15, 0.02, 0.7]) + fig.colorbar(im, cax=cbar_ax, format=fmt, ticks=tickz) + plt.show() diff --git a/scripts/export_sam_models.py b/scripts/export_sam_models.py new file mode 100644 index 00000000..72578604 --- /dev/null +++ b/scripts/export_sam_models.py @@ -0,0 +1,217 @@ +# Script to export SAM models to ONNX files and add them to FarmVibes.AI cluster. +# This was heavily inspired by Visheratin's export_onnx_model script available in: +# https://github.com/visheratin/segment-anything/blob/main/scripts/export_onnx_model.py + +import argparse +import os +import subprocess +import warnings +from dataclasses import dataclass +from tempfile import TemporaryDirectory +from typing import Optional, Tuple + +import onnx +import torch +from onnx.external_data_helper import convert_model_to_external_data +from segment_anything import sam_model_registry +from segment_anything.modeling.sam import Sam +from segment_anything.utils.onnx import SamOnnxModel + +from vibe_core.file_downloader import download_file + +try: + import onnxruntime # type: ignore + + onnxruntime_exists = True +except ImportError: + onnxruntime_exists = False + + +@dataclass +class ModelInfo: + url: str + should_use_data_file: bool + + +MODELS = { + "vit_b": ModelInfo( + url="https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth", + should_use_data_file=False, + ), + "vit_l": ModelInfo( + url="https://dl.fbaipublicfiles.com/segment_anything/sam_vit_l_0b3195.pth", + should_use_data_file=False, + ), + "vit_h": ModelInfo( + url="https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth", + should_use_data_file=True, + ), +} +RETURN_SINGLE_MASK = True +ONNX_OPSET = 17 + +HERE = os.path.dirname(os.path.abspath(__file__)) +PROJECT_DIR = os.path.abspath(os.path.join(HERE, "..")) + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Download SAM model(s), export to ONNX files, and add to FarmVibes.AI cluster." + ) + + parser.add_argument( + "--models", + nargs="+", + choices=["vit_b", "vit_l", "vit_h"], + required=True, + help="A list of SAM model types to export (among 'vit_b', 'vit_l', and 'vit_h').", + ) + + return parser.parse_args() + + +def export_model(model_type: str, downloaded_path: str, dir_path: str) -> Tuple[str, str]: + encoder_output = os.path.join(dir_path, f"{model_type}_encoder.onnx") + encoder_data_file = ( + os.path.join(dir_path, f"{model_type}_encoder_data_file.onnx") + if MODELS[model_type].should_use_data_file + else None + ) + + decoder_output = os.path.join(dir_path, f"{model_type}_decoder.onnx") + + sam = sam_model_registry[model_type](checkpoint=downloaded_path) + + encoder_path = export_encoder(sam, encoder_output, encoder_data_file) + decoder_path = export_decoder(sam, decoder_output) + + return (encoder_path, decoder_path) + + +def export_encoder(sam: Sam, output: str, data_file_output: Optional[str]) -> str: + dynamic_axes = { + "x": {0: "batch"}, + } + dummy_inputs = { + "x": torch.randn(1, 3, 1024, 1024, dtype=torch.float), + } + _ = sam.image_encoder(**dummy_inputs) + + output_names = ["image_embeddings"] + + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=torch.jit.TracerWarning) # type: ignore + warnings.filterwarnings("ignore", category=UserWarning) + print(f"Exporting onnx model to {output}...") + torch.onnx.export( + sam.image_encoder, + tuple(dummy_inputs.values()), + output, + export_params=True, + verbose=False, + opset_version=ONNX_OPSET, + do_constant_folding=True, + input_names=list(dummy_inputs.keys()), + output_names=output_names, + dynamic_axes=dynamic_axes, + ) + + if data_file_output: + onnx_model = onnx.load(output) + convert_model_to_external_data( + onnx_model, + all_tensors_to_one_file=True, + location=data_file_output, + size_threshold=1024, + convert_attribute=False, + ) + onnx.save_model(onnx_model, output) + + if onnxruntime_exists: + ort_inputs = {k: v.cpu().numpy() for k, v in dummy_inputs.items()} + ort_session = onnxruntime.InferenceSession(output) # type: ignore + _ = ort_session.run(None, ort_inputs) + print("Encoder has successfully been run with ONNXRuntime.") + + return output + + +def export_decoder(sam: Sam, output: str) -> str: + onnx_model = SamOnnxModel(model=sam, return_single_mask=RETURN_SINGLE_MASK) + + dynamic_axes = { + "point_coords": {1: "num_points"}, + "point_labels": {1: "num_points"}, + } + + embed_dim = sam.prompt_encoder.embed_dim + embed_size = sam.prompt_encoder.image_embedding_size + mask_input_size = [4 * x for x in embed_size] + dummy_inputs = { + "image_embeddings": torch.randn(1, embed_dim, *embed_size, dtype=torch.float), + "point_coords": torch.randint(low=0, high=1024, size=(1, 5, 2), dtype=torch.float), + "point_labels": torch.randint(low=0, high=4, size=(1, 5), dtype=torch.float), + "mask_input": torch.randn(1, 1, *mask_input_size, dtype=torch.float), + "has_mask_input": torch.tensor([1], dtype=torch.float), + "orig_im_size": torch.tensor([1500, 2250], dtype=torch.float), + } + + _ = onnx_model(**dummy_inputs) + + output_names = ["masks", "iou_predictions", "low_res_masks"] + + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=torch.jit.TracerWarning) # type: ignore + warnings.filterwarnings("ignore", category=UserWarning) + with open(output, "wb") as f: + print(f"Exporting onnx model to {output}...") + torch.onnx.export( + onnx_model, + tuple(dummy_inputs.values()), + f, # type: ignore + export_params=True, + verbose=False, + opset_version=ONNX_OPSET, + do_constant_folding=True, + input_names=list(dummy_inputs.keys()), + output_names=output_names, + dynamic_axes=dynamic_axes, + ) + + if onnxruntime_exists: + ort_inputs = {k: v.cpu().numpy() for k, v in dummy_inputs.items()} + providers = ["CPUExecutionProvider"] + ort_session = onnxruntime.InferenceSession(output, providers=providers) # type: ignore + _ = ort_session.run(None, ort_inputs) + print("Decoder has successfully been run with ONNXRuntime.") + + return output + + +def add_to_cluster(exported_paths: Tuple[str, str]): + for path in exported_paths: + print(f"Adding {path} to cluster...") + subprocess.run( + [ + "farmvibes-ai", + "local", + "add-onnx", + path, + ], + check=True, + ) + + +def main(): + args = parse_args() + + with TemporaryDirectory() as tmp_dir: + for model_type in args.models: + model_url = MODELS[model_type].url + downloaded_path = download_file(model_url, os.path.join(tmp_dir, f"{model_type}.pth")) + exported_paths = export_model(model_type, downloaded_path, tmp_dir) + add_to_cluster(exported_paths) + + +if __name__ == "__main__": + main() diff --git a/src/vibe_core/pyproject.toml b/src/vibe_core/pyproject.toml index 0a82306a..108d9d01 100644 --- a/src/vibe_core/pyproject.toml +++ b/src/vibe_core/pyproject.toml @@ -18,7 +18,7 @@ vibe_core = ["terraform/*.tf"] [project] name = "vibe-core" -version ="2024.02.08" +version ="2024.04.04" authors = [ { name="Microsoft FarmVibes.AI Team", email="eywa-devs@microsoft.com" }, ] diff --git a/src/vibe_core/vibe_core/admag_client.py b/src/vibe_core/vibe_core/admag_client.py index 8ec85f79..f7f0b9f8 100644 --- a/src/vibe_core/vibe_core/admag_client.py +++ b/src/vibe_core/vibe_core/admag_client.py @@ -104,20 +104,50 @@ def header(self) -> Dict[str, str]: return header - def _request(self, method: str, endpoint: str, *args: Any, **kwargs: Any): - response = self.session.request(method, urljoin(self.base_url, endpoint), *args, **kwargs) + def _request( + self, method: str, endpoint: str, data: Dict[str, Any] = {}, *args: Any, **kwargs: Any + ): + resp = self.session.request( + method, urljoin(self.base_url, endpoint), *args, **kwargs, json=data + ) try: - r = json.loads(response.text) + r = json.loads(resp.text) except json.JSONDecodeError: - r = response.text + r = resp.text try: - response.raise_for_status() + resp.raise_for_status() except HTTPError as e: error_message = r.get("message", "") if isinstance(r, dict) else r msg = f"{e}. {error_message}" raise HTTPError(msg, response=e.response) + return cast(Any, r) + def _iterate(self, response: Dict[str, Any]): + visited_next_links = set() + + composed_response = {self.CONTENT_TAG: response[self.CONTENT_TAG]} + next_link = "" if self.LINK_TAG not in response else response[self.LINK_TAG] + next_link_index = 0 + while next_link: + if next_link in visited_next_links: + raise RuntimeError(f"Repeated nextLink {next_link} in ADMAg get request") + + if next_link_index >= self.NEXT_PAGES_LIMIT: + raise RuntimeError(f"Next pages limit {self.NEXT_PAGES_LIMIT} exceded") + tmp_response = self._request( + "GET", + next_link, + timeout=self.DEFAULT_TIMEOUT, + ) + if self.CONTENT_TAG in tmp_response: + composed_response[self.CONTENT_TAG].extend(tmp_response[self.CONTENT_TAG]) + visited_next_links.add(next_link) + next_link_index = next_link_index + 1 + next_link = "" if self.LINK_TAG not in tmp_response else tmp_response[self.LINK_TAG] + response = composed_response + return response + def _get(self, endpoint: str, params: Dict[str, Any] = {}): request_params = {"api-version": self.api_version} request_params.update(params) @@ -127,41 +157,36 @@ def _get(self, endpoint: str, params: Dict[str, Any] = {}): params=request_params, timeout=self.DEFAULT_TIMEOUT, ) - visited_next_links = set() if self.CONTENT_TAG in response: - composed_response = {self.CONTENT_TAG: response[self.CONTENT_TAG]} - next_link = "" if self.LINK_TAG not in response else response[self.LINK_TAG] - next_link_index = 0 - while next_link: - if next_link in visited_next_links: - raise RuntimeError(f"Repeated nextLink {next_link} in ADMAg get request") - - if next_link_index >= self.NEXT_PAGES_LIMIT: - raise RuntimeError(f"Next pages limit {self.NEXT_PAGES_LIMIT} exceded") - tmp_response = self._request( - "GET", - next_link, - timeout=self.DEFAULT_TIMEOUT, - ) - if self.CONTENT_TAG in tmp_response: - composed_response[self.CONTENT_TAG].extend(tmp_response[self.CONTENT_TAG]) - visited_next_links.add(next_link) - next_link_index = next_link_index + 1 - next_link = "" if self.LINK_TAG not in tmp_response else tmp_response[self.LINK_TAG] - response = composed_response + response = self._iterate(response) + return response - def get_seasonal_fields(self, farmer_id: str, params: Dict[str, Any] = {}): - """Retrieves the seasonal fields for a given farmer. + def _post( + self, endpoint: str, params: Dict[str, Any] = {}, data: Dict[str, Any] = {} + ) -> Dict[str, Any]: + request_params = {"api-version": self.api_version, "maxPageSize": 1000} + request_params.update(params) + response = self._request( + "POST", endpoint, params=request_params, timeout=self.DEFAULT_TIMEOUT, data=data + ) - :param farmer_id: The ID of the farmer. + if self.CONTENT_TAG in response: + response = self._iterate(response) + + return response + + def get_seasonal_fields(self, party_id: str, params: Dict[str, Any] = {}): + """Retrieves the seasonal fields for a given party. + + :param party_id: The ID of the party. :param params: Additional parameters to be passed to the request. Defaults to {}. :return: The information for each seasonal fields. """ - endpoint = f"/farmers/{farmer_id}/seasonal-fields" + endpoint = f"/parties/{party_id}/seasonal-fields" request_params = {"api-version": self.api_version} request_params.update(params) @@ -170,41 +195,29 @@ def get_seasonal_fields(self, farmer_id: str, params: Dict[str, Any] = {}): params=request_params, ) - def get_field(self, farmer_id: str, field_id: str): + def get_field(self, party_id: str, field_id: str): """ - Retrieves the field information for a given farmer and field. + Retrieves the field information for a given party and field. - :param farmer_id: The ID of the farmer. + :param party_id: The ID of the party. :param field_id: The ID of the field. :return: The field information. """ - endpoint = f"/farmers/{farmer_id}/fields/{field_id}" + endpoint = f"/parties/{party_id}/fields/{field_id}" return self._get(endpoint) - def get_seasonal_field(self, farmer_id: str, seasonal_field_id: str): - """Retrieves the information of a seasonal field for a given farmer. + def get_seasonal_field(self, party_id: str, seasonal_field_id: str): + """Retrieves the information of a seasonal field for a given party. - :param farmer_id: The ID of the farmer. + :param party_id: The ID of the party. :param seasonal_field_id: The ID of the seasonal field. :return: The seasonal field information. """ - endpoint = f"/farmers/{farmer_id}/seasonal-fields/{seasonal_field_id}" - return self._get(endpoint) - - def get_boundary(self, farmer_id: str, boundary_id: str): - """Retrieves the information of a boundary for a given farmer. - - :param farmer_id: The ID of the farmer. - - :param boundary_id: The ID of the boundary. - - :return: The boundary information. - """ - endpoint = f"farmers/{farmer_id}/boundaries/{boundary_id}" + endpoint = f"/parties/{party_id}/seasonal-fields/{seasonal_field_id}" return self._get(endpoint) def get_season(self, season_id: str): @@ -219,22 +232,23 @@ def get_season(self, season_id: str): def get_operation_info( self, - farmer_id: str, - associated_boundary_ids: List[str], + party_id: str, + intersects_with_geometry: Dict[str, Any], operation_name: str, min_start_operation: str, max_end_operation: str, + associated_resource: Dict[str, str], sources: List[str] = [], ): """ - Retrieves the information of a specified operation for a given farmer. + Retrieves the information of a specified operation for a given party. This method will return information about the specified operation name, - in the specified time range, for the given farmer and associated boundary IDs. + in the specified time range, for the given party and associated resource. - :param farmer_id: The ID of the farmer. + :param party_id: The ID of the party. - :param associated_boundary_ids: The IDs of the boundaries associated to the operation. + :param intersects_with_geometry: geometry of associated resource. :param operation_name: The name of the operation. @@ -246,35 +260,42 @@ def get_operation_info( :return: The operation information. """ - endpoint = f"/farmers/{farmer_id}/{operation_name}" + endpoint = f"/{operation_name}:search" params = { "api-version": self.api_version, - "associatedBoundaryIds": associated_boundary_ids, + } + + data = { + "partyId": party_id, + "intersectsWithGeometry": intersects_with_geometry, "minOperationStartDateTime": min_start_operation, "maxOperationEndDateTime": max_end_operation, + "associatedResourceType": associated_resource["type"], + "associatedResourceIds": [associated_resource["id"]], } if sources: - params["sources"] = sources + data["sources"] = sources - return self._get(endpoint, params=params) + return self._post(endpoint, params=params, data=data) def get_harvest_info( self, - farmer_id: str, - associated_boundary_ids: List[str], + party_id: str, + intersects_with_geometry: Dict[str, Any], min_start_operation: str, max_end_operation: str, + associated_resource: Dict[str, str], ): - """Retrieves the harvest information for a given farmer. + """Retrieves the harvest information for a given party. - This method will return the harvest information for a given farmer, - associated with the provided boundary ids, between the start and end - operation dates specified. + This method will return the harvest information for a given resource, + associated with the provided party id, between the start & end + operation dates specified and intersecting with input geometry. - :param farmer_id: ID of the farmer. + :param party_id: ID of the party. - :param associated_boundary_ids: List of associated boundary IDs. + :param intersects_with_geometry: geometry of associated resource. :param min_start_operation: The minimum start date of the operation. @@ -283,29 +304,31 @@ def get_harvest_info( :return: Dictionary with harvest information. """ return self.get_operation_info( - farmer_id=farmer_id, - associated_boundary_ids=associated_boundary_ids, + party_id=party_id, + intersects_with_geometry=intersects_with_geometry, operation_name="harvest-data", min_start_operation=min_start_operation, max_end_operation=max_end_operation, + associated_resource=associated_resource, ) def get_fertilizer_info( self, - farmer_id: str, - associated_boundary_ids: List[str], + party_id: str, + intersects_with_geometry: Dict[str, Any], min_start_operation: str, max_end_operation: str, + associated_resource: Dict[str, str], ): - """Retrieves the fertilizer information for a given farmer. + """Retrieves the fertilizer information for a given party. - This method will return the fertilizer information for a given farmer, - associated with the provided boundary ids, between the start and end - operation dates specified. + This method will return the fertilizer information for a given resource, + associated with the provided party id, between the start & end + operation dates specified and intersecting with input geometry. - :param farmer_id: ID of the farmer. + :param party_id: ID of the party. - :param associated_boundary_ids: List of associated boundary IDs. + :param intersects_with_geometry: geometry of associated resource. :param min_start_operation: The minimum start date of the operation. @@ -314,30 +337,32 @@ def get_fertilizer_info( :return: Dictionary with fertilizer information. """ return self.get_operation_info( - farmer_id=farmer_id, - associated_boundary_ids=associated_boundary_ids, + party_id=party_id, + intersects_with_geometry=intersects_with_geometry, operation_name="application-data", min_start_operation=min_start_operation, max_end_operation=max_end_operation, sources=["Fertilizer"], + associated_resource=associated_resource, ) def get_organic_amendments_info( self, - farmer_id: str, - associated_boundary_ids: List[str], + party_id: str, + intersects_with_geometry: Dict[str, Any], min_start_operation: str, max_end_operation: str, + associated_resource: Dict[str, str], ): - """Retrieves the organic amendments information for a given farmer. + """Retrieves the organic amendments information for a given party. - This method will return the organic amendments information for a given farmer, - associated with the provided boundary ids, between the start and end - operation dates specified. + This method will return the organic amendments information for a given resource, + associated with the provided party id, between the start & end + operation dates specified and intersecting with input geometry. - :param farmer_id: ID of the farmer. + :param party_id: ID of the party. - :param associated_boundary_ids: List of associated boundary IDs. + :param intersects_with_geometry: geometry of associated resource. :param min_start_operation: The minimum start date of the operation. @@ -347,30 +372,32 @@ def get_organic_amendments_info( """ return self.get_operation_info( - farmer_id=farmer_id, - associated_boundary_ids=associated_boundary_ids, + party_id=party_id, + intersects_with_geometry=intersects_with_geometry, operation_name="application-data", min_start_operation=min_start_operation, max_end_operation=max_end_operation, sources=["Omad"], + associated_resource=associated_resource, ) def get_tillage_info( self, - farmer_id: str, - associated_boundary_ids: List[str], + party_id: str, + intersects_with_geometry: Dict[str, Any], min_start_operation: str, max_end_operation: str, + associated_resource: Dict[str, str], ): - """Retrieves the tillage information for a given farmer. + """Retrieves the tillage information for a given party. - This method will return the tillage information for a given farmer, - associated with the provided boundary ids, between the start and end - operation dates specified. + This method will return the tillage information for a given resource, + associated with the provided party id, between the start & end + operation dates specified and intersecting with input geometry. - :param farmer_id: ID of the farmer. + :param party_id: ID of the Party. - :param associated_boundary_ids: List of associated boundary IDs. + :param intersects_with_geometry: geometry of associated resource. :param min_start_operation: The minimum start date of the operation. @@ -379,20 +406,21 @@ def get_tillage_info( :return: Dictionary with tillage information. """ return self.get_operation_info( - farmer_id=farmer_id, - associated_boundary_ids=associated_boundary_ids, + party_id=party_id, + intersects_with_geometry=intersects_with_geometry, operation_name="tillage-data", min_start_operation=min_start_operation, max_end_operation=max_end_operation, + associated_resource=associated_resource, ) - def get_prescription_map_id(self, farmer_id: str, field_id: str, crop_id: str): - """Retrieves the prescription map ID for a given farmer. + def get_prescription_map_id(self, party_id: str, field_id: str, crop_id: str): + """Retrieves the prescription map ID for a given party. - This method will return the prescription map ID for a given farmer, + This method will return the prescription map ID for a given party, associated with the provided field and crop IDs. - :param farmer_id: ID of the farmer. + :param party_id: ID of the Party. :param field_id: ID of the field. @@ -400,20 +428,80 @@ def get_prescription_map_id(self, farmer_id: str, field_id: str, crop_id: str): return: Dictionary with prescription map ID. """ - endpoint = f"farmers/{farmer_id}/prescription-maps" - return self._get(endpoint, params={"fieldId": field_id, "cropId": crop_id}) + endpoint = f"parties/{party_id}/prescription-maps" + return self._get(endpoint, params={"fieldIds": [field_id], "cropIds": [crop_id]}) - def get_prescriptions(self, farmer_id: str, prescription_map_id: str): - """Retrieves the prescriptions for a given farmer. + def get_prescriptions( + self, party_id: str, prescription_map_id: str, geometry: Dict[str, Any] = {} + ) -> Dict[str, Any]: + """Retrieves the prescriptions for a given party. - This method will return the prescriptions for a given farmer, + This method will return the prescriptions for a given party, associated with the provided prescription map ID. - :param farmer_id: ID of the farmer. + :param party_id: ID of the party. :param prescription_map_id: ID of the prescription map. + :param geometry: geometry intersect with prescriptions. + return: Dictionary with prescriptions. """ - endpoint = f"farmers/{farmer_id}/prescriptions" - return self._get(endpoint, params={"prescriptionMapIds": prescription_map_id}) + endpoint = "/prescription:search" + return self._post( + endpoint, + params={}, + data={ + "partyId": party_id, + "prescriptionMapIds": [prescription_map_id], + "intersectsWithGeometry": geometry, + }, + ) + + def get_prescription(self, party_id: str, prescription_id: str): + """Retrieves the prescription for a given party. + + This method will return the prescription for a given party, + associated with the provided party_id. + + :param party_id: ID of the Party. + + :param prescription_id: ID of the prescription. + + return: Dictionary with prescription. + """ + endpoint = f"parties/{party_id}/prescriptions/{prescription_id}" + return self._get(endpoint) + + def get_planting_info( + self, + party_id: str, + intersects_with_geometry: Dict[str, Any], + min_start_operation: str, + max_end_operation: str, + associated_resource: Dict[str, str], + ): + """Retrieves the Planting information for a given resource. + + This method will return the Planting information for a given resource, + associated with the provided party id, between the start & end + operation dates specified and intersecting with input geometry. + + :param resource: resource linked to planting information. + + :param intersects_with_geometry: resource geometry. + + :param min_start_operation: The minimum start date of the operation. + + :param max_end_operation: The maximum end date of the operation. + + :return: Dictionary with planting information. + """ + return self.get_operation_info( + party_id=party_id, + intersects_with_geometry=intersects_with_geometry, + operation_name="planting-data", + min_start_operation=min_start_operation, + max_end_operation=max_end_operation, + associated_resource=associated_resource, + ) diff --git a/src/vibe_core/vibe_core/cli/constants.py b/src/vibe_core/vibe_core/cli/constants.py index 2107b1ad..998af048 100644 --- a/src/vibe_core/vibe_core/cli/constants.py +++ b/src/vibe_core/vibe_core/cli/constants.py @@ -1,5 +1,5 @@ DEFAULT_IMAGE_PREFIX = "farmai/terravibes/" -DEFAULT_IMAGE_TAG = "2024.02.08" +DEFAULT_IMAGE_TAG = "2024.04.04" DEFAULT_REGISTRY_PATH = "mcr.microsoft.com" LOCAL_SERVICE_URL_PATH_FILE = "service_url" diff --git a/src/vibe_core/vibe_core/cli/helper.py b/src/vibe_core/vibe_core/cli/helper.py index e49efbf3..51f7f6b9 100644 --- a/src/vibe_core/vibe_core/cli/helper.py +++ b/src/vibe_core/vibe_core/cli/helper.py @@ -10,6 +10,7 @@ AUTO_CONFIRMATION = False DEFAULT_ERROR_STRING = "Unable to execute command" +WARNING_STRINGS = ("[warning]", "[Warning]", "[WARNING]", "WARNING:", "Warning:", "warning:") @lru_cache @@ -42,10 +43,12 @@ def execute_cmd( stdout_capture: List[str] = [] with process.stdout: # type: ignore binary = os.path.basename(cmd[0]) + is_running_az = binary.split(".")[0].lower() == "az" for line in iter(process.stdout.readline, b""): # type: ignore if line: decoded = line.decode(get_subprocess_encoding()).rstrip() - stdout_capture.append(decoded) + if not is_running_az or (is_running_az and not decoded.startswith(WARNING_STRINGS)): + stdout_capture.append(decoded) if not censor_output: log_subprocess(binary, decoded, subprocess_log_level) retcode = process.wait() @@ -74,8 +77,16 @@ def verify_to_proceed(message: str) -> bool: if AUTO_CONFIRMATION: return True - confirmation = input(f"{message} (y/n): ") - if confirmation and confirmation.lower() == "y": + answered = False + confirmation = False + while not answered: + confirmation = input(f"{message} (y/n): ").lower() + if confirmation not in ["y", "n", "yes", "no"]: + print("Invalid input. Please enter 'y' or 'n'") + continue + answered = True + confirmation = confirmation[0] + if confirmation == "y": return True return False diff --git a/src/vibe_core/vibe_core/cli/local.py b/src/vibe_core/vibe_core/cli/local.py index 509d6684..9af42564 100644 --- a/src/vibe_core/vibe_core/cli/local.py +++ b/src/vibe_core/vibe_core/cli/local.py @@ -18,6 +18,7 @@ from vibe_core.cli.osartifacts import InstallType, OSArtifacts from vibe_core.cli.wrappers import ( AzureCliWrapper, + DaprWrapper, DockerWrapper, K3dWrapper, KubectlWrapper, @@ -237,6 +238,7 @@ def setup( image_prefix: str = DEFAULT_IMAGE_PREFIX, data_path: str = "", worker_replicas: int = 0, + enable_telemetry: bool = False, port: int = DEFAULT_PORT, host: str = DEFAULT_HOST, is_update: bool = False, @@ -304,6 +306,10 @@ def setup( if username and password: log(f"Creating Docker credentials for registry {registry}") + try: + kubectl.delete_secret("acrtoken") + except Exception: + pass kubectl.create_docker_token("acrtoken", registry, username, password) if not worker_replicas: @@ -314,6 +320,15 @@ def setup( ) return False + dapr_updated = False + dapr = DaprWrapper(kubectl.os_artifacts, kubectl) + if is_update and dapr.needs_upgrade(): + log("Upgrading Dapr CRDs") + if not dapr.upgrade_crds(): + log("Unable to upgrade Dapr CRDs", level="error") + return False + dapr_updated = True + terraform = TerraformWrapper(k3d.os_artifacts, az) with terraform.workspace(f"farmvibes-k3d-{k3d.cluster_name}"): terraform.ensure_local_cluster( @@ -327,6 +342,7 @@ def setup( data_path, worker_replicas, kubectl.context_name, + enable_telemetry, is_update=is_update, ) # We might have downloaded newer images, so we have to fix permissions @@ -340,6 +356,13 @@ def setup( except Exception: log("Unable to fix permissions on containerd image path", level="warning") + if dapr_updated: + log("dapr upgraded, restarting services") + with kubectl.context(kubectl.cluster_name): + kubectl.restart( + "deployment", selectors=["backend=terravibes"] + ) + log(f"Cluster {'update' if is_update else 'setup'} complete!") if not is_update: @@ -574,6 +597,7 @@ def dispatch(args: argparse.Namespace): else: log("Aborting update due to old cluster being present", level="error") return False + enable_telemetry = args.enable_telemetry if hasattr(args, "enable_telemetry") else False return setup( k3d, args.servers, @@ -589,6 +613,7 @@ def dispatch(args: argparse.Namespace): args.image_prefix, data_path, args.worker_replicas, + enable_telemetry, args.port, args.host, is_update=is_update, diff --git a/src/vibe_core/vibe_core/cli/parsers.py b/src/vibe_core/vibe_core/cli/parsers.py index 4e8aba20..c10ff46e 100644 --- a/src/vibe_core/vibe_core/cli/parsers.py +++ b/src/vibe_core/vibe_core/cli/parsers.py @@ -34,6 +34,11 @@ "china", ] +HERE = os.path.dirname(os.path.abspath(__file__)) +CORE_DIR = os.path.dirname(HERE) +LOCAL_OTEL_PATH = os.path.join(CORE_DIR, "terraform", "local", "modules", "kubernetes", "otel.tf") +REMOTE_OTEL_PATH = os.path.join(CORE_DIR, "terraform", "aks", "modules", "kubernetes", "otel.tf") + class CliParser(ABC): SUPPORTED_COMMANDS = [ @@ -196,6 +201,14 @@ def _add_setup_update_flags(self): help="Port to use for registry on host", ) + if os.path.exists(LOCAL_OTEL_PATH): + command.add_argument( + "--enable-telemetry", + default=False, + action="store_true", + help="Enable telemetry for FarmVibes.AI", + ) + def _add_common_flags(self): cluster_name = os.environ.get( "FARMVIBES_AI_CLUSTER_NAME", @@ -314,3 +327,11 @@ def _add_setup_update_flags(self): default=3, help="Number of worker replicas to use", ) + + if os.path.exists(REMOTE_OTEL_PATH): + command.add_argument( + "--enable-telemetry", + default=False, + action="store_true", + help="Enable telemetry for FarmVibes.AI", + ) diff --git a/src/vibe_core/vibe_core/cli/remote.py b/src/vibe_core/vibe_core/cli/remote.py index 5f62cdf6..8318ce5a 100644 --- a/src/vibe_core/vibe_core/cli/remote.py +++ b/src/vibe_core/vibe_core/cli/remote.py @@ -7,7 +7,7 @@ from vibe_core.cli.helper import in_wsl, log_should_be_logged_in, verify_to_proceed from vibe_core.cli.logging import ColorFormatter, log from vibe_core.cli.osartifacts import OSArtifacts -from vibe_core.cli.wrappers import AzureCliWrapper, KubectlWrapper, TerraformWrapper +from vibe_core.cli.wrappers import AzureCliWrapper, DaprWrapper, KubectlWrapper, TerraformWrapper DESTROY_WARNING = ( "Destroying the cluster will delete *ALL* resources under the resource group " @@ -27,7 +27,9 @@ def _initialize_kubectl( if not config_context: log("Couldn't get Kubernetes config context", level="error") return None - return KubectlWrapper(az.os_artifacts, config_context=config_context) + return KubectlWrapper( + az.os_artifacts, cluster_name=az.cluster_name, config_context=config_context + ) def status(os_artifacts: OSArtifacts, az: AzureCliWrapper, environment: str) -> bool: @@ -100,6 +102,7 @@ def setup_or_upgrade( log_level: str, is_update: bool, max_worker_nodes: int = MAX_WORKER_NODES, + enable_telemetry: bool = False, worker_replicas: int = 0, environment: str = "", current_user_name: str = "", @@ -172,6 +175,8 @@ def setup_or_upgrade( az.cluster_name, az.resource_group, ) + else: + az.refresh_aks_credentials() storage_name, container_name, storage_access_key = az.ensure_azurerm_backend( region, @@ -210,9 +215,24 @@ def setup_or_upgrade( storage_name, container_name, storage_access_key, - cleanup_state=not is_update, + enable_telemetry, # Required to create azure monitor and application insights + cleanup_state=True, is_update=is_update, ) + + dapr_updated = False + kubectl = _initialize_kubectl(az, terraform) + if not kubectl: + log("Couldn't initialize kubectl, not updating", level="error") + return False + dapr = DaprWrapper(kubectl.os_artifacts, kubectl) + if is_update and dapr.needs_upgrade(): + log("Upgrading Dapr CRDs") + if not dapr.upgrade_crds(): + log("Unable to upgrade Dapr CRDs", level="error") + return False + dapr_updated = True + k8s_results = terraform.ensure_k8s_cluster( az.cluster_name, tenant_id, @@ -231,10 +251,12 @@ def setup_or_upgrade( infra_results["storage_connection_key"]["value"], infra_results["storage_account_name"]["value"], infra_results["userfile_container_name"]["value"], + infra_results["monitor_instrumentation_key"]["value"], storage_name, container_name, storage_access_key, - cleanup_state=not is_update, + enable_telemetry, + cleanup_state=True, ) terraform.ensure_services( az.cluster_name, @@ -247,11 +269,17 @@ def setup_or_upgrade( image_prefix, image_tag, k8s_results["shared_resource_pv_claim_name"]["value"], + k8s_results["otel_service_name"]["value"] if enable_telemetry else "", worker_replicas, log_level, - cleanup_state=not is_update, + cleanup_state=True, ) + if dapr_updated: + log("dapr upgraded, restarting services") + with kubectl.context(kubectl.cluster_name): + kubectl.restart("deployment", selectors=["backend=terravibes"]) + except Exception as e: log(f"{e.__class__.__name__}: {e}") log( @@ -392,6 +420,7 @@ def dispatch(args: argparse.Namespace): if args.action in {"setup", "update"}: az.refresh_az_creds() az.expand_azure_region(args.region.strip()) + enable_telemetry = args.enable_telemetry if hasattr(args, "enable_telemetry") else False ret = setup_or_upgrade( os_artifacts, az, @@ -405,6 +434,7 @@ def dispatch(args: argparse.Namespace): args.log_level, any([args.action in e for e in {"up", "upgrade", "update"}]), max_worker_nodes=args.max_worker_nodes, + enable_telemetry=enable_telemetry, worker_replicas=args.worker_replicas, environment=args.environment, current_user_name=args.cluster_admin_name, diff --git a/src/vibe_core/vibe_core/cli/wrappers.py b/src/vibe_core/vibe_core/cli/wrappers.py index 9cde8739..d4df6b96 100644 --- a/src/vibe_core/vibe_core/cli/wrappers.py +++ b/src/vibe_core/vibe_core/cli/wrappers.py @@ -1,6 +1,7 @@ import hashlib import json import os +import pkgutil import platform import re import shutil @@ -11,6 +12,8 @@ from functools import partialmethod from typing import Any, Dict, List, Optional, Tuple +import requests + from .constants import RABBITMQ_IMAGE_TAG, REDIS_IMAGE_TAG from .helper import execute_cmd, is_port_free, log_should_be_logged_in, verify_to_proceed from .logging import ColorFormatter, log @@ -208,7 +211,7 @@ def init( if backend_config: f = tempfile.NamedTemporaryFile(mode="w", dir=temp_dir, delete=False) contents = "\n".join([f'{k} = "{v}"' for k, v in backend_config.items()]) - if on_windows: + if on_windows(): log( ( "We're on Windows, replacing backslashes in backend file " @@ -271,6 +274,7 @@ def ensure_infra( storage_name: str, container_name: str, storage_access_key: str, + enable_telemetry: bool, cleanup_state: bool = False, is_update: bool = False, ): @@ -296,6 +300,7 @@ def ensure_infra( "prefix": cluster_name, "kubeconfig_location": self.os_artifacts.config_dir, "max_worker_nodes": worker_nodes, + "enable_telemetry": f"{'true' if enable_telemetry else 'false'}", "resource_group_name": resource_group, } @@ -353,9 +358,11 @@ def ensure_k8s_cluster( storage_connection_key: str, storage_account_name: str, userfile_container_name: str, + monitor_instrumentation_key: str, backend_storage_name: str, backend_container_name: str, backend_storage_access_key: str, + enable_telemetry: bool, cleanup_state: bool = False, ): # Do kubernetes infra now @@ -390,9 +397,11 @@ def ensure_k8s_cluster( "storage_connection_key": storage_connection_key, "storage_account_name": storage_account_name, "userfile_container_name": userfile_container_name, + "monitor_instrumentation_key": monitor_instrumentation_key, "resource_group_name": resource_group, "current_user_name": current_user_name, "certificate_email": certificate_email, + "enable_telemetry": str(enable_telemetry).lower(), } state_file = self.os_artifacts.get_terraform_file( @@ -414,6 +423,7 @@ def ensure_services( image_prefix: str, image_tag: str, shared_resource_pv_claim_name: str, + otel_service_name: str, worker_replicas: int, log_level: str, cleanup_state: bool = False, @@ -442,6 +452,7 @@ def ensure_services( "image_prefix": image_prefix, "image_tag": image_tag, "shared_resource_pv_claim_name": shared_resource_pv_claim_name, + "otel_service_name": otel_service_name, "worker_replicas": worker_replicas, "farmvibes_log_level": log_level, } @@ -465,6 +476,7 @@ def ensure_local_cluster( data_path: str, worker_replicas: int, config_context: str, + enable_telemetry: bool, redis_image_tag: str = REDIS_IMAGE_TAG, rabbitmq_image_tag: str = RABBITMQ_IMAGE_TAG, is_update: bool = False, @@ -484,6 +496,7 @@ def ensure_local_cluster( "image_prefix": image_prefix, "redis_image_tag": redis_image_tag, "rabbitmq_image_tag": rabbitmq_image_tag, + "enable_telemetry": f"{'true' if enable_telemetry else 'false'}", "farmvibes_log_level": log_level, "max_log_file_bytes": f"{max_log_file_bytes}" if max_log_file_bytes else "", "log_backup_count": f"{log_backup_count}" if log_backup_count else "", @@ -1018,6 +1031,7 @@ def get_storage_account_key(self, storage_name: str): storage_name, "-o", "json", + "--only-show-errors", ] error = "Couldn't get storage account keys. Do you have access to the resource group?" results = execute_cmd(cmd, True, False, error, censor_output=True) @@ -1446,6 +1460,27 @@ def restart(self, kind: str, selectors: List[str] = [], name: str = "", cluster_ ) return True + def apply_or_replace(self, file_path: str, cluster_name: str = ""): + cluster_name = self._actual_cluster_name(cluster_name) + with self.context(cluster_name): + for kind in "apply replace".split(): + try: + log(f"Applying {kind} {file_path}", level="debug") + cmd = [self.os_artifacts.kubectl, kind, "-f", file_path] + execute_cmd( + cmd, + error_string=f"Unable to {kind} {file_path}", + subprocess_log_level="debug", + ) + log(f"Successfully {kind} {file_path}", level="debug") + return True + except Exception as e: + if kind == "apply": + log(f"Failed to apply {file_path}: {e} (will try again)", level="warning") + continue + log(f"Failed to apply updates to CRD {file_path}", level="error") + return False # Should never reach here + class K3dWrapper: CONTAINERD_IMAGE_PATH = "/var/lib/rancher/k3s/agent/containerd/io.containerd.content.v1.content" @@ -1652,3 +1687,94 @@ def exec(self, container_name: str, command: List[str]): check_empty_result=False, ) return result + + +class DaprWrapper: # DaprWrapr 🫠 + VERSION_STRING = "VERSION" + CRD_BASE = "https://raw.githubusercontent.com/dapr/dapr/v{}/charts/dapr/crds/" + CRD_FILES = [ + "components.yaml", + "configuration.yaml", + "subscription.yaml", + "resiliency.yaml", + "httpendpoints.yaml", + ] + + def __init__( + self, + os_artifacts: OSArtifacts, + kubectl: KubectlWrapper, + cluster_kind: str = "local", + namespace: str = "dapr-system", + ): + self.cluster_kind = cluster_kind + self.os_artifacts = os_artifacts + self.namespace = namespace + self.kubectl = kubectl + + def _version_column(self, header: str) -> int: + reversed_header = list(reversed(header.split())) + return -reversed_header.index(self.VERSION_STRING) - 1 - 1 + + def _target_version(self) -> str: + # use pkg_resources to find dapr.tf: + dapr_tf = pkgutil.get_data( + "vibe_core.terraform", f"{self.cluster_kind}/modules/kubernetes/dapr.tf" + ) + if not dapr_tf: + raise ValueError("Unable to find dapr.tf") + target = re.findall('version\\s+=\\s+"(.*)"', dapr_tf.decode("utf-8"))[0] + assert len(target) > 0, "Unable to find Dapr version in dapr.tf" + return target + + def version(self): + cmd = [self.os_artifacts.dapr, "status", "-k"] + with self.kubectl.context(self.kubectl.cluster_name): + result = execute_cmd( + cmd, error_string="Unable to get Dapr version", subprocess_log_level="debug" + ) + lines = result.split("\n") + version_column = self._version_column(lines[0]) + all_versions = set([line.split()[version_column] for line in lines[1:] if line]) + return [v for v in all_versions] + + def needs_upgrade(self): + version_tuple = tuple(map(int, self._target_version().split("."))) + current_versions_tuples = [tuple(map(int, v.split("."))) for v in self.version()] + return len(current_versions_tuples) == 0 or any( + [v < version_tuple for v in current_versions_tuples if v > (1, 0, 0)] + ) + + def url_exists(self, url: str) -> bool: + try: + response = requests.head(url) + return response.status_code == 200 + except requests.exceptions.RequestException: + return False + + def upgrade_crds(self): + # Upgrading dapr is a two-stage process. + # First, we upgrade the CRDs, then, we use terraform to upgrade the dapr runtime. + status = [] + for crd in self.CRD_FILES: + url = self.CRD_BASE.format(self._target_version()) + crd + if not self.url_exists(url): + log(f"CRD {crd} not found at {url}, ignoring it", level="warning") + continue + status.append(self.kubectl.apply_or_replace(url)) + return all(status) + + def upgrade(self): + cmd = [ + self.os_artifacts.dapr, + "upgrade", + "-k", + f"--runtime-version={self._target_version()}", + ] + log(f"Upgrading Dapr to version {self._target_version()}") + with self.kubectl.context(self.kubectl.cluster_name): + execute_cmd( + cmd, + error_string="Unable to upgrade Dapr", + subprocess_log_level="debug", + ) diff --git a/src/vibe_core/vibe_core/client.py b/src/vibe_core/vibe_core/client.py index 108adc1c..4e397d0e 100644 --- a/src/vibe_core/vibe_core/client.py +++ b/src/vibe_core/vibe_core/client.py @@ -1,4 +1,5 @@ import json +import logging import os import time import warnings @@ -93,7 +94,6 @@ def list_workflows(self) -> List[str]: """Lists all available workflows. :return: A list of workflow names. - :raises NotImplementedError: If the method is not implemented by a subclass. """ raise NotImplementedError @@ -110,9 +110,7 @@ def run( :param workflow: The name of the workflow to run. :param geometry: The geometry to run the workflow on. :param time_range: The time range to run the workflow on. - :return: A :class:`WorkflowRun` object. - :raises NotImplementedError: If the method is not implemented by a subclass. """ raise NotImplementedError @@ -275,6 +273,12 @@ def describe_workflow(self, workflow_name: str) -> Dict[str, Any]: The keys are 'name', 'description', 'inputs', 'outputs' and 'parameters'. """ desc = self._request("GET", f"v0/workflows/{workflow_name}?return_format=description") + + param_descriptions = desc["description"]["parameters"] + for p, d in param_descriptions.items(): + if isinstance(d, List): + param_descriptions[p] = d[0] + desc["description"] = TaskDescription(**desc["description"]) return desc @@ -432,6 +436,29 @@ def get_run_by_id(self, id: str) -> "VibeWorkflowRun": run = self.list_runs(id, fields=fields)[0] return VibeWorkflowRun(*(run[f] for f in fields), self) # type: ignore + def get_last_runs(self, n: int) -> List["VibeWorkflowRun"]: + """Gets the last 'n' workflow runs. + + This method returns a list of :class:`VibeWorkflowRun` objects containing + the details of the last n workflow runs. + + :param n: The number of workflow runs to get (with n>0). + + :return: A list of :class:`VibeWorkflowRun` objects. + """ + if n <= 0: + raise ValueError(f"The number of runs (n) must be greater than 0. Got {n} instead.") + + last_runs = self.list_runs()[-n:] + if not last_runs: + raise ValueError("No past runs available.") + elif len(last_runs) < n: + logging.warning( + f"Requested {n} runs, but only {len(last_runs)} are available. " + "Returning all available runs." + ) + return [self.get_run_by_id(run_id) for run_id in last_runs] + def get_api_time_zone(self) -> tzfile: """Gets the time zone of the FarmVibes.AI REST-API. @@ -582,19 +609,25 @@ def _loop_update_monitor_table( ) time.sleep(refresh_time_s) - curent_time = time.monotonic() + current_time = time.monotonic() # Check for warnings every refresh_warnings_time_min minutes - if (curent_time - last_warning_refresh) / 60.0 > refresh_warnings_time_min: + if (current_time - last_warning_refresh) / 60.0 > refresh_warnings_time_min: self.verify_disk_space() - last_warning_refresh = curent_time + last_warning_refresh = current_time # Check for timeout did_timeout = ( - timeout_min is not None and (curent_time - time_start) / 60.0 > timeout_min + timeout_min is not None and (current_time - time_start) / 60.0 > timeout_min ) stop_monitoring = ( - all([RunStatus.finished(r.status) for r in runs]) or did_timeout + all( + [ + RunStatus.finished(r.status) or r.status == RunStatus.deleted + for r in runs + ] + ) + or did_timeout ) # Update one last time to make sure we have the latest state @@ -605,7 +638,7 @@ def _loop_update_monitor_table( def monitor( self, - runs: Union[List["VibeWorkflowRun"], "VibeWorkflowRun"], + runs: Union[List["VibeWorkflowRun"], "VibeWorkflowRun", int] = 1, refresh_time_s: int = 1, refresh_warnings_time_min: int = 5, timeout_min: Optional[int] = None, @@ -614,11 +647,14 @@ def monitor( """Monitors workflow runs. This method will block and print the status of the runs each refresh_time_s seconds, - until the workflow run finishes or it reaches timeout_min minutes. It will also + until the workflow runs finish or it reaches timeout_min minutes. It will also print warnings every refresh_warnings_time_min minutes. - :param runs: A list of workflow runs to monitor. If only one run is provided, - the method will monitor that run directly. + :param runs: A list of workflow runs, a single run object, or an integer. The method will + monitor the provided workflow runs. If a list of runs is provided, the method will + provide a summarized table with the status of each run. If only one run is provided, + the method will monitor that run directly. If an integer > 0 is provided, the method + will fetch the respective last runs and provide the summarized monitor table. :param refresh_time_s: Refresh interval in seconds (defaults to 1 second). @@ -633,9 +669,14 @@ def monitor( :raises ValueError: If no workflow runs are provided (empty list). """ + if isinstance(runs, int): + runs = self.get_last_runs(runs) + if isinstance(runs, VibeWorkflowRun): runs = [runs] + runs = cast(List[VibeWorkflowRun], runs) + if len(runs) == 0: raise ValueError("At least one workflow run must be provided.") diff --git a/src/vibe_core/vibe_core/data/__init__.py b/src/vibe_core/vibe_core/data/__init__.py index d0dc6292..dee86916 100644 --- a/src/vibe_core/vibe_core/data/__init__.py +++ b/src/vibe_core/vibe_core/data/__init__.py @@ -14,8 +14,10 @@ GeometryCollection, GHGFlux, GHGProtocolVibe, + OrdinalTrendTest, Point, ProteinSequence, + RasterPixelCount, TimeRange, TimeSeries, TypeDictVibe, @@ -23,6 +25,8 @@ gen_hash_id, ) from .farm import ( + ADMAgPrescription, + ADMAgPrescriptionInput, ADMAgSeasonalFieldInput, FertilizerInformation, HarvestInformation, @@ -40,6 +44,7 @@ GEDIProduct, GLADProduct, GNATSGOProduct, + HansenProduct, HerbieProduct, LandsatProduct, ModisProduct, diff --git a/src/vibe_core/vibe_core/data/core_types.py b/src/vibe_core/vibe_core/data/core_types.py index 2ce8888b..3bc381af 100644 --- a/src/vibe_core/vibe_core/data/core_types.py +++ b/src/vibe_core/vibe_core/data/core_types.py @@ -2,6 +2,7 @@ import logging import re import uuid +from copy import deepcopy from dataclasses import asdict, dataclass, field, fields, is_dataclass from datetime import datetime, timezone from pathlib import Path @@ -353,6 +354,10 @@ def schema(cls, *args, **kwargs): # type: ignore def pydantic_model(cls): # type: ignore if is_dataclass(cls): if issubclass(cls, DataVibe): + cls = deepcopy(cls) + if 'asset_geometry' in cls.__dataclass_fields__: # type: ignore + f = cls.__dataclass_fields__['asset_geometry'] + f.type = Dict[str, Any] # type: ignore @pydataclass class PydanticAssetVibe(AssetVibe): @@ -512,6 +517,13 @@ class TimeSeries(DataVibe): pass +@dataclass +class RasterPixelCount(DataVibe): + """Represents a data object in FarmVibes.AI that stores the pixel count of a raster.""" + + pass + + @dataclass class DataSummaryStatistics(DataVibe): """Represents a data summary statistics object in FarmVibes.AI.""" @@ -519,6 +531,14 @@ class DataSummaryStatistics(DataVibe): pass +@dataclass +class OrdinalTrendTest(DataVibe): + """Represents a trend test (Chochan-Armitage) result object in FarmVibes.AI.""" + + p_value: float + z_score: float + + @dataclass class DataSequence(DataVibe): """Represents a sequence of data assets in FarmVibes.AI.""" diff --git a/src/vibe_core/vibe_core/data/farm.py b/src/vibe_core/vibe_core/data/farm.py index 02312b34..1fb4a5ad 100644 --- a/src/vibe_core/vibe_core/data/farm.py +++ b/src/vibe_core/vibe_core/data/farm.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional from .core_types import BaseVibe, DataVibe @@ -10,12 +10,10 @@ class ADMAgSeasonalFieldInput(BaseVibe): Represents an ADMAg Seasonal Field input. """ - farmer_id: str - """The ID of the farmer.""" + party_id: str + """The ID of the party.""" seasonal_field_id: str """The ID of the seasonal field.""" - boundary_id: str - """The ID of the boundary.""" @dataclass @@ -111,3 +109,73 @@ class SeasonalFieldInformation(DataVibe): organic_amendments: List[OrganicAmendmentInformation] """A list of :class:`OrganicAmendmentInformation` objects representing the organic amendments for the seasonal field.""" + + +@dataclass +class ADMAgPrescriptionMapInput(BaseVibe): + """ + Represents an ADMAg Prescription Map input. + """ + + party_id: str + """The ID of the party.""" + fieldId: str + """The ID of the field.""" + seasonal_field_id: Optional[str] + """The ID of the seasonal field.""" + cropId: str + """The ID of the crop.""" + + +@dataclass +class ADMAgPrescriptionInput(BaseVibe): + """ + Represents an ADMAg Prescriptions input. + """ + + party_id: str + """The ID of the party.""" + prescription_id: str + """The ID of the prescription.""" + + +@dataclass +class ADMAgPrescription(BaseVibe): + """ + Represents an ADMAg Prescriptions. + """ + + partyId: str + """The id of Party.""" + prescriptionMapId: str + """The id of mapping with seasonal field.""" + productCode: str + """The productCode of the sensor.""" + productName: str + """The productName of the sensor.""" + type: str + """type of the analysis.""" + measurements: str + """The measurements received from the sensor.""" + id: str + """Prescription Id.""" + eTag: str + """eTag of the prescription.""" + status: str + """status of the analysis.""" + createdDateTime: str + """createdDateTime of the prescription.""" + modifiedDateTime: str + """modifiedDateTime of the prescription.""" + source: str + """source of the analysis.""" + geometry: Dict[str, Any] + """The geometry of the nutrient analysis location.""" + name: str + """The name of the analysis.""" + description: str + """The description of the nutrient analysis.""" + createdBy: str + """createdBy of the prescription.""" + modifiedBy: str + """modifiedBy of the prescription.""" diff --git a/src/vibe_core/vibe_core/data/json_converter.py b/src/vibe_core/vibe_core/data/json_converter.py index 7d218913..9ea6f9fd 100644 --- a/src/vibe_core/vibe_core/data/json_converter.py +++ b/src/vibe_core/vibe_core/data/json_converter.py @@ -8,10 +8,7 @@ class DataclassJSONEncoder(json.JSONEncoder): - """ - A class that extends the `json.JSONEncoder` class to support - encoding of dataclasses and pydantic models. - """ + """Class that extends `json.JSONEncoder` to support encoding dataclasses and pydantic models""" def default(self, obj: Any): """Encodes a dataclass or pydantic model to JSON. diff --git a/src/vibe_core/vibe_core/data/products.py b/src/vibe_core/vibe_core/data/products.py index fe3ef9b6..c5cd8b9b 100644 --- a/src/vibe_core/vibe_core/data/products.py +++ b/src/vibe_core/vibe_core/data/products.py @@ -1,4 +1,5 @@ import mimetypes +import re from dataclasses import dataclass, field from typing import Dict, cast @@ -188,6 +189,107 @@ def tile_name(self) -> str: return tile_name +@dataclass +class HansenProduct(DataVibe): + """ + Represents metadata information about a Hansen product. + """ + + asset_keys = ["treecover2000", "gain", "lossyear", "datamask", "first", "last"] + """ The asset keys (dataset layers) for the Hansen products.""" + + asset_url: str = field(default_factory=str) + """ The URL of the Hansen product.""" + + def __post_init__(self): + super().__post_init__() + valid = self.validate_url() + if not valid: + raise ValueError(f"Invalid URL: {self.asset_url}") + + def validate_url(self): + # Urls are expected to be in the format: + # 'https://storage.googleapis.com/earthenginepartners-hansen/GFC-2022-v1.10/Hansen_GFC-2022-v1.10_treecover2000_20N_090W.tif' + pattern = ( + r"https://storage\.googleapis\.com/earthenginepartners-hansen" + r"/GFC-\d{4}-v\d+\.\d+/Hansen_GFC-\d{4}-v\d+\.\d+_\w+" + r"_\d{2}[NS]_\d{3}[WE]\.tif" + ) + match = re.match(pattern, self.asset_url) + return bool(match) + + @staticmethod + def extract_hansen_url_property( + asset_url: str, regular_expression: str, property_name: str + ) -> str: + """Extracts the property from the base URL and the tile name.""" + + # Use re.search to find the pattern in the URL + match = re.search(regular_expression, asset_url) + + if match is None: + raise ValueError(f"Could not extract {property_name} from {asset_url}") + + return match.group(1) + + @staticmethod + def extract_tile_name(asset_url: str) -> str: + """Extracts the tile name from the base URL and the tile name.""" + + # Define the regex pattern for the tile name + # The tile name is expected to be in the format: '20N_090W' + pattern = r"(\d{2}[NS]_\d{3}[WE])" + + return HansenProduct.extract_hansen_url_property(asset_url, pattern, "tile name") + + @staticmethod + def extract_last_year(asset_url: str) -> int: + """Extracts the last year from the base URL and the tile name.""" + + # Define the regex pattern for the last year - e.g., GFC-2022-v1.10 -> 2022 + pattern = r"GFC-(\d{4})-" + + return int(HansenProduct.extract_hansen_url_property(asset_url, pattern, "last year")) + + @staticmethod + def extract_version(asset_url: str) -> str: + """Extracts the version from the base URL and the tile name.""" + + # Define the regex pattern for the version - e.g., GFC-2022-v1.10 -> v1.10 + pattern = r"GFC-\d{4}-(v\d+\.\d+)" + + return HansenProduct.extract_hansen_url_property(asset_url, pattern, "version") + + @staticmethod + def extract_layer_name(asset_url: str) -> str: + """Extracts the layer name from the base URL and the tile name.""" + + # Define the regex pattern for the layer name + pattern = r"_(\w+)_(\d{2}[NS]_\d{3}[WE])" + + return HansenProduct.extract_hansen_url_property(asset_url, pattern, "layer name") + + @property + def tile_name(self) -> str: + """The tile name of the Hansen product.""" + return self.extract_tile_name(self.asset_url) + + @property + def last_year(self) -> int: + """The last year of the Hansen product.""" + return self.extract_last_year(self.asset_url) + + @property + def version(self) -> str: + """The version of the Hansen product.""" + return self.extract_version(self.asset_url) + + @property + def layer_name(self) -> str: + """The layer name of the Hansen product.""" + return self.extract_layer_name(self.asset_url) + + @dataclass class EsriLandUseLandCoverProduct(DataVibe): """Represents metadata information about Esri LandUse/LandCover (9-class) dataset.""" diff --git a/src/vibe_core/vibe_core/monitor.py b/src/vibe_core/vibe_core/monitor.py index 31d36dbd..0decd5ed 100644 --- a/src/vibe_core/vibe_core/monitor.py +++ b/src/vibe_core/vibe_core/monitor.py @@ -24,6 +24,8 @@ RunStatus.done: "[green]done[/]", RunStatus.queued: "[yellow]queued[/]", RunStatus.cancelled: "[yellow]cancelled[/]", + RunStatus.deleted: "[orange_red1]deleted[/]", + RunStatus.deleting: "[dark_orange]deleting[/]", } FETCHING_ICON_STR = ":hourglass_not_done:" @@ -108,9 +110,11 @@ def formatted_parameters(self) -> Dict[str, str]: :return: A dictionary containing the formatted parameters and default values. """ return { - param_name: "default: task defined" - if isinstance(param_value, list) - else f"default: {param_value}" + param_name: ( + "default: task defined" + if isinstance(param_value, list) + else f"default: {param_value}" + ) for param_name, param_value in self.parameters.items() } @@ -136,7 +140,7 @@ def _print_sinks(self, section_name: str = "Sinks"): def _print_parameters(self, section_name: str = "Parameters"): if self.parameters: desc = { - k: str(v) if not isinstance(v, list) else "" + k: str(v) if not isinstance(v, dict) else list(v.values())[0] for k, v in self.description.parameters.items() } self._print_items_description(desc, section_name, self.formatted_parameters) @@ -205,6 +209,11 @@ class VibeWorkflowRunMonitor: "Total duration: [dodger_blue3]{}[/][/]" ) + DELETE_RUN_STR = ( + "[light_salmon1]Run status marked as[/] {}\n" + "[light_salmon1]Associated cached data will be / has been deleted as long as there have " + "been no other runs with operations in common with this run.[/]\n" + ) WARNING_HEADER_STR = "\n[yellow]:warning: Warnings :warning:[/]" WARNING_STR = "\n{}\n[yellow]:warning: :warning: :warning:[/]" TABLE_FIELDS = [ @@ -323,13 +332,17 @@ def _add_task_row(self, task_name: str, task_info: RunDetails): def _add_workflow_row( self, run: MonitoredWorkflowRun, sorted_tasks: List[Tuple[str, RunDetails]] ): - start_time_str = self._get_time_str(sorted_tasks[-1][1].submission_time) - end_time_str = self._get_time_str(sorted_tasks[0][1].end_time) + if sorted_tasks: + start_time_str = self._get_time_str(sorted_tasks[-1][1].submission_time) + end_time_str = self._get_time_str(sorted_tasks[0][1].end_time) - run_progress = self._render_progress(sorted_tasks) + run_progress = self._render_progress(sorted_tasks) - # Compute run duration - run_duration = self._get_run_duration(sorted_tasks, run.status) + # Compute run duration + run_duration = self._get_run_duration(sorted_tasks, run.status) + else: # For runs with no tasks set (e.g. deleted runs) + start_time_str = end_time_str = run_duration = "N/A".center(len(self.TIME_FORMAT), " ") + run_progress = "" # TODO: Add missing fields self.table.add_row( diff --git a/src/vibe_core/vibe_core/terraform/aks/main.tf b/src/vibe_core/vibe_core/terraform/aks/main.tf index 39a10a5c..68b7dbc3 100644 --- a/src/vibe_core/vibe_core/terraform/aks/main.tf +++ b/src/vibe_core/vibe_core/terraform/aks/main.tf @@ -14,31 +14,34 @@ module "infrastructure" { subscriptionId = var.subscriptionId resource_group_name = var.resource_group_name max_worker_nodes = var.worker_replicas + enable_telemetry = var.enable_telemetry farmvibes_log_level = var.farmvibes_log_level depends_on = [module.rg] } module "kubernetes" { - source = "./modules/kubernetes" - tenantId = var.tenantId - namespace = var.namespace - acr_registry = var.acr_registry - acr_registry_username = var.acr_registry_username - acr_registry_password = var.acr_registry_password - kubernetes_config_path = module.infrastructure.kubernetes_config_path - kubernetes_config_context = module.infrastructure.kubernetes_config_context - public_ip_address = module.infrastructure.public_ip_address - public_ip_fqdn = module.infrastructure.public_ip_fqdn - public_ip_dns = module.infrastructure.public_ip_dns - keyvault_name = module.infrastructure.keyvault_name - application_id = module.infrastructure.application_id - storage_connection_key = module.infrastructure.storage_connection_key - storage_account_name = module.infrastructure.storage_account_name - userfile_container_name = module.infrastructure.userfile_container_name - resource_group_name = module.infrastructure.resource_group_name - size_of_shared_volume = var.size_of_shared_volume - certificate_email = var.certificate_email - current_user_name = module.infrastructure.current_user_name + source = "./modules/kubernetes" + tenantId = var.tenantId + namespace = var.namespace + acr_registry = var.acr_registry + acr_registry_username = var.acr_registry_username + acr_registry_password = var.acr_registry_password + kubernetes_config_path = module.infrastructure.kubernetes_config_path + kubernetes_config_context = module.infrastructure.kubernetes_config_context + public_ip_address = module.infrastructure.public_ip_address + public_ip_fqdn = module.infrastructure.public_ip_fqdn + public_ip_dns = module.infrastructure.public_ip_dns + keyvault_name = module.infrastructure.keyvault_name + application_id = module.infrastructure.application_id + storage_connection_key = module.infrastructure.storage_connection_key + storage_account_name = module.infrastructure.storage_account_name + userfile_container_name = module.infrastructure.userfile_container_name + resource_group_name = module.infrastructure.resource_group_name + size_of_shared_volume = var.size_of_shared_volume + monitor_instrumentation_key = var.monitor_instrumentation_key + enable_telemetry = var.enable_telemetry + certificate_email = var.certificate_email + current_user_name = module.infrastructure.current_user_name } module "services" { @@ -53,6 +56,7 @@ module "services" { dapr_sidecars_deployed = module.kubernetes.dapr_sidecars_deployed startup_type = "aks" shared_resource_pv_claim_name = module.kubernetes.shared_resource_pv_claim_name + otel_service_name = try(module.kubernetes.otel_service_name, "") image_prefix = var.image_prefix image_tag = var.image_tag worker_replicas = var.worker_replicas diff --git a/src/vibe_core/vibe_core/terraform/aks/modules/infra/azure_monitor.tf b/src/vibe_core/vibe_core/terraform/aks/modules/infra/azure_monitor.tf new file mode 100644 index 00000000..0c9bca85 --- /dev/null +++ b/src/vibe_core/vibe_core/terraform/aks/modules/infra/azure_monitor.tf @@ -0,0 +1,39 @@ +resource "azurerm_log_analytics_workspace" "analyticsworkspace" { + name = "${var.prefix}-analytics-workspace-${resource.random_string.name_suffix.result}" + count = var.enable_telemetry ? 1 : 0 + location = var.location + resource_group_name = var.resource_group_name + sku = "PerGB2018" +} + +resource "azurerm_application_insights" "appinsights" { + name = "${var.prefix}-app-insights-${resource.random_string.name_suffix.result}" + count = var.enable_telemetry ? 1 : 0 + location = var.location + resource_group_name = var.resource_group_name + application_type = "web" +} + + +resource "azurerm_monitor_diagnostic_setting" "diagsetting" { + name = "${var.prefix}-diagsetting-${resource.random_string.name_suffix.result}" + count = var.enable_telemetry ? 1 : 0 + target_resource_id = azurerm_application_insights.appinsights[0].id + log_analytics_workspace_id = azurerm_log_analytics_workspace.analyticsworkspace[0].id + + enabled_log { + category = "AppTraces" + + retention_policy { + enabled = false + } + } + + metric { + category = "AllMetrics" + + retention_policy { + enabled = false + } + } +} diff --git a/src/vibe_core/vibe_core/terraform/aks/modules/infra/keyvault.tf b/src/vibe_core/vibe_core/terraform/aks/modules/infra/keyvault.tf index a296a5f3..8ac3a46c 100644 --- a/src/vibe_core/vibe_core/terraform/aks/modules/infra/keyvault.tf +++ b/src/vibe_core/vibe_core/terraform/aks/modules/infra/keyvault.tf @@ -50,12 +50,6 @@ resource "azurerm_key_vault" "keyvault" { depends_on = [data.azurerm_resource_group.resourcegroup, data.http.ip, data.azurerm_user_assigned_identity.kubernetesidentity] } -resource "time_sleep" "wait_keyvault_pe" { - depends_on = [azurerm_key_vault.keyvault] - - create_duration = "900s" # 5 min should give us enough time for the Private endpoint to come online -} - resource "azurerm_key_vault_secret" "cosmosdbsecret" { name = "cosmos-db-database" value = azurerm_cosmosdb_sql_database.cosmosdb.name diff --git a/src/vibe_core/vibe_core/terraform/aks/modules/infra/outputs.tf b/src/vibe_core/vibe_core/terraform/aks/modules/infra/outputs.tf index 1251eb87..44a54738 100644 --- a/src/vibe_core/vibe_core/terraform/aks/modules/infra/outputs.tf +++ b/src/vibe_core/vibe_core/terraform/aks/modules/infra/outputs.tf @@ -55,4 +55,9 @@ output "max_worker_nodes" { output "max_default_nodes" { value = azurerm_kubernetes_cluster.kubernetes.default_node_pool[0].max_count +} + +output "monitor_instrumentation_key" { + value = var.enable_telemetry ? azurerm_application_insights.appinsights[0].instrumentation_key : "" + sensitive = true } \ No newline at end of file diff --git a/src/vibe_core/vibe_core/terraform/aks/modules/infra/variables.tf b/src/vibe_core/vibe_core/terraform/aks/modules/infra/variables.tf index 7299f0c7..da7cd61d 100644 --- a/src/vibe_core/vibe_core/terraform/aks/modules/infra/variables.tf +++ b/src/vibe_core/vibe_core/terraform/aks/modules/infra/variables.tf @@ -30,3 +30,8 @@ variable "max_worker_nodes" { variable "environment" { description = "Azure Cloud Environment to use" } + +variable "enable_telemetry" { + description = "Use telemetry" + type = bool +} diff --git a/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/dapr.tf b/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/dapr.tf index 27467ddb..56aa3769 100644 --- a/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/dapr.tf +++ b/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/dapr.tf @@ -141,8 +141,8 @@ resource "kubectl_manifest" "resiliency-sidecar" { opExecution: 3h # should be bigger than any individual op run retries: workerRetry: - policy: constant - duration: 60s + policy: exponential + maxInterval: 60s maxRetries: -1 targets: components: diff --git a/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/init.tf b/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/init.tf index c4b645bb..5aee9b92 100644 --- a/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/init.tf +++ b/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/init.tf @@ -27,6 +27,20 @@ resource "kubernetes_secret" "user-storage-secret" { depends_on = [data.kubernetes_namespace.kubernetesnamespace] } +resource "kubernetes_secret" "monitor_instrumentation_key_secret" { + metadata { + name = "monitor-instrumentation-key-secret" + namespace = var.namespace + } + + data = { + monitor_instrumentation_key = var.monitor_instrumentation_key + } + + type = "Opaque" + depends_on = [data.kubernetes_namespace.kubernetesnamespace] +} + resource "kubernetes_secret" "eywaregistrysecret" { metadata { name = "acrtoken" diff --git a/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/otel.tf b/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/otel.tf deleted file mode 100644 index 17079cf8..00000000 --- a/src/vibe_core/vibe_core/terraform/aks/modules/kubernetes/otel.tf +++ /dev/null @@ -1,157 +0,0 @@ -resource "kubernetes_config_map" "otel" { - metadata { - name = "otel-collector-conf" - labels = { - app = "opentelemetry" - component = "otel-collector-conf" - } - } - data = { - "otel-collector-config" = <