diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..b0057d30 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,55 @@ +name: Deploy Documentation +on: + release: + types: [published] + push: + branches: + - draft + - master +jobs: + deploy: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [14.x] + steps: + - name: Inject env variables + uses: rlespinasse/github-slug-action@v3.x + - uses: actions/setup-node@v1 + - uses: actions/checkout@v2 + - run: | + npm install + npm run generate + working-directory: tests + - name: clone gh-pages and clean-up + if: ${{ env.GITHUB_REF_SLUG == 'master' }} + run: | + git clone --branch gh-pages https://github.com/Open-EO/openeo-processes.git gh-pages + find gh-pages -maxdepth 1 -type f -delete + rm -rf gh-pages/examples/ + rm -rf gh-pages/meta/ + rm -rf gh-pages/proposals/ + - name: create empty gh-pages folder + if: ${{ env.GITHUB_REF_SLUG != 'master' }} + run: mkdir gh-pages + - run: | + cp tests/docs.html index.html + cp tests/processes.json processes.json + rsync -vrm --include='*.json' --include='*.html' --include='examples/***' --include='meta/***' --include='proposals/***' --exclude='*' . gh-pages + - name: deploy to root (master) + uses: peaceiris/actions-gh-pages@v3 + if: ${{ env.GITHUB_REF_SLUG == 'master' }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: gh-pages + user_name: 'openEO CI' + user_email: openeo.ci@uni-muenster.de + - name: deploy to ${{ env.GITHUB_REF_SLUG }} + uses: peaceiris/actions-gh-pages@v3 + if: ${{ env.GITHUB_REF_SLUG != 'master' }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: gh-pages + destination_dir: ${{ env.GITHUB_REF_SLUG }} + user_name: 'openEO CI' + user_email: openeo.ci@uni-muenster.de \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..a2efdf8c --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,16 @@ +name: Test Processes +on: [push, pull_request] +jobs: + deploy: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [14.x] + steps: + - uses: actions/setup-node@v1 + - uses: actions/checkout@v2 + - name: Run tests + run: | + npm install + npm run test + working-directory: tests \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 82ce515a..00000000 --- a/.travis.yml +++ /dev/null @@ -1,60 +0,0 @@ -language: node_js - -node_js: - - stable - -sudo: false - -install: -- cd tests -- npm install - -script: -- npm run test - -before_deploy: -- npm run generate -- cd .. -- git clone --branch gh-pages https://$GITHUB_TOKEN@github.com/Open-EO/openeo-processes.git gh-pages -- cp tests/docs.html index.html -- cp tests/processes.json processes.json -- | - if [[ $TRAVIS_BRANCH == 'draft' ]] ; then - rm -rf gh-pages/draft - mkdir -p gh-pages/draft - rsync -vrm --include='*.json' --include='*.html' --include='examples/***' --include='meta/***' --exclude='*' . gh-pages/draft - fi -- | - if [[ $TRAVIS_BRANCH == 'master' ]] ; then - find gh-pages -maxdepth 1 -type f -delete - rm -rf gh-pages/examples/ - mkdir -p gh-pages - rsync -vrm --include='*.json' --include='*.html' --include='examples/***' --include='meta/***' --exclude='*' . gh-pages - fi -- | - if [ -n "$TRAVIS_TAG" ] ; then - rm -rf gh-pages/$TRAVIS_TAG - mkdir -p gh-pages/$TRAVIS_TAG - rsync -vrm --include='*.json' --include='*.html' --include='examples/***' --include='meta/***' --exclude='*' . gh-pages/$TRAVIS_TAG - fi - -deploy: - - provider: pages - skip-cleanup: true - github-token: $GITHUB_TOKEN - local-dir: gh-pages - keep-history: true - name: openEO CI - email: openeo.ci@uni-muenster.de - on: - tags: true - - provider: pages - skip-cleanup: true - github-token: $GITHUB_TOKEN - local-dir: gh-pages - keep-history: true - name: openEO CI - email: openeo.ci@uni-muenster.de - on: - all_branches: true - condition: $TRAVIS_BRANCH =~ ^(master|draft)$ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 167c081f..fcb4bc3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,68 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased / Draft +## [1.1.0] - 2021-06-29 -## 1.0.0 - 2020-07-31 +### Added +- New processes in proposal state + - `array_append` + - `array_concat` + - `array_create` + - `array_create_labeled` + - `array_find_label` + - `array_interpolate_linear` [#173](https://github.com/Open-EO/openeo-processes/issues/173) + - `array_modify` + - `date_shift` + - `is_infinite` + - `nan` + - `reduce_spatial` +- Added return value details (property `returns`) for the schemas with the subtype `process-graph`. [API#350](https://github.com/Open-EO/openeo-api/issues/350) +- `apply_neighborhood`: Clarify behavior for data cubes returned by the child processes and for that add the exception `DataCubePropertiesImmutable`. +- Added a guide for implementors that describes numerours implementation details for processes that could not be covered in the specifications itself, for example a recommended implementation for the `if` process. [#246](https://github.com/Open-EO/openeo-processes/issues/246) + +### Changed +- Added `proposals` folder for experimental processes. Experimental processes are not covered by the CHANGELOG and MAY include breaking changes! [#196](https://github.com/Open-EO/openeo-processes/issues/196), [#207](https://github.com/Open-EO/openeo-processes/issues/207), [PSC#8](https://github.com/Open-EO/PSC/issues/8) + - Moved the experimental process `run_udf_externally` to the proposals. + - Moved the rarely used and implemented processes `cummax`, `cummin`, `cumproduct`, `cumsum`, `debug`, `filter_labels`, `load_result`, `load_uploaded_files`, `resample_cube_temporal` to the proposals. +- Exception messages have been aligned always use ` instead of '. Tooling could render it with CommonMark. +- `load_collection` and `mask_polygon`: Also support multi polygons instead of just polygons. [#237](https://github.com/Open-EO/openeo-processes/issues/237) +- `run_udf` and `run_udf_externally`: Specify specific (extensible) protocols for UDF URIs. +- `resample_cube_spatial` and `resample_spatial`: Aligned with GDAL and added `rms` and `sum` options to methods. Also added better descriptions. +- `resample_cube_temporal`: Process has been simplified and only offers the nearest neighbor method now. The `process` parameter has been removed, the `dimension` parameter was made less restrictive, the parameter `valid_within` was added. [#194](https://github.com/Open-EO/openeo-processes/issues/194) + +### Deprecated +- `GeometryCollection`s are discouraged in all relevant processes. + +### Removed + +- Removed the experimental processes `aggregate_spatial_binary` and `reduce_dimension_binary`. [#258](https://github.com/Open-EO/openeo-processes/issues/258) + +### Fixed +- Clarify that the user workspace is server-side. [#225](https://github.com/Open-EO/openeo-processes/issues/225) +- Clarify that the `condition` parameter for `array_filter` works also on indices and labels. +- Clarify contradicting statements in `filter_temporal` for the default value of the `dimension` parameter. By default *all* temporal dimensions are affected by the process. [#203](https://github.com/Open-EO/openeo-processes/issues/203) +- Clarify how the parameters passed to the overlap resolver correspond to the data cubes. [#184](https://github.com/Open-EO/openeo-processes/issues/184) +- Improve and clarify specifications for `is_nan`, `is_nodata`, `is_valid`. [#189](https://github.com/Open-EO/openeo-processes/issues/189) +- Improve and clarify specifications for `all` and `any`. [#189](https://github.com/Open-EO/openeo-processes/issues/199) +- `array_element`: Clarify that `ArrayNotLabeled` exception is thrown when parameter `label` is specified and the given array is not labeled. +- `array_apply`, `array_element`, `array_filter`: Added the `minimum: 0` constraint to all schemas describing zero-based indices (parameter `index`). +- `array_labels`: Clarified the accepted data type for array elements passed to the parameter `data`. +- `merge_cubes`: Clarified the dimension label order after the merge. [#212](https://github.com/Open-EO/openeo-processes/issues/212) +- `merge_cubes`: Clarified the fourth example. [#266](https://github.com/Open-EO/openeo-processes/issues/266) +- Fixed typos, grammar issues and other spelling-related issues in many of the processes. +- Fixed the examples `array_contains_nodata` and `array_find_nodata`. +- Fixed links to openEO glossary and added links to data cube introduction. [#216](https://github.com/Open-EO/openeo-processes/issues/216) +- Fixed description of `apply_dimension` with regards to reference systems. Made description easier to understand, too. [#234](https://github.com/Open-EO/openeo-processes/issues/234) +- Clarified disallowed characters in subtype `file-path`. +- Clarified that UDF source code must contain a newline/line-break (affects `run_udf`). +- `aggregate_spatial`, `aggregate_spatial_binary`: Clarified that Features, Geometries and GeometryCollections are a single entity in computations. Only FeatureCollections are multiple entities. [#252](https://github.com/Open-EO/openeo-processes/issues/252) +- `aggregate_spatial`: Clarified that the values have no predefined order and reducers such as `first` and `last` return unpredictable results. [#260](https://github.com/Open-EO/openeo-processes/issues/260) +- `load_collection`, parameter `spatial_extent`: Clarified that all pixels that are inside the bounding box of the given polygons but do not intersect with any polygon have to be set to no-data (`null`). [#256](https://github.com/Open-EO/openeo-processes/issues/256) +- `load_collection`: Clarified that the parameters are recommended to be used in favor of `filter_*` processes. +- `aggregate_temporal` and `aggregate_temporal_period`: Clarified that reducers are also executed for intervals/periods with no data. [#263](https://github.com/Open-EO/openeo-processes/issues/263) +- `dimension_labels`: Clarified that the process fails with a `DimensionNotAvailable` exception, if a dimension with the specified name does not exist. + +## [1.0.0] - 2020-07-31 ### Added - `subtype-schemas.json`: A list of predefined subtypes is available as JSON Schema; Moved over from openeo-api. @@ -41,13 +101,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `aggregate_temporal`: Fixed outdated message for exception `TooManyDimensions`. - `clip`: Fixed examples. - `linear_scale_range`: Clarify that the process implicitly clips the values. [#159](https://github.com/Open-EO/openeo-processes/issues/159) -- `mean`: Clarify behaviour for arrays with `null`-values only. -- `mod`: Clarified behaviour. [#168](https://github.com/Open-EO/openeo-processes/issues/168) -- `resample_*`: Clarified behaviour. +- `mean`: Clarify behavior for arrays with `null`-values only. +- `mod`: Clarified behavior. [#168](https://github.com/Open-EO/openeo-processes/issues/168) +- `resample_*`: Clarified behavior. - `first`, `last`, `max`, `mean`, `median`, `min`, `sd`, `variance`: Clarify behavior for arrays with `null`-values only. - Clarified (and fixed if necessary) for all processes in the "cubes" category the descriptions for the returned data cube. [#149](https://github.com/Open-EO/openeo-processes/issues/149) -## 1.0.0-rc.1 - 2020-01-31 +## [1.0.0-rc.1] - 2020-01-31 ### Added - Processes: @@ -159,3 +219,13 @@ First version which is separated from the openEO API. Complete rework of all pro ## Legacy versions Older versions of the processes were released as part of the openEO API, see the corresponding changelog for more information. + + +[Unreleased]: +[1.1.0]: +[1.0.0]: +[1.0.0-rc.1]: +[0.4.2]: +[0.4.1]: +[0.4.0]: + diff --git a/README.md b/README.md index d7390d2d..e819ce3c 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,15 @@ openEO develops interoperable processes for big Earth observation cloud processi ## Versions / Branches -The [master branch](https://github.com/Open-EO/openeo-processes/tree/master) is the 'stable' version of the openEO processes specification. The latest release is version **1.0.0**. The [draft branch](https://github.com/Open-EO/openeo-processes/tree/draft) is where active development takes place. +The [master branch](https://github.com/Open-EO/openeo-processes/tree/master) is the 'stable' version of the openEO processes specification. An exception is the [`proposals`](proposals/) folder, which provides experimental new processes currently under discussion. They may still change, but everyone is encouraged to implement them and give feedback. + +The latest release is version **1.1.0**. The [draft branch](https://github.com/Open-EO/openeo-processes/tree/draft) is where active development takes place. PRs should be made against the draft branch. | Version / Branch | Status | openEO API versions | | ------------------------------------------------------------ | ------------------------- | ------------------- | | [unreleased / draft](https://processes.openeo.org/draft) | in development | 1.x.x | -| [**1.0.0** / master](https://processes.openeo.org/1.0.0/) | **latest stable version** | 1.x.x | +| [**1.1.0** / master](https://processes.openeo.org/1.1.0/) | **latest stable version** | 1.x.x | +| [1.0.0](https://processes.openeo.org/1.0.0/) | legacy version | 1.x.x | | [1.0.0 RC1](https://processes.openeo.org/1.0.0-rc.1/) | legacy version | 1.x.x | | [0.4.2](https://processes.openeo.org/0.4.2/) | legacy version | 0.4.x | | [0.4.1](https://processes.openeo.org/0.4.1/) | legacy version | 0.4.x | @@ -25,7 +28,18 @@ See also the [changelog](CHANGELOG.md) for the changes between versions and the This repository contains a set of files formally describing the openEO Processes: -* The `*.json` files provide the process specifications as defined by the openEO API. +* The `*.json` files provide stable process specifications as defined by openEO. Stable processes need at least two implementations and a use-case example added to the [`examples`](examples/) folder *or* consensus from the openEO PSC. +* The `*.json` files in the [`proposals`](proposals/) folder provide proposed new process specifications that are still experimental and subject to change, including breaking changes. Everyone is encouraged to base their work on the proposals and give feedback so that eventually the processes evolve into stable process specifications. +* [implementation.md](meta/implementation.md) in the `meta` folder provide some additional implementation details for back-ends. For back-end implementors, it's highly recommended to read them. * [subtype-schemas.json](meta/subtype-schemas.json) in the `meta` folder defines common data types (`subtype`s) for JSON Schema used in openEO processes. * The [`examples`](examples/) folder contains some useful examples that the processes link to. All of these are non-binding additions. -* The [`tests`](tests/) folder can be used to test the process specification for validity and and consistent "style". It also allows to render the processes in a web browser. +* The [`tests`](tests/) folder can be used to test the process specification for validity and consistent "style". It also allows rendering the processes in a web browser. + + +## Process + +* All new processes must be added to the [`proposals`](proposals/) folder. +* Processes will only be moved from proposals to the stable process specifications once there are at least two implementations and an example process in the [`examples`](examples/) folder showing it in a use case. This doesn't require a PSC vote individually as it's not a breaking change, just an addition. +* The [`proposals`](proposals/) folder allows breaking changes without a PSC vote and without increasing the major version number (i.e. a breaking change in the proposals doesn't require us to make the next version number 2.0.0). +* The proposals are released as experimental processes with the other processes. +* Each release and all breaking changes in the stable process specifications must go through PSC vote. \ No newline at end of file diff --git a/add.json b/add.json index 58db5f2e..ac65541c 100644 --- a/add.json +++ b/add.json @@ -1,7 +1,7 @@ { "id": "add", "summary": "Addition of two numbers", - "description": "Sums up the two numbers `x` and `y` (*x + y*) and returns the computed sum.\n\nNo-data values are taken into account so that `null` is returned if any element is such a value.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it.", + "description": "Sums up the two numbers `x` and `y` (*`x + y`*) and returns the computed sum.\n\nNo-data values are taken into account so that `null` is returned if any element is such a value.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it.", "categories": [ "math" ], diff --git a/add_dimension.json b/add_dimension.json index 727456b2..a3b07075 100644 --- a/add_dimension.json +++ b/add_dimension.json @@ -1,7 +1,7 @@ { "id": "add_dimension", "summary": "Add a new dimension", - "description": "Adds a new named dimension to the data cube.\n\nAfterwards, the dimension can be referenced with the specified `name`. If a dimension with the specified name exists, the process fails with a `DimensionExists` error. The dimension label of the dimension is set to the specified `label`.", + "description": "Adds a new named dimension to the data cube.\n\nAfterwards, the dimension can be referred to with the specified `name`. If a dimension with the specified name exists, the process fails with a `DimensionExists` exception. The dimension label of the dimension is set to the specified `label`.", "categories": [ "cubes" ], diff --git a/aggregate_spatial.json b/aggregate_spatial.json index 1cd4533b..9b0c1bd8 100644 --- a/aggregate_spatial.json +++ b/aggregate_spatial.json @@ -1,7 +1,7 @@ { "id": "aggregate_spatial", "summary": "Zonal statistics for geometries", - "description": "Aggregates statistics for one or more geometries (e.g. zonal statistics for polygons) over the spatial dimensions. This process passes a list of values to the reducer. In contrast, ``aggregate_spatial_binary()`` passes two values, which may be better suited especially for UDFs in case the number of values gets too large to be processed at once.\n\n- For **polygons**, the process considers all pixels for which the point at the pixel center intersects with the corresponding polygon (as defined in the Simple Features standard by the OGC).\n- For **points**, the process considers the closest pixel center.\n- For **lines** (line strings), the process considers all the pixels whose centers are closest to at least one point on the line.\n\nThus, pixels may be part of multiple geometries and be part of multiple aggregations.\n\nThe data cube must have been reduced to only contain two spatial dimensions and a third dimension the values are aggregated for, for example the temporal dimension to get a time series. Otherwise this process fails with the `TooManyDimensions` error.\n\nThe number of total and valid pixels is returned together with the calculated values.", + "description": "Aggregates statistics for one or more geometries (e.g. zonal statistics for polygons) over the spatial dimensions. The number of total and valid pixels is returned together with the calculated values.\n\nAn 'unbounded' aggregation over the full extent of the horizontal spatial dimensions can be computed with the process ``reduce_spatial()``.\n\nThis process passes a list of values to the reducer. The list of values has an undefined order, therefore processes such as ``last()`` and ``first()`` that depend on the order of the values will lead to unpredictable results.", "categories": [ "cubes", "aggregate & resample" @@ -9,7 +9,7 @@ "parameters": [ { "name": "data", - "description": "A raster data cube. The data cube implicitly gets restricted to the bounds of the geometries as if ``filter_spatial()`` would have been used with the same values for the corresponding parameters immediately before this process.", + "description": "A raster data cube.\n\nThe data cube must have been reduced to only contain two spatial dimensions and a third dimension the values are aggregated for, for example the temporal dimension to get a time series. Otherwise, this process fails with the `TooManyDimensions` exception.\n\nThe data cube implicitly gets restricted to the bounds of the geometries as if ``filter_spatial()`` would have been used with the same values for the corresponding parameters immediately before this process.", "schema": { "type": "object", "subtype": "raster-cube" @@ -17,7 +17,7 @@ }, { "name": "geometries", - "description": "Geometries as GeoJSON on which the aggregation will be based.", + "description": "Geometries as GeoJSON on which the aggregation will be based.\n\nOne value will be computed per GeoJSON `Feature`, `Geometry` or `GeometryCollection`. For a `FeatureCollection` multiple values will be computed, one value per contained `Feature`. For example, a single value will be computed for a `MultiPolygon`, but two values will be computed for a `FeatureCollection` containing two polygons.\n\n- For **polygons**, the process considers all pixels for which the point at the pixel center intersects with the corresponding polygon (as defined in the Simple Features standard by the OGC).\n- For **points**, the process considers the closest pixel center.\n- For **lines** (line strings), the process considers all the pixels whose centers are closest to at least one point on the line.\n\nThus, pixels may be part of multiple geometries and be part of multiple aggregations.\n\nTo maximize interoperability, a nested `GeometryCollection` should be avoided. Furthermore, a `GeometryCollection` composed of a single type of geometries should be avoided in favour of the corresponding multi-part type (e.g. `MultiPolygon`).", "schema": { "type": "object", "subtype": "geojson" @@ -49,7 +49,13 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "The value to be set in the vector data cube.", + "schema": { + "description": "Any data type." + } + } } }, { @@ -72,7 +78,7 @@ } ], "returns": { - "description": "A vector data cube with the computed results and restricted to the bounds of the geometries.\n\nThe computed value is stored in dimension with the name that was specified in the parameter `target_dimension`.\n\nThe computation also stores information about the total count of pixels (valid + invalid pixels) and the number of valid pixels (see ``is_valid()``) for each geometry. These values are stored as new dimension with a dimension name derived from `target_dimension` by adding the suffix `_meta`. The new dimension has the dimension labels `total_count` and `valid_count`.", + "description": "A vector data cube with the computed results and restricted to the bounds of the geometries.\n\nThe computed value is used for the dimension with the name that was specified in the parameter `target_dimension`.\n\nThe computation also stores information about the total count of pixels (valid + invalid pixels) and the number of valid pixels (see ``is_valid()``) for each geometry. These values are added as a new dimension with a dimension name derived from `target_dimension` by adding the suffix `_meta`. The new dimension has the dimension labels `total_count` and `valid_count`.", "schema": { "type": "object", "subtype": "vector-cube" @@ -80,14 +86,14 @@ }, "exceptions": { "TooManyDimensions": { - "message": "The number of dimensions must be reduced to three for 'aggregate_spatial'." + "message": "The number of dimensions must be reduced to three for `aggregate_spatial`." } }, "links": [ { - "href": "https://openeo.org/documentation/1.0/glossary.html#aggregate-reducing-resolution", + "href": "https://openeo.org/documentation/1.0/datacubes.html#aggregate", "rel": "about", - "title": "Aggregation explained in the openEO glossary" + "title": "Aggregation explained in the openEO documentation" }, { "href": "http://www.opengeospatial.org/standards/sfa", @@ -95,4 +101,4 @@ "title": "Simple Features standard by the OGC" } ] -} \ No newline at end of file +} diff --git a/aggregate_spatial_binary.json b/aggregate_spatial_binary.json deleted file mode 100644 index 04fec738..00000000 --- a/aggregate_spatial_binary.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "id": "aggregate_spatial_binary", - "summary": "Zonal statistics for geometries by binary aggregation", - "description": "Aggregates statistics for one or more geometries (e.g. zonal statistics for polygons) over the spatial dimensions. This process consecutively passes a pair of values to the reducer. This may be better suited especially for UDFs in case the number of values gets too large to be processed at once. In contrast, ``aggregate_spatial()`` passes a list of values.\n\n- For **polygons**, the process considers all pixels for which the point at the pixel center intersects with the corresponding polygon (as defined in the Simple Features standard by the OGC).\n- For **points**, the process considers the closest pixel center.\n- For **lines** (line strings), the process considers all the pixels whose centers are closest to at least one point on the line.\n\nThe data cube must have been reduced to only contain two raster dimensions and a third dimension the values are aggregated for, for example the temporal dimension to get a time series. Otherwise this process fails with the `TooManyDimensions` error.\n\nThe number of total and valid pixels is returned together with the calculated values.", - "categories": [ - "cubes", - "aggregate & resample" - ], - "experimental": true, - "parameters": [ - { - "name": "data", - "description": "A raster data cube. The data cube implicitly gets restricted to the bounds of the geometries as if ``filter_spatial()`` would have been used with the same values for the corresponding parameters immediately before this process.", - "schema": { - "type": "object", - "subtype": "raster-cube" - } - }, - { - "name": "geometries", - "description": "Geometries as GeoJSON on which the aggregation will be based.", - "schema": { - "type": "object", - "subtype": "geojson" - } - }, - { - "name": "reducer", - "description": "A reduction operator to be applied consecutively on tuples of values. It must be both associative and commutative as the execution may be executed in parallel and therefore the order of execution is arbitrary. The reduction operator may be a single process such as ``multiply()`` or consist of multiple sub-processes.", - "schema": { - "type": "object", - "subtype": "process-graph", - "parameters": [ - { - "name": "x", - "description": "The first value.", - "schema": { - "description": "Any data type." - } - }, - { - "name": "y", - "description": "The second value.", - "schema": { - "description": "Any data type." - } - }, - { - "name": "context", - "description": "Additional data passed by the user.", - "schema": { - "description": "Any data type." - }, - "optional": true, - "default": null - } - ] - } - }, - { - "name": "target_dimension", - "description": "The new dimension name to be used for storing the results. Defaults to `result`.", - "schema": { - "type": "string" - }, - "default": "result", - "optional": true - }, - { - "name": "context", - "description": "Additional data to be passed to the reducer.", - "schema": { - "description": "Any data type." - }, - "optional": true, - "default": null - } - ], - "returns": { - "description": "A vector data cube with the computed results and restricted to the bounds of the geometries.\n\nThe computed value is stored in dimension with the name that was specified in the parameter `target_dimension`.\n\nThe computation also stores information about the total count of pixels (valid + invalid pixels) and the number of valid pixels (see ``is_valid()``) for each geometry. These values are stored as new dimension with a dimension name derived from `target_dimension` by adding the suffix `_meta`. The new dimension has the dimension labels `total_count` and `valid_count`.", - "schema": { - "type": "object", - "subtype": "vector-cube" - } - }, - "exceptions": { - "TooManyDimensions": { - "message": "The number of dimensions must be reduced to three for 'aggregate_spatial_binary'." - } - }, - "links": [ - { - "href": "https://openeo.org/documentation/1.0/glossary.html#aggregate-reducing-resolution", - "rel": "about", - "title": "Aggregation explained in the openEO glossary" - }, - { - "href": "http://www.opengeospatial.org/standards/sfa", - "rel": "about", - "title": "Simple Features standard by the OGC" - }, - { - "rel": "about", - "href": "https://en.wikipedia.org/wiki/Reduction_Operator", - "title": "Background information on reduction operators (binary reducers) by Wikipedia" - } - ] -} \ No newline at end of file diff --git a/aggregate_temporal.json b/aggregate_temporal.json index 51cefbca..b68b366c 100644 --- a/aggregate_temporal.json +++ b/aggregate_temporal.json @@ -1,7 +1,7 @@ { "id": "aggregate_temporal", "summary": "Temporal aggregations", - "description": "Computes a temporal aggregation based on an array of temporal intervals.\n\nFor common regular calendar hierarchies such as year, month, week or seasons ``aggregate_temporal_period()`` can be used. Other calendar hierarchies must be transformed into specific intervals by the clients.\n\nFor each interval, all data along the dimension will be passed through the reducer.\n\nThe computed values will be projected to the labels. If no labels are specified, the start of the temporal interval will be used as label for the corresponding values. In case of a conflict (i.e. the user-specified values for the start times of the temporal intervals are not distinct), the user-defined labels must be specified in the parameter `labels` as otherwise a `DistinctDimensionLabelsRequired` error would be thrown. The number of user-defined labels and the number of intervals need to be equal.\n\nIf the dimension is not set or is set to `null`, the data cube is expected to only have one temporal dimension.", + "description": "Computes a temporal aggregation based on an array of temporal intervals.\n\nFor common regular calendar hierarchies such as year, month, week or seasons ``aggregate_temporal_period()`` can be used. Other calendar hierarchies must be transformed into specific intervals by the clients.\n\nFor each interval, all data along the dimension will be passed through the reducer.\n\nThe computed values will be projected to the labels. If no labels are specified, the start of the temporal interval will be used as label for the corresponding values. In case of a conflict (i.e. the user-specified values for the start times of the temporal intervals are not distinct), the user-defined labels must be specified in the parameter `labels` as otherwise a `DistinctDimensionLabelsRequired` exception would be thrown. The number of user-defined labels and the number of intervals need to be equal.\n\nIf the dimension is not set or is set to `null`, the data cube is expected to only have one temporal dimension.", "categories": [ "cubes", "aggregate & resample" @@ -17,7 +17,7 @@ }, { "name": "intervals", - "description": "Left-closed temporal intervals, which are allowed to overlap. Each temporal interval in the array has exactly two elements:\n\n1. The first element is the start of the temporal interval. The specified instance in time is **included** in the interval.\n2. The second element is the end of the temporal interval. The specified instance in time is **excluded** from the interval.\n\nThe specified temporal strings follow [RFC 3339](https://tools.ietf.org/html/rfc3339). Although [RFC 3339 prohibits the hour to be '24'](https://tools.ietf.org/html/rfc3339#section-5.7), **this process allows the value '24' for the hour** of an end time in order to make it possible that left-closed time intervals can fully cover the day.", + "description": "Left-closed temporal intervals, which are allowed to overlap. Each temporal interval in the array has exactly two elements:\n\n1. The first element is the start of the temporal interval. The specified instance in time is **included** in the interval.\n2. The second element is the end of the temporal interval. The specified instance in time is **excluded** from the interval.\n\nThe specified temporal strings follow [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html). Although [RFC 3339 prohibits the hour to be '24'](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.7), **this process allows the value '24' for the hour** of an end time in order to make it possible that left-closed time intervals can fully cover the day.", "schema": { "type": "array", "subtype": "temporal-intervals", @@ -87,14 +87,14 @@ }, { "name": "reducer", - "description": "A reducer to be applied on all values along the specified dimension. A reducer is a single process such as ``mean()`` or a set of processes, which computes a single value for a list of values, see the category 'reducer' for such processes.", + "description": "A reducer to be applied for the values contained in each interval. A reducer is a single process such as ``mean()`` or a set of processes, which computes a single value for a list of values, see the category 'reducer' for such processes. Intervals may not contain any values, which for most reducers leads to no-data (`null`) values by default.", "schema": { "type": "object", "subtype": "process-graph", "parameters": [ { "name": "data", - "description": "A labeled array with elements of any type.", + "description": "A labeled array with elements of any type. If there's no data for the interval, the array is empty.", "schema": { "type": "array", "subtype": "labeled-array", @@ -112,7 +112,13 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "The value to be set in the new data cube.", + "schema": { + "description": "Any data type." + } + } } }, { @@ -121,13 +127,9 @@ "schema": { "type": "array", "items": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } + "type": [ + "number", + "string" ] } }, @@ -136,7 +138,7 @@ }, { "name": "dimension", - "description": "The name of the temporal dimension for aggregation. All data along the dimension is passed through the specified reducer. If the dimension is not set or set to `null`, the data cube is expected to only have one temporal dimension. Fails with a `TooManyDimensions` error if it has more dimensions. Fails with a `DimensionNotAvailable` error if the specified dimension does not exist.", + "description": "The name of the temporal dimension for aggregation. All data along the dimension is passed through the specified reducer. If the dimension is not set or set to `null`, the data cube is expected to only have one temporal dimension. Fails with a `TooManyDimensions` exception if it has more dimensions. Fails with a `DimensionNotAvailable` exception if the specified dimension does not exist.", "schema": { "type": [ "string", @@ -157,7 +159,7 @@ } ], "returns": { - "description": "A data cube with the same dimensions. The dimension properties (name, type, labels, reference system and resolution) remain unchanged, except for the resolution and dimension labels of the given temporal dimension.", + "description": "A new data cube with the same dimensions. The dimension properties (name, type, labels, reference system and resolution) remain unchanged, except for the resolution and dimension labels of the given temporal dimension.", "schema": { "type": "object", "subtype": "raster-cube" @@ -227,9 +229,9 @@ }, "links": [ { - "href": "https://openeo.org/documentation/1.0/glossary.html#aggregate-reducing-resolution", + "href": "https://openeo.org/documentation/1.0/datacubes.html#aggregate", "rel": "about", - "title": "Aggregation explained in the openEO glossary" + "title": "Aggregation explained in the openEO documentation" } ] } \ No newline at end of file diff --git a/aggregate_temporal_period.json b/aggregate_temporal_period.json index b5b13a56..b0d4c110 100644 --- a/aggregate_temporal_period.json +++ b/aggregate_temporal_period.json @@ -18,7 +18,7 @@ }, { "name": "period", - "description": "The time intervals to aggregate. The following pre-defined values are available:\n\n* `hour`: Hour of the day\n* `day`: Day of the year\n* `week`: Week of the year\n* `dekad`: Ten day periods, counted per year with three periods per month (day 1 - 10, 11 - 20 and 21 - end of month). The third dekad of the month can range from 8 to 11 days. For example, the fourth dekad is Feb, 1 - Feb, 10 each year.\n* `month`: Month of the year\n* `season`: Three month periods of the calendar seasons (December - February, March - May, June - August, September - November).\n* `tropical-season`: Six month periods of the tropical seasons (November - April, May - October).\n* `year`: Proleptic years\n* `decade`: Ten year periods ([0-to-9 decade](https://en.wikipedia.org/wiki/Decade#0-to-9_decade)), from a year ending in a 0 to the next year ending in a 9.\n* `decade-ad`: Ten year periods ([1-to-0 decade](https://en.wikipedia.org/wiki/Decade#1-to-0_decade)) better aligned with the Anno Domini (AD) calendar era, from a year ending in a 1 to the next year ending in a 0.", + "description": "The time intervals to aggregate. The following pre-defined values are available:\n\n* `hour`: Hour of the day\n* `day`: Day of the year\n* `week`: Week of the year\n* `dekad`: Ten day periods, counted per year with three periods per month (day 1 - 10, 11 - 20 and 21 - end of month). The third dekad of the month can range from 8 to 11 days. For example, the fourth dekad is Feb, 1 - Feb, 10 each year.\n* `month`: Month of the year\n* `season`: Three month periods of the calendar seasons (December - February, March - May, June - August, September - November).\n* `tropical-season`: Six month periods of the tropical seasons (November - April, May - October).\n* `year`: Proleptic years\n* `decade`: Ten year periods ([0-to-9 decade](https://en.wikipedia.org/wiki/Decade#0-to-9_decade)), from a year ending in a 0 to the next year ending in a 9.\n* `decade-ad`: Ten year periods ([1-to-0 decade](https://en.wikipedia.org/wiki/Decade#1-to-0_decade)) better aligned with the anno Domini (AD) calendar era, from a year ending in a 1 to the next year ending in a 0.", "schema": { "type": "string", "enum": [ @@ -37,14 +37,14 @@ }, { "name": "reducer", - "description": "A reducer to be applied on all values along the specified dimension. A reducer is a single process such as ``mean()`` or a set of processes, which computes a single value for a list of values, see the category 'reducer' for such processes.", + "description": "A reducer to be applied for the values contained in each period. A reducer is a single process such as ``mean()`` or a set of processes, which computes a single value for a list of values, see the category 'reducer' for such processes. Periods may not contain any values, which for most reducers leads to no-data (`null`) values by default.", "schema": { "type": "object", "subtype": "process-graph", "parameters": [ { "name": "data", - "description": "A labeled array with elements of any type.", + "description": "A labeled array with elements of any type. If there's no data for the period, the array is empty.", "schema": { "type": "array", "subtype": "labeled-array", @@ -62,12 +62,18 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "The value to be set in the new data cube.", + "schema": { + "description": "Any data type." + } + } } }, { "name": "dimension", - "description": "The name of the temporal dimension for aggregation. All data along the dimension is passed through the specified reducer. If the dimension is not set or set to `null`, the data cube is expected to only have one temporal dimension. Fails with a `TooManyDimensions` error if it has more dimensions. Fails with a `DimensionNotAvailable` error if the specified dimension does not exist.", + "description": "The name of the temporal dimension for aggregation. All data along the dimension is passed through the specified reducer. If the dimension is not set or set to `null`, the data cube is expected to only have one temporal dimension. Fails with a `TooManyDimensions` exception if it has more dimensions. Fails with a `DimensionNotAvailable` exception if the specified dimension does not exist.", "schema": { "type": [ "string", @@ -88,7 +94,7 @@ } ], "returns": { - "description": "A data cube with the same dimensions. The dimension properties (name, type, labels, reference system and resolution) remain unchanged, except for the resolution and dimension labels of the given temporal dimension. The specified temporal dimension has the following dimension labels (`YYYY` = four-digit year, `MM` = two-digit month, `DD` two-digit day of month):\n\n* `hour`: `YYYY-MM-DD-00` - `YYYY-MM-DD-23`\n* `day`: `YYYY-001` - `YYYY-365`\n* `week`: `YYYY-01` - `YYYY-52`\n* `dekad`: `YYYY-00` - `YYYY-36`\n* `month`: `YYYY-01` - `YYYY-12`\n* `season`: `YYYY-djf` (December - February), `YYYY-mam` (March - May), `YYYY-jja` (June - August), `YYYY-son` (September - November).\n* `tropical-season`: `YYYY-ndjfma` (November - April), `YYYY-mjjaso` (May - October).\n* `year`: `YYYY`\n* `decade`: `YYY0`\n* `decade-ad`: `YYY1`", + "description": "A new data cube with the same dimensions. The dimension properties (name, type, labels, reference system and resolution) remain unchanged, except for the resolution and dimension labels of the given temporal dimension. The specified temporal dimension has the following dimension labels (`YYYY` = four-digit year, `MM` = two-digit month, `DD` two-digit day of month):\n\n* `hour`: `YYYY-MM-DD-00` - `YYYY-MM-DD-23`\n* `day`: `YYYY-001` - `YYYY-365`\n* `week`: `YYYY-01` - `YYYY-52`\n* `dekad`: `YYYY-00` - `YYYY-36`\n* `month`: `YYYY-01` - `YYYY-12`\n* `season`: `YYYY-djf` (December - February), `YYYY-mam` (March - May), `YYYY-jja` (June - August), `YYYY-son` (September - November).\n* `tropical-season`: `YYYY-ndjfma` (November - April), `YYYY-mjjaso` (May - October).\n* `year`: `YYYY`\n* `decade`: `YYY0`\n* `decade-ad`: `YYY1`", "schema": { "type": "object", "subtype": "raster-cube" @@ -107,9 +113,9 @@ }, "links": [ { - "href": "https://openeo.org/documentation/1.0/glossary.html#aggregate-reducing-resolution", + "href": "https://openeo.org/documentation/1.0/datacubes.html#aggregate", "rel": "about", - "title": "Aggregation explained in the openEO glossary" + "title": "Aggregation explained in the openEO documentation" } ] } \ No newline at end of file diff --git a/all.json b/all.json index 7d8b5ebb..b12059de 100644 --- a/all.json +++ b/all.json @@ -1,7 +1,7 @@ { "id": "all", "summary": "Are all of the values true?", - "description": "Checks if **all** of the values in `data` are true. Evaluates all values from the first to the last element and stops once the outcome is unambiguous.\n\nIf only one value is given, the process evaluates to the given value. If no value is given (i.e. the array is empty) the process returns `null`.\n\nBy default all no-data values are ignored so that the process returns `null` if all values are no-data, `true` if all other values are true and `false` otherwise. Setting the `ignore_nodata` flag to `false` considers no-data values so that `null` is a valid logical object. If a component is `null`, the result will be `null` if the outcome is ambiguous. See the following truth table:\n\n```\n || null | false | true\n----- || ----- | ----- | -----\nnull || null | false | null\nfalse || false | false | false\ntrue || null | false | true\n```", + "description": "Checks if **all** of the values in `data` are true. If no value is given (i.e. the array is empty) the process returns `null`.\n\nBy default all no-data values are ignored so that the process returns `null` if all values are no-data, `true` if all values are true and `false` otherwise. Setting the `ignore_nodata` flag to `false` takes no-data values into account and the array values are reduced pairwise according to the following truth table:\n\n```\n || null | false | true\n----- || ----- | ----- | -----\nnull || null | false | null\nfalse || false | false | false\ntrue || null | false | true\n```\n\n**Remark:** The process evaluates all values from the first to the last element and stops once the outcome is unambiguous. A result is ambiguous unless a value is `false` or all values have been taken into account.", "categories": [ "logic", "reducer" diff --git a/anomaly.json b/anomaly.json index 06e9d9da..8dee2b68 100644 --- a/anomaly.json +++ b/anomaly.json @@ -1,6 +1,6 @@ { "id": "anomaly", - "summary": "Computes anomalies", + "summary": "Compute anomalies", "description": "Computes anomalies based on normals for temporal periods. It compares the data for each label in the temporal dimension with the corresponding data in the normals data cube by subtracting the normal from the data.", "categories": [ "climatology", @@ -25,7 +25,7 @@ }, { "name": "period", - "description": "Specifies the time intervals available in the normals data cube. The following options are available:\n\n* `hour`: Hour of the day\n* `day`: Day of the year\n* `week`: Week of the year\n* `dekad`: Ten day periods, counted per year with three periods per month (day 1 - 10, 11 - 20 and 21 - end of month). The third dekad of the month can range from 8 to 11 days. For example, the fourth dekad is Feb, 1 - Feb, 10 each year.\n* `month`: Month of the year\n* `season`: Three month periods of the calendar seasons (December - February, March - May, June - August, September - November).\n* `tropical-season`: Six month periods of the tropical seasons (November - April, May - October).\n* `year`: Proleptic years\n* `decade`: Ten year periods ([0-to-9 decade](https://en.wikipedia.org/wiki/Decade#0-to-9_decade)), from a year ending in a 0 to the next year ending in a 9.\n* `decade-ad`: Ten year periods ([1-to-0 decade](https://en.wikipedia.org/wiki/Decade#1-to-0_decade)) better aligned with the Anno Domini (AD) calendar era, from a year ending in a 1 to the next year ending in a 0.\n* `single-period` / `climatology-period`: A single period of arbitrary length", + "description": "Specifies the time intervals available in the normals data cube. The following options are available:\n\n* `hour`: Hour of the day\n* `day`: Day of the year\n* `week`: Week of the year\n* `dekad`: Ten day periods, counted per year with three periods per month (day 1 - 10, 11 - 20 and 21 - end of month). The third dekad of the month can range from 8 to 11 days. For example, the fourth dekad is Feb, 1 - Feb, 10 each year.\n* `month`: Month of the year\n* `season`: Three month periods of the calendar seasons (December - February, March - May, June - August, September - November).\n* `tropical-season`: Six month periods of the tropical seasons (November - April, May - October).\n* `year`: Proleptic years\n* `decade`: Ten year periods ([0-to-9 decade](https://en.wikipedia.org/wiki/Decade#0-to-9_decade)), from a year ending in a 0 to the next year ending in a 9.\n* `decade-ad`: Ten year periods ([1-to-0 decade](https://en.wikipedia.org/wiki/Decade#1-to-0_decade)) better aligned with the anno Domini (AD) calendar era, from a year ending in a 1 to the next year ending in a 0.\n* `single-period` / `climatology-period`: A single period of arbitrary length", "schema": { "type": "string", "enum": [ diff --git a/any.json b/any.json index b99453b9..545c1669 100644 --- a/any.json +++ b/any.json @@ -1,7 +1,7 @@ { "id": "any", "summary": "Is at least one value true?", - "description": "Checks if **any** (i.e. at least one) value in `data` is `true`. Evaluates all values from the first to the last element and stops once the outcome is unambiguous.\n\nIf only one value is given, the process evaluates to the given value. If no value is given (i.e. the array is empty) the process returns `null`.\n\nBy default all no-data values are ignored so that the process returns `null` if all values are no-data, `true` if at least one of the other values is true and `false` otherwise. Setting the `ignore_nodata` flag to `false` considers no-data values so that `null` is a valid logical object. If a component is `null`, the result will be `null` if the outcome is ambiguous. See the following truth table:\n\n```\n || null | false | true\n----- || ---- | ----- | ----\nnull || null | null | true\nfalse || null | false | true\ntrue || true | true | true\n```", + "description": "Checks if **any** (i.e. at least one) value in `data` is `true`. If no value is given (i.e. the array is empty) the process returns `null`.\n\nBy default all no-data values are ignored so that the process returns `null` if all values are no-data, `true` if at least one value is true and `false` otherwise. Setting the `ignore_nodata` flag to `false` takes no-data values into account and the array values are reduced pairwise according to the following truth table:\n\n```\n || null | false | true\n----- || ---- | ----- | ----\nnull || null | null | true\nfalse || null | false | true\ntrue || true | true | true\n```\n\n**Remark:** The process evaluates all values from the first to the last element and stops once the outcome is unambiguous. A result is ambiguous unless a value is `true`.", "categories": [ "logic", "reducer" diff --git a/apply.json b/apply.json index 430c960f..a39292e0 100644 --- a/apply.json +++ b/apply.json @@ -1,7 +1,7 @@ { "id": "apply", "summary": "Apply a process to each pixel", - "description": "Applies a *unary* process to each pixel value in the data cube (i.e. a local operation). A unary process takes a single value and returns a single value, for example ``abs()`` or ``linear_scale_range()``. In contrast, the process ``apply_dimension()`` applies a process to all pixel values along a particular dimension.", + "description": "Applies a process to each pixel value in the data cube (i.e. a local operation). In contrast, the process ``apply_dimension()`` applies a process to all pixel values along a particular dimension.", "categories": [ "cubes" ], @@ -16,7 +16,7 @@ }, { "name": "process", - "description": "A unary process to be applied on each value, may consist of multiple sub-processes.", + "description": "A process that accepts and returns a single value and is applied on each individual value in the data cube. The process may consist of multiple sub-processes and could, for example, consist of processes such as ``abs()`` or ``linear_scale_range()``.", "schema": { "type": "object", "subtype": "process-graph", @@ -37,7 +37,13 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "The value to be set in the new data cube.", + "schema": { + "description": "Any data type." + } + } } }, { @@ -56,5 +62,12 @@ "type": "object", "subtype": "raster-cube" } - } + }, + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#apply", + "rel": "about", + "title": "Apply explained in the openEO documentation" + } + ] } \ No newline at end of file diff --git a/apply_dimension.json b/apply_dimension.json index 873f098f..796393f4 100644 --- a/apply_dimension.json +++ b/apply_dimension.json @@ -16,7 +16,7 @@ }, { "name": "process", - "description": "Process to be applied on all pixel values. The specified process needs to accept an array as parameter and must return an array with least one element. A process may consist of multiple sub-processes.", + "description": "Process to be applied on all pixel values. The specified process needs to accept an array and must return an array with at least one element. A process may consist of multiple sub-processes.", "schema": { "type": "object", "subtype": "process-graph", @@ -41,19 +41,28 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "The value to be set in the new data cube.", + "schema": { + "type": "array", + "items": { + "description": "Any data type." + } + } + } } }, { "name": "dimension", - "description": "The name of the source dimension to apply the process on. Fails with a `DimensionNotAvailable` error if the specified dimension does not exist.", + "description": "The name of the source dimension to apply the process on. Fails with a `DimensionNotAvailable` exception if the specified dimension does not exist.", "schema": { "type": "string" } }, { "name": "target_dimension", - "description": "The name of the target dimension or `null` (the default) to use the source dimension specified in the parameter `dimension`.\n\nBy specifying a target dimension, the source dimension is removed. The target dimension with the specified name and the type `other` (see ``add_dimension()``) is created, if if doesn't exist yet.", + "description": "The name of the target dimension or `null` (the default) to use the source dimension specified in the parameter `dimension`.\n\nBy specifying a target dimension, the source dimension is removed. The target dimension with the specified name and the type `other` (see ``add_dimension()``) is created, if it doesn't exist yet.", "schema": { "type": [ "string", @@ -74,7 +83,7 @@ } ], "returns": { - "description": "A data cube with the newly computed values. All dimensions stay the same, except for the dimensions specified in corresponding parameters. There are three cases how the data cube changes:\n\n1. The source dimension **is** the target dimension:\n * The (number of) dimensions remain unchanged.\n * The source dimension properties name, type and reference system remain unchanged.\n * The dimension labels and the resolution are preserved when the number of pixel values in the source dimension is equal to the number of values computed by the process. The other case is described below.\n2. The source dimension **is not** the target dimension and the latter **exists**:\n * The number of dimensions decreases by one as the source dimension is dropped.\n * The target dimension properties name, type and reference system remain unchanged.\n * The resolution changes, the number of dimension labels is equal to the number of values computed by the process and the dimension labels are incrementing integers starting from zero\n3. The source dimension **is not** the target dimension and the latter **does not exist**:\n * The number of dimensions remain unchanged, but the source dimension is replaced with the target dimension.\n * The target dimension has the specified name and the type other. The reference system is not changed.\n * The resolution changes, the number of dimension labels is equal to the number of values computed by the process and the dimension labels are incrementing integers starting from zero\n\nFor all three cases except for the exception in the first case, the resolution changes, the number of dimension labels is equal to the number of values computed by the process and the dimension labels are incrementing integers starting from zero.", + "description": "A data cube with the newly computed values.\n\nAll dimensions stay the same, except for the dimensions specified in corresponding parameters. There are three cases how the dimensions can change:\n\n1. The source dimension is the target dimension:\n - The (number of) dimensions remain unchanged as the source dimension is the target dimension.\n - The source dimension properties name and type remain unchanged.\n - The dimension labels, the reference system and the resolution are preserved only if the number of pixel values in the source dimension is equal to the number of values computed by the process. Otherwise, all other dimension properties change as defined in the list below.\n2. The source dimension is not the target dimension and the latter exists:\n - The number of dimensions decreases by one as the source dimension is dropped.\n - The target dimension properties name and type remain unchanged. All other dimension properties change as defined in the list below.\n3. The source dimension is not the target dimension and the latter does not exist:\n - The number of dimensions remain unchanged, but the source dimension is replaced with the target dimension.\n - The target dimension has the specified name and the type other. All other dimension properties are set as defined in the list below.\n\nUnless otherwise stated above, for the given (target) dimension the following applies:\n\n- the number of dimension labels is equal to the number of values computed by the process,\n- the dimension labels are incrementing integers starting from zero,\n- the resolution changes, and\n- the reference system is undefined.", "schema": { "type": "object", "subtype": "raster-cube" @@ -84,5 +93,12 @@ "DimensionNotAvailable": { "message": "A dimension with the specified name does not exist." } - } + }, + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#apply", + "rel": "about", + "title": "Apply explained in the openEO documentation" + } + ] } \ No newline at end of file diff --git a/apply_kernel.json b/apply_kernel.json index dddacd5f..20d940c2 100644 --- a/apply_kernel.json +++ b/apply_kernel.json @@ -17,7 +17,7 @@ }, { "name": "kernel", - "description": "Kernel as a two-dimensional array of weights. The inner level of the nested array aligns with the `x` axis and the outer level aligns with the `y` axis. Each level of the kernel must have an uneven number of elements, otherwise the process throws a `KernelDimensionsUneven` error.", + "description": "Kernel as a two-dimensional array of weights. The inner level of the nested array aligns with the `x` axis and the outer level aligns with the `y` axis. Each level of the kernel must have an uneven number of elements, otherwise the process throws a `KernelDimensionsUneven` exception.", "schema": { "description": "A two-dimensional array of numbers.", "type": "array", @@ -82,6 +82,11 @@ } }, "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#apply", + "rel": "about", + "title": "Apply explained in the openEO documentation" + }, { "rel": "about", "href": "http://www.songho.ca/dsp/convolution/convolution.html", diff --git a/apply_neighborhood.json b/apply_neighborhood.json index 28b27366..05fb117a 100644 --- a/apply_neighborhood.json +++ b/apply_neighborhood.json @@ -1,7 +1,7 @@ { "id": "apply_neighborhood", - "summary": "Apply a process to pixels in a n-dimensional neighbourhood", - "description": "Applies a focal process to a data cube.\n\nA focal process is a process that works on a 'neighbourhood' of pixels. The neighbourhood can extend into multiple dimensions, this extent is specified by the `size` argument. It is not only (part of) the size of the input window, but also the size of the output for a given position of the sliding window. The sliding window moves with multiples of `size`.\n\nAn overlap can be specified so that neighbourhoods can have overlapping boundaries. This allows for continuity of the output. The values included in the data cube as overlap can't be modified by the given `process`. The missing overlap at the borders of the original data cube are made available as no-data (`null`) in the sub data cubes.\n\nThe neighbourhood size should be kept small enough, to avoid running beyond computational resources, but a too small size will result in a larger number of process invocations, which may slow down processing. Window sizes for spatial dimensions typically are in the range of 64 to 512 pixels, while overlaps of 8 to 32 pixels are common.\n\nThe process must not add new dimensions, or remove entire dimensions, but the result can have different dimension labels.\n\nFor the special case of 2D convolution, it is recommended to use ``apply_kernel()``.", + "summary": "Apply a process to pixels in a n-dimensional neighborhood", + "description": "Applies a focal process to a data cube.\n\nA focal process is a process that works on a 'neighborhood' of pixels. The neighborhood can extend into multiple dimensions, this extent is specified by the `size` argument. It is not only (part of) the size of the input window, but also the size of the output for a given position of the sliding window. The sliding window moves with multiples of `size`.\n\nAn overlap can be specified so that neighborhoods can have overlapping boundaries. This allows for continuity of the output. The values included in the data cube as overlap can't be modified by the given `process`. The missing overlap at the borders of the original data cube are made available as no-data (`null`) in the sub data cubes.\n\nThe neighborhood size should be kept small enough, to avoid running beyond computational resources, but a too small size will result in a larger number of process invocations, which may slow down processing. Window sizes for spatial dimensions typically are in the range of 64 to 512 pixels, while overlaps of 8 to 32 pixels are common.\n\nThe process must not add new dimensions, or remove entire dimensions, but the result can have different dimension labels.\n\nFor the special case of 2D convolution, it is recommended to use ``apply_kernel()``.", "categories": [ "cubes" ], @@ -16,7 +16,7 @@ }, { "name": "process", - "description": "Process to be applied on all neighbourhoods.", + "description": "Process to be applied on all neighborhoods.", "schema": { "type": "object", "subtype": "process-graph", @@ -38,12 +38,19 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "The data cube with the newly computed values and the same dimensions. The dimension properties (name, type, labels, reference system and resolution) must remain unchanged, otherwise a `DataCubePropertiesImmutable` exception will be thrown.", + "schema": { + "type": "object", + "subtype": "raster-cube" + } + } } }, { "name": "size", - "description": "Neighbourhood sizes along each dimension.\n\nThis object maps dimension names to either a physical measure (e.g. 100 m, 10 days) or pixels (e.g. 32 pixels). For dimensions not specified, the default is to provide all values. Be aware that including all values from overly large dimensions may not be processed at once.", + "description": "Neighborhood sizes along each dimension.\n\nThis object maps dimension names to either a physical measure (e.g. 100 m, 10 days) or pixels (e.g. 32 pixels). For dimensions not specified, the default is to provide all values. Be aware that including all values from overly large dimensions may not be processed at once.", "schema": { "type": "array", "items": { @@ -59,7 +66,7 @@ }, "value": { "default": null, - "oneOf": [ + "anyOf": [ { "type": "null", "title": "All values" @@ -79,7 +86,7 @@ }, "unit": { "type": "string", - "description": "The unit the values are given in, either meters (`m`) or pixels (`px`). If no unit is given, uses the unit specified for the dimension or otherwise the default unit of the reference system.", + "description": "The unit the values are given in, either in meters (`m`) or pixels (`px`). If no unit is given, uses the unit specified for the dimension or otherwise the default unit of the reference system.", "enum": [ "px", "m" @@ -91,7 +98,7 @@ }, { "name": "overlap", - "description": "Overlap of neighbourhoods along each dimension to avoid border effects.\n\nFor instance a temporal dimension can add 1 month before and after a neighbourhood. In the spatial dimensions, this is often a number of pixels. The overlap specified is added before and after, so an overlap of 8 pixels will add 8 pixels on both sides of the window, so 16 in total.\n\nBe aware that large overlaps increase the need for computational resources and modifying overlapping data in subsequent operations have no effect.", + "description": "Overlap of neighborhoods along each dimension to avoid border effects.\n\nFor instance a temporal dimension can add 1 month before and after a neighborhood. In the spatial dimensions, this is often a number of pixels. The overlap specified is added before and after, so an overlap of 8 pixels will add 8 pixels on both sides of the window, so 16 in total.\n\nBe aware that large overlaps increase the need for computational resources and modifying overlapping data in subsequent operations have no effect.", "optional": true, "schema": { "type": "array", @@ -108,7 +115,7 @@ }, "value": { "default": null, - "oneOf": [ + "anyOf": [ { "type": "null", "title": "No values" @@ -128,7 +135,7 @@ }, "unit": { "type": "string", - "description": "The unit the values are given in, either meters (`m`) or pixels (`px`). If no unit is given, uses the unit specified for the dimension or otherwise the default unit of the reference system.", + "description": "The unit the values are given in, either in meters (`m`) or pixels (`px`). If no unit is given, uses the unit specified for the dimension or otherwise the default unit of the reference system.", "enum": [ "px", "m" @@ -214,6 +221,16 @@ "exceptions": { "DimensionNotAvailable": { "message": "A dimension with the specified name does not exist." + }, + "DataCubePropertiesImmutable": { + "message": "The dimension properties (name, type, labels, reference system and resolution) must remain unchanged." + } + }, + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#apply", + "rel": "about", + "title": "Apply explained in the openEO documentation" } - } + ] } \ No newline at end of file diff --git a/arccos.json b/arccos.json index a75c7300..5ffbce35 100644 --- a/arccos.json +++ b/arccos.json @@ -1,7 +1,7 @@ { "id": "arccos", "summary": "Inverse cosine", - "description": "Computes the arc cosine of `x`. The arc cosine is the inverse function of the cosine so that *arccos(cos(x)) = x*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Computes the arc cosine of `x`. The arc cosine is the inverse function of the cosine so that *`arccos(cos(x)) = x`*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math > trigonometric" ], diff --git a/arcosh.json b/arcosh.json index 6b5dc948..6ed581fe 100644 --- a/arcosh.json +++ b/arcosh.json @@ -1,7 +1,7 @@ { "id": "arcosh", "summary": "Inverse hyperbolic cosine", - "description": "Computes the inverse hyperbolic cosine of `x`. It is the inverse function of the hyperbolic cosine so that *arcosh(cosh(x)) = x*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Computes the inverse hyperbolic cosine of `x`. It is the inverse function of the hyperbolic cosine so that *`arcosh(cosh(x)) = x`*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math > trigonometric" ], diff --git a/arcsin.json b/arcsin.json index b85e0eaf..e37eb2d3 100644 --- a/arcsin.json +++ b/arcsin.json @@ -1,7 +1,7 @@ { "id": "arcsin", "summary": "Inverse sine", - "description": "Computes the arc sine of `x`. The arc sine is the inverse function of the sine so that *arcsin(sin(x)) = x*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Computes the arc sine of `x`. The arc sine is the inverse function of the sine so that *`arcsin(sin(x)) = x`*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math > trigonometric" ], diff --git a/arctan.json b/arctan.json index 6c9e2be3..dc8d5a68 100644 --- a/arctan.json +++ b/arctan.json @@ -1,7 +1,7 @@ { "id": "arctan", "summary": "Inverse tangent", - "description": "Computes the arc tangent of `x`. The arc tangent is the inverse function of the tangent so that *arctan(tan(x)) = x*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Computes the arc tangent of `x`. The arc tangent is the inverse function of the tangent so that *`arctan(tan(x)) = x`*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math > trigonometric" ], diff --git a/arctan2.json b/arctan2.json index a4d91b2a..ca7d507f 100644 --- a/arctan2.json +++ b/arctan2.json @@ -1,14 +1,14 @@ { "id": "arctan2", "summary": "Inverse tangent of two numbers", - "description": "Computes the arc tangent of two numbers `x` and `y`. It is similar to calculating the arc tangent of *y / x*, except that the signs of both arguments are used to determine the quadrant of the result.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated if any of the arguments is `null`.", + "description": "Computes the arc tangent of two numbers `x` and `y`. It is similar to calculating the arc tangent of *`y / x`*, except that the signs of both arguments are used to determine the quadrant of the result.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated if any of the arguments is `null`.", "categories": [ "math > trigonometric" ], "parameters": [ { "name": "y", - "description": "A number to be used as dividend.", + "description": "A number to be used as the dividend.", "schema": { "type": [ "number", @@ -18,7 +18,7 @@ }, { "name": "x", - "description": "A number to be used as divisor.", + "description": "A number to be used as the divisor.", "schema": { "type": [ "number", diff --git a/array_apply.json b/array_apply.json index 9d10d48c..bea8a744 100644 --- a/array_apply.json +++ b/array_apply.json @@ -1,7 +1,7 @@ { "id": "array_apply", - "summary": "Applies a unary process to each array element", - "description": "Applies a **unary** process which takes a single value such as `abs` or `sqrt` to each value in the array. This is basically what other languages call either a `for each` loop or a `map` function.", + "summary": "Apply a process to each array element", + "description": "Applies a process to each individual value in the array. This is basically what other languages call either a `for each` loop or a `map` function.", "categories": [ "arrays" ], @@ -18,7 +18,7 @@ }, { "name": "process", - "description": "A process to be applied on each value, may consist of multiple sub-processes. The specified process must be unary meaning that it must work on a single value.", + "description": "A process that accepts and returns a single value and is applied on each individual value in the array. The process may consist of multiple sub-processes and could, for example, consist of processes such as ``abs()`` or ``linear_scale_range()``.", "schema": { "type": "object", "subtype": "process-graph", @@ -34,7 +34,8 @@ "name": "index", "description": "The zero-based index of the current element being processed.", "schema": { - "type": "integer" + "type": "integer", + "minimum": 0 } }, { @@ -63,7 +64,13 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "The value to be set in the new array.", + "schema": { + "description": "Any data type." + } + } } }, { @@ -89,13 +96,13 @@ { "rel": "example", "type": "application/json", - "href": "https://processes.openeo.org/1.0.0/examples/array_find_nodata.json", + "href": "https://processes.openeo.org/1.1.0/examples/array_find_nodata.json", "title": "Find no-data values in arrays" }, { "rel": "example", "type": "application/json", - "href": "https://processes.openeo.org/1.0.0/examples/array_contains_nodata.json", + "href": "https://processes.openeo.org/1.1.0/examples/array_contains_nodata.json", "title": "Check for no-data values in arrays" } ] diff --git a/array_contains.json b/array_contains.json index fdbc602b..cabfcf23 100644 --- a/array_contains.json +++ b/array_contains.json @@ -1,7 +1,7 @@ { "id": "array_contains", "summary": "Check whether the array contains a given value", - "description": "Checks whether the array specified for `data` contains the value specified in `value`. Returns `true` if there's a match, otherwise `false`.\n\n**Remarks:**\n\n* To get the index or the label of the value found, use ``array_find()``.\n* All definitions for the process ``eq()`` regarding the comparison of values apply here as well. A `null` return value from ``eq()`` is handled exactly as `false` (no match).\n* Data types MUST be checked strictly, for example a string with the content *1* is not equal to the number *1*.\n* An integer *1* is equal to a floating point number *1.0* as `integer` is a sub-type of `number`. Still, this process may return unexpectedly `false` when comparing floating point numbers due to floating point inaccuracy in machine-based computation.\n* Temporal strings are treated as normal strings and MUST NOT be interpreted.\n* If the specified value is an array, object or null, the process always returns `false`. See the examples for one to check for `null` values.", + "description": "Checks whether the array specified for `data` contains the value specified in `value`. Returns `true` if there's a match, otherwise `false`.\n\n**Remarks:**\n\n* To get the index or the label of the value found, use ``array_find()``.\n* All definitions for the process ``eq()`` regarding the comparison of values apply here as well. A `null` return value from ``eq()`` is handled exactly as `false` (no match).\n* Data types MUST be checked strictly. For example, a string with the content *1* is not equal to the number *1*.\n* An integer *1* is equal to a floating-point number *1.0* as `integer` is a sub-type of `number`. Still, this process may return unexpectedly `false` when comparing floating-point numbers due to floating-point inaccuracy in machine-based computation.\n* Temporal strings are treated as normal strings and MUST NOT be interpreted.\n* If the specified value is an array, object or null, the process always returns `false`. See the examples for one to check for `null` values.", "categories": [ "arrays", "comparison", @@ -27,7 +27,7 @@ } ], "returns": { - "description": "Returns `true` if the list contains the value, false` otherwise.", + "description": "`true` if the list contains the value, false` otherwise.", "schema": { "type": "boolean" } @@ -133,7 +133,7 @@ { "rel": "example", "type": "application/json", - "href": "https://processes.openeo.org/1.0.0/examples/array_contains_nodata.json", + "href": "https://processes.openeo.org/1.1.0/examples/array_contains_nodata.json", "title": "Check for no-data values in arrays" } ], diff --git a/array_element.json b/array_element.json index 389030bf..8b70a2e5 100644 --- a/array_element.json +++ b/array_element.json @@ -1,7 +1,7 @@ { "id": "array_element", "summary": "Get an element from an array", - "description": "Returns the element with the specified index or label from the array.\n\nEither the parameter `index` or `label` must be specified, otherwise the `ArrayElementParameterMissing` exception is thrown. If both parameters are set the `ArrayElementParameterConflict` exception is thrown.", + "description": "Gives the element with the specified index or label from the array.\n\nEither the parameter `index` or `label` must be specified, otherwise the `ArrayElementParameterMissing` exception is thrown. If both parameters are set the `ArrayElementParameterConflict` exception is thrown.", "categories": [ "arrays", "reducer" @@ -21,13 +21,14 @@ "name": "index", "description": "The zero-based index of the element to retrieve.", "schema": { - "type": "integer" + "type": "integer", + "minimum": 0 }, "optional": true }, { "name": "label", - "description": "The label of the element to retrieve.", + "description": "The label of the element to retrieve. Throws an `ArrayNotLabeled` exception, if the given array is not a labeled array and this parameter is set.", "schema": [ { "type": "number" @@ -59,10 +60,13 @@ "message": "The array has no element with the specified index or label." }, "ArrayElementParameterMissing": { - "message": "The process 'array_element' requires either the 'index' or 'labels' parameter to be set." + "message": "The process `array_element` requires either the `index` or `labels` parameter to be set." }, "ArrayElementParameterConflict": { - "message": "The process 'array_element' only allows that either the 'index' or the 'labels' parameter is set." + "message": "The process `array_element` only allows that either the `index` or the `labels` parameter is set." + }, + "ArrayNotLabeled": { + "message": "The array is not a labeled array, but the `label` parameter is set. Use the `index` instead." } }, "examples": [ diff --git a/array_filter.json b/array_filter.json index e9bc5d14..f5b92b63 100644 --- a/array_filter.json +++ b/array_filter.json @@ -1,7 +1,7 @@ { "id": "array_filter", "summary": "Filter an array based on a condition", - "description": "Filters the array elements based on a logical expression so that afterwards an array is returned that only contains the values conforming to the condition.", + "description": "Filters the array elements based on a logical expression so that afterwards an array is returned that only contains the values, indices and/or labels conforming to the condition.", "categories": [ "arrays", "filter" @@ -19,7 +19,7 @@ }, { "name": "condition", - "description": "A condition that is evaluated against each value in the array. Only the array elements where the condition returns `true` are preserved.", + "description": "A condition that is evaluated against each value, index and/or label in the array. Only the array elements for which the condition returns `true` are preserved.", "schema": { "type": "object", "subtype": "process-graph", @@ -35,7 +35,8 @@ "name": "index", "description": "The zero-based index of the current element being processed.", "schema": { - "type": "integer" + "type": "integer", + "minimum": 0 } }, { @@ -64,7 +65,13 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "`true` if the value should be kept in the array, otherwise `false`.", + "schema": { + "type": "boolean" + } + } } }, { diff --git a/array_find.json b/array_find.json index 9a2335b1..d60a450d 100644 --- a/array_find.json +++ b/array_find.json @@ -1,7 +1,7 @@ { "id": "array_find", "summary": "Get the index for a value in an array", - "description": "Checks whether the array specified for `data` contains the value specified in `value` and returns the zero-based index for the first match. If there's no match, `null` is returned.\n\n**Remarks:**\n\n* To get a boolean value returned use ``array_contains()``.\n* All definitions for the process ``eq()`` regarding the comparison of values apply here as well. A `null` return value from ``eq()`` is handled exactly as `false` (no match).\n* Data types MUST be checked strictly, for example a string with the content *1* is not equal to the number *1*.\n* An integer *1* is equal to a floating point number *1.0* as `integer` is a sub-type of `number`. Still, this process may return unexpectedly `false` when comparing floating point numbers due to floating point inaccuracy in machine-based computation.\n* Temporal strings are treated as normal strings and MUST NOT be interpreted.\n* If the specified value is an array, object or null, the process always returns `null`. See the examples for one to find `null` values.", + "description": "Checks whether the array specified for `data` contains the value specified in `value` and returns the zero-based index for the first match. If there's no match, `null` is returned.\n\n**Remarks:**\n\n* To get a boolean value returned use ``array_contains()``.\n* All definitions for the process ``eq()`` regarding the comparison of values apply here as well. A `null` return value from ``eq()`` is handled exactly as `false` (no match).\n* Data types MUST be checked strictly. For example, a string with the content *1* is not equal to the number *1*.\n* An integer *1* is equal to a floating-point number *1.0* as `integer` is a sub-type of `number`. Still, this process may return unexpectedly `false` when comparing floating-point numbers due to floating-point inaccuracy in machine-based computation.\n* Temporal strings are treated as normal strings and MUST NOT be interpreted.\n* If the specified value is an array, object or null, the process always returns `null`. See the examples for one to find `null` values.", "categories": [ "arrays", "reducer" @@ -26,7 +26,7 @@ } ], "returns": { - "description": "Returns the index of the first element with the specified value. If no element was found, `null` is returned.", + "description": "The index of the first element with the specified value. If no element was found, `null` is returned.", "schema": [ { "type": "null" @@ -139,7 +139,7 @@ { "rel": "example", "type": "application/json", - "href": "https://processes.openeo.org/1.0.0/examples/array_find_nodata.json", + "href": "https://processes.openeo.org/1.1.0/examples/array_find_nodata.json", "title": "Find no-data values in arrays" } ] diff --git a/array_labels.json b/array_labels.json index 2e26c62b..52dcad0e 100644 --- a/array_labels.json +++ b/array_labels.json @@ -1,7 +1,7 @@ { "id": "array_labels", "summary": "Get the labels for an array", - "description": "Returns all labels for a labeled array in the data cube. The labels have the same order as in the array.", + "description": "Gives all labels for a labeled array. The labels have the same order as in the array.", "categories": [ "arrays" ], @@ -11,22 +11,21 @@ "description": "An array with labels.", "schema": { "type": "array", - "subtype": "labeled-array" + "subtype": "labeled-array", + "items": { + "description": "Any data type." + } } } ], "returns": { - "description": "The labels as array.", + "description": "The labels as an array.", "schema": { "type": "array", "items": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } + "type": [ + "number", + "string" ] } } diff --git a/arsinh.json b/arsinh.json index 1475772f..37384dcd 100644 --- a/arsinh.json +++ b/arsinh.json @@ -1,7 +1,7 @@ { "id": "arsinh", "summary": "Inverse hyperbolic sine", - "description": "Computes the inverse hyperbolic sine of `x`. It is the inverse function of the hyperbolic sine so that *arsinh(sinh(x)) = x*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Computes the inverse hyperbolic sine of `x`. It is the inverse function of the hyperbolic sine so that *`arsinh(sinh(x)) = x`*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math > trigonometric" ], diff --git a/artanh.json b/artanh.json index add380b0..926b48ea 100644 --- a/artanh.json +++ b/artanh.json @@ -1,7 +1,7 @@ { "id": "artanh", "summary": "Inverse hyperbolic tangent", - "description": "Computes the inverse hyperbolic tangent of `x`. It is the inverse function of the hyperbolic tangent so that *artanh(tanh(x)) = x*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Computes the inverse hyperbolic tangent of `x`. It is the inverse function of the hyperbolic tangent so that *`artanh(tanh(x)) = x`*.\n\nWorks on radians only.\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math > trigonometric" ], diff --git a/between.json b/between.json index dcd1fa92..7d8f14df 100644 --- a/between.json +++ b/between.json @@ -1,7 +1,7 @@ { "id": "between", "summary": "Between comparison", - "description": "By default this process checks whether `x` is greater than or equal to `min` and lower than or equal to `max`, which is the same as computing `and(gte(x, min), lte(x, max))`. Therefore, all definitions from ``and()``, ``gte()`` and ``lte()`` apply here as well.\n\nIf `exclude_max` is set to `true` the upper bound is excluded so that the process checks whether `x` is greater than or equal to `min` and lower than `max`. In this case the process works the same as computing `and(gte(x, min), lt(x, max))`.\n\nLower and upper bounds are not allowed to be swapped. So `min` MUST be lower than or equal to `max` or otherwise the process always returns `false`.", + "description": "By default, this process checks whether `x` is greater than or equal to `min` and lower than or equal to `max`, which is the same as computing `and(gte(x, min), lte(x, max))`. Therefore, all definitions from ``and()``, ``gte()`` and ``lte()`` apply here as well.\n\nIf `exclude_max` is set to `true` the upper bound is excluded so that the process checks whether `x` is greater than or equal to `min` and lower than `max`. In this case, the process works the same as computing `and(gte(x, min), lt(x, max))`.\n\nLower and upper bounds are not allowed to be swapped. So `min` MUST be lower than or equal to `max` or otherwise the process always returns `false`.", "categories": [ "comparison" ], diff --git a/climatological_normal.json b/climatological_normal.json index a2ac7ae9..efaedd74 100644 --- a/climatological_normal.json +++ b/climatological_normal.json @@ -1,6 +1,6 @@ { "id": "climatological_normal", - "summary": "Computes climatology normals", + "summary": "Compute climatology normals", "description": "Climatological normal period is a usually 30 year average of a weather variable. Climatological normals are used as an average or baseline to evaluate climate events and provide context for yearly, monthly, daily or seasonal variability. The default climatology period is from 1981 until 2010 (both inclusive).", "categories": [ "climatology" @@ -30,7 +30,7 @@ }, { "name": "climatology_period", - "description": "The climatology period as closed temporal interval. The first element of the array is the first year to be fully included in the temporal interval. The second element is the last year to be fully included in the temporal interval. The default period is from 1981 until 2010 (both inclusive).", + "description": "The climatology period as a closed temporal interval. The first element of the array is the first year to be fully included in the temporal interval. The second element is the last year to be fully included in the temporal interval. The default period is from 1981 until 2010 (both inclusive).", "schema": { "type": "array", "subtype": "temporal-interval", diff --git a/clip.json b/clip.json index 9e5709dc..adbf7eaa 100644 --- a/clip.json +++ b/clip.json @@ -1,7 +1,7 @@ { "id": "clip", "summary": "Clip a value between a minimum and a maximum", - "description": "Clips a number between specified minimum and maximum values. A value larger than the maximal value will have the maximal value, a value lower than minimal value will have the minimal value.\n\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Clips a number between specified minimum and maximum values. A value larger than the maximum value is set to the maximum value, a value lower than the minimum value is set to the minimum value.\n\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math" ], diff --git a/count.json b/count.json index 0a54a927..ed1044bd 100644 --- a/count.json +++ b/count.json @@ -19,7 +19,7 @@ }, { "name": "condition", - "description": "A condition consists of one ore more processes, which in the end return a boolean value. It is evaluated against each element in the array. An element is counted only if the condition returns `true`. Defaults to count valid elements in a list (see ``is_valid()``). Setting this parameter to boolean `true` counts all elements in the list.", + "description": "A condition consists of one or more processes, which in the end return a boolean value. It is evaluated against each element in the array. An element is counted only if the condition returns `true`. Defaults to count valid elements in a list (see ``is_valid()``). Setting this parameter to boolean `true` counts all elements in the list.", "schema": [ { "title": "Condition", @@ -43,7 +43,13 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "`true` if the element should increase the counter, otherwise `false`.", + "schema": { + "type": "boolean" + } + } }, { "title": "All elements", diff --git a/create_raster_cube.json b/create_raster_cube.json index 8872931f..576728ee 100644 --- a/create_raster_cube.json +++ b/create_raster_cube.json @@ -12,5 +12,12 @@ "type": "object", "subtype": "raster-cube" } - } + }, + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html", + "rel": "about", + "title": "Data Cubes explained in the openEO documentation" + } + ] } \ No newline at end of file diff --git a/dimension_labels.json b/dimension_labels.json index 6e3bc205..37a5908d 100644 --- a/dimension_labels.json +++ b/dimension_labels.json @@ -1,7 +1,7 @@ { "id": "dimension_labels", "summary": "Get the dimension labels", - "description": "Returns all labels for a dimension in the data cube. The labels have the same order as in the data cube.", + "description": "Gives all labels for a dimension in the data cube. The labels have the same order as in the data cube.\n\nIf a dimension with the specified name does not exist, the process fails with a `DimensionNotAvailable` exception.", "categories": [ "cubes" ], @@ -23,19 +23,20 @@ } ], "returns": { - "description": "The labels as array.", + "description": "The labels as an array.", "schema": { "type": "array", "items": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } + "type": [ + "number", + "string" ] } } + }, + "exceptions": { + "DimensionNotAvailable": { + "message": "A dimension with the specified name does not exist." + } } } \ No newline at end of file diff --git a/divide.json b/divide.json index d5cc39ac..5dd664f1 100644 --- a/divide.json +++ b/divide.json @@ -1,7 +1,7 @@ { "id": "divide", "summary": "Division of two numbers", - "description": "Divides argument `x` by the argument `y` (*x / y*) and returns the computed result.\n\nNo-data values are taken into account so that `null` is returned if any element is such a value.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it. Therefore, a division by zero results in ±infinity if the processing environment supports it. Otherwise a `DivisionByZero` error must the thrown.", + "description": "Divides argument `x` by the argument `y` (*`x / y`*) and returns the computed result.\n\nNo-data values are taken into account so that `null` is returned if any element is such a value.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it. Therefore, a division by zero results in ±infinity if the processing environment supports it. Otherwise, a `DivisionByZero` exception must the thrown.", "categories": [ "math" ], diff --git a/drop_dimension.json b/drop_dimension.json index b946aee0..90212dd9 100644 --- a/drop_dimension.json +++ b/drop_dimension.json @@ -1,7 +1,7 @@ { "id": "drop_dimension", "summary": "Remove a dimension", - "description": "Drops a dimension from the data cube.\n\nDropping a dimension only works on dimensions with a single dimension label left, otherwise the process fails with a `DimensionLabelCountMismatch` error. Dimension values can be reduced to a single value with a filter such as ``filter_bands()`` or the ``reduce_dimension()`` process. If a dimension with the specified name does not exist, the process fails with a `DimensionNotAvailable` error.", + "description": "Drops a dimension from the data cube.\n\nDropping a dimension only works on dimensions with a single dimension label left, otherwise the process fails with a `DimensionLabelCountMismatch` exception. Dimension values can be reduced to a single value with a filter such as ``filter_bands()`` or the ``reduce_dimension()`` process. If a dimension with the specified name does not exist, the process fails with a `DimensionNotAvailable` exception.", "categories": [ "cubes" ], diff --git a/e.json b/e.json index 7c1c5ff6..79506861 100644 --- a/e.json +++ b/e.json @@ -1,7 +1,7 @@ { "id": "e", "summary": "Euler's number (e)", - "description": "The real number *e* is a mathematical constant that is the base of the natural logarithm such that *ln(e) = 1*. The numerical value is approximately *2.71828*.", + "description": "The real number *e* is a mathematical constant that is the base of the natural logarithm such that *`ln(e) = 1`*. The numerical value is approximately *2.71828*.", "categories": [ "math > constants", "math > exponential & logarithmic" diff --git a/eq.json b/eq.json index 15f02968..6550098e 100644 --- a/eq.json +++ b/eq.json @@ -1,7 +1,7 @@ { "id": "eq", "summary": "Equal to comparison", - "description": "Compares whether `x` is strictly equal to `y`.\n\n**Remarks:**\n\n* Data types MUST be checked strictly, for example a string with the content *1* is not equal to the number *1*. Nevertheless, an integer *1* is equal to a floating point number *1.0* as `integer` is a sub-type of `number`.\n* If any operand is `null`, the return value is `null`. Therefore, `eq(null, null)` returns `null` instead of `true`.\n* If any operand is an array or object, the return value is `false`.\n* Strings are expected to be encoded in UTF-8 by default.\n* Temporal strings MUST be compared differently than other strings and MUST NOT be compared based on their string representation due to different possible representations. For example, the UTC time zone representation `Z` has the same meaning as `+00:00`.", + "description": "Compares whether `x` is strictly equal to `y`.\n\n**Remarks:**\n\n* Data types MUST be checked strictly. For example, a string with the content *1* is not equal to the number *1*. Nevertheless, an integer *1* is equal to a floating-point number *1.0* as `integer` is a sub-type of `number`.\n* If any operand is `null`, the return value is `null`. Therefore, `eq(null, null)` returns `null` instead of `true`.\n* If any operand is an array or object, the return value is `false`.\n* Strings are expected to be encoded in UTF-8 by default.\n* Temporal strings MUST be compared differently than other strings and MUST NOT be compared based on their string representation due to different possible representations. For example, the time zone representation `Z` (for UTC) has the same meaning as `+00:00`.", "categories": [ "texts", "comparison" @@ -23,7 +23,7 @@ }, { "name": "delta", - "description": "Only applicable for comparing two numbers. If this optional parameter is set to a positive non-zero number the equality of two numbers is checked against a delta value. This is especially useful to circumvent problems with floating point inaccuracy in machine-based computation.\n\nThis option is basically an alias for the following computation: `lte(abs(minus([x, y]), delta)`", + "description": "Only applicable for comparing two numbers. If this optional parameter is set to a positive non-zero number the equality of two numbers is checked against a delta value. This is especially useful to circumvent problems with floating-point inaccuracy in machine-based computation.\n\nThis option is basically an alias for the following computation: `lte(abs(minus([x, y]), delta)`", "schema": { "type": [ "number", @@ -44,7 +44,7 @@ } ], "returns": { - "description": "Returns `true` if `x` is equal to `y`, `null` if any operand is `null`, otherwise `false`.", + "description": "`true` if `x` is equal to `y`, `null` if any operand is `null`, otherwise `false`.", "schema": { "type": [ "boolean", diff --git a/examples/array_contains_nodata.json b/examples/array_contains_nodata.json index 96c84999..3b1fe6f0 100644 --- a/examples/array_contains_nodata.json +++ b/examples/array_contains_nodata.json @@ -18,7 +18,7 @@ } ], "returns": { - "description": "Returns `true` if the list contains a no-data value, false` otherwise.", + "description": "`true` if the list contains a no-data value, false` otherwise.", "schema": { "type": "boolean" } @@ -31,11 +31,13 @@ "from_parameter": "data" }, "process": { - "process-graph": { + "process_graph": { "is_null": { "process_id": "is_nodata", "arguments": { - "from_parameter": "x" + "x": { + "from_parameter": "x" + } }, "result": true } diff --git a/examples/array_find_nodata.json b/examples/array_find_nodata.json index b2cd3f7c..b57fc35b 100644 --- a/examples/array_find_nodata.json +++ b/examples/array_find_nodata.json @@ -18,7 +18,7 @@ } ], "returns": { - "description": "Returns the index of the first element with a no-data value. If only data values are available, `null` is returned.", + "description": "The index of the first element with a no-data value. If only data values are available, `null` is returned.", "schema": [ { "type": "null" @@ -37,11 +37,13 @@ "from_parameter": "data" }, "process": { - "process-graph": { + "process_graph": { "is_null": { "process_id": "is_nodata", "arguments": { - "from_parameter": "x" + "x": { + "from_parameter": "x" + } }, "result": true } diff --git a/extrema.json b/extrema.json index d4a4c0d2..e2503f04 100644 --- a/extrema.json +++ b/extrema.json @@ -37,9 +37,7 @@ "minItems": 2, "maxItems": 2, "items": { - "type": [ - "number" - ] + "type": "number" } }, { @@ -47,9 +45,7 @@ "minItems": 2, "maxItems": 2, "items": { - "type": [ - "null" - ] + "type": "null" } } ] diff --git a/filter_bands.json b/filter_bands.json index 94a9f448..ee9c9aae 100644 --- a/filter_bands.json +++ b/filter_bands.json @@ -1,7 +1,7 @@ { "id": "filter_bands", - "summary": "Filter the bands by name", - "description": "Filters the bands in the data cube so that bands that don't match any of the criteria are dropped from the data cube. The data cube is expected to have only one dimension of type `bands`. Fails with a `DimensionMissing` error if no such dimension exists.\n\nThe following criteria can be used to select bands:\n\n* `bands`: band name or common band name (e.g. `B01`, `B8A`, `red` or `nir`)\n* `wavelengths`: ranges of wavelengths in micrometres (μm) (e.g. 0.5 - 0.6)\n\nAll these information are exposed in the band metadata of the collection. To keep algorithms interoperable it is recommended to prefer the common bands names or the wavelengths over collection and/or back-end specific band names.\n\nIf multiple criteria are specified, any of them must match and not all of them, i.e. they are combined with an OR-operation. If no criteria is specified, the `BandFilterParameterMissing` exception must be thrown.\n\n**Important:** The order of the specified array defines the order of the bands in the data cube, which can be important for subsequent processes. If multiple bands are matched by a single criterion (e.g. a range of wavelengths), they stay in the original order.", + "summary": "Filter the bands by names", + "description": "Filters the bands in the data cube so that bands that don't match any of the criteria are dropped from the data cube. The data cube is expected to have only one dimension of type `bands`. Fails with a `DimensionMissing` exception if no such dimension exists.\n\nThe following criteria can be used to select bands:\n\n* `bands`: band name or common band name (e.g. `B01`, `B8A`, `red` or `nir`)\n* `wavelengths`: ranges of wavelengths in micrometers (μm) (e.g. 0.5 - 0.6)\n\nAll these information are exposed in the band metadata of the collection. To keep algorithms interoperable it is recommended to prefer the common band names or the wavelengths over band names that are specific to the collection and/or back-end.\n\nIf multiple criteria are specified, any of them must match and not all of them, i.e. they are combined with an OR-operation. If no criteria are specified, the `BandFilterParameterMissing` exception must be thrown.\n\n**Important:** The order of the specified array defines the order of the bands in the data cube, which can be important for subsequent processes. If multiple bands are matched by a single criterion (e.g. a range of wavelengths), they stay in the original order.", "categories": [ "cubes", "filter" @@ -17,7 +17,7 @@ }, { "name": "bands", - "description": "A list of band names. Either the unique band name (metadata field `name` in bands) or one of the common band names (metadata field `common_name` in bands). If unique band name and common name conflict, the unique band name has higher priority.\n\nThe order of the specified array defines the order of the bands in the data cube. If multiple bands match a common name, all matched bands are included in the original order.", + "description": "A list of band names. Either the unique band name (metadata field `name` in bands) or one of the common band names (metadata field `common_name` in bands). If the unique band name and the common name conflict, the unique band name has a higher priority.\n\nThe order of the specified array defines the order of the bands in the data cube. If multiple bands match a common name, all matched bands are included in the original order.", "schema": { "type": "array", "items": { @@ -30,7 +30,7 @@ }, { "name": "wavelengths", - "description": "A list of sub-lists with each sub-list consisting of two elements. The first element is the minimum wavelength and the second element is the maximum wavelength. Wavelengths are specified in micrometres (μm).\n\nThe order of the specified array defines the order of the bands in the data cube. If multiple bands match the wavelengths, all matched bands are included in the original order.", + "description": "A list of sub-lists with each sub-list consisting of two elements. The first element is the minimum wavelength and the second element is the maximum wavelength. Wavelengths are specified in micrometers (μm).\n\nThe order of the specified array defines the order of the bands in the data cube. If multiple bands match the wavelengths, all matched bands are included in the original order.", "schema": { "type": "array", "items": { @@ -67,7 +67,7 @@ }, "exceptions": { "BandFilterParameterMissing": { - "message": "The process 'filter_bands' requires any of the parameters 'bands', 'common_names' or 'wavelengths' to be set." + "message": "The process `filter_bands` requires any of the parameters `bands`, `common_names` or `wavelengths` to be set." }, "DimensionMissing": { "message": "A band dimension is missing." @@ -78,6 +78,11 @@ "rel": "about", "href": "https://github.com/radiantearth/stac-spec/tree/master/extensions/eo#common-band-names", "title": "List of common band names as specified by the STAC specification" + }, + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#filter", + "rel": "about", + "title": "Filters explained in the openEO documentation" } ] } \ No newline at end of file diff --git a/filter_bbox.json b/filter_bbox.json index c1339111..8cc2103a 100644 --- a/filter_bbox.json +++ b/filter_bbox.json @@ -98,6 +98,11 @@ } }, "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#filter", + "rel": "about", + "title": "Filters explained in the openEO documentation" + }, { "rel": "about", "href": "https://proj.org/usage/projections.html", diff --git a/filter_spatial.json b/filter_spatial.json index 101469c5..b807b8df 100644 --- a/filter_spatial.json +++ b/filter_spatial.json @@ -32,6 +32,11 @@ } }, "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#filter", + "rel": "about", + "title": "Filters explained in the openEO documentation" + }, { "href": "http://www.opengeospatial.org/standards/sfa", "rel": "about", diff --git a/filter_temporal.json b/filter_temporal.json index dbb3f201..a94366a3 100644 --- a/filter_temporal.json +++ b/filter_temporal.json @@ -1,7 +1,7 @@ { "id": "filter_temporal", "summary": "Temporal filter for a temporal intervals", - "description": "Limits the data cube to the specified interval of dates and/or times.\n\nMore precisely, the filter checks whether the temporal dimension label is greater than or equal to the lower boundary (start date/time) and the temporal dimension label is less than the value of the upper boundary (end date/time). This corresponds to a left-closed interval, which contains the lower boundary but not the upper boundary.\n\nIf the dimension is set to `null` (it's the default value), the data cube is expected to only have one temporal dimension.", + "description": "Limits the data cube to the specified interval of dates and/or times.\n\nMore precisely, the filter checks whether each of the temporal dimension labels is greater than or equal to the lower boundary (start date/time) and less than the value of the upper boundary (end date/time). This corresponds to a left-closed interval, which contains the lower boundary but not the upper boundary.", "categories": [ "cubes", "filter" @@ -17,7 +17,7 @@ }, { "name": "extent", - "description": "Left-closed temporal interval, i.e. an array with exactly two elements:\n\n1. The first element is the start of the temporal interval. The specified instance in time is **included** in the interval.\n2. The second element is the end of the temporal interval. The specified instance in time is **excluded** from the interval.\n\nThe specified temporal strings follow [RFC 3339](https://tools.ietf.org/html/rfc3339). Also supports open intervals by setting one of the boundaries to `null`, but never both.", + "description": "Left-closed temporal interval, i.e. an array with exactly two elements:\n\n1. The first element is the start of the temporal interval. The specified instance in time is **included** in the interval.\n2. The second element is the end of the temporal interval. The specified instance in time is **excluded** from the interval.\n\nThe specified temporal strings follow [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html). Also supports open intervals by setting one of the boundaries to `null`, but never both.", "schema": { "type": "array", "subtype": "temporal-interval", @@ -61,7 +61,7 @@ }, { "name": "dimension", - "description": "The name of the temporal dimension to filter on. If the dimension is not set or is set to `null`, the filter applies to all temporal dimensions. Fails with a `DimensionNotAvailable` error if the specified dimension does not exist.", + "description": "The name of the temporal dimension to filter on. If no specific dimension is specified or it is set to `null`, the filter applies to all temporal dimensions. Fails with a `DimensionNotAvailable` exception if the specified dimension does not exist.", "schema": { "type": [ "string", @@ -73,7 +73,7 @@ } ], "returns": { - "description": "A data cube restricted to the specified temporal extent. The dimensions and dimension properties (name, type, labels, reference system and resolution) remain unchanged, except that the given temporal dimension(s) have less (or the same) dimension labels.", + "description": "A data cube restricted to the specified temporal extent. The dimensions and dimension properties (name, type, labels, reference system and resolution) remain unchanged, except that the temporal dimensions (determined by `dimensions` parameter) may have less dimension labels.", "schema": { "type": "object", "subtype": "raster-cube" @@ -83,5 +83,12 @@ "DimensionNotAvailable": { "message": "A dimension with the specified name does not exist." } - } -} \ No newline at end of file + }, + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#filter", + "rel": "about", + "title": "Filters explained in the openEO documentation" + } + ] +} diff --git a/is_nan.json b/is_nan.json index 37d64157..91f4bcf9 100644 --- a/is_nan.json +++ b/is_nan.json @@ -1,9 +1,10 @@ { "id": "is_nan", "summary": "Value is not a number", - "description": "Checks whether the specified value `x` is not a number (often abbreviated as `NaN`). The definition of `NaN` follows the [IEEE Standard 754](https://ieeexplore.ieee.org/document/4610935). All non-numeric data types MUST also return `true`.", + "description": "Checks whether the specified value `x` is not a number. Returns `true` for numeric values (integers and floating-point numbers), except for the special value `NaN` as defined by the [IEEE Standard 754](https://ieeexplore.ieee.org/document/4610935). All non-numeric data types MUST also return `true`, including arrays that contain `NaN` values.", "categories": [ - "comparison" + "comparison", + "math > constants" ], "parameters": [ { @@ -15,7 +16,7 @@ } ], "returns": { - "description": "`true` if the data is not a number, otherwise `false`", + "description": "`true` if the data is not a number, otherwise `false`.", "schema": { "type": "boolean" } @@ -32,6 +33,12 @@ "x": "Test" }, "returns": true + }, + { + "arguments": { + "x": null + }, + "returns": true } ], "links": [ @@ -39,6 +46,11 @@ "rel": "about", "href": "https://ieeexplore.ieee.org/document/4610935", "title": "IEEE Standard 754-2008 for Floating-Point Arithmetic" + }, + { + "rel": "about", + "href": "http://mathworld.wolfram.com/NaN.html", + "title": "NaN explained by Wolfram MathWorld" } ] -} \ No newline at end of file +} diff --git a/is_nodata.json b/is_nodata.json index f2ab4d5e..0b8b38d3 100644 --- a/is_nodata.json +++ b/is_nodata.json @@ -1,7 +1,7 @@ { "id": "is_nodata", "summary": "Value is not a no-data value", - "description": "Checks whether the specified data is a missing data, i.e. equals to any of the no-data values / `null`.", + "description": "Checks whether the specified data is a missing data, i.e. equals to `null` or any of the no-data values specified in the metadata. The special numerical value `NaN` (not a number) as defined by the [IEEE Standard 754](https://ieeexplore.ieee.org/document/4610935) is not considered no-data and must return `false`.", "categories": [ "comparison" ], @@ -15,7 +15,7 @@ } ], "returns": { - "description": "`true` if the data is a no-data value, otherwise `false`", + "description": "`true` if the data is a no-data value, otherwise `false`.", "schema": { "type": "boolean" } @@ -38,6 +38,15 @@ "x": null }, "returns": true + }, + { + "arguments": { + "x": [ + null, + null + ] + }, + "returns": false } ] -} \ No newline at end of file +} diff --git a/is_valid.json b/is_valid.json index 84f67ce8..51924de4 100644 --- a/is_valid.json +++ b/is_valid.json @@ -1,7 +1,7 @@ { "id": "is_valid", "summary": "Value is valid data", - "description": "Checks whether the specified value `x` is valid. A value is considered valid if it is\n\n1. not a no-data value (`null`) and\n2. a finite number (only if `x` is a number). The definition of finite and infinite numbers follows the [IEEE Standard 754](https://ieeexplore.ieee.org/document/4610935).", + "description": "Checks whether the specified value `x` is valid. The following values are considered valid:\n\n* Any finite numerical value (integers and floating-point numbers). The definition of finite numbers follows the [IEEE Standard 754](https://ieeexplore.ieee.org/document/4610935) and excludes the special value `NaN` (not a number).\n* Any other value that is not a no-data value according to ``is_nodata()`. Thus all arrays, objects and strings are valid, regardless of their content.", "categories": [ "comparison" ], @@ -38,6 +38,15 @@ "x": null }, "returns": false + }, + { + "arguments": { + "x": [ + null, + null + ] + }, + "returns": true } ], "links": [ diff --git a/linear_scale_range.json b/linear_scale_range.json index c29978fe..172027c9 100644 --- a/linear_scale_range.json +++ b/linear_scale_range.json @@ -1,7 +1,7 @@ { "id": "linear_scale_range", "summary": "Linear transformation between two ranges", - "description": "Performs a linear transformation between the input and output range.\n\nThe given number in `x` is clipped to the bounds specified in `inputMin` and `inputMax` so that the underlying formula *((x - inputMin) / (inputMax - inputMin)) * (outputMax - outputMin) + outputMin* never returns any value lower than `outputMin` or greater than `outputMax`.\n\nPotential use case include\n\n* scaling values to the 8-bit range (0 - 255) often used for numeric representation of values in one of the channels of the [RGB colour model](https://en.wikipedia.org/wiki/RGB_color_model#Numeric_representations) or\n* calculating percentages (0 - 100).\n\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Performs a linear transformation between the input and output range.\n\nThe given number in `x` is clipped to the bounds specified in `inputMin` and `inputMax` so that the underlying formula *`((x - inputMin) / (inputMax - inputMin)) * (outputMax - outputMin) + outputMin`* never returns any value lower than `outputMin` or greater than `outputMax`.\n\nPotential use case include\n\n* scaling values to the 8-bit range (0 - 255) often used for numeric representation of values in one of the channels of the [RGB colour model](https://en.wikipedia.org/wiki/RGB_color_model#Numeric_representations) or\n* calculating percentages (0 - 100).\n\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math" ], diff --git a/ln.json b/ln.json index 0b9fa6c3..e073c7a2 100644 --- a/ln.json +++ b/ln.json @@ -1,7 +1,7 @@ { "id": "ln", "summary": "Natural logarithm", - "description": "The natural logarithm is the logarithm to the base *e* of the number `x`, which equals to using the *log* process with the base set to *e*. The natural logarithm is the inverse function of taking *e* to the power x.\n\nThe no-data value `null` is passed through.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it. Therefore, `ln(0)` results in ±infinity if the processing environment supports it or otherwise an error is thrown.", + "description": "The natural logarithm is the logarithm to the base *e* of the number `x`, which equals to using the *log* process with the base set to *e*. The natural logarithm is the inverse function of taking *e* to the power x.\n\nThe no-data value `null` is passed through.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it. Therefore, *`ln(0)`* results in ±infinity if the processing environment supports it or otherwise an exception is thrown.", "categories": [ "math > exponential & logarithmic" ], diff --git a/load_collection.json b/load_collection.json index b76ca004..6a0a080b 100644 --- a/load_collection.json +++ b/load_collection.json @@ -1,7 +1,7 @@ { "id": "load_collection", "summary": "Load a collection", - "description": "Loads a collection from the current back-end by its id and returns it as processable data cube. The data that is added to the data cube can be restricted with the additional `spatial_extent`, `temporal_extent`, `bands` and `properties`.\n\n**Remarks:**\n\n* The bands (and all dimensions that specify nominal dimension labels) are expected to be ordered as specified in the metadata if the `bands` parameter is set to `null`.\n* If no additional parameter is specified this would imply that the whole data set is expected to be loaded. Due to the large size of many data sets this is not recommended and may be optimized by back-ends to only load the data that is actually required after evaluating subsequent processes such as filters. This means that the pixel values should be processed only after the data has been limited to the required extents and as a consequence also to a manageable size.", + "description": "Loads a collection from the current back-end by its id and returns it as a processable data cube. The data that is added to the data cube can be restricted with the additional `spatial_extent`, `temporal_extent`, `bands` and `properties`.\n\n**Remarks:**\n\n* The bands (and all dimensions that specify nominal dimension labels) are expected to be ordered as specified in the metadata if the `bands` parameter is set to `null`.\n* If no additional parameter is specified this would imply that the whole data set is expected to be loaded. Due to the large size of many data sets, this is not recommended and may be optimized by back-ends to only load the data that is actually required after evaluating subsequent processes such as filters. This means that the pixel values should be processed only after the data has been limited to the required extent and as a consequence also to a manageable size.", "categories": [ "cubes", "import" @@ -18,7 +18,7 @@ }, { "name": "spatial_extent", - "description": "Limits the data to load from the collection to the specified bounding box or polygons.\n\nThe process puts a pixel into the data cube if the point at the pixel center intersects with the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC).\n\nThe GeoJSON can be one of the following GeoJSON types:\n\n* A `Polygon` geometry,\n* a `GeometryCollection` containing Polygons,\n* a `Feature` with a `Polygon` geometry or\n* a `FeatureCollection` containing `Feature`s with a `Polygon` geometry.\n\nSet this parameter to `null` to set no limit for the spatial extent. Be careful with this when loading large datasets!", + "description": "Limits the data to load from the collection to the specified bounding box or polygons.\n\nThe process puts a pixel into the data cube if the point at the pixel center intersects with the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC).\n\nThe GeoJSON can be one of the following feature types:\n\n* A `Polygon` or `MultiPolygon` geometry,\n* a `Feature` with a `Polygon` or `MultiPolygon` geometry,\n* a `FeatureCollection` containing at least one `Feature` with `Polygon` or `MultiPolygon` geometries, or\n* a `GeometryCollection` containing `Polygon` or `MultiPolygon` geometries. To maximize interoperability, `GeometryCollection` should be avoided in favour of one of the alternatives above.\n\nSet this parameter to `null` to set no limit for the spatial extent. Be careful with this when loading large datasets! It is recommended to use this parameter instead of using ``filter_bbox()`` or ``filter_spatial()`` directly after loading unbounded data.", "schema": [ { "title": "Bounding Box", @@ -93,6 +93,7 @@ }, { "title": "GeoJSON", + "description": "Limits the data cube to the bounding box of the given geometry. All pixels inside the bounding box that do not intersect with any of the polygons will be set to no data (`null`).", "type": "object", "subtype": "geojson" }, @@ -105,7 +106,7 @@ }, { "name": "temporal_extent", - "description": "Limits the data to load from the collection to the specified left-closed temporal interval. Applies to all temporal dimensions. The interval has to be specified as an array with exactly two elements:\n\n1. The first element is the start of the temporal interval. The specified instance in time is **included** in the interval.\n2. The second element is the end of the temporal interval. The specified instance in time is **excluded** from the interval.\n\nThe specified temporal strings follow [RFC 3339](https://tools.ietf.org/html/rfc3339). Also supports open intervals by setting one of the boundaries to `null`, but never both.\n\nSet this parameter to `null` to set no limit for the spatial extent. Be careful with this when loading large datasets!", + "description": "Limits the data to load from the collection to the specified left-closed temporal interval. Applies to all temporal dimensions. The interval has to be specified as an array with exactly two elements:\n\n1. The first element is the start of the temporal interval. The specified instance in time is **included** in the interval.\n2. The second element is the end of the temporal interval. The specified instance in time is **excluded** from the interval.\n\nThe specified temporal strings follow [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html). Also supports open intervals by setting one of the boundaries to `null`, but never both.\n\nSet this parameter to `null` to set no limit for the temporal extent. Be careful with this when loading large datasets! It is recommended to use this parameter instead of using ``filter_temporal()`` directly after loading unbounded data.", "schema": [ { "type": "array", @@ -156,7 +157,7 @@ }, { "name": "bands", - "description": "Only adds the specified bands into the data cube so that bands that don't match the list of band names are not available. Applies to all dimensions of type `bands`.\n\nEither the unique band name (metadata field `name` in bands) or one of the common band names (metadata field `common_name` in bands) can be specified. If unique band name and common name conflict, the unique band name has higher priority.\n\nThe order of the specified array defines the order of the bands in the data cube. f multiple bands match a common name, all matched bands are included in the original order.", + "description": "Only adds the specified bands into the data cube so that bands that don't match the list of band names are not available. Applies to all dimensions of type `bands`.\n\nEither the unique band name (metadata field `name` in bands) or one of the common band names (metadata field `common_name` in bands) can be specified. If the unique band name and the common name conflict, the unique band name has a higher priority.\n\nThe order of the specified array defines the order of the bands in the data cube. If multiple bands match a common name, all matched bands are included in the original order.\n\nIt is recommended to use this parameter instead of using ``filter_bands()`` directly after loading unbounded data.", "schema": [ { "type": "array", @@ -194,7 +195,13 @@ "description": "Any data type." } } - ] + ], + "returns": { + "description": "`true` if the data should be loaded into the data cube, otherwise `false`.", + "schema": { + "type": "boolean" + } + } } }, { @@ -265,6 +272,11 @@ } ], "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html", + "rel": "about", + "title": "Data Cubes explained in the openEO documentation" + }, { "rel": "about", "href": "https://proj.org/usage/projections.html", diff --git a/log.json b/log.json index e964961d..89500837 100644 --- a/log.json +++ b/log.json @@ -1,7 +1,7 @@ { "id": "log", "summary": "Logarithm to a base", - "description": "Logarithm to the base `base` of the number `x` is defined to be the inverse function of taking b to the power of x.\n\nThe no-data value `null` is passed through and therefore gets propagated if any of the arguments is `null`.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it. Therefore, `log(0, 2)` results in ±infinity if the processing environment supports it or otherwise an error is thrown.", + "description": "Logarithm to the base `base` of the number `x` is defined to be the inverse function of taking b to the power of x.\n\nThe no-data value `null` is passed through and therefore gets propagated if any of the arguments is `null`.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it. Therefore, `log(0, 2)` results in ±infinity if the processing environment supports it or otherwise an exception is thrown.", "categories": [ "math > exponential & logarithmic" ], diff --git a/mask.json b/mask.json index 95da2b66..d7b591e1 100644 --- a/mask.json +++ b/mask.json @@ -1,8 +1,9 @@ { "id": "mask", "summary": "Apply a raster mask", - "description": "Applies a mask to a raster data cube. To apply a vector mask use ``mask_polygon()``.\n\nA mask is a raster data cube for which corresponding pixels among `data` and `mask` are compared and those pixels in `data` are replaced whose pixels in `mask` are non-zero (for numbers) or `true` (for boolean values). The pixel values are replaced with the value specified for `replacement`, which defaults to `null` (no data).\n\nThe data cubes have to be compatible so that each dimension in mask must also be available in the raster data cube with the same name, type, reference system, resolution and labels. Dimensions can be missing in the mask with the result that the mask is applied for each label of the missing dimension in the data cube. The process fails if there's an incompatibility found between the raster data cube and the mask.", + "description": "Applies a mask to a raster data cube. To apply a vector mask use ``mask_polygon()``.\n\nA mask is a raster data cube for which corresponding pixels among `data` and `mask` are compared and those pixels in `data` are replaced whose pixels in `mask` are non-zero (for numbers) or `true` (for boolean values). The pixel values are replaced with the value specified for `replacement`, which defaults to `null` (no data).\n\nThe data cubes have to be compatible so that each dimension in the mask must also be available in the raster data cube with the same name, type, reference system, resolution and labels. Dimensions can be missing in the mask with the result that the mask is applied for each label of the missing dimension in the data cube. The process fails if there's an incompatibility found between the raster data cube and the mask.", "categories": [ + "cubes", "masks" ], "parameters": [ @@ -16,7 +17,7 @@ }, { "name": "mask", - "description": "A mask as raster data cube. Every pixel in `data` must have a corresponding element in `mask`.", + "description": "A mask as a raster data cube. Every pixel in `data` must have a corresponding element in `mask`.", "schema": { "type": "object", "subtype": "raster-cube" diff --git a/mask_polygon.json b/mask_polygon.json index adf15e61..c1f59d4e 100644 --- a/mask_polygon.json +++ b/mask_polygon.json @@ -1,7 +1,7 @@ { "id": "mask_polygon", "summary": "Apply a polygon mask", - "description": "Applies a polygon mask to a raster data cube. To apply a raster mask use ``mask()``.\n\nAll pixels for which the point at the pixel center **does not** intersect with any polygon (as defined in the Simple Features standard by the OGC) are replaced. This behaviour can be inverted by setting the parameter `inside` to `true`.\n\nThe pixel values are replaced with the value specified for `replacement`, which defaults to `null` (no data). No data values in `data` will be left untouched by the masking operation.", + "description": "Applies a (multi) polygon mask to a raster data cube. To apply a raster mask use ``mask()``.\n\nAll pixels for which the point at the pixel center **does not** intersect with any polygon (as defined in the Simple Features standard by the OGC) are replaced. This behavior can be inverted by setting the parameter `inside` to `true`.\n\nThe pixel values are replaced with the value specified for `replacement`, which defaults to `null` (no data). No data values in `data` will be left untouched by the masking operation.", "categories": [ "cubes", "masks" @@ -17,7 +17,7 @@ }, { "name": "mask", - "description": "A GeoJSON object containing a polygon. The provided feature types can be one of the following:\n\n* A `Polygon` geometry,\n* a `GeometryCollection` containing Polygons,\n* a `Feature` with a `Polygon` geometry or\n* a `FeatureCollection` containing `Feature`s with a `Polygon` geometry.", + "description": "A GeoJSON object containing at least one polygon. The provided feature types can be one of the following:\n\n* A `Polygon` or `MultiPolygon` geometry,\n* a `Feature` with a `Polygon` or `MultiPolygon` geometry,\n* a `FeatureCollection` containing at least one `Feature` with `Polygon` or `MultiPolygon` geometries, or\n* a `GeometryCollection` containing `Polygon` or `MultiPolygon` geometries. To maximize interoperability, `GeometryCollection` should be avoided in favour of one of the alternatives above.", "schema": { "type": "object", "subtype": "geojson" @@ -26,14 +26,20 @@ { "name": "replacement", "description": "The value used to replace masked values with.", - "schema": { - "type": [ - "number", - "boolean", - "string", - "null" - ] - }, + "schema": [ + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], "default": null, "optional": true }, diff --git a/max.json b/max.json index 71a13b61..5a5b7f71 100644 --- a/max.json +++ b/max.json @@ -1,7 +1,7 @@ { "id": "max", "summary": "Maximum value", - "description": "Computes the largest value of an array of numbers, which is is equal to the first element of a sorted (i.e., ordered) version the array.\n\nAn array without non-`null` elements resolves always with `null`.", + "description": "Computes the largest value of an array of numbers, which is equal to the first element of a sorted (i.e., ordered) version of the array.\n\nAn array without non-`null` elements resolves always with `null`.", "categories": [ "math", "reducer" diff --git a/median.json b/median.json index 2d5e49c1..3bc87d5a 100644 --- a/median.json +++ b/median.json @@ -1,7 +1,7 @@ { "id": "median", "summary": "Statistical median", - "description": "The statistical median of an array of numbers is the value separating the higher half from the lower half of the data.\n\nAn array without non-`null` elements resolves always with `null`.\n\n**Remarks:**\n\n* For a symmetric arrays, the result is equal to the ``mean()``.\n* The median can also be calculated by computing the ``quantiles()`` with a probability of *0.5*.", + "description": "The statistical median of an array of numbers is the value separating the higher half from the lower half of the data.\n\nAn array without non-`null` elements resolves always with `null`.\n\n**Remarks:**\n\n* For symmetric arrays, the result is equal to the ``mean()``.\n* The median can also be calculated by computing the ``quantiles()`` with a probability of *0.5*.", "categories": [ "math", "reducer" diff --git a/merge_cubes.json b/merge_cubes.json index 7aee9a3c..28b4803b 100644 --- a/merge_cubes.json +++ b/merge_cubes.json @@ -1,7 +1,7 @@ { "id": "merge_cubes", - "summary": "Merging two data cubes", - "description": "The data cubes have to be compatible. A merge operation without overlap should be reversible with (a set of) filter operations for each of the two cubes. The process performs the join on overlapping dimensions, with the same name and type.\n\nAn overlapping dimension has the same name, type, reference system and resolution in both dimensions, but can have different labels. One of the dimensions can have different labels, for all other dimensions the labels must be equal. If data overlaps, the parameter `overlap_resolver` must be specified to resolve the overlap.\n\n**Examples for merging two data cubes:**\n\n1. Data cubes with the dimensions `x`, `y`, `t` and `bands` have the same dimension labels in `x`,`y` and `t`, but the labels for the dimension `bands` are `B1` and `B2` for the first cube and `B3` and `B4`. An overlap resolver is *not needed*. The merged data cube has the dimensions `x`, `y`, `t` and `bands` and the dimension `bands` has four dimension labels: `B1`, `B2`, `B3`, `B4`.\n2. Data cubes with the dimensions `x`, `y`, `t` and `bands` have the same dimension labels in `x`,`y` and `t`, but the labels for the dimension `bands` are `B1` and `B2` for the first data cube and `B2` and `B3` for the second. An overlap resolver is *required* to resolve overlap in band `B2`. The merged data cube has the dimensions `x`, `y`, `t` and `bands` and the dimension `bands` has three dimension labels: `B1`, `B2`, `B3`.\n3. Data cubes with the dimensions `x`, `y` and `t` have the same dimension labels in `x`,`y` and `t`. There are two options:\n 1. Keep the overlapping values separately in the merged data cube: An overlap resolver is *not needed*, but for each data cube you need to add a new dimension using ``add_dimension()``. The new dimensions must be equal, except that the labels for the new dimensions must differ by name. The merged data cube has the same dimensions and labels as the original data cubes, plus the dimension added with ``add_dimension()``, which has the two dimension labels after the merge.\n 2. Combine the overlapping values into a single value: An overlap resolver is *required* to resolve the overlap for all pixels. The merged data cube has the same dimensions and labels as the original data cubes, but all pixel values have been processed by the overlap resolver.\n4. Merging a data cube with dimensions `x`, `y`, `t` with another cube with dimensions `x`, `y` will join on the `x`, `y` dimension, so the lower dimension cube is merged with each time step in the higher dimensional cube. This can for instance be used to apply a digital elevation model to a spatiotemporal data cube.", + "summary": "Merge two data cubes", + "description": "The data cubes have to be compatible. A merge operation without overlap should be reversible with (a set of) filter operations for each of the two cubes. The process performs the join on overlapping dimensions, with the same name and type.\n\nAn overlapping dimension has the same name, type, reference system and resolution in both dimensions, but can have different labels. One of the dimensions can have different labels, for all other dimensions the labels must be equal. If data overlaps, the parameter `overlap_resolver` must be specified to resolve the overlap.\n\n**Examples for merging two data cubes:**\n\n1. Data cubes with the dimensions (`x`, `y`, `t`, `bands`) have the same dimension labels in `x`, `y` and `t`, but the labels for the dimension `bands` are `B1` and `B2` for the first cube and `B3` and `B4`. An overlap resolver is *not needed*. The merged data cube has the dimensions `x`, `y`, `t` and `bands` and the dimension `bands` has four dimension labels: `B1`, `B2`, `B3`, `B4`.\n2. Data cubes with the dimensions (`x`, `y`, `t`, `bands`) have the same dimension labels in `x`, `y` and `t`, but the labels for the dimension `bands` are `B1` and `B2` for the first data cube and `B2` and `B3` for the second. An overlap resolver is *required* to resolve overlap in band `B2`. The merged data cube has the dimensions `x`, `y`, `t` and `bands` and the dimension `bands` has three dimension labels: `B1`, `B2`, `B3`.\n3. Data cubes with the dimensions (`x`, `y`, `t`) have the same dimension labels in `x`, `y` and `t`. There are two options:\n 1. Keep the overlapping values separately in the merged data cube: An overlap resolver is *not needed*, but for each data cube you need to add a new dimension using ``add_dimension()``. The new dimensions must be equal, except that the labels for the new dimensions must differ by name. The merged data cube has the same dimensions and labels as the original data cubes, plus the dimension added with ``add_dimension()``, which has the two dimension labels after the merge.\n 2. Combine the overlapping values into a single value: An overlap resolver is *required* to resolve the overlap for all pixels. The merged data cube has the same dimensions and labels as the original data cubes, but all pixel values have been processed by the overlap resolver.\n4. A data cube with dimensions (`x`, `y`, `t` / `bands`) or (`x`, `y`, `t`, `bands`) and another data cube with dimensions (`x`, `y`) have the same dimension labels in `x` and `y`. Merging them will join dimensions `x` and `y`, so the lower dimension cube is merged with each time step and band available in the higher dimensional cube. This can for instance be used to apply a digital elevation model to a spatio-temporal data cube. An overlap resolver is *required* to resolve the overlap for all pixels.\n\nAfter the merge, the dimensions with a natural/inherent label order (with a reference system this is each spatial and temporal dimensions) still have all dimension labels sorted. For other dimensions where there is no inherent order, including bands, the dimension labels keep the order in which they are present in the original data cubes and the dimension labels of `cube2` are appended to the dimension labels of `cube1`.", "categories": [ "cubes" ], @@ -31,14 +31,14 @@ "parameters": [ { "name": "x", - "description": "The first value.", + "description": "The overlapping value from the first data cube `cube1`.", "schema": { "description": "Any data type." } }, { "name": "y", - "description": "The second value.", + "description": "The overlapping value from the second data cube `cube2`.", "schema": { "description": "Any data type." } @@ -52,7 +52,13 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "The value to be set in the merged data cube.", + "schema": { + "description": "Any data type." + } + } }, "default": null, "optional": true diff --git a/meta/implementation.md b/meta/implementation.md new file mode 100644 index 00000000..af8ac782 --- /dev/null +++ b/meta/implementation.md @@ -0,0 +1,143 @@ +# Implementation Guide for back-ends + +This file is meant to provide some additional implementation details for back-ends. + +## Optimizations for conditions (e.g. `if`) + +None of the openEO processes per se is "special" and thus all are treated the same way by default. +Nevertheless, there are some cases where a special treatment can make a huge difference. + +### Branching behavior + +The `if` process (and any process that is working on some kind of condition) are usually +special control structures and not normal functions. Those conditionals usually decide between +one outcome or the other. Evaluating them in a naive way would compute both outcomes and depending +on the condition use one outcome and discard the other. +This can and should be optimized by "lazily" only computing the outcome that is actually used. +This could have a huge impact on performance as some computation doesn't need to be executed at all. + +openEO doesn't require special handling for the `if` process, but it is **strongly recommended** +that back-ends treat them special and only compute the outcome that is actually needed. +In the end, this is faster and cheaper for the user and thus users may prefer back-ends +that offer this optimization. Fortunately, both ways still lead to the same results +and comparability and reproducibility of the results is still given. + +### Short-circuit evaluation + +Similarly, back-ends **should** ["short-circuit"](https://en.wikipedia.org/wiki/Short-circuit_evaluation) +the evaluation of conditions that use processes processes such as `and`, `or` or `xor`, +which means that once a condition has reached an unambiguous result +the evaluation should stop and provide the result directly. +This is basically the same behavior that is also described in the processes `all` and `any`. + +For example, the condition `A > 0 or B > 0` should only execute `B > 0` if `A > 0` is false as +otherwise the result is already unambiguous and will be `true` regardless of the rest of the +condition. + +Implementing this behavior does not have any negative side-effects so that +comparability and reproducibility of the results is still given. + +## Enums for processing methods + +There are numerours processes that provide a predefined set of processing methods. +For example: +- `ard_surface_reflectance`: `atmospheric_correction_method` and `cloud_detection_method` +- `athmospheric_correction`: `method` +- `cloud_detection`: `method` +- `resample_cube_spatial`: `method` +- `resample_spatial`: `method` + +Those methods are meant to provide a common naming for well-known processing methods. +Back-ends should check which methods they can implement and remove all the methods +they can't implement. Similarly, you can add new methods. We'd likely ask you to +open [a new issue](https://github.com/Open-EO/openeo-processes/issues) and provide +us your additions so that we can align implementations and eventually update the +process specifications with all methods out there. Thanks in advance! + +Also make sure to update the textual descriptions accordingly. + +This applies similarly to other enums specied in parameter schemas, e.g. the +`period` parameter in `aggregate_temporal_period`. + +## Proprietary options in `ard_surface_reflectance`, `athmospheric_correction` and `cloud_detection` + +The processes mentioned above have all at least one parameter for proprietary +options that can be passed to the corresponsing `methods`: +- `ard_surface_reflectance`: `atmospheric_correction_options` and `cloud_detection_options` +- `athmospheric_correction`: `options` +- `cloud_detection`: `options` + +By default, the parameters don't allow any value except an empty opject. +Back-ends have to either remove the parameter or define schema to give user +details about the supported parameters per supported method. + +For example, if you support the methods `iCor` and `FORCE` in `atmospheric_correction`, +you may define something like the following for the parameter: + +```json +{ + "description": "Proprietary options for the atmospheric correction method.", + "name": "options", + "optional": true, + "default": {}, + "schema": [ + { + "title": "FORCE options", + "type": "object", + "properties": { + "force_option1": { + "type": "number", + "description": "Description for option 1", + "default": 0 + }, + "force_option2": { + "type": "boolean", + "description": "Description for option 1", + "default": true + } + } + }, + { + "title": "iCor options", + "type": "object", + "properties": { + "icor_option1": { + "type": "string", + "description": "Description for option 1", + "default": "example" + } + } + } + + ] +} +``` + +Default values should be specified for each of the additional options given in `properties`. +The top-level default value should always be an empty object `{}`. The default values for the empty object will be provided by the schema. +None of the additional options should be required for better interoperability. + +## Date and Time manipulation + +Working with dates is a lot more complex than it seems to be at first sight. Issues arise especially with daylight saving times (DST), time zones, leap years and leap seconds. + +The date/time functions in openEO don't have any effect on time zones right now as only dates and times in UTC (with potential numerical time zone modifier) are supported. + +Month overflows, including the specific case of leap years, are implemented in a way that computations handle them gracefully. For example: + +- If you add a month to January, 31th, it will result in February 29th (leap year) or 28th (other years). This means for invalid dates due to month overflow we round down (or "snap") to the last valid date of the month. +- If you add a month to February, 29th, it will result in March, 29. So the "snap" behavior doesn't work the other way round. + +Leap seconds are basically ignored in manipulations as they don't follow a regular pattern. So leap seconds may be passed into the processes, but will never be returned by date manipulation processes in openEO. See the examples for the leap second `2016-12-31T23:59:60Z`: + +- If you add a minute to `2016-12-31T23:59:60Z`, it will result in `2017-01-01T00:00:59Z`. This means for invalid times we round down (or "snap") to the next valid time. +- If you add a seconds to `2016-12-31T23:59:59Z`, it will result in `2017-01-01T00:00:00Z`. + +### Language support + +To make `date_shift` easier to implement, we have found some libraries that follow this specification and can be used for implementations: + +- Java: [java.time](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) +- JavaScript: [Moment.js](https://momentjs.com/) +- Python: [dateutil](https://dateutil.readthedocs.io/en/stable/index.html) +- R: [lubridate](https://lubridate.tidyverse.org/) ([Cheatsheet](https://rawgit.com/rstudio/cheatsheets/master/lubridate.pdf)) diff --git a/meta/subtype-schemas.json b/meta/subtype-schemas.json index 8f6bcccb..fbbdb867 100644 --- a/meta/subtype-schemas.json +++ b/meta/subtype-schemas.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "http://processes.openeo.org/1.0.0/meta/subtype-schemas.json", + "$id": "http://processes.openeo.org/1.1.0/meta/subtype-schemas.json", "title": "Subtype Schemas", "description": "This file defines the schemas for subtypes we define for openEO processes.", "definitions": { @@ -8,7 +8,7 @@ "type": "string", "subtype": "band-name", "title": "Band Name", - "description": "Either a unique band name (metadata field `name`) or a [common band name](https://github.com/radiantearth/stac-spec/tree/v0.9.0/extensions/eo#common-band-names) (metadata field `common_name`) available in the data cube. If unique band name and common name conflict, the unique band name has higher priority." + "description": "Either a unique band name (metadata field `name`) or a [common band name](https://github.com/radiantearth/stac-spec/tree/v0.9.0/extensions/eo#common-band-names) (metadata field `common_name`) available in the data cube. If the unique band name and the common name conflict, the unique band name has a higher priority." }, "bounding-box": { "type": "object", @@ -84,7 +84,7 @@ }, "value": { "default": null, - "oneOf": [ + "anyOf": [ { "type": "null" }, @@ -115,14 +115,14 @@ "subtype": "date", "format": "date", "title": "Date only", - "description": "Date only representation, as defined for `full-date` by [RFC 3339 in section 5.6](https://tools.ietf.org/html/rfc3339#section-5.6). The time zone is UTC." + "description": "Date only representation, as defined for `full-date` by [RFC 3339 in section 5.6](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6). The time zone is UTC." }, "date-time": { "type": "string", "subtype": "date-time", "format": "date-time", "title": "Date with Time", - "description": "Date and time representation, as defined for `date-time` by [RFC 3339 in section 5.6](https://tools.ietf.org/html/rfc3339#section-5.6)." + "description": "Date and time representation, as defined for `date-time` by [RFC 3339 in section 5.6](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6)." }, "duration": { "type": "string", @@ -143,6 +143,7 @@ "file-path": { "type": "string", "subtype": "file-path", + "pattern": "^[^\r\n\\:'\"]+$", "title": "Single File path", "description": "A relative path to a user-uploaded file. Folders can't be specified." }, @@ -159,7 +160,7 @@ "type": "object", "subtype": "geojson", "title": "GeoJSON", - "description": "GeoJSON as defined by [RFC 7946](https://tools.ietf.org/html/rfc7946).", + "description": "GeoJSON as defined by [RFC 7946](https://www.rfc-editor.org/rfc/rfc7946.html).", "allOf": [ { "$ref": "https://geojson.org/schema/GeoJSON.json" @@ -222,7 +223,13 @@ "description": "Any data type." } } - ] + ], + "returns": { + "description": "`true` if the data should be used, otherwise `false`.", + "schema": { + "type": "boolean" + } + } } }, "output-format": { @@ -280,7 +287,7 @@ "type": "array", "subtype": "temporal-interval", "title": "Single temporal interval", - "description": "Left-closed temporal interval, represented as two-element array with the following elements:\n\n1. The first element is the start of the temporal interval. The specified instance in time is **included** in the interval.\n2. The second element is the end of the temporal interval. The specified instance in time is **excluded** from the interval.\n\nThe specified temporal strings follow [RFC 3339](https://tools.ietf.org/html/rfc3339). Although [RFC 3339 prohibits the hour to be '24'](https://tools.ietf.org/html/rfc3339#section-5.7), **this process allows the value '24' for the hour** of an end time in order to make it possible that left-closed time intervals can fully cover the day. `null` can be used to specify open intervals.", + "description": "Left-closed temporal interval, represented as two-element array with the following elements:\n\n1. The first element is the start of the temporal interval. The specified instance in time is **included** in the interval.\n2. The second element is the end of the temporal interval. The specified instance in time is **excluded** from the interval.\n\nThe specified temporal strings follow [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html). Although [RFC 3339 prohibits the hour to be '24'](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.7), **this process allows the value '24' for the hour** of an end time in order to make it possible that left-closed time intervals can fully cover the day. `null` can be used to specify open intervals.", "minItems": 2, "maxItems": 2, "items": { @@ -326,7 +333,7 @@ "type": "array", "subtype": "temporal-intervals", "title": "Multiple temporal intervals", - "description": "Left-closed temporal intervals, which are allowed to overlap. Formatted as array of two-element arrays, each being an array with subtype `temporal-interval`.", + "description": "Left-closed temporal intervals, which are allowed to overlap. Formatted as an array of two-element arrays, each being an array with subtype `temporal-interval`.", "items": { "$ref": "#/definitions/temporal-interval" }, @@ -369,32 +376,33 @@ "subtype": "time", "format": "time", "title": "Time only", - "description": "Time only representation, as defined for `full-time` by [RFC 3339 in section 5.6](https://tools.ietf.org/html/rfc3339#section-5.6). Although [RFC 3339 prohibits the hour to be '24'](https://tools.ietf.org/html/rfc3339#section-5.7), this definition allows the value '24' for the hour as end time in an interval in order to make it possible that left-closed time intervals can fully cover the day." + "description": "Time only representation, as defined for `full-time` by [RFC 3339 in section 5.6](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6). Although [RFC 3339 prohibits the hour to be '24'](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.7), this definition allows the value '24' for the hour as end time in an interval in order to make it possible that left-closed time intervals can fully cover the day." }, "udf-code": { "type": "string", "subtype": "udf-code", "title": "UDF source code", - "description": "The (multi-line) source code of an user-defined function (UDF)." + "description": "The multi-line source code of a user-defined function (UDF), must contain a newline/line-break.", + "pattern": "(\r\n|\r|\n)" }, "udf-runtime": { "type": "string", "subtype": "udf-runtime", "title": "UDF runtime", - "description": "The name of an UDF runtime." + "description": "The name of a UDF runtime." }, "udf-runtime-version": { "type": "string", "subtype": "udf-runtime-version", "title": "UDF Runtime version", - "description": "The version of an UDF runtime." + "description": "The version of a UDF runtime." }, "uri": { "type": "string", "subtype": "uri", "format": "uri", "title": "URI", - "description": "A valid URI according to [RFC3986](https://tools.ietf.org/html/rfc3986)." + "description": "A valid URI according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986.html). Can be restricted using a regular expression, e.g. to (dis)allow certain protocols." }, "vector-cube": { "type": "object", @@ -415,7 +423,7 @@ "maxLength": 4, "pattern": "^\\d{4}$", "title": "Year only", - "description": "Year representation, as defined for `date-fullyear` by [RFC 3339 in section 5.6](https://tools.ietf.org/html/rfc3339#section-5.6)." + "description": "Year representation, as defined for `date-fullyear` by [RFC 3339 in section 5.6](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6)." } } } \ No newline at end of file diff --git a/min.json b/min.json index 9d55fb8a..ce161c95 100644 --- a/min.json +++ b/min.json @@ -1,7 +1,7 @@ { "id": "min", "summary": "Minimum value", - "description": "Computes the smallest value of an array of numbers, which is is equal to the last element of a sorted (i.e., ordered) version the array.\n\nAn array without non-`null` elements resolves always with `null`.", + "description": "Computes the smallest value of an array of numbers, which is equal to the last element of a sorted (i.e., ordered) version of the array.\n\nAn array without non-`null` elements resolves always with `null`.", "categories": [ "math", "reducer" diff --git a/mod.json b/mod.json index 5409df05..ca709386 100644 --- a/mod.json +++ b/mod.json @@ -1,14 +1,14 @@ { "id": "mod", "summary": "Modulo", - "description": "Remainder after division of `x` by `y` for both integers and floating-point numbers.\n\nThe result of a modulo operation has the sign of the divisor. The handling regarding the sign of the result [differs between programming languages](https://en.wikipedia.org/wiki/Modulo_operation#In_programming_languages) and needs careful consideration to avoid unexpected results.\n\nThe no-data value `null` is passed through and therefore gets propagated if any of the arguments is `null`. A modulo by zero results in ±infinity if the processing environment supports it. Otherwise a `DivisionByZero` error must the thrown.", + "description": "Remainder after a division of `x` by `y` for both integers and floating-point numbers.\n\nThe result of a modulo operation has the sign of the divisor. The handling regarding the sign of the result [differs between programming languages](https://en.wikipedia.org/wiki/Modulo_operation#In_programming_languages) and needs careful consideration to avoid unexpected results.\n\nThe no-data value `null` is passed through and therefore gets propagated if any of the arguments is `null`. A modulo by zero results in ±infinity if the processing environment supports it. Otherwise, a `DivisionByZero` exception must the thrown.", "categories": [ "math" ], "parameters": [ { "name": "x", - "description": "A number to be used as dividend.", + "description": "A number to be used as the dividend.", "schema": { "type": [ "number", @@ -18,7 +18,7 @@ }, { "name": "y", - "description": "A number to be used as divisor.", + "description": "A number to be used as the divisor.", "schema": { "type": [ "number", diff --git a/multiply.json b/multiply.json index ef0d5cb3..afa88daa 100644 --- a/multiply.json +++ b/multiply.json @@ -1,7 +1,7 @@ { "id": "multiply", "summary": "Multiplication of two numbers", - "description": "Multiplies the two numbers `x` and `y` (*x * y*) and returns the computed product.\n\nNo-data values are taken into account so that `null` is returned if any element is such a value.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it.", + "description": "Multiplies the two numbers `x` and `y` (*`x * y`*) and returns the computed product.\n\nNo-data values are taken into account so that `null` is returned if any element is such a value.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it.", "categories": [ "math" ], diff --git a/ndvi.json b/ndvi.json index 39a49f6b..ba5e54fb 100644 --- a/ndvi.json +++ b/ndvi.json @@ -1,7 +1,7 @@ { "id": "ndvi", "summary": "Normalized Difference Vegetation Index", - "description": "Computes the Normalized Difference Vegetation Index (NDVI). The NDVI is computed as *(nir - red) / (nir + red)*.\n\nThe `data` parameter expects a raster data cube with a dimension of type `bands` or a `DimensionAmbiguous` error is thrown otherwise. By default, the dimension must have at least two bands with the common names `red` and `nir` assigned or the user need to specify the parameters `nir` and `red`. Otherwise either the error `NirBandAmbiguous` or `RedBandAmbiguous` is thrown. The common names for each band are specified in the collection's band metadata and are *not* equal to the band names.\n\nBy default, the dimension of type `bands` is dropped by this process. To keep the dimension specify a new band name in the parameter `target_band`. This adds a new dimension label with the specified name to the dimension, which can be used to access the computed values. If a band with the specified name exists, a `BandExists` is thrown.\n\nThis process is very similar to the process ``normalized_difference()``, but determines the bands automatically based on the common names (`red`/`nir`) specified in the metadata.", + "description": "Computes the Normalized Difference Vegetation Index (NDVI). The NDVI is computed as *`(nir - red) / (nir + red)`*.\n\nThe `data` parameter expects a raster data cube with a dimension of type `bands` or a `DimensionAmbiguous` exception is thrown otherwise. By default, the dimension must have at least two bands with the common names `red` and `nir` assigned. Otherwise, the user has to specify the parameters `nir` and `red`. If neither is the case, either the exception `NirBandAmbiguous` or `RedBandAmbiguous` is thrown. The common names for each band are specified in the collection's band metadata and are *not* equal to the band names.\n\nBy default, the dimension of type `bands` is dropped by this process. To keep the dimension specify a new band name in the parameter `target_band`. This adds a new dimension label with the specified name to the dimension, which can be used to access the computed values. If a band with the specified name exists, a `BandExists` is thrown.\n\nThis process is very similar to the process ``normalized_difference()``, but determines the bands automatically based on the common names (`red`/`nir`) specified in the metadata.", "categories": [ "math > indices", "vegetation indices" @@ -17,7 +17,7 @@ }, { "name": "nir", - "description": "The name of the NIR band. Defaults to the band that has the common name `nir` assigned.\n\nEither the unique band name (metadata field `name` in bands) or one of the common band names (metadata field `common_name` in bands) can be specified. If unique band name and common name conflict, the unique band name has higher priority.", + "description": "The name of the NIR band. Defaults to the band that has the common name `nir` assigned.\n\nEither the unique band name (metadata field `name` in bands) or one of the common band names (metadata field `common_name` in bands) can be specified. If the unique band name and the common name conflict, the unique band name has a higher priority.", "schema": { "type": "string", "subtype": "band-name" @@ -27,7 +27,7 @@ }, { "name": "red", - "description": "The name of the red band. Defaults to the band that has the common name `red` assigned.\n\nEither the unique band name (metadata field `name` in bands) or one of the common band names (metadata field `common_name` in bands) can be specified. If unique band name and common name conflict, the unique band name has higher priority.", + "description": "The name of the red band. Defaults to the band that has the common name `red` assigned.\n\nEither the unique band name (metadata field `name` in bands) or one of the common band names (metadata field `common_name` in bands) can be specified. If the unique band name and the common name conflict, the unique band name has a higher priority.", "schema": { "type": "string", "subtype": "band-name" @@ -52,7 +52,7 @@ } ], "returns": { - "description": "A raster data cube containing the computed NDVI values. The structure of the data cube differs depending on the value passed to `target_band`:\n\n* `target_band` is `null`: The data cube does not contain the dimension of type `bands` any more, the number of dimensions decreases by one. The dimension properties (name, type, labels, reference system and resolution) for all other dimensions remain unchanged.\n* `target_band` is a string: The data cube keeps the same dimensions. The dimension properties remain unchanged, but the number of dimension labels for the dimension of type `bands` increases by one. The additional label is named as specified in `target_band`.", + "description": "A raster data cube containing the computed NDVI values. The structure of the data cube differs depending on the value passed to `target_band`:\n\n* `target_band` is `null`: The data cube does not contain the dimension of type `bands`, the number of dimensions decreases by one. The dimension properties (name, type, labels, reference system and resolution) for all other dimensions remain unchanged.\n* `target_band` is a string: The data cube keeps the same dimensions. The dimension properties remain unchanged, but the number of dimension labels for the dimension of type `bands` increases by one. The additional label is named as specified in `target_band`.", "schema": { "type": "object", "subtype": "raster-cube" @@ -60,10 +60,10 @@ }, "exceptions": { "NirBandAmbiguous": { - "message": "The NIR band can't be resolved, please specify a band name." + "message": "The NIR band can't be resolved, please specify the specific NIR band name." }, "RedBandAmbiguous": { - "message": "The red band can't be resolved, please specify a band name." + "message": "The red band can't be resolved, please specify the specific red band name." }, "DimensionAmbiguous": { "message": "dimension of type `bands` is not available or is ambiguous.." diff --git a/neq.json b/neq.json index b19bf50b..ec3908e4 100644 --- a/neq.json +++ b/neq.json @@ -1,7 +1,7 @@ { "id": "neq", "summary": "Not equal to comparison", - "description": "Compares whether `x` is *not* strictly equal to `y`.\n\n**Remarks:**\n\n* Data types MUST be checked strictly, for example a string with the content *1* is not equal to the number *1*. Nevertheless, an integer *1* is equal to a floating point number *1.0* as `integer` is a sub-type of `number`.\n* If any operand is `null`, the return value is `null`. Therefore, `neq(null, null)` returns `null` instead of `false`.\n* If any operand is an array or object, the return value is `false`.\n* Strings are expected to be encoded in UTF-8 by default.\n* Temporal strings MUST be compared differently than other strings and MUST NOT be compared based on their string representation due to different possible representations. For example, the UTC time zone representation `Z` has the same meaning as `+00:00`.", + "description": "Compares whether `x` is *not* strictly equal to `y`.\n\n**Remarks:**\n\n* Data types MUST be checked strictly. For example, a string with the content *1* is not equal to the number *1*. Nevertheless, an integer *1* is equal to a floating-point number *1.0* as `integer` is a sub-type of `number`.\n* If any operand is `null`, the return value is `null`. Therefore, `neq(null, null)` returns `null` instead of `false`.\n* If any operand is an array or object, the return value is `false`.\n* Strings are expected to be encoded in UTF-8 by default.\n* Temporal strings MUST be compared differently than other strings and MUST NOT be compared based on their string representation due to different possible representations. For example, the time zone representation `Z` (for UTC) has the same meaning as `+00:00`.", "categories": [ "texts", "comparison" @@ -23,7 +23,7 @@ }, { "name": "delta", - "description": "Only applicable for comparing two numbers. If this optional parameter is set to a positive non-zero number the non-equality of two numbers is checked against a delta value. This is especially useful to circumvent problems with floating point inaccuracy in machine-based computation.\n\nThis option is basically an alias for the following computation: `gt(abs(minus([x, y]), delta)`", + "description": "Only applicable for comparing two numbers. If this optional parameter is set to a positive non-zero number the non-equality of two numbers is checked against a delta value. This is especially useful to circumvent problems with floating-point inaccuracy in machine-based computation.\n\nThis option is basically an alias for the following computation: `gt(abs(minus([x, y]), delta)`", "schema": { "type": [ "number", @@ -44,7 +44,7 @@ } ], "returns": { - "description": "Returns `true` if `x` is *not* equal to `y`, `null` if any operand is `null`, otherwise `false`.", + "description": "`true` if `x` is *not* equal to `y`, `null` if any operand is `null`, otherwise `false`.", "schema": { "type": [ "boolean", diff --git a/normalized_difference.json b/normalized_difference.json index 9d766d94..7050822c 100644 --- a/normalized_difference.json +++ b/normalized_difference.json @@ -1,7 +1,7 @@ { "id": "normalized_difference", "summary": "Normalized difference", - "description": "Computes the normalized difference for two bands. The normalized difference is computed as *(x - y) / (x + y)*.\n\nThis process could be used for a number of remote sensing indices such as:\n\n* [NDVI](https://eos.com/ndvi/): `x` = NIR band, `y` = red band\n* [NDWI](https://eos.com/ndwi/): `x` = NIR band, `y` = SWIR band\n* [NDSI](https://eos.com/ndsi/): `x` = green band, `y` = SWIR band\n\nSome back-ends may have native processes such as ``ndvi()`` available for convenience.", + "description": "Computes the normalized difference for two bands. The normalized difference is computed as *`(x - y) / (x + y)`*.\n\nThis process could be used for a number of remote sensing indices such as:\n\n* [NDVI](https://eos.com/ndvi/): `x` = NIR band, `y` = red band\n* [NDWI](https://eos.com/ndwi/): `x` = NIR band, `y` = SWIR band\n* [NDSI](https://eos.com/ndsi/): `x` = green band, `y` = SWIR band\n\nSome back-ends may have native processes such as ``ndvi()`` available for convenience.", "categories": [ "math > indices", "vegetation indices" diff --git a/order.json b/order.json index 72976dd1..0002d467 100644 --- a/order.json +++ b/order.json @@ -1,7 +1,7 @@ { "id": "order", "summary": "Create a permutation", - "description": "Computes a permutation which allows rearranging the data into ascending or descending order. In other words, this process computes the ranked (sorted) element positions in the original list.\n\n**Remarks:**\n\n* The positions in the result are zero-based.\n* Ties will be left in their original ordering.\n* Temporal strings can *not* be compared based on their string representation due to the time zone / time-offset representations.", + "description": "Computes a permutation which allows rearranging the data into ascending or descending order. In other words, this process computes the ranked (sorted) element positions in the original list.\n\n**Remarks:**\n\n* The positions in the result are zero-based.\n* Ties will be left in their original ordering.\n* Temporal strings can *not* be compared based on their string representation due to the time zone/time-offset representations.", "categories": [ "arrays", "sorting" @@ -50,7 +50,7 @@ }, { "name": "nodata", - "description": "Controls the handling of no-data values (`null`). By default they are removed. If `true`, missing values in the data are put last; if `false`, they are put first.", + "description": "Controls the handling of no-data values (`null`). By default, they are removed. If set to `true`, missing values in the data are put last; if set to `false`, they are put first.", "schema": { "type": [ "boolean", diff --git a/proposals/aggregate_spatial_window.json b/proposals/aggregate_spatial_window.json new file mode 100644 index 00000000..77230275 --- /dev/null +++ b/proposals/aggregate_spatial_window.json @@ -0,0 +1,119 @@ +{ + "id": "aggregate_spatial_window", + "summary": "Zonal statistics for rectangular windows", + "description": "Aggregates statistics over the horizontal spatial dimensions (axes `x` and `y`) of the data cube.\n\nThe pixel grid for the axes `x` and `y` is divided into non-overlapping windows with the size specified in the parameter `size`. If the number of values for the axes `x` and `y` is not a multiple of the corresponding window size, the behavior specified in the parameters `boundary` and `align` is applied.\nFor each of these windows, the reducer process computes the result.", + "categories": [ + "cubes", + "aggregate & resample" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "A raster data cube with exactly two horizontal spatial dimensions and an arbitrary number of additional dimensions. The process is applied to all additional dimensions individually.", + "schema": { + "type": "object", + "subtype": "raster-cube" + } + }, + { + "name": "reducer", + "description": "A reducer to be applied on the list of values, which contain all pixels covered by the window. A reducer is a single process such as ``mean()`` or a set of processes, which computes a single value for a list of values, see the category 'reducer' for such processes.", + "schema": { + "type": "object", + "subtype": "process-graph", + "parameters": [ + { + "name": "data", + "description": "An array with elements of any type.", + "schema": { + "type": "array", + "items": { + "description": "Any data type." + } + } + }, + { + "name": "context", + "description": "Additional data passed by the user.", + "schema": { + "description": "Any data type." + }, + "optional": true, + "default": null + } + ], + "returns": { + "description": "The value to be set in the new data cube.", + "schema": { + "description": "Any data type." + } + } + } + }, + { + "name": "size", + "description": "Window size in pixels along the horizontal spatial dimensions.\n\nThe first value corresponds to the `x` axis, the second value corresponds to the `y` axis.", + "schema": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 1 + } + } + }, + { + "name": "boundary", + "description": "Behavior to apply if the number of values for the axes `x` and `y` is not a multiple of the corresponding value in the `size` parameter. Options are:\n\n- `pad` (default): pad the data cube with the no-data value `null` to fit the required window size.\n\n- `trim`: trim the data cube to fit the required window size.\n\nSet the parameter `align` to specifies to which corner the data is aligned to.", + "schema": { + "type": "string", + "enum": [ + "pad", + "trim" + ] + }, + "optional": true, + "default": "pad" + }, + { + "name": "align", + "description": "If the data requires padding or trimming (see parameter `boundary`), specifies to which corner of the spatial extent the data is aligned to. For example, if the data is aligned to the upper left, the process pads/trims at the lower-right.", + "schema": { + "type": "string", + "enum": [ + "lower-left", + "upper-left", + "lower-right", + "upper-right" + ] + }, + "default": "upper-left", + "optional": true + }, + { + "name": "context", + "description": "Additional data to be passed to the reducer.", + "schema": { + "description": "Any data type." + }, + "optional": true, + "default": null + } + ], + "returns": { + "description": "A data cube with the newly computed values and the same dimensions.\n\nThe resolution will change depending on the chosen values for the `size` and `boundary` parameter. It usually decreases for the dimensions which have the corresponding parameter `size` set to values greater than 1.\n\nThe dimension labels will be set to the coordinate at the center of the window. The other dimension properties (name, type and reference system) remain unchanged.", + "schema": { + "type": "object", + "subtype": "raster-cube" + } + }, + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#aggregate", + "rel": "about", + "title": "Aggregation explained in the openEO documentation" + } + ] +} \ No newline at end of file diff --git a/proposals/ard_normalized_radar_backscatter.json b/proposals/ard_normalized_radar_backscatter.json new file mode 100644 index 00000000..46f5f48a --- /dev/null +++ b/proposals/ard_normalized_radar_backscatter.json @@ -0,0 +1,118 @@ +{ + "id": "ard_normalized_radar_backscatter", + "summary": "CARD4L compliant SAR NRB generation", + "description": "Computes CARD4L compliant backscatter from SAR input. The radiometric correction coefficient is gamma0 (terrain), which is the ground area computed with terrain earth model in sensor line of sight.\n\nNote that backscatter computation may require instrument specific metadata that is tightly coupled to the original SAR products. As a result, this process may only work in combination with loading data from specific collections, not with general data cubes.\n\nThis process uses bilinear interpolation, both for resampling the DEM and the backscatter.", + "categories": [ + "cubes", + "sar", + "ard" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "The source data cube containing SAR input.", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + { + "name": "elevation_model", + "description": "The digital elevation model to use. Set to `null` (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility.", + "optional": true, + "default": null, + "schema": [ + { + "type": "string", + "subtype": "collection-id" + }, + { + "type": "null" + } + ] + }, + { + "name": "contributing_area", + "description": "If set to `true`, a DEM-based local contributing area band named `contributing_area` is added. The values are given in square meters.", + "optional": true, + "default": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "ellipsoid_incidence_angle", + "description": "If set to `true`, an ellipsoidal incidence angle band named `ellipsoid_incidence_angle` is added. The values are given in degrees.", + "optional": true, + "default": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "noise_removal", + "description": "If set to `false`, no noise removal is applied. Defaults to `true`, which removes noise.", + "optional": true, + "default": true, + "schema": { + "type": "boolean" + } + } + ], + "returns": { + "description": "Backscatter values expressed as gamma0 in linear scale.\n\nIn addition to the bands `contributing_area` and `ellipsoid_incidence_angle` that can optionally be added with corresponding parameters, the following bands are always added to the data cube:\n\n- `mask`: A data mask that indicates which values are valid (1), invalid (0) or contain no-data (null).\n- `local_incidence_angle`: A band with DEM-based local incidence angles in degrees.\n\nThe data returned is CARD4L compliant with corresponding metadata.", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + "exceptions": { + "DigitalElevationModelInvalid": { + "message": "The digital elevation model specified is either not a DEM or can't be used with the data cube given." + } + }, + "links": [ + { + "rel": "about", + "href": "http://ceos.org/ard/files/PFS/NRB/v5.0/CARD4L-PFS_Normalised_Radar_Backscatter-v5.0.pdf", + "title": "CEOS CARD4L specification" + }, + { + "rel": "about", + "href": "https://bok.eo4geo.eu/PP2-2-4-3", + "title": "Gamma nought (0) explained by EO4GEO body of knowledge." + }, + { + "rel": "about", + "href": "https://doi.org/10.3390/data4030093", + "title": "Reasoning behind the choice of bilinear resampling" + } + ], + "process_graph": { + "nrb": { + "process_id": "sar_backscatter", + "arguments": { + "data": { + "from_parameter": "data" + }, + "coefficient": "gamma0-terrain", + "elevation_model": { + "from_parameter": "elevation_model" + }, + "mask": true, + "contributing_area": { + "from_parameter": "contributing_area" + }, + "local_incidence_angle": true, + "ellipsoid_incidence_angle": { + "from_parameter": "ellipsoid_incidence_angle" + }, + "noise_removal": { + "from_parameter": "noise_removal" + } + }, + "result": true + } + } +} \ No newline at end of file diff --git a/proposals/ard_surface_reflectance.json b/proposals/ard_surface_reflectance.json new file mode 100644 index 00000000..3fee8b54 --- /dev/null +++ b/proposals/ard_surface_reflectance.json @@ -0,0 +1,97 @@ +{ + "id": "ard_surface_reflectance", + "summary": "CARD4L compliant Surface Reflectance generation", + "description": "Computes CARD4L compliant surface (bottom of atmosphere/top of canopy) reflectance values from optical input.", + "categories": [ + "cubes", + "sar", + "ard" + ], + "experimental": true, + "parameters": [ + { + "description": "The source data cube containing multi-spectral optical top of the atmosphere (TOA) reflectances. There must be a single dimension of type `bands` available.", + "name": "data", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + { + "description": "The atmospheric correction method to use.", + "name": "atmospheric_correction_method", + "schema": { + "type": [ + "string" + ], + "enum": [ + "FORCE", + "iCOR" + ] + } + }, + { + "description": "The cloud detection method to use.\n\nEach method supports detecting different atmospheric disturbances such as clouds, cloud shadows, aerosols, haze, ozone and/or water vapour in optical imagery.", + "name": "cloud_detection_method", + "schema": { + "type": [ + "string" + ], + "enum": [ + "Fmask", + "s2cloudless", + "Sen2Cor" + ] + } + }, + { + "description": "The digital elevation model to use. Set to `null` (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility.", + "name": "elevation_model", + "optional": true, + "default": null, + "schema": [ + { + "type": "string", + "subtype": "collection-id" + }, + { + "type": "null" + } + ] + }, + { + "description": "Proprietary options for the atmospheric correction method. Specifying proprietary options will reduce portability.", + "name": "atmospheric_correction_options", + "optional": true, + "default": {}, + "schema": { + "type": "object", + "additionalProperties": false + } + }, + { + "description": "Proprietary options for the cloud detection method. Specifying proprietary options will reduce portability.", + "name": "cloud_detection_options", + "optional": true, + "default": {}, + "schema": { + "type": "object", + "additionalProperties": false + } + } + ], + "returns": { + "description": "Data cube containing bottom of atmosphere reflectances for each spectral band in the source data cube, with atmospheric disturbances like clouds and cloud shadows removed. No-data values (null) are directly set in the bands. Depending on the methods used, several additional bands will be added to the data cube:\n\nData cube containing bottom of atmosphere reflectances for each spectral band in the source data cube, with atmospheric disturbances like clouds and cloud shadows removed. Depending on the methods used, several additional bands will be added to the data cube:\n\n- `date` (optional): Specifies per-pixel acquisition timestamps.\n- `incomplete-testing` (required): Identifies pixels with a value of 1 for which the per-pixel tests (at least saturation, cloud and cloud shadows, see CARD4L specification for details) have not all been successfully completed. Otherwise, the value is 0.\n- `saturation` (required) / `saturation_{band}` (optional): Indicates where pixels in the input spectral bands are saturated (1) or not (0). If the saturation is given per band, the band names are `saturation_{band}` with `{band}` being the band name from the source data cube.\n- `cloud`, `shadow` (both required),`aerosol`, `haze`, `ozone`, `water_vapor` (all optional): Indicates the probability of pixels being an atmospheric disturbance such as clouds. All bands have values between 0 (clear) and 1, which describes the probability that it is an atmospheric disturbance.\n- `snow-ice` (optional): Points to a file that indicates whether a pixel is assessed as being snow/ice (1) or not (0). All values describe the probability and must be between 0 and 1.\n- `land-water` (optional): Indicates whether a pixel is assessed as being land (1) or water (0). All values describe the probability and must be between 0 and 1.\n- `incidence-angle` (optional): Specifies per-pixel incidence angles in degrees.\n- `azimuth` (optional): Specifies per-pixel azimuth angles in degrees.\n- `sun-azimuth:` (optional): Specifies per-pixel sun azimuth angles in degrees.\n- `sun-elevation` (optional): Specifies per-pixel sun elevation angles in degrees.\n- `terrain-shadow` (optional): Indicates with a value of 1 whether a pixel is not directly illuminated due to terrain shadowing. Otherwise, the value is 0.\n- `terrain-occlusion` (optional): Indicates with a value of 1 whether a pixel is not visible to the sensor due to terrain occlusion during off-nadir viewing. Otherwise, the value is 0.\n- `terrain-illumination` (optional): Contains coefficients used for terrain illumination correction are provided for each pixel.\n\nThe data returned is CARD4L compliant with corresponding metadata.", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + "links": [ + { + "rel": "about", + "href": "http://ceos.org/ard/files/PFS/SR/v5.0/CARD4L_Product_Family_Specification_Surface_Reflectance-v5.0.pdf", + "title": "CEOS CARD4L specification" + } + ] +} \ No newline at end of file diff --git a/proposals/array_append.json b/proposals/array_append.json new file mode 100644 index 00000000..59d8b178 --- /dev/null +++ b/proposals/array_append.json @@ -0,0 +1,69 @@ +{ + "id": "array_append", + "summary": "Append a value to an array", + "description": "Appends a value to the end of the array. Array labels get discarded from the array.", + "categories": [ + "arrays" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "An array.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + { + "name": "value", + "description": "Value to append to the array.", + "schema": { + "description": "Any data type is allowed." + } + } + ], + "returns": { + "description": "The new array with the value being appended.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + "examples": [ + { + "arguments": { + "data": [ + 1, + 2 + ], + "value": 3 + }, + "returns": [ + 1, + 2, + 3 + ] + } + ], + "process_graph": { + "append": { + "process_id": "array_concat", + "arguments": { + "array1": { + "from_parameter": "data" + }, + "array2": [ + { + "from_parameter": "value" + } + ] + }, + "result": true + } + } +} \ No newline at end of file diff --git a/proposals/array_concat.json b/proposals/array_concat.json new file mode 100644 index 00000000..d095973a --- /dev/null +++ b/proposals/array_concat.json @@ -0,0 +1,61 @@ +{ + "id": "array_concat", + "summary": "Merge two arrays", + "description": "Concatenates two arrays into a single array by appending the second array to the first array. Array labels get discarded from both arrays before merging.", + "categories": [ + "arrays" + ], + "experimental": true, + "parameters": [ + { + "name": "array1", + "description": "The first array.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + { + "name": "array2", + "description": "The second array.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + } + ], + "returns": { + "description": "The merged array.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + "examples": [ + { + "description": "Concatenates two arrays containing different data type.", + "arguments": { + "array1": [ + "a", + "b" + ], + "array2": [ + 1, + 2 + ] + }, + "returns": [ + "a", + "b", + 1, + 2 + ] + } + ] +} \ No newline at end of file diff --git a/proposals/array_create.json b/proposals/array_create.json new file mode 100644 index 00000000..71d7003d --- /dev/null +++ b/proposals/array_create.json @@ -0,0 +1,95 @@ +{ + "id": "array_create", + "summary": "Create an array", + "description": "Creates a new array, which by default is empty.\n\nThe second parameter `repeat` allows to add the given array multiple times to the new array.\n\nIn most cases you can simply pass a (native) array to processes directly, but this process is especially useful to create a new array that is getting returned by a child process, for example in ``apply_dimension()``.", + "categories": [ + "arrays" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "A (native) array to fill the newly created array with. Defaults to an empty array.", + "optional": true, + "default": [], + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + { + "name": "repeat", + "description": "The number of times the (native) array specified in `data` is repeatedly added after each other to the new array being created. Defaults to `1`.", + "optional": true, + "default": 1, + "schema": { + "type": "integer", + "minimum": 1 + } + } + ], + "returns": { + "description": "The newly created array.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + "examples": [ + { + "arguments": {}, + "returns": [] + }, + { + "arguments": { + "data": [ + "this", + "is", + "a", + "test" + ] + }, + "returns": [ + "this", + "is", + "a", + "test" + ] + }, + { + "arguments": { + "data": [ + null + ], + "repeat": 3 + }, + "returns": [ + null, + null, + null + ] + }, + { + "arguments": { + "data": [ + 1, + 2, + 3 + ], + "repeat": 2 + }, + "returns": [ + 1, + 2, + 3, + 1, + 2, + 3 + ] + } + ] +} \ No newline at end of file diff --git a/proposals/array_create_labeled.json b/proposals/array_create_labeled.json new file mode 100644 index 00000000..8b5d2034 --- /dev/null +++ b/proposals/array_create_labeled.json @@ -0,0 +1,46 @@ +{ + "id": "array_create_labeled", + "summary": "Create a labeled array", + "description": "Creates a new labeled array by using the values from the `labels` array as labels and the values from the `data` array as the corresponding values.\n\nThe exception `ArrayLengthMismatch` is thrown, if the number of the values in the given arrays don't match exactly.\n\nThe primary use case here is to be able to transmit labeled arrays from the client to the server as JSON doesn't support this data type.", + "categories": [ + "arrays" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "An array of values to be used.", + "schema": { + "description": "Any data type is allowed." + } + }, + { + "name": "labels", + "description": "An array of labels to be used.", + "schema": { + "type": "array", + "items": { + "type": [ + "number", + "string" + ] + } + } + } + ], + "returns": { + "description": "The newly created labeled array.", + "schema": { + "type": "array", + "subtype": "labeled-array", + "items": { + "description": "Any data type is allowed." + } + } + }, + "exceptions": { + "ArrayLengthMismatch": { + "message": "The number of values in the parameters `data` and `labels` don't match." + } + } +} \ No newline at end of file diff --git a/proposals/array_find_label.json b/proposals/array_find_label.json new file mode 100644 index 00000000..7f501871 --- /dev/null +++ b/proposals/array_find_label.json @@ -0,0 +1,46 @@ +{ + "id": "array_find_label", + "summary": "Get the index for a label in a labeled array", + "description": "Checks whether the labeled array specified for `data` has the label specified in `label` and returns the zero-based index for it. If there's no match as either the label doesn't exist or the array is not labeled, `null` is returned.", + "categories": [ + "arrays", + "reducer" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "List to find the label in.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + { + "name": "label", + "description": "Label to find in `data`.", + "schema": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + ], + "returns": { + "description": "The index of the element with the specified label assigned. If no such label was found, `null` is returned.", + "schema": [ + { + "type": "null" + }, + { + "type": "integer", + "minimum": 0 + } + ] + } +} \ No newline at end of file diff --git a/proposals/array_interpolate_linear.json b/proposals/array_interpolate_linear.json new file mode 100644 index 00000000..3a106c77 --- /dev/null +++ b/proposals/array_interpolate_linear.json @@ -0,0 +1,64 @@ +{ + "id": "array_interpolate_linear", + "summary": "One-dimensional linear interpolation for arrays", + "description": "Performs a linear interpolation for each of the no-data values (`null`) in the array given, except for leading and trailing no-data values.\n\nThe linear interpolants are defined by the array indices or labels (x) and the values in the array (y).", + "categories": [ + "arrays", + "math", + "math > interpolation" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "An array of numbers and no-data values.\n\nIf the given array is a labeled array, the labels must have a natural/inherent label order and the process expects the labels to be sorted accordingly. This is the default behavior in openEO for spatial and temporal dimensions.", + "schema": { + "type": "array", + "items": { + "type": [ + "number", + "null" + ] + } + } + } + ], + "returns": { + "description": "An array with no-data values being replaced with interpolated values. If not at least 2 numerical values are available in the array, the array stays the same.", + "schema": { + "type": [ + "number", + "null" + ] + } + }, + "examples": [ + { + "arguments": { + "data": [ + null, + 1, + null, + 6, + null, + -8 + ] + }, + "returns": [ + null, + 1, + 3.5, + 6, + -1, + -8 + ] + } + ], + "links": [ + { + "rel": "about", + "href": "https://en.wikipedia.org/wiki/Linear_interpolation", + "title": "Linear interpolation explained by Wikipedia" + } + ] +} \ No newline at end of file diff --git a/proposals/array_modify.json b/proposals/array_modify.json new file mode 100644 index 00000000..497016db --- /dev/null +++ b/proposals/array_modify.json @@ -0,0 +1,186 @@ +{ + "id": "array_modify", + "summary": "Change the content of an array (insert, remove, update)", + "description": "Allows to insert into, remove from or update an array.\n\nAll labels get discarded and the array indices are always a sequence of numbers with the step size of 1 and starting at 0.", + "categories": [ + "arrays" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "An array.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + { + "name": "values", + "description": "The values to fill the array with.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + { + "name": "index", + "description": "The index of the element to insert the value(s) before. If the index is greater than the number of elements, the process throws an `ArrayElementNotAvailable` exception.\n\nTo insert after the last element, there are two options:\n\n1. Use the simpler processes ``array_append()`` to append a single value or ``array_concat`` to append multiple values.\n2. Specify the number of elements in the array. You can retrieve the number of elements with the process ``count()``, having the parameter `condition` set to `true`.", + "schema": { + "type": "integer", + "minimum": 0 + } + }, + { + "name": "length", + "description": "The number of elements to replace. This parameter has no effect in case the given `index` does not exist in the array given.", + "optional": true, + "default": 1, + "schema": { + "type": "integer", + "minimum": 0 + } + } + ], + "returns": { + "description": "An array with values added, updated or removed.", + "schema": { + "type": "array", + "items": { + "description": "Any data type is allowed." + } + } + }, + "exceptions": { + "ArrayElementNotAvailable": { + "message": "The array has no element with the specified index." + } + }, + "examples": [ + { + "description": "Replace a single value in the array.", + "arguments": { + "data": [ + "a", + "d", + "c" + ], + "values": [ + "b" + ], + "index": 1 + }, + "returns": [ + "a", + "b", + "c" + ] + }, + { + "description": "Replace multiple values in the array.", + "arguments": { + "data": [ + "a", + "b", + 4, + 5 + ], + "values": [ + 1, + 2, + 3 + ], + "index": 0, + "length": 2 + }, + "returns": [ + 1, + 2, + 3, + 4, + 5 + ] + }, + { + "description": "Insert a value to the array at a given position.", + "arguments": { + "data": [ + "a", + "c" + ], + "values": [ + "b" + ], + "index": 1, + "length": 0 + }, + "returns": [ + "a", + "b", + "c" + ] + }, + { + "description": "Add a value at a specific non-existing position after the array, fill missing elements with `null`.", + "arguments": { + "data": [ + "a", + "b" + ], + "values": [ + "e" + ], + "index": 4 + }, + "returns": [ + "a", + "b", + null, + null, + "e" + ] + }, + { + "description": "Remove a single value from the array.", + "arguments": { + "data": [ + "a", + "b", + null, + "c" + ], + "values": [], + "index": 2 + }, + "returns": [ + "a", + "b", + "c" + ] + }, + { + "description": "Remove multiple values from the array.", + "arguments": { + "data": [ + null, + null, + "a", + "b", + "c" + ], + "values": [], + "index": 0, + "length": 2 + }, + "returns": [ + "a", + "b", + "c" + ] + } + ] +} \ No newline at end of file diff --git a/proposals/atmospheric_correction.json b/proposals/atmospheric_correction.json new file mode 100644 index 00000000..9b537322 --- /dev/null +++ b/proposals/atmospheric_correction.json @@ -0,0 +1,82 @@ +{ + "id": "atmospheric_correction", + "summary": "Apply atmospheric correction", + "description": "Applies an atmospheric correction that converts top of atmosphere reflectance values into bottom of atmosphere/top of canopy reflectance values.", + "categories": [ + "cubes", + "optical" + ], + "experimental": true, + "parameters": [ + { + "description": "Data cube containing multi-spectral optical top of atmosphere reflectances to be corrected.", + "name": "data", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + { + "description": "The atmospheric correction method to use. To get reproducible results, you have to set a specific method.\n\nSet to `null` to allow the back-end to choose, which will improve portability, but reduce reproducibility as you *may* get different results if you run the processes multiple times.", + "name": "method", + "schema": [ + { + "type": [ + "string" + ], + "enum": [ + "FORCE", + "iCOR" + ] + }, + { + "type": "null" + } + ] + }, + { + "description": "The digital elevation model to use. Set to `null` (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility.", + "name": "elevation_model", + "optional": true, + "default": null, + "schema": [ + { + "type": "string", + "subtype": "collection-id" + }, + { + "type": "null" + } + ] + }, + { + "description": "Proprietary options for the atmospheric correction method. Specifying proprietary options will reduce portability.", + "name": "options", + "optional": true, + "default": {}, + "schema": { + "type": "object", + "additionalProperties": false + } + } + ], + "returns": { + "description": "Data cube containing bottom of atmosphere reflectances.", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + "exceptions": { + "DigitalElevationModelInvalid": { + "message": "The digital elevation model specified is either not a DEM or can't be used with the data cube given." + } + }, + "links": [ + { + "rel": "about", + "href": "https://bok.eo4geo.eu/IP1-7-1", + "title": "Atmospheric correction explained by EO4GEO body of knowledge." + } + ] +} \ No newline at end of file diff --git a/proposals/cloud_detection.json b/proposals/cloud_detection.json new file mode 100644 index 00000000..f9025c5b --- /dev/null +++ b/proposals/cloud_detection.json @@ -0,0 +1,63 @@ +{ + "id": "cloud_detection", + "summary": "Create cloud masks", + "description": "Detects atmospheric disturbances such as clouds, cloud shadows, aerosols, haze, ozone and/or water vapour in optical imagery.\n\nIt creates a data cube with the spatial and temporal dimensions compatible to the source data cube and a dimension that contains a dimension label for each of the supported/considered atmospheric disturbances. The naming of the bands follows these pre-defined values:\n\n- `cloud`\n- `shadow`\n- `aerosol`\n- `haze`\n- `ozone`\n- `water_vapor`\n\nAll bands have values between 0 (clear) and 1, which describes the probability that it is an atmospheric disturbance.", + "categories": [ + "cubes", + "optical" + ], + "experimental": true, + "parameters": [ + { + "description": "The source data cube containing multi-spectral optical top of the atmosphere (TOA) reflectances on which to perform cloud detection.", + "name": "data", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + { + "description": "The cloud detection method to use. To get reproducible results, you have to set a specific method.\n\nSet to `null` to allow the back-end to choose, which will improve portability, but reduce reproducibility as you *may* get different results if you run the processes multiple times.", + "name": "method", + "schema": [ + { + "type": [ + "string" + ], + "enum": [ + "Fmask", + "s2cloudless", + "Sen2Cor" + ] + }, + { + "type": "null" + } + ] + }, + { + "description": "Proprietary options for the cloud detection method. Specifying proprietary options will reduce portability.", + "name": "options", + "optional": true, + "default": {}, + "schema": { + "type": "object", + "additionalProperties": false + } + } + ], + "returns": { + "description": "A data cube with bands for the atmospheric disturbances. Each of the masks contains values between 0 and 1. The data cube has the same spatial and temporal dimensions as the source data cube and a dimension that contains a dimension label for each of the supported/considered atmospheric disturbance.", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + "links": [ + { + "rel": "about", + "href": "https://bok.eo4geo.eu/TA14-2-2-1-3", + "title": "Cloud mask explained by EO4GEO body of knowledge." + } + ] +} \ No newline at end of file diff --git a/cummax.json b/proposals/cummax.json similarity index 79% rename from cummax.json rename to proposals/cummax.json index 18a37abd..69580459 100644 --- a/cummax.json +++ b/proposals/cummax.json @@ -1,10 +1,11 @@ { "id": "cummax", "summary": "Cumulative maxima", - "description": "Finds cumulative maxima of an array of numbers. Every computed element is equal to the bigger one between current element and the previously computed element. The returned array and the input array have always the same length.\n\nBy default, no-data values are skipped, but stay in the result. Setting the `ignore_nodata` flag to `true` makes that once a no-data value / `null` is reached all following elements are set to `null` in the result.", + "description": "Finds cumulative maxima of an array of numbers. Every computed element is equal to the bigger one between the current element and the previously computed element. The returned array and the input array have always the same length.\n\nBy default, no-data values are skipped, but stay in the result. Setting the `ignore_nodata` flag to `true` makes that once a no-data value (`null`) is reached all following elements are set to `null` in the result.", "categories": [ "math > cumulative" ], + "experimental": true, "parameters": [ { "name": "data", @@ -21,7 +22,7 @@ }, { "name": "ignore_nodata", - "description": "Indicates whether no-data values are ignored or not. Ignores them by default. Setting this flag to `false` considers no-data values so that `null` is set for all the following elements.", + "description": "Indicates whether no-data values are ignored or not and ignores them by default. Setting this flag to `false` considers no-data values so that `null` is set for all the following elements.", "schema": { "type": "boolean" }, diff --git a/cummin.json b/proposals/cummin.json similarity index 79% rename from cummin.json rename to proposals/cummin.json index fd20a92b..d84612e3 100644 --- a/cummin.json +++ b/proposals/cummin.json @@ -1,10 +1,11 @@ { "id": "cummin", "summary": "Cumulative minima", - "description": "Finds cumulative minima of an array of numbers. Every computed element is equal to the smaller one between current element and the previously computed element. The returned array and the input array have always the same length.\n\nBy default, no-data values are skipped, but stay in the result. Setting the `ignore_nodata` flag to `true` makes that once a no-data value / `null` is reached all following elements are set to `null` in the result.", + "description": "Finds cumulative minima of an array of numbers. Every computed element is equal to the smaller one between the current element and the previously computed element. The returned array and the input array have always the same length.\n\nBy default, no-data values are skipped, but stay in the result. Setting the `ignore_nodata` flag to `true` makes that once a no-data value (`null`) is reached all following elements are set to `null` in the result.", "categories": [ "math > cumulative" ], + "experimental": true, "parameters": [ { "name": "data", @@ -21,7 +22,7 @@ }, { "name": "ignore_nodata", - "description": "Indicates whether no-data values are ignored or not. Ignores them by default. Setting this flag to `false` considers no-data values so that `null` is set for all the following elements.", + "description": "Indicates whether no-data values are ignored or not and ignores them by default. Setting this flag to `false` considers no-data values so that `null` is set for all the following elements.", "schema": { "type": "boolean" }, diff --git a/cumproduct.json b/proposals/cumproduct.json similarity index 80% rename from cumproduct.json rename to proposals/cumproduct.json index cf135e2f..f5e6ae1b 100644 --- a/cumproduct.json +++ b/proposals/cumproduct.json @@ -1,10 +1,11 @@ { "id": "cumproduct", "summary": "Cumulative products", - "description": "Computes cumulative products of an array of numbers. Every computed element is equal to the product of current and all previous values. The returned array and the input array have always the same length.\n\nBy default, no-data values are skipped, but stay in the result. Setting the `ignore_nodata` flag to `true` makes that once a no-data value / `null` is reached all following elements are set to `null` in the result.", + "description": "Computes cumulative products of an array of numbers. Every computed element is equal to the product of the current and all previous values. The returned array and the input array have always the same length.\n\nBy default, no-data values are skipped, but stay in the result. Setting the `ignore_nodata` flag to `true` makes that once a no-data value (`null`) is reached all following elements are set to `null` in the result.", "categories": [ "math > cumulative" ], + "experimental": true, "parameters": [ { "name": "data", @@ -21,7 +22,7 @@ }, { "name": "ignore_nodata", - "description": "Indicates whether no-data values are ignored or not. Ignores them by default. Setting this flag to `false` considers no-data values so that `null` is set for all the following elements.", + "description": "Indicates whether no-data values are ignored or not and ignores them by default. Setting this flag to `false` considers no-data values so that `null` is set for all the following elements.", "schema": { "type": "boolean" }, diff --git a/cumsum.json b/proposals/cumsum.json similarity index 91% rename from cumsum.json rename to proposals/cumsum.json index 6ce6b10c..717999e5 100644 --- a/cumsum.json +++ b/proposals/cumsum.json @@ -1,10 +1,11 @@ { "id": "cumsum", "summary": "Cumulative sums", - "description": "Computes cumulative sums of an array of numbers. Every computed element is equal to the sum of current and all previous values. The returned array and the input array have always the same length.\n\nBy default, no-data values are skipped, but stay in the result. Setting the `ignore_nodata` flag to `true` makes that once a no-data value / `null` is reached all following elements are set to `null` in the result.", + "description": "Computes cumulative sums of an array of numbers. Every computed element is equal to the sum of current and all previous values. The returned array and the input array have always the same length.\n\nBy default, no-data values are skipped, but stay in the result. Setting the `ignore_nodata` flag to `true` makes that once a no-data value (`null`) is reached all following elements are set to `null` in the result.", "categories": [ "math > cumulative" ], + "experimental": true, "parameters": [ { "name": "data", @@ -21,7 +22,7 @@ }, { "name": "ignore_nodata", - "description": "Indicates whether no-data values are ignored or not. Ignores them by default. Setting this flag to `false` considers no-data values so that `null` is set for all the following elements.", + "description": "Indicates whether no-data values are ignored or not and ignores them by default. Setting this flag to `false` considers no-data values so that `null` is set for all the following elements.", "schema": { "type": "boolean" }, diff --git a/proposals/date_shift.json b/proposals/date_shift.json new file mode 100644 index 00000000..e9b6226b --- /dev/null +++ b/proposals/date_shift.json @@ -0,0 +1,136 @@ +{ + "id": "date_shift", + "summary": "Manipulates dates and times by addition or subtraction", + "description": "Based on a given date (and optionally time), calculates a new date (and time if given) by adding or subtracting a given temporal period.\n\nSome specifics about dates and times need to be taken into account:\n\n* This process doesn't have any effect on the time zone.\n* It doesn't take daylight saving time (DST) into account as only dates and time in UTC (with potential numerical time zone modifier) are supported.\n* Leap years are implemented in a way that computations handle them gracefully (see parameter `unit` for details).\n* Leap seconds are mostly ignored in manipulations as they don't follow a regular pattern. Leap seconds can be passed to the process, but will never be returned.", + "categories": [ + "date & time" + ], + "experimental": true, + "parameters": [ + { + "name": "date", + "description": "The date (and optionally time) to manipulate.\n\nIf the given date doesn't include the time, the process assumes that the time component is `00:00:00Z` (i.e. midnight, in UTC). The millisecond part of the time is optional and defaults to `0` if not given.", + "schema": [ + { + "type": "string", + "format": "date-time", + "subtype": "date-time" + }, + { + "type": "string", + "format": "date", + "subtype": "date" + } + ] + }, + { + "name": "value", + "description": "The period of time in the unit given that is added (positive numbers) or subtracted (negative numbers). The value `0` doesn't have any effect.", + "schema": { + "type": "integer" + } + }, + { + "name": "unit", + "description": "The unit for the value given. The following pre-defined units are available:\n\n- millisecond: Milliseconds\n- second: Seconds - leap seconds are ignored in computations.\n- minute: Minutes\n- hour: Hours\n- day: Days - changes only the the day part of a date\n- week: Weeks (equivalent to 7 days)\n- month: Months\n- year: Years\n\nManipulations with the unit `year`, `month`, `week` or `day` do never change the time. If any of the manipulations result in an invalid date or time, the corresponding part is rounded down to the next valid date or time respectively. For example, adding a month to `2020-01-31` would result in `2020-02-29`.", + "schema": { + "type": "string", + "enum": [ + "millisecond", + "second", + "minute", + "hour", + "day", + "week", + "month", + "year" + ] + } + } + ], + "returns": { + "description": "The manipulated date. If a time component was given in the parameter `date`, the time component is returned with the date.", + "schema": [ + { + "type": "string", + "format": "date-time", + "subtype": "date-time" + }, + { + "type": "string", + "format": "date", + "subtype": "date" + } + ] + }, + "examples": [ + { + "arguments": { + "date": "2020-02-01T17:22:45Z", + "value": 6, + "unit": "month" + }, + "returns": "2020-08-01T17:22:45Z" + }, + { + "arguments": { + "date": "2021-03-31T00:00:00+02:00", + "value": -7, + "unit": "day" + }, + "returns": "2021-03-24T00:00:00+02:00" + }, + { + "description": "Adding a year to February 29th in a leap year will result in February 28th in the next (non-leap) year.", + "arguments": { + "date": "2020-02-29T17:22:45Z", + "value": 1, + "unit": "year" + }, + "returns": "2021-02-28T17:22:45Z" + }, + { + "description": "Adding a month to January 31th will result in February 29th in leap years.", + "arguments": { + "date": "2020-01-31", + "value": 1, + "unit": "month" + }, + "returns": "2020-02-29" + }, + { + "description": "The process skips over the leap second `2016-12-31T23:59:60Z`.", + "arguments": { + "date": "2016-12-31T23:59:59Z", + "value": 1, + "unit": "second" + }, + "returns": "2017-01-01T00:00:00Z" + }, + { + "description": "Milliseconds can be added or subtracted. If not given, the default value is `0`.", + "arguments": { + "date": "2018-12-31T17:22:45Z", + "value": 1150, + "unit": "millisecond" + }, + "returns": "2018-12-31T17:22:46.150Z" + }, + { + "arguments": { + "date": "2018-01-01", + "value": 25, + "unit": "hour" + }, + "returns": "2018-01-02" + }, + { + "arguments": { + "date": "2018-01-01", + "value": -1, + "unit": "hour" + }, + "returns": "2017-12-31" + } + ] +} diff --git a/debug.json b/proposals/debug.json similarity index 92% rename from debug.json rename to proposals/debug.json index a6726a0c..cf902efd 100644 --- a/debug.json +++ b/proposals/debug.json @@ -5,6 +5,7 @@ "categories": [ "development" ], + "experimental": true, "parameters": [ { "name": "data", @@ -48,7 +49,7 @@ } ], "returns": { - "description": "Returns the data as passed to the `data` parameter.", + "description": "The data as passed to the `data` parameter without any modification.", "schema": { "description": "Any data type is allowed." } diff --git a/filter_labels.json b/proposals/filter_labels.json similarity index 85% rename from filter_labels.json rename to proposals/filter_labels.json index 54aefcbd..01d77035 100644 --- a/filter_labels.json +++ b/proposals/filter_labels.json @@ -6,6 +6,7 @@ "cubes", "filter" ], + "experimental": true, "parameters": [ { "name": "data", @@ -24,7 +25,7 @@ "parameters": [ { "name": "value", - "description": "A single dimension label to compare against. The data type of the parameter depends on the dimension labels stored for the dimension.", + "description": "A single dimension label to compare against. The data type of the parameter depends on the dimension labels set for the dimension.", "schema": [ { "type": "number" @@ -43,12 +44,18 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "`true` if the dimension label should be kept in the data cube, otherwise `false`.", + "schema": { + "type": "boolean" + } + } } }, { "name": "dimension", - "description": "The name of the dimension to filter on. Fails with a `DimensionNotAvailable` error if the specified dimension does not exist.", + "description": "The name of the dimension to filter on. Fails with a `DimensionNotAvailable` exception if the specified dimension does not exist.", "schema": { "type": "string" } @@ -100,5 +107,12 @@ "dimension": "platform" } } + ], + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#filter", + "rel": "about", + "title": "Filters explained in the openEO documentation" + } ] } \ No newline at end of file diff --git a/proposals/is_infinite.json b/proposals/is_infinite.json new file mode 100644 index 00000000..b6a5acca --- /dev/null +++ b/proposals/is_infinite.json @@ -0,0 +1,31 @@ +{ + "id": "is_infinite", + "summary": "Value is an infinite number", + "description": "Checks whether the specified value `x` is an infinite number. The definition of infinite numbers follows the [IEEE Standard 754](https://ieeexplore.ieee.org/document/4610935). The special numerical value `NaN` (not a number) as defined by the [IEEE Standard 754](https://ieeexplore.ieee.org/document/4610935) is not an infinite number and must return `false`.", + "categories": [ + "comparison" + ], + "experimental": true, + "parameters": [ + { + "name": "x", + "description": "The data to check.", + "schema": { + "description": "Any data type is allowed." + } + } + ], + "returns": { + "description": "`true` if the data is an infinite number, otherwise `false`.", + "schema": { + "type": "boolean" + } + }, + "links": [ + { + "rel": "about", + "href": "https://ieeexplore.ieee.org/document/4610935", + "title": "IEEE Standard 754-2008 for Floating-Point Arithmetic" + } + ] +} \ No newline at end of file diff --git a/load_result.json b/proposals/load_result.json similarity index 73% rename from load_result.json rename to proposals/load_result.json index c0377abe..ebc81718 100644 --- a/load_result.json +++ b/proposals/load_result.json @@ -1,11 +1,12 @@ { "id": "load_result", "summary": "Load batch job results", - "description": "Loads batch job results by job id from the local user workspace / data store. The job must have been stored by the authenticated user on the back-end currently connected to.", + "description": "Loads batch job results by job id from the server-side user workspace. The job must have been stored by the authenticated user on the back-end currently connected to.", "categories": [ "cubes", "import" ], + "experimental": true, "parameters": [ { "name": "id", diff --git a/load_uploaded_files.json b/proposals/load_uploaded_files.json similarity index 82% rename from load_uploaded_files.json rename to proposals/load_uploaded_files.json index bcd11c1d..bf811b4e 100644 --- a/load_uploaded_files.json +++ b/proposals/load_uploaded_files.json @@ -1,21 +1,23 @@ { "id": "load_uploaded_files", "summary": "Load files from the user workspace", - "description": "Loads one or more user-uploaded files from the local user workspace / data store and returns them as a single data cube. The files must have been stored by the authenticated user on the back-end currently connected to.", + "description": "Loads one or more user-uploaded files from the server-side workspace of the authenticated user and returns them as a single data cube. The files must have been stored by the authenticated user on the back-end currently connected to.", "categories": [ "cubes", "import" ], + "experimental": true, "parameters": [ { "name": "paths", - "description": "The files to read. Folders can't be specified, instead specify all files. An error is thrown if a file can't be read.", + "description": "The files to read. Folders can't be specified, specify all files instead. An exception is thrown if a file can't be read.", "schema": { "type": "array", "subtype": "file-paths", "items": { "type": "string", - "subtype": "file-path" + "subtype": "file-path", + "pattern": "^[^\r\n\\:'\"]+$" } } }, diff --git a/proposals/nan.json b/proposals/nan.json new file mode 100644 index 00000000..ae19dd6e --- /dev/null +++ b/proposals/nan.json @@ -0,0 +1,28 @@ +{ + "id": "nan", + "summary": "Not a Number (NaN)", + "description": "`NaN` (not a number) is a symbolic floating-point representation which is neither a signed infinity nor a finite number.", + "categories": [ + "math > constants" + ], + "experimental": true, + "parameters": [], + "returns": { + "description": "Returns `NaN`.", + "schema": { + "description": "JSON Schema can't represent `NaN` and thus a schema can't be specified." + } + }, + "links": [ + { + "rel": "about", + "href": "https://ieeexplore.ieee.org/document/4610935", + "title": "IEEE Standard 754-2008 for Floating-Point Arithmetic" + }, + { + "rel": "about", + "href": "http://mathworld.wolfram.com/NaN.html", + "title": "NaN explained by Wolfram MathWorld" + } + ] +} \ No newline at end of file diff --git a/proposals/reduce_spatial.json b/proposals/reduce_spatial.json new file mode 100644 index 00000000..d9a2fb56 --- /dev/null +++ b/proposals/reduce_spatial.json @@ -0,0 +1,79 @@ +{ + "id": "reduce_spatial", + "summary": "Reduce spatial dimensions 'x' and 'y'", + "description": "Applies a reducer to a data cube by collapsing all the pixel values along the horizontal spatial dimensions (i.e. axes `x` and `y`) into an output value computed by the reducer. The horizontal spatial dimensions are dropped.\n\nAn aggregation over certain spatial areas can be computed with the process ``aggregate_spatial()``.\n\nThis process passes a list of values to the reducer. The list of values has an undefined order, therefore processes such as ``last()`` and ``first()`` that depend on the order of the values will lead to unpredictable results.", + "categories": [ + "aggregate & resample", + "cubes", + "reducer" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "A data cube.", + "schema": { + "type": "object", + "subtype": "raster-cube" + } + }, + { + "name": "reducer", + "description": "A reducer to apply on the horizontal spatial dimensions. A reducer is a single process such as ``mean()`` or a set of processes, which computes a single value for a list of values, see the category 'reducer' for such processes.", + "schema": { + "type": "object", + "subtype": "process-graph", + "parameters": [ + { + "name": "data", + "description": "An array with elements of any type.", + "schema": { + "type": "array", + "items": { + "description": "Any data type." + } + } + }, + { + "name": "context", + "description": "Additional data passed by the user.", + "schema": { + "description": "Any data type." + }, + "optional": true, + "default": null + } + ], + "returns": { + "description": "The value to be set in the new data cube.", + "schema": { + "description": "Any data type." + } + } + } + }, + { + "name": "context", + "description": "Additional data to be passed to the reducer.", + "schema": { + "description": "Any data type." + }, + "optional": true, + "default": null + } + ], + "returns": { + "description": "A data cube with the newly computed values. It is missing the horizontal spatial dimensions, the number of dimensions decreases by two. The dimension properties (name, type, labels, reference system and resolution) for all other dimensions remain unchanged.", + "schema": { + "type": "object", + "subtype": "raster-cube" + } + }, + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#reduce", + "rel": "about", + "title": "Reducers explained in the openEO documentation" + } + ] +} \ No newline at end of file diff --git a/proposals/resample_cube_temporal.json b/proposals/resample_cube_temporal.json new file mode 100644 index 00000000..2bd38dde --- /dev/null +++ b/proposals/resample_cube_temporal.json @@ -0,0 +1,74 @@ +{ + "id": "resample_cube_temporal", + "summary": "Resample temporal dimensions to match a target data cube", + "description": "Resamples one or more given temporal dimensions from a source data cube to align with the corresponding dimensions of the given target data cube using the nearest neighbor method. Returns a new data cube with the resampled dimensions.\n\nBy default, this process simply takes the nearest neighbor independent of the value (including values such as no-data / `null`). Depending on the data cubes this may lead to values being assigned to two target timestamps. To only consider valid values in a specific range around the target timestamps, use the parameter `valid_within`.\n\nThe rare case of ties is resolved by choosing the earlier timestamps.", + "categories": [ + "cubes", + "aggregate & resample" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "A data cube with one or more temporal dimensions.", + "schema": { + "type": "object", + "subtype": "raster-cube" + } + }, + { + "name": "target", + "description": "A data cube that describes the temporal target resolution.", + "schema": { + "type": "object", + "subtype": "raster-cube" + } + }, + { + "name": "dimension", + "description": "The name of the temporal dimension to resample, which must exist with this name in both data cubes. If the dimension is not set or is set to `null`, the process resamples all temporal dimensions that exist with the same names in both data cubes.\n\nThe following exceptions may occur:\n\n* A dimension is given, but it does not exist in any of the data cubes: `DimensionNotAvailable`\n* A dimension is given, but one of them is not temporal: `DimensionMismatch`\n\n* No specific dimension name is given and there are no temporal dimensions with the same name in the data: `DimensionMismatch`", + "schema": { + "type": [ + "string", + "null" + ] + }, + "default": null, + "optional": true + }, + { + "name": "valid_within", + "description": "Setting this parameter to a numerical value enables that the process searches for valid values within the given period of days before and after the target timestamps. Valid values are determined based on the function ``is_valid()``. For example, the limit of `7` for the target timestamps `2020-01-15 12:00:00` looks for a nearest neighbor after `2020-01-08 12:00:00` and before `2020-01-22 12:00:00`. If no valid value is found within the given period, the value will be set to no-data (`null`).", + "schema": { + "type": [ + "number", + "null" + ] + }, + "default": null, + "optional": true + } + ], + "returns": { + "description": "A raster data cube with the same dimensions and the same dimension properties (name, type, labels, reference system and resolution) for all non-temporal dimensions. For the temporal dimension, the name and type remain unchanged, but the dimension labels, resolution and reference system may change.", + "schema": { + "type": "object", + "subtype": "raster-cube" + } + }, + "exceptions": { + "DimensionMismatch": { + "message": "The temporal dimensions for resampling don't match." + }, + "DimensionNotAvailable": { + "message": "A dimension with the specified name does not exist." + } + }, + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#resample", + "rel": "about", + "title": "Resampling explained in the openEO documentation" + } + ] +} \ No newline at end of file diff --git a/run_udf_externally.json b/proposals/run_udf_externally.json similarity index 76% rename from run_udf_externally.json rename to proposals/run_udf_externally.json index f52efcc1..521f7bef 100644 --- a/run_udf_externally.json +++ b/proposals/run_udf_externally.json @@ -1,7 +1,7 @@ { "id": "run_udf_externally", "summary": "Run an externally hosted UDF container", - "description": "Runs a compatible UDF container that is either externally hosted by a service provider or running on a local machine of the user. The UDF container must follow the [openEO UDF specification](https://openeo.org/documentation/1.0/udfs.html).\n\nThe referenced UDF service can be executed in several processes such as ``aggregate_spatial()``, ``apply()``, ``apply_dimension()`` and ``reduce_dimension()``. In this case an array is passed instead of a raster data cube. The user must ensure that the data is properly passed as an array so that the UDF can make sense of it.", + "description": "Runs a compatible UDF container that is either externally hosted by a service provider or running on a local machine of the user. The UDF container must follow the [openEO UDF specification](https://openeo.org/documentation/1.0/udfs.html).\n\nThe referenced UDF service can be executed in several processes such as ``aggregate_spatial()``, ``apply()``, ``apply_dimension()`` and ``reduce_dimension()``. In this case, an array is passed instead of a raster data cube. The user must ensure that the data is properly passed as an array so that the UDF can make sense of it.", "categories": [ "cubes", "import", @@ -11,7 +11,7 @@ "parameters": [ { "name": "data", - "description": "The data to be passed to the UDF as array or raster data cube.", + "description": "The data to be passed to the UDF as an array or raster data cube.", "schema": [ { "title": "Raster data cube", @@ -34,16 +34,17 @@ }, { "name": "url", - "description": "URL to a remote UDF service.", + "description": "Absolute URL to a remote UDF service.", "schema": { "type": "string", "format": "uri", - "subtype": "uri" + "subtype": "uri", + "pattern": "^(http|https)://" } }, { "name": "context", - "description": "Additional data such as configuration options that should be passed to the UDF.", + "description": "Additional data such as configuration options to be passed to the UDF.", "schema": { "type": "object" }, @@ -52,7 +53,7 @@ } ], "returns": { - "description": "The data processed by the UDF service.\n\n* Returns a raster data cube, if a raster data cube is passed for `data`. Details on the dimensions and dimension properties (name, type, labels, reference system and resolution) depend on the UDF.\n* If an array is passed for `data`, the returned value can be of any data type, but is exactly what the UDF returns.", + "description": "The data processed by the UDF service.\n\n* Returns a raster data cube if a raster data cube is passed for `data`. Details on the dimensions and dimension properties (name, type, labels, reference system and resolution) depend on the UDF.\n* If an array is passed for `data`, the returned value can be of any data type, but is exactly what the UDF returns.", "schema": [ { "title": "Raster data cube", diff --git a/proposals/sar_backscatter.json b/proposals/sar_backscatter.json new file mode 100644 index 00000000..07945438 --- /dev/null +++ b/proposals/sar_backscatter.json @@ -0,0 +1,136 @@ +{ + "id": "sar_backscatter", + "summary": "Computes backscatter from SAR input", + "description": "Computes backscatter from SAR input.\n\nNote that backscatter computation may require instrument specific metadata that is tightly coupled to the original SAR products. As a result, this process may only work in combination with loading data from specific collections, not with general data cubes.\n\nThis process uses bilinear interpolation, both for resampling the DEM and the backscatter.", + "categories": [ + "cubes", + "sar" + ], + "experimental": true, + "parameters": [ + { + "name": "data", + "description": "The source data cube containing SAR input.", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + { + "name": "coefficient", + "description": "Select the radiometric correction coefficient. The following options are available:\n\n* `beta0`: radar brightness\n* `sigma0-ellipsoid`: ground area computed with ellipsoid earth model\n* `sigma0-terrain`: ground area computed with terrain earth model\n* `gamma0-ellipsoid`: ground area computed with ellipsoid earth model in sensor line of sight\n* `gamma0-terrain`: ground area computed with terrain earth model in sensor line of sight (default)\n* `null`: non-normalized backscatter", + "optional": true, + "default": "gamma0-terrain", + "schema": [ + { + "type": "string", + "enum": [ + "beta0", + "sigma0-ellipsoid", + "sigma0-terrain", + "gamma0-ellipsoid", + "gamma0-terrain" + ] + }, + { + "title": "Non-normalized backscatter", + "type": "null" + } + ] + }, + { + "name": "elevation_model", + "description": "The digital elevation model to use. Set to `null` (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility.", + "optional": true, + "default": null, + "schema": [ + { + "type": "string", + "subtype": "collection-id" + }, + { + "type": "null" + } + ] + }, + { + "name": "mask", + "description": "If set to `true`, a data mask is added to the bands with the name `mask`. It indicates which values are valid (1), invalid (0) or contain no-data (null).", + "optional": true, + "default": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "contributing_area", + "description": "If set to `true`, a DEM-based local contributing area band named `contributing_area` is added. The values are given in square meters.", + "optional": true, + "default": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "local_incidence_angle", + "description": "If set to `true`, a DEM-based local incidence angle band named `local_incidence_angle` is added. The values are given in degrees.", + "optional": true, + "default": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "ellipsoid_incidence_angle", + "description": "If set to `true`, an ellipsoidal incidence angle band named `ellipsoid_incidence_angle` is added. The values are given in degrees.", + "optional": true, + "default": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "noise_removal", + "description": "If set to `false`, no noise removal is applied. Defaults to `true`, which removes noise.", + "optional": true, + "default": true, + "schema": { + "type": "boolean" + } + } + ], + "returns": { + "description": "Backscatter values corresponding to the chosen parametrization. The values are given in linear scale.", + "schema": { + "subtype": "raster-cube", + "type": "object" + } + }, + "exceptions": { + "DigitalElevationModelInvalid": { + "message": "The digital elevation model specified is either not a DEM or can't be used with the data cube given." + } + }, + "links": [ + { + "rel": "about", + "href": "https://bok.eo4geo.eu/PP2-2-4-3", + "title": "Gamma nought (0) explained by EO4GEO body of knowledge." + }, + { + "rel": "about", + "href": "https://bok.eo4geo.eu/PP2-2-4-2", + "title": "Sigma nought (0) explained by EO4GEO body of knowledge." + }, + { + "rel": "about", + "href": "https://www.geo.uzh.ch/microsite/rsl-documents/research/publications/peer-reviewed-articles/201108-TGRS-Small-tcGamma-3809999360/201108-TGRS-Small-tcGamma.pdf", + "title": "Flattening Gamma: Radiometric Terrain Correction for SAR Imagery" + }, + { + "rel": "about", + "href": "https://doi.org/10.3390/data4030093", + "title": "Reasoning behind the choice of bilinear resampling" + } + ] +} diff --git a/quantiles.json b/quantiles.json index 91b8756d..35079b86 100644 --- a/quantiles.json +++ b/quantiles.json @@ -1,7 +1,7 @@ { "id": "quantiles", "summary": "Quantiles", - "description": "Calculates quantiles, which are cut points dividing the range of a probability distribution into either\n\n* intervals corresponding to the given `probabilities` or\n* (nearly) equal-sized intervals (q-quantiles based on the parameter `q`).\n\nEither the parameter `probabilites` or `q` must be specified, otherwise the `QuantilesParameterMissing` exception is thrown. If both parameters are set the `QuantilesParameterConflict` exception is thrown.", + "description": "Calculates quantiles, which are cut points dividing the range of a probability distribution into either\n\n* intervals corresponding to the given `probabilities` or\n* (nearly) equal-sized intervals (q-quantiles based on the parameter `q`).\n\nEither the parameter `probabilities` or `q` must be specified, otherwise the `QuantilesParameterMissing` exception is thrown. If both parameters are set the `QuantilesParameterConflict` exception is thrown.", "categories": [ "math" ], @@ -34,7 +34,7 @@ }, { "name": "q", - "description": "A number of intervals to calculate quantiles for. Calculates q-quantiles with (nearly) equal-sized intervals.", + "description": "Intervals to calculate quantiles for. Calculates q-quantiles with (nearly) equal-sized intervals.", "schema": { "type": "integer", "minimum": 2 @@ -52,7 +52,7 @@ } ], "returns": { - "description": "An array with the computed quantiles. The list has either\n\n* as many elements as the given list of `probabilities` had or\n* *`q`-1* elements.\n\nIf the input array is empty the resulting array is filled with as many `null` values as required according to the list above. For an example, see the 'Empty array example'.", + "description": "An array with the computed quantiles. The list has either\n\n* as many elements as the given list of `probabilities` had or\n* *`q`-1* elements.\n\nIf the input array is empty the resulting array is filled with as many `null` values as required according to the list above. See the 'Empty array' example for an example.", "schema": { "type": "array", "items": { @@ -65,10 +65,10 @@ }, "exceptions": { "QuantilesParameterMissing": { - "message": "The process 'quantiles' requires either the 'probabilities' or 'q' parameter to be set." + "message": "The process `quantiles` requires either the `probabilities` or `q` parameter to be set." }, "QuantilesParameterConflict": { - "message": "The process 'quantiles' only allows that either the 'probabilities' or the 'q' parameter is set." + "message": "The process `quantiles` only allows that either the `probabilities` or the `q` parameter is set." } }, "examples": [ @@ -154,7 +154,7 @@ ] }, { - "title": "Empty array example", + "title": "Empty array", "arguments": { "data": [], "probabilities": [ diff --git a/reduce_dimension.json b/reduce_dimension.json index f8e79e81..27ed34de 100644 --- a/reduce_dimension.json +++ b/reduce_dimension.json @@ -1,7 +1,7 @@ { "id": "reduce_dimension", "summary": "Reduce dimensions", - "description": "Applies a unary reducer to a data cube dimension by collapsing all the pixel values along the specified dimension into an output value computed by the reducer. This process passes a list of values to the reducer. In contrast, ``reduce_dimension_binary()`` passes two values, which may be better suited especially for UDFs in case the number of values gets too large to be processed at once.\n\nThe dimension is dropped. To avoid this, use ``apply_dimension()`` instead.", + "description": "Applies a reducer to a data cube dimension by collapsing all the pixel values along the specified dimension into an output value computed by the reducer.\n\nThe dimension is dropped. To avoid this, use ``apply_dimension()`` instead.", "categories": [ "cubes", "reducer" @@ -42,12 +42,18 @@ "optional": true, "default": null } - ] + ], + "returns": { + "description": "The value to be set in the new data cube.", + "schema": { + "description": "Any data type." + } + } } }, { "name": "dimension", - "description": "The name of the dimension over which to reduce. Fails with a `DimensionNotAvailable` error if the specified dimension does not exist.", + "description": "The name of the dimension over which to reduce. Fails with a `DimensionNotAvailable` exception if the specified dimension does not exist.", "schema": { "type": "string" } @@ -73,5 +79,12 @@ "DimensionNotAvailable": { "message": "A dimension with the specified name does not exist." } - } + }, + "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#reduce", + "rel": "about", + "title": "Reducers explained in the openEO documentation" + } + ] } \ No newline at end of file diff --git a/reduce_dimension_binary.json b/reduce_dimension_binary.json deleted file mode 100644 index 31b5c583..00000000 --- a/reduce_dimension_binary.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "id": "reduce_dimension_binary", - "summary": "Reduce dimensions using binary reduction", - "description": "Applies a binary reducer to a data cube dimension by collapsing all the pixel values along the specified dimension into an output value computed by the reducer. This process consecutively passes a pair of values to the reducer. This may be better suited especially for UDFs in case the number of values gets too large to be processed at once. In contrast, ``reduce_dimension()`` passes a list of values.\n\nThe dimension is dropped. To avoid this, use ``apply_dimension()`` instead.", - "categories": [ - "cubes", - "reducer" - ], - "experimental": true, - "parameters": [ - { - "name": "data", - "description": "A data cube.", - "schema": { - "type": "object", - "subtype": "raster-cube" - } - }, - { - "name": "reducer", - "description": "A reduction operator to be applied consecutively on pairs of values. It must be both associative and commutative as the execution may be executed in parallel and therefore the order of execution is arbitrary. The reduction operator may be a single process such as ``multiply()`` or consist of multiple sub-processes.", - "schema": { - "type": "object", - "subtype": "process-graph", - "parameters": [ - { - "name": "x", - "description": "The first value.", - "schema": { - "description": "Any data type." - } - }, - { - "name": "y", - "description": "The second value.", - "schema": { - "description": "Any data type." - } - }, - { - "name": "context", - "description": "Additional data passed by the user.", - "schema": { - "description": "Any data type." - }, - "optional": true, - "default": null - } - ] - } - }, - { - "name": "dimension", - "description": "The name of the dimension over which to reduce. Fails with a `DimensionNotAvailable` error if the specified dimension does not exist.", - "schema": { - "type": "string" - } - }, - { - "name": "context", - "description": "Additional data to be passed to the reducer.", - "schema": { - "description": "Any data type." - }, - "optional": true, - "default": null - } - ], - "returns": { - "description": "A data cube with the newly computed values. It is missing the given dimension, the number of dimensions decreases by one. The dimension properties (name, type, labels, reference system and resolution) for all other dimensions remain unchanged.", - "schema": { - "type": "object", - "subtype": "raster-cube" - } - }, - "exceptions": { - "DimensionNotAvailable": { - "message": "A dimension with the specified name does not exist." - } - }, - "links": [ - { - "rel": "about", - "href": "https://en.wikipedia.org/wiki/Reduction_Operator", - "title": "Background information on reduction operators (binary reducers) by Wikipedia" - } - ] -} \ No newline at end of file diff --git a/rename_dimension.json b/rename_dimension.json index 6de0e3c2..15c46410 100644 --- a/rename_dimension.json +++ b/rename_dimension.json @@ -16,14 +16,14 @@ }, { "name": "source", - "description": "The current name of the dimension. Fails with a `DimensionNotAvailable` error if the specified dimension does not exist.", + "description": "The current name of the dimension. Fails with a `DimensionNotAvailable` exception if the specified dimension does not exist.", "schema": { "type": "string" } }, { "name": "target", - "description": "A new Name for the dimension. Fails with a `DimensionExists` error if a dimension with the specified name exists.", + "description": "A new Name for the dimension. Fails with a `DimensionExists` exception if a dimension with the specified name exists.", "schema": { "type": "string" } diff --git a/rename_labels.json b/rename_labels.json index 37b7522f..6ed32f6f 100644 --- a/rename_labels.json +++ b/rename_labels.json @@ -1,7 +1,7 @@ { "id": "rename_labels", "summary": "Rename dimension labels", - "description": "Renames the labels of the specified dimension in the data cube from `source` to `target`.\n\nIf the array for the source labels is empty (the default), the dimension labels are expected to be enumerated with zero-based numbering (0,1,2,3,...) so that the dimension labels directly map to the indices of the array specified for the parameter `target`. If the dimension labels are not enumerated and the `target` parameter is not specified, a `LabelsNotEnumerated` is thrown. The number of source and target labels must be equal, otherwise the error `LabelMismatch` is thrown.\n\nThis process doesn't change the order of the labels and their corresponding data.", + "description": "Renames the labels of the specified dimension in the data cube from `source` to `target`.\n\nIf the array for the source labels is empty (the default), the dimension labels are expected to be enumerated with zero-based numbering (0,1,2,3,...) so that the dimension labels directly map to the indices of the array specified for the parameter `target`. If the dimension labels are not enumerated and the `target` parameter is not specified, the `LabelsNotEnumerated` exception is thrown. The number of the source and target labels must be equal. Otherwise, the exception `LabelMismatch` is thrown.\n\nThis process doesn't change the order of the labels and their corresponding data.", "categories": [ "cubes" ], @@ -23,34 +23,26 @@ }, { "name": "target", - "description": "The new names for the labels. The dimension labels in the data cube are expected to be enumerated, if the parameter `target` is not specified. If a target dimension label already exists in the data cube, a `LabelExists` error is thrown.", + "description": "The new names for the labels. The dimension labels in the data cube are expected to be enumerated if the parameter `target` is not specified. If a target dimension label already exists in the data cube, a `LabelExists` exception is thrown.", "schema": { "type": "array", "items": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } + "type": [ + "number", + "string" ] } } }, { "name": "source", - "description": "The names of the labels as they are currently in the data cube. The array defines an unsorted and potentially incomplete list of labels that should be renamed to the names available in the corresponding array elements in the parameter `target`. If one of the source dimension labels doesn't exist, a `LabelNotAvailable` error is thrown. By default, the array is empty so that the dimension labels in the data cube are expected to be enumerated.", + "description": "The names of the labels as they are currently in the data cube. The array defines an unsorted and potentially incomplete list of labels that should be renamed to the names available in the corresponding array elements in the parameter `target`. If one of the source dimension labels doesn't exist, the `LabelNotAvailable` exception is thrown. By default, the array is empty so that the dimension labels in the data cube are expected to be enumerated.", "schema": { "type": "array", "items": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } + "type": [ + "number", + "string" ] } }, @@ -105,7 +97,7 @@ { "rel": "example", "type": "application/json", - "href": "https://processes.openeo.org/1.0.0/examples/rename-enumerated-labels.json", + "href": "https://processes.openeo.org/1.1.0/examples/rename-enumerated-labels.json", "title": "Rename enumerated labels" } ] diff --git a/resample_cube_spatial.json b/resample_cube_spatial.json index d35a127f..54a5f801 100644 --- a/resample_cube_spatial.json +++ b/resample_cube_spatial.json @@ -25,22 +25,24 @@ }, { "name": "method", - "description": "Resampling method. Methods are inspired by GDAL, see [gdalwarp](https://www.gdal.org/gdalwarp.html) for more information.", + "description": "Resampling method to use. The following options are available and are meant to align with [`gdalwarp`](https://gdal.org/programs/gdalwarp.html#cmdoption-gdalwarp-r):\n\n* `average`: average (mean) resampling, computes the weighted average of all valid pixels\n* `bilinear`: bilinear resampling\n* `cubic`: cubic resampling\n* `cubicspline`: cubic spline resampling\n* `lanczos`: Lanczos windowed sinc resampling\n* `max`: maximum resampling, selects the maximum value from all valid pixels\n* `med`: median resampling, selects the median value of all valid pixels\n* `min`: minimum resampling, selects the minimum value from all valid pixels\n* `mode`: mode resampling, selects the value which appears most often of all the sampled points\n* `near`: nearest neighbour resampling (default)\n* `q1`: first quartile resampling, selects the first quartile value of all valid pixels\n* `q3`: third quartile resampling, selects the third quartile value of all valid pixels\n* `rms` root mean square (quadratic mean) of all valid pixels\n* `sum`: compute the weighted sum of all valid pixels\n\nValid pixels are determined based on the function ``is_valid()``.", "schema": { "type": "string", "enum": [ - "near", + "average", "bilinear", "cubic", "cubicspline", "lanczos", - "average", - "mode", "max", - "min", "med", + "min", + "mode", + "near", "q1", - "q3" + "q3", + "rms", + "sum" ] }, "default": "near", @@ -56,9 +58,9 @@ }, "links": [ { - "href": "https://openeo.org/documentation/1.0/glossary.html#resample-changing-data-cube-geometry", + "href": "https://openeo.org/documentation/1.0/datacubes.html#resample", "rel": "about", - "title": "Resampling explained in the openEO glossary" + "title": "Resampling explained in the openEO documentation" } ] } diff --git a/resample_cube_temporal.json b/resample_cube_temporal.json deleted file mode 100644 index d31e31c9..00000000 --- a/resample_cube_temporal.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "id": "resample_cube_temporal", - "summary": "Resample a temporal dimension to match a target data cube", - "description": "Resamples the given temporal dimension from a source data cube to align with the corresponding dimension of the given target data cube. Returns a new data cube with the resampled dimension.\n\nIf the dimension is not set or is set to `null`, the data cube is expected to have one temporal dimension only.", - "categories": [ - "cubes", - "aggregate & resample" - ], - "parameters": [ - { - "name": "data", - "description": "A data cube.", - "schema": { - "type": "object", - "subtype": "raster-cube" - } - }, - { - "name": "target", - "description": "A data cube that describes the temporal target resolution.", - "schema": { - "type": "object", - "subtype": "raster-cube" - } - }, - { - "name": "method", - "description": "A resampling method to be applied, could be a reducer for downsampling or other methods for upsampling. A reducer is a single process such as ``mean()`` or a set of processes, which computes a single value for a list of values, see the category 'reducer' for such processes.", - "schema": { - "type": "object", - "subtype": "process-graph", - "parameters": [ - { - "name": "data", - "description": "A labeled array with elements of any type.", - "schema": { - "type": "array", - "subtype": "labeled-array", - "items": { - "description": "Any data type." - } - } - }, - { - "name": "context", - "description": "Additional data passed by the user.", - "schema": { - "description": "Any data type." - }, - "optional": true, - "default": null - } - ] - } - }, - { - "name": "dimension", - "description": "The name of the temporal dimension to resample, which must exist with this name in both data cubes. If the dimension is not set or is set to `null`, the data cube is expected to only have one temporal dimension. Fails with a `TooManyDimensions` error if it has more dimensions. Fails with a `DimensionNotAvailable` error if the specified dimension does not exist.", - "schema": { - "type": [ - "string", - "null" - ] - }, - "default": null, - "optional": true - }, - { - "name": "context", - "description": "Additional data to be passed to the process specified for the parameter `method`.", - "schema": { - "description": "Any data type." - }, - "optional": true, - "default": null - } - ], - "returns": { - "description": "A raster data cube with the same dimensions and the same dimension properties (name, type, labels, reference system and resolution) for all non-temporal dimensions. For the temporal dimension the name and type remain unchanged, but the reference system changes and the labels and resolution may change.", - "schema": { - "type": "object", - "subtype": "raster-cube" - } - }, - "exceptions": { - "TooManyDimensions": { - "message": "The number of temporal dimensions must be reduced to one for 'resample_cube_temporal'." - }, - "DimensionNotAvailable": { - "message": "A dimension with the specified name does not exist." - } - }, - "links": [ - { - "href": "https://openeo.org/documentation/1.0/glossary.html#resample-changing-data-cube-geometry", - "rel": "about", - "title": "Resampling explained in the openEO glossary" - } - ] -} \ No newline at end of file diff --git a/resample_spatial.json b/resample_spatial.json index 29c53fd2..91d6bc5f 100644 --- a/resample_spatial.json +++ b/resample_spatial.json @@ -20,7 +20,7 @@ "description": "Resamples the data cube to the target resolution, which can be specified either as separate values for x and y or as a single value for both axes. Specified in the units of the target projection. Doesn't change the resolution by default (`0`).", "schema": [ { - "description": "A single number used as resolution for both x and y.", + "description": "A single number used as the resolution for both x and y.", "type": "number", "minimum": 0 }, @@ -72,22 +72,24 @@ }, { "name": "method", - "description": "Resampling method. Methods are inspired by GDAL, see [gdalwarp](https://www.gdal.org/gdalwarp.html) for more information.", + "description": "Resampling method to use. The following options are available and are meant to align with [`gdalwarp`](https://gdal.org/programs/gdalwarp.html#cmdoption-gdalwarp-r):\n\n* `average`: average (mean) resampling, computes the weighted average of all valid pixels\n* `bilinear`: bilinear resampling\n* `cubic`: cubic resampling\n* `cubicspline`: cubic spline resampling\n* `lanczos`: Lanczos windowed sinc resampling\n* `max`: maximum resampling, selects the maximum value from all valid pixels\n* `med`: median resampling, selects the median value of all valid pixels\n* `min`: minimum resampling, selects the minimum value from all valid pixels\n* `mode`: mode resampling, selects the value which appears most often of all the sampled points\n* `near`: nearest neighbour resampling (default)\n* `q1`: first quartile resampling, selects the first quartile value of all valid pixels\n* `q3`: third quartile resampling, selects the third quartile value of all valid pixels\n* `rms` root mean square (quadratic mean) of all valid pixels\n* `sum`: compute the weighted sum of all valid pixels\n\nValid pixels are determined based on the function ``is_valid()``.", "schema": { "type": "string", "enum": [ - "near", + "average", "bilinear", "cubic", "cubicspline", "lanczos", - "average", - "mode", "max", - "min", "med", + "min", + "mode", + "near", "q1", - "q3" + "q3", + "rms", + "sum" ] }, "default": "near", @@ -117,6 +119,11 @@ } }, "links": [ + { + "href": "https://openeo.org/documentation/1.0/datacubes.html#resample", + "rel": "about", + "title": "Resampling explained in the openEO documentation" + }, { "rel": "about", "href": "https://proj.org/usage/projections.html", @@ -131,6 +138,11 @@ "rel": "about", "href": "http://www.epsg.io", "title": "Unofficial EPSG code database" + }, + { + "href": "https://gdal.org/programs/gdalwarp.html#cmdoption-gdalwarp-r", + "rel": "about", + "title": "gdalwarp resampling methods" } ] } \ No newline at end of file diff --git a/round.json b/round.json index 1b95a444..dbdd1323 100644 --- a/round.json +++ b/round.json @@ -1,7 +1,7 @@ { "id": "round", "summary": "Round to a specified precision", - "description": "Rounds a real number `x` to specified precision `p`.\n\nIf the fractional part of `x` is halfway between two integers, one of which is even and the other odd, then the even number is returned.\nThis behaviour follows [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229). This kind of rounding is also called \"round to nearest (even)\" or \"banker's rounding\". It minimizes rounding errors that result from consistently rounding a midpoint value in a single direction.\n\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Rounds a real number `x` to specified precision `p`.\n\nIf the fractional part of `x` is halfway between two integers, one of which is even and the other odd, then the even number is returned.\nThis behavior follows [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229). This kind of rounding is also called \"round to nearest (even)\" or \"banker's rounding\". It minimizes rounding errors that result from consistently rounding a midpoint value in a single direction.\n\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math > rounding" ], diff --git a/run_udf.json b/run_udf.json index 43a933f8..3586f06c 100644 --- a/run_udf.json +++ b/run_udf.json @@ -1,7 +1,7 @@ { "id": "run_udf", - "summary": "Run an UDF", - "description": "Runs an UDF in one of the supported runtime environments.\n\nThe process can either:\n\n1. load and run a locally stored UDF from a file in the workspace of the authenticated user. The path to the UDF file must be relative to the root directory of the user's workspace.\n2. fetch and run a remotely stored and published UDF by absolute URI, for example from [openEO Hub](https://hub.openeo.org)).\n3. run the source code specified inline as string.\n\nThe loaded UDF can be executed in several processes such as ``aggregate_spatial()``, ``apply()``, ``apply_dimension()`` and ``reduce_dimension()``. In this case an array is passed instead of a raster data cube. The user must ensure that the data is properly passed as an array so that the UDF can make sense of it.", + "summary": "Run a UDF", + "description": "Runs a UDF in one of the supported runtime environments.\n\nThe process can either:\n\n1. load and run a UDF stored in a file on the server-side workspace of the authenticated user. The path to the UDF file must be relative to the root directory of the user's workspace.\n2. fetch and run a remotely stored and published UDF by absolute URI.\n3. run the source code specified inline as string.\n\nThe loaded UDF can be executed in several processes such as ``aggregate_spatial()``, ``apply()``, ``apply_dimension()`` and ``reduce_dimension()``. In this case, an array is passed instead of a raster data cube. The user must ensure that the data is properly passed as an array so that the UDF can make sense of it.", "categories": [ "cubes", "import", @@ -10,7 +10,7 @@ "parameters": [ { "name": "data", - "description": "The data to be passed to the UDF as array or raster data cube.", + "description": "The data to be passed to the UDF as an array or raster data cube.", "schema": [ { "title": "Raster data cube", @@ -33,29 +33,32 @@ }, { "name": "udf", - "description": "Either source code, an absolute URL or a path to an UDF script.", + "description": "Either source code, an absolute URL or a path to a UDF script.", "schema": [ { - "description": "URI to an UDF", + "description": "Absolute URL to a UDF", "type": "string", "format": "uri", - "subtype": "uri" + "subtype": "uri", + "pattern": "^(http|https)://" }, { - "description": "Path to an UDF uploaded to the server.", + "description": "Path to a UDF uploaded to the server.", "type": "string", - "subtype": "file-path" + "subtype": "file-path", + "pattern": "^[^\r\n\\:'\"]+$" }, { - "description": "Source code as string", + "description": "The multi-line source code of a UDF, must contain a newline/line-break.", "type": "string", - "subtype": "udf-code" + "subtype": "udf-code", + "pattern": "(\r\n|\r|\n)" } ] }, { "name": "runtime", - "description": "An UDF runtime identifier available at the back-end.", + "description": "A UDF runtime identifier available at the back-end.", "schema": { "type": "string", "subtype": "udf-runtime" @@ -79,7 +82,7 @@ }, { "name": "context", - "description": "Additional data such as configuration options that should be passed to the UDF.", + "description": "Additional data such as configuration options to be passed to the UDF.", "schema": { "type": "object" }, diff --git a/save_result.json b/save_result.json index 2dbffeb9..72ecfaae 100644 --- a/save_result.json +++ b/save_result.json @@ -1,7 +1,7 @@ { "id": "save_result", "summary": "Save processed data to storage", - "description": "Saves processed data to the local user workspace / data store of the authenticated user. This process aims to be compatible to GDAL/OGR formats and options. STAC-compatible metadata should be stored with the processed data.\n\nCalling this process may be rejected by back-ends in the context of secondary web services.", + "description": "Saves processed data to the server-side user workspace of the authenticated user. This process aims to be compatible with GDAL/OGR formats and options. STAC-compatible metadata should be stored with the processed data.\n\nCalling this process may be rejected by back-ends in the context of secondary web services.", "categories": [ "cubes", "export" diff --git a/sort.json b/sort.json index ff510a90..14e56e9d 100644 --- a/sort.json +++ b/sort.json @@ -1,7 +1,7 @@ { "id": "sort", "summary": "Sort data", - "description": "Sorts an array into ascending (default) or descending order.\n\n**Remarks:**\n\n* Ties will be left in their original ordering.\n* Temporal strings can *not* be compared based on their string representation due to the time zone / time-offset representations.", + "description": "Sorts an array into ascending (default) or descending order.\n\n**Remarks:**\n\n* Ties will be left in their original ordering.\n* Temporal strings can *not* be compared based on their string representation due to the time zone/time-offset representations.", "categories": [ "arrays", "sorting" @@ -50,7 +50,7 @@ }, { "name": "nodata", - "description": "Controls the handling of no-data values (`null`). By default they are removed. If `true`, missing values in the data are put last; if `false`, they are put first.", + "description": "Controls the handling of no-data values (`null`). By default, they are removed. If set to `true`, missing values in the data are put last; if set to `false`, they are put first.", "schema": { "type": [ "boolean", diff --git a/sqrt.json b/sqrt.json index 99762bb3..bc1aeb6c 100644 --- a/sqrt.json +++ b/sqrt.json @@ -1,7 +1,7 @@ { "id": "sqrt", "summary": "Square root", - "description": "Computes the square root of a real number `x`, which is equal to calculating `x` to the power of *0.5*.\n\nA square root of x is a number a such that *a^2^ = x*. Therefore, the square root is the inverse function of a to the power of 2, but only for *a >= 0*.\n\nThe no-data value `null` is passed through and therefore gets propagated.", + "description": "Computes the square root of a real number `x`, which is equal to calculating `x` to the power of *0.5*.\n\nA square root of x is a number a such that *`a² = x`*. Therefore, the square root is the inverse function of a to the power of 2, but only for *a >= 0*.\n\nThe no-data value `null` is passed through and therefore gets propagated.", "categories": [ "math", "math > exponential & logarithmic" diff --git a/subtract.json b/subtract.json index 5f8f8d0c..2cf8aba7 100644 --- a/subtract.json +++ b/subtract.json @@ -1,7 +1,7 @@ { "id": "subtract", "summary": "Subtraction of two numbers", - "description": "Subtracts argument `y` from the argument `x` (*x - y*) and returns the computed result.\n\nNo-data values are taken into account so that `null` is returned if any element is such a value.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it.", + "description": "Subtracts argument `y` from the argument `x` (*`x - y`*) and returns the computed result.\n\nNo-data values are taken into account so that `null` is returned if any element is such a value.\n\nThe computations follow [IEEE Standard 754](https://ieeexplore.ieee.org/document/8766229) whenever the processing environment supports it.", "categories": [ "math" ], diff --git a/tests/.words b/tests/.words index 67f19cb4..b9fe6130 100644 --- a/tests/.words +++ b/tests/.words @@ -1,39 +1,39 @@ +0-to-9 +1-to-0 +anno +behavior boolean -MathWorld -openEO -signum +center +centers +dekad +DEM-based +Domini +gamma0 GeoJSON +labeled +MathWorld n-ary -unary -STAC -band1 -band2 -Resample +neighbor +neighborhood +neighborhoods +openEO +orthorectification +orthorectified +radiometrically +reflectances resample -Resamples -resamples -Resampled resampled -Resampling +resamples +Resamples resampling -nir -common_names -gdalwarp -center -UDFs -summand -inputMin -inputMax -outputMin -outputMax Sentinel-2 Sentinel-2A Sentinel-2B -labeled -centers -spatiotemporal -0-to-9 -1-to-0 -Anno -Domini -dekad \ No newline at end of file +signum +STAC +summand +UDFs +gdalwarp +Lanczos +sinc +interpolants diff --git a/tests/docs.html b/tests/docs.html index dafd2273..d7ba767c 100644 --- a/tests/docs.html +++ b/tests/docs.html @@ -113,8 +113,9 @@ props: { document: 'processes.json', categorize: true, - apiVersion: '1.0.0', - title: 'openEO processes (1.0.0)' + apiVersion: '1.1.0', + title: 'openEO processes (1.1.0)', + notice: '**Note:** This is the list of all processes specified by the openEO project. Back-ends implement a varying set of processes. Thus, the processes you can use at a specific back-end may derive from the specification, may include non-standardized processes and may not implement all processes listed here. Please check each back-end individually for the processes they support. The client libraries usually have a function called `listProcesses` or `list_processes` for that.' } }) }); diff --git a/tests/package.json b/tests/package.json index d9cab1cb..c2137589 100644 --- a/tests/package.json +++ b/tests/package.json @@ -19,18 +19,18 @@ }, "devDependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.6", - "@openeo/js-processgraphs": "^1.0.0-beta.3", - "ajv": "^6.10.2", + "@openeo/js-processgraphs": "^1.0.0", + "ajv": "^6.12.4", "concat-json-files": "^1.1.0", "glob": "^7.1.6", "http-server": "^0.12.3", - "jest": "^24.9.0", + "jest": "^26.4.2", "markdown-spellcheck": "^1.3.1", "markdownlint": "^0.18.0" }, "scripts": { "test": "jest", - "generate": "concat-json-files \"../*.json\" -t \"processes.json\"", + "generate": "concat-json-files \"../{*,proposals/*}.json\" -t \"processes.json\"", "render": "npm run generate && http-server -p 9876 -o docs.html -c-1" } } diff --git a/tests/processes.test.js b/tests/processes.test.js index 40a60cf7..089328f9 100644 --- a/tests/processes.test.js +++ b/tests/processes.test.js @@ -13,24 +13,30 @@ beforeAll(async () => { jsv = await getAjv(); }); -var processes = []; -const files = glob.sync("../*.json", {realpath: true}); -files.forEach(file => { +var loader = (file, proposal = false) => { try { var fileContent = fs.readFileSync(file); // Check JSON structure for faults var p = JSON.parse(fileContent); // Prepare for tests - processes.push([file, p, fileContent.toString()]); + processes.push([file, p, fileContent.toString(), proposal]); } catch(err) { - processes.push([file, {}, ""]); + processes.push([file, {}, "", proposal]); console.error(err); expect(err).toBeUndefined(); } -}); +}; + +var processes = []; + +const files = glob.sync("../*.json", {realpath: true}); +files.forEach(file => loader(file)); + +const proposals = glob.sync("../proposals/*.json", {realpath: true}); +proposals.forEach(file => loader(file, true)); -describe.each(processes)("%s", (file, p, fileContent) => { +describe.each(processes)("%s", (file, p, fileContent, proposal) => { test("File / JSON", () => { const ext = path.extname(file); @@ -77,7 +83,7 @@ describe.each(processes)("%s", (file, p, fileContent) => { }); test("Flags", () => { - checkFlags(p); + checkFlags(p, proposal); }); test("Parameters", () => { @@ -97,11 +103,14 @@ describe.each(processes)("%s", (file, p, fileContent) => { // return value description expect(typeof p.returns.description).toBe('string'); + // lint: Description should not be empty + expect(p.returns.description.length).toBeGreaterThan(0); checkDescription(p.returns.description, p); // return value schema expect(typeof p.returns.schema).toBe('object'); expect(p.returns.schema).not.toBeNull(); + // lint: Description should not be empty checkJsonSchema(jsv, p.returns.schema); }); @@ -204,15 +213,20 @@ describe.each(processes)("%s", (file, p, fileContent) => { } }); -function checkFlags(p) { +function checkFlags(p, proposal = false) { // deprecated expect(typeof p.deprecated === 'undefined' || typeof p.deprecated === 'boolean').toBeTruthy(); // lint: don't specify defaults expect(typeof p.deprecated === 'undefined' || p.deprecated === true).toBeTruthy(); - // experimental - expect(typeof p.experimental === 'undefined' || typeof p.experimental === 'boolean').toBeTruthy(); - // lint: don't specify defaults - expect(typeof p.experimental === 'undefined' || p.experimental === true).toBeTruthy(); + if (proposal) { + // experimental must be true for proposals + expect(p.experimental).toBe(true); + } + else { + // experimental must not be false for stable + // lint: don't specify defaults, so false should not be set explicitly + expect(p.experimental).toBeUndefined(); + } } function checkParam(param, p, checkCbParams = true) { @@ -222,6 +236,8 @@ function checkParam(param, p, checkCbParams = true) { // parameter description expect(typeof param.description).toBe('string'); + // lint: Description should not be empty + expect(param.description.length).toBeGreaterThan(0); checkDescription(param.description, p); // Parameter flags diff --git a/tests/testHelpers.js b/tests/testHelpers.js index ef57ca47..385d0449 100644 --- a/tests/testHelpers.js +++ b/tests/testHelpers.js @@ -27,7 +27,7 @@ for(let i in words) { spellcheck.spellcheck.addWord(words[i]); } // Add the process IDs to the word list -const files = glob.sync("../*.json", {realpath: true}); +const files = glob.sync("../{*,proposals/*}.json", {realpath: true}); for(let i in files) { spellcheck.spellcheck.addWord(path.basename(files[i], path.extname(files[i]))); } diff --git a/text_merge.json b/text_merge.json index e65f49c7..ff6e07c2 100644 --- a/text_merge.json +++ b/text_merge.json @@ -1,7 +1,7 @@ { "id": "text_merge", - "summary": "Concatenate elements to a string", - "description": "Merges string representations of a set of elements together to a single string, with the separator between each element.", + "summary": "Concatenate elements to a single text", + "description": "Merges text representations (also known as *string*) of a set of elements to a single text, having the separator between each element.", "categories": [ "texts" ], @@ -37,7 +37,7 @@ } ], "returns": { - "description": "Returns a string containing a string representation of all the array elements in the same order, with the separator between each element.", + "description": "A string containing a string representation of all the array elements in the same order, with the separator between each element.", "schema": { "type": "string" }